## [Unreleased]

## [2.43.3] - 2026-05-17 (May 2026)

FIXED:
- Style Curator (and any GetAllCatalog consumer: Coverage, House Editor catalog
  reads, Preview row builders) no longer renders empty after a warm-load where
  the persisted catalog was dropped on clientVer drift or never persisted at
  all. WarmCollectionCache previously gated only on ownedSearchDone, so once
  LoadOwnedSet restored the owned-decorID set but left _catalogReady=false,
  nothing in the addon kicked another sweep -- the catalog stayed empty until
  the user hit the Refresh button. Now WarmCollectionCache requires BOTH
  ownedSearchDone AND _catalogReady for the fast-path return; if the owned
  set is warm but the catalog is empty, it kicks RunOwnedSearch to refill,
  honouring the "sweep refills" comment in LoadOwnedSet that was previously
  a no-op. Self-heals on next window open without a Refresh click.
- Goblin tab Queued / Hide Queued checkboxes silently never matched anything.
  The queue-rollup pass keyed lookups on q.id / q.spell, but the rest of the
  codebase migrated those fields to q.itemID / q.spellID back in v2.43.0.
  Re-keyed; the queue filters now see queue contents again.

ADDED:
- TSM price source supports DBMarket as a third option alongside Server
  (DBMinBuyout) and Region (DBRegionSaleAvg). Pick via the new Server /
  Region / Market dropdown on the Goblin tab; only visible when TSM is the
  active price source. Old two-radio toggle replaced.

CHANGED:
- Goblin tab filter chrome now content-fits actual text width. Dropdowns,
  checkboxes, and the price source toggle re-measure on OnShow and shrink
  to fit, instead of reserving the old fixed 120-145px slots. Filter
  checkbox labels shortened to Known / All Known / Auctions / Queued /
  Hide Queued so more chips fit per row.

DATA:
- "High Tides" Ren, "Len" Splinthoof, and "Yen" Malone (the rotating
  Founder's Point and Razorwind Shores vendors) now correctly tagged as
  Midnight expansion in VendorDB. Five vendor rows total.

## [2.43.2] - 2026-05-13 (May 2026)

FIXED:
- MultiHouse widget no longer throws ADDON_ACTION_BLOCKED on
  Frame:EnableMouse when refreshed from a cross-addon-tainted call
  stack. The card parent picks up protected-frame status from its
  SecureActionButtonTemplate child (tpBtn). EnableMouse and SetAttribute
  calls in the Bind() block run through pcall guards (gated by
  not InCombatLockdown()) so the rare contamination case is absorbed
  silently; routine binds succeed normally. Reported by pxspin
  2026-05-12.
- VendorPin world-map pool: pin release now calls SetToDefaults() (Tier-2
  pattern from Blizzard's Pools.lua) to clear any inherited Secret state
  before the pin is re-acquired. Prevents the "one secret object
  contaminates the whole pool" scenario that bit VPP on the same day.
  See Reference/MIDNIGHT_SECRET_VALUES.md.
- VendorResolver NPC-name probes (4 sites): replaced pcall taint guards
  around UnitGUID+strsplit and C_TooltipInfo.GetHyperlink+leftText with
  explicit issecretvalue() / canaccessvalue() value-level checks. More
  declarative about the secret-handling invariant. Probes 1 and 2 (target
  / npc unit lookup) now also pre-check C_Secrets.ShouldUnitIdentityBeSecret
  -- added in 12.0.1.66838 -- so we skip the whole probe when Blizzard
  already knows the result will be secret.
- MultiHouse teleport button: SetAttribute block now also pre-checks
  tpBtn:HasSecretAspect("Attributes") before writing. If the button has
  already been marked with the Attributes Secret Aspect by a prior
  tainted SetAttribute (cross-addon contamination), further writes would
  compound the issue; we skip cleanly and the next Refresh re-attempts
  after the aspect clears. Defense in depth with the existing pcall.
- "Reset Configuration" now actually resets font, scale, theme, and the
  other appearance/behaviour preferences. The v2.41 SavedVariables
  flatten moved these keys from HDG_DB.config.* to HDG_DB.* (top level),
  but the reset handler was still only nil'ing the old nested block —
  so users stuck with a bad font (e.g. CJK client with FRIZQT__ chosen,
  showing glyph-fallback boxes for item names) couldn't escape by
  resetting. Reset now wipes every top-level config key as well.

## [2.43.1] (Released May 2026)

FIXED:
- Ctrl-click on the Goblin tab no longer silently drops items. The tab
  was still constructing queue records with the pre-rename field names
  (`id` / `spell`) and dict-form reagents, so MakeQueueItem bailed
  before dispatching. Field names now match the canonical shape
  (`itemID` / `spellID`) and reagent normalization moved into
  MakeQueueItem so any caller's shape flows through correctly. Fixes
  the "chat says added, queue empty" bug reported on 2.43.0.
- Shift-click in the Materials list popout (the per-reagent recipe
  list) now actually adds the chosen recipe to the queue. Same
  root cause: BuildReagentIndex was emitting recipeEntries with
  `id` / `spell` instead of `itemID` / `spellID`.
- Add-to-queue paths from the Vendor Shopping List, Acquisition tab,
  Decor Preview tab, and Styles item panel now produce queue items
  with correctly-shaped reagent data. Previously they passed
  DecorDB-shaped (dict-form) reagents straight through, so the items
  appeared in the queue but the queue panel's per-reagent readiness
  display was blank. MakeQueueItem now normalizes both shapes.
- "Add to Crafting Queue" from the Styles tab item panel now also
  refreshes the Materials panel rollup. StyleEngine:GetRecipe was
  returning the raw ProfessionsDB row (uses `slots`, not `reagents`,
  and no `spellID`), so the queue entry had nil reagents and the
  Materials panel couldn't aggregate it. The lookup now goes through
  the canonical DecorDB recipe cache.
- Materials list per-reagent recipe popout: the row tooltip threw
  a SetItemByID error because it was reading the pre-rename `id`
  field. Updated to read `itemID`.

## [2.43.0] (Released May 2026)

User-facing additions to the HouseEditor companion plus a heavy
internal-hygiene pass. Smoke-tested across all queue-add paths,
Acquisition + Recipes filters, post-/reload state restoration, and
the new HouseEditor strip + filter controls.

* HouseEditor companion: header search box (under the title) filters
  the grid by item name across whatever view is currently selected.
  Persists across mode switches; Esc clears; clear-X button to the
  right of the box clears on click.

* HouseEditor companion: indoor/outdoor filter button (cycles
  Indoor + Outdoor / Indoor only / Outdoor only) right of the
  placement-cost icon. Filters the visible grid by each item's
  catalog isAllowedIndoors / isAllowedOutdoors fields.

* HouseEditor companion: per-cell placement-cost badge in the
  bottom-left of every grid card, using the same budget-icon atlas
  as the Decor Preview detail panel. Toggle on/off via the icon to
  the right of the title; greyed out when off.

* HouseEditor companion: cards for items with 0 copies in storage
  (everything you own is already placed) are now greyed out + slightly
  desaturated, so "you own this but cannot place another" is visible
  at a glance.

* HouseEditor companion: "By Placement Cost" virtual collections
  appear at the bottom of the Collections sidebar -- Small (1-2),
  Medium (3-4), Large (5), X-Large (6+). Click any bucket to see all
  decor in that cost range. Header rows in Themes and Collections
  also picked up an underline for cleaner section divides.

* HouseEditor companion: "Recent placements" strip across the bottom
  shows your last 8 placed items. Newest enters from the right; older
  shifts left as new placements come in. Reuses the same card chrome
  as the main grid (tooltips, badges, dye markers all work). Refreshes
  live as placements happen in the editor.

* HouseEditor companion: window background is now opaque (chat /
  world no longer bleed through behind the chest atlas).

* Acquisition tab: collapsible Advanced Filters panel + preset
  buttons. Reduces visual noise on the left filter row and gives
  one-click access to common filter combos.

* Fix: crafting-queue items now persist their `profession` field through
  the Store on insert. Previously HDG_PowerCrafting.MakeQueueItem set
  it but Store:AddToCraftingQueue dropped it on the way to
  SavedVariables, so post-/reload `GetCharactersWhoKnowRecipe(spellID,
  profession)` calls passed nil and crafter-grouping in the queue
  picked from any profession that knew the spell instead of the
  recipe's actual profession. Row icons recovered via the itemID
  fallback so this was visible-only after a reload, but the grouping
  was less precise. Single-line fix at HDG_Store.lua:725.

* Refactor: crafting-queue mutations now have a single canonical
  refresh path instead of two. Previously every Add/Remove/Update/
  Clear dispatched through Store -> EventBus (which refreshed
  QueuePanel + MaterialsPanel) AND then explicitly called
  HDG_UI.RefreshUI() (which refreshed QueuePanel + MaterialsPanel
  again, plus RecipesTab). The materials aggregation is the
  expensive bit -- it walks the whole queue summing reagents -- so
  the duplication was meaningful per click. EventBus is now
  authoritative: it refreshes queue + materials + recipes (added
  recipe refresh so in-queue badges still update); the post-dispatch
  HDG_UI.RefreshUI() calls were dropped from
  HDG_RecipesTab:AddToCraftingQueue and the four queue-mutation
  paths in HDG_QueuePanel (remove, shift-remove, decrement, clear).
  Expand/collapse paths in QueuePanel still call RefreshUI directly
  -- they don't dispatch and so don't trip the EventBus.

* Refactor: HDG_AcquisitionTab:SelectItem split into a small
  orchestrator + three mode-specific helpers. Was a 75-line
  if/elseif/else with three branches that each repeated the same
  4-line detailPanel anchor reset, the same UpdateHeaderPanel call,
  and (for the crafted/non-vendor cases) the same vendor-state
  clear + waypoint/map hide + cell release. Now SelectItem owns
  the shared prelude (selectedItemID, headerPanel/detailPanel show,
  detailPanel anchor reset), data probe (vendors / hasVendors /
  isCrafted), single dispatch (vendor wins over crafted, matching
  original priority), and shared postlude (UpdateHeaderPanel,
  UpdateNoteDisplay, vendor-note widgets, cart buttons,
  UpdatePreviewModel, UpdateRowHighlights). The three new methods
  -- :SelectVendorItem, :SelectCraftedItem, :SelectNonVendorItem --
  each own only the work that actually differs by mode. ~30 lines
  of duplication gone; behaviour preserved.

* Refactor: same surgery on the Acquisition tab. HDG_AcqData.filters
  was a public mutable table on a "data" module that the Acquisition
  UI mutated directly (HDG_AcqData.filters.search = val,
  .zone = val, .source = val etc.) -- worse smell than the Recipes
  side because there weren't even setter wrappers; the UI just grabbed
  the table and wrote to it. HDG_AcqData.sortMode same shape.
  Both now live as module-locals (acqFilters, acqSortMode) on
  HDG_AcquisitionTab where they belong. HDG_AcqData's three filter
  consumers (RebuildFilteredItems, RebuildFilteredVendors,
  ItemPassesFilters) take filters as a parameter -- pure data-layer
  logic, no shared mutable globals. Signatures changed:
    RebuildFilteredItems(CONFIG)   -> RebuildFilteredItems(filters, sortMode)
    RebuildFilteredVendors(CONFIG) -> RebuildFilteredVendors(filters)
    ItemPassesFilters(itemID, CONFIG) -> ItemPassesFilters(itemID, filters)
  CONFIG was dead in all three after the itemFacts refactor (used to
  feed BuildSourceMatchers which is now data-driven). Behavior
  preserved -- filters still session-only, reset on /reload, same
  defaults. ~30 mutation sites in HDG_AcquisitionTab updated;
  external API surface (BuildCaches still takes CONFIG) unchanged.

* Refactor: pulled recipe filter state out of HDG_Data and wired
  consumers to read Store directly. The 14 thin filter accessors
  in HDG_Data (GetSearchFilter / IsUncollectedFilterEnabled /
  IsCraftableFilterEnabled / IsKnownFilterEnabled / Get/SetExpansion
  Filter / IsSearchReagentsEnabled / Get/SetProfessionFilter and
  their Set* siblings) were zero-abstraction passthroughs to
  HDG.Store:GetConfig / Dispatch -- they didn't validate, transform,
  log, or hide anything; they just relocated the call into a "data"
  module that has nothing to do with UI filter state. Side-effect:
  RecipeMatchesFilters used to read those globals plus a module-local
  `recipeSearchFilter` that lived in HDG_Data only because the Edit
  Box and the matcher happened to share the file. The matcher now
  takes a filterContext (search / searchReagents / uncollectedOnly /
  expansion / knownOnly); HDG_RecipesTab owns the search-box state as
  its own module-local + a BuildFilterContext() helper that pulls the
  rest from Store. HDG.Store gets two new methods --
  GetCharacterProfessionFilter() / SetCharacterProfessionFilter() --
  that hide the per-character key lookup so callers don't duplicate
  HDG_Data.GetCharacterKey() + nil-guard chains. Net: HDG_Data shrank
  by ~14 functions + the `recipeSearchFilter` local + two unused
  GetConfig/GetUIState helpers; data-layer logic is now pure (takes
  filter state as parameter); state ownership is unambiguous (Store
  for persisted toggles, RecipesTab for transient search text).
  Sets up future HDG_Data domain split with no cross-module filter
  entanglement to untangle.

* Perf: scoped style-cache invalidation. The EventBus handler at
  the bottom of HDG_StyleEngine.lua used to call
  InvalidateCache() (full nuke -- vocab, facetStore, reverseIndex,
  every per-style bucket) on every HDG_COLLECTION_UPSERTED /
  DELETED / DECOR_ADDED / DECOR_REMOVED / FIELD_CHANGED event with
  payload.type == "style". So adding a single decor to a single
  curated style burned ~237ms (60ms steps 1-6 + 177ms step 7) on
  the next StylesTab:Show even though steps 1-6 don't depend on
  style definitions at all and ~99% of the per-style buckets were
  untouched. Now: derive the styleId from payload.collID
  ("style:..." -> "...") and dispatch to the existing scoped
  helpers -- InvalidateCustomStyle for mutations (rebuilds just
  that style's bucket + clears its compatCache slice),
  RemoveCustomStyle for deletes. Steps 1-6 stay valid forever
  (until /reload), the other ~100 styles' buckets stay built,
  next Show is instant. Guarded with `if not cacheBuilt then
  return end` so events fired before the first StylesTab open
  are no-ops (BuildCache picks up fresh state on first show
  anyway via RebuildAllStyleDefs).

* Perf: per-refresh memoization for HDG_Data.IsItemCollected on
  the Acquisition rebuild path. Item collection state is volatile
  (changes on collect events) so it can't go in itemFacts, but
  within a single RefreshList cycle it's called multiple times
  per item: ItemPassesFilters (when uncollectedOnly is on),
  RebuildFilteredItems' filteredUncollectedCount walk,
  RebuildFilteredVendors' per-vendor counters (an item sold by
  N vendors used to do N live calls), and pushItem's
  uncollectedCount in RefreshVendorList. Cache is wiped at the
  top of each Rebuild* call so each refresh sees fresh state;
  downstream consumers in the same cycle hit warm cache.
  Tooltip path (HDG_AcqRows row 668) intentionally left on the
  live API -- hover-time should reflect current state.
  HDG_AcqData.IsCollectedCached / ResetCollectedCache are the
  helpers; cache is private to HDG_AcqData.

* Perf: ItemPassesFilters reduced to mostly indexed reads. New
  HDG_AcqData.itemFacts table populated by BuildItemFacts (called
  at the end of BuildCaches) precomputes per-item static flags
  that don't change during a session: hasVendor, isCrafted,
  hasSource, isDyeable, releasedOK, srcType/altSrcType, and the
  per-source-category booleans (isAchievement / isQuest / isDrop
  / isTreasure / isPromotional / isShop / isReputation /
  isEndeavor / isGoldOnly). The rewritten ItemPassesFilters reads
  flags from the cache for everything except the inherently
  dynamic checks (IsItemCollected, search match, vendor-side
  expansion/zone/faction match -- those depend on filter values
  so can't be pre-baked). The rewritten SOURCE_MATCHERS each
  collapse to `function(f) return f.isX end`. The biggest wins:
  Reputation / Endeavor / Gold Only source filters were doing a
  per-item npcID walk on every call; releasedOnly was doing a
  per-item zero-cost vendor walk on every call; both are now
  single boolean reads. Trade-off: BuildItemFacts adds a one-time
  pass at BuildCaches time. Names that haven't loaded by that
  point fall through the legacy "Unreleased / Loading..."
  heuristic at snapshot time, which means new releases between
  patches don't update releasedOK until /reload -- accepted
  because retail item-release cadence is patch-day, not daily.
  Measured before/after on retail with 1676 items in scope:
  vendor mode RebuildFilteredVendors dropped 30-50%
  (full-scope 2.86 -> 1.76ms; heavy-filter 1.5-2.0 -> 0.6-0.75ms).

* Perf: vendor-mode RefreshList no longer double-filters every
  item. Was running both RebuildFilteredItems (full universe-wide
  pass: ItemPassesFilters * allItems + a sort) AND
  RebuildFilteredVendors (which already runs ItemPassesFilters on
  every item-per-vendor and populates vendorFilteredItems) on
  every keystroke / filter toggle / search update in vendor mode.
  Vendor mode now skips the universe-wide pass and derives the
  status-bar / header item count from a post-loop distinct walk
  over vendorFilteredItems (set as HDG_AcqData.filteredItemCount).
  By Item mode is unchanged. Map All button now calls
  RebuildFilteredItems(CONFIG) on click to keep its waypoint
  iteration correct in vendor mode where filteredItems is now
  intentionally stale -- one-time cost on a rare click. Added
  Acq.Rebuild.FilteredVendors to HDG_Debug.Timed for before/after
  measurement of this change and an upcoming itemFacts precompute
  refactor.

* Refactor: code-smell sweep prompted by the 2.42.1 reagent-quantity bug.
  Renamed in-memory recipe objects' `id`/`spell` fields to `itemID`/`spellID`
  for readability (~40 sites). Renamed crafting-queue payload fields to
  match (`{id, spell}` -> `{itemID, spellID}`) with a one-shot SavedVars
  migration on load -- existing queued items are rewritten in place,
  no data loss. Stripped dead `or 1` and `or mat.total` fallbacks that
  were hiding bugs behind silent defaults. Consolidated six queue-item
  builder sites (Recipes, Mogul, Acquire, Preview, Vendor List, Styles)
  through a single `HDG_PowerCrafting.MakeQueueItem` helper. Mogul tests
  rewritten to match new field names; 28/28 still green.

* Refactor: HousingDecorGuide.lua slimmed from 1806 to ~370 lines (-79%).
  Per-domain Blizzard event hooks now live in their owning modules'
  `RegisterEvents()` on their own event frames instead of being routed
  through one giant OnEvent dispatcher in the main file:
    - shopping-list `BuyMerchantItem` decrement -> HDG_VendorShoppingList
    - mail/merchant/bank/trade UI suspend + lumber achievement + logout
      session save + PEW lumber init -> HDG_LumberTracker
    - tooltip "Housing Decor reagent" tag -> HDG_PowerCrafting
    - crafting queue auto-decrement on craft -> HDG_PowerCrafting
    - profession-cache invalidation + recipe-learn UI refresh + craft
      acquisition log -> HDG_Data
    - HOUSING_STORAGE_ENTRY_UPDATED repaint + QueueInventoryUpdate +
      QueueRecipeUpdate fan-outs -> HDG_UI
    - HOUSE_DECOR_ADDED_TO_CHEST log + housing-achievement display
      refresh -> HDG_DataTab
    - chattiness-gated talking-head craft quote + counter -> HDG_Vamoose
    - ZONE_CHANGED_NEW_AREA: main file debounces and broadcasts
      HDG_ZONE_CHANGED on the bus; LumberTracker, LumberHUD, and
      ZoneMode subscribe themselves
  Main file now only handles lifecycle/coordination events
  (ADDON_LOADED bootstrap, PEW login-restore, BAG_UPDATE inventory
  fan-out, PLAYER_LOGOUT Store flush) and orchestrator init calls.

* Refactor: slash command cleanup. /hdg is the user-facing slash
  exclusively; all 12 dev/diagnostic commands (collection, featuredtest,
  costtest, tsm, debuglumber, debugprof, exportreagents, testquote,
  scantags (was tags), order, plus /lumberhud test/show/testdist
  aliases) live exclusively on /hdgdebug now. Bodies fully extracted
  from main file into HDG_Debug.lua; no delegation. /hdg help banner
  added listing user commands. /hdgdebug exportreagents reuses the
  existing HDG_Debug copy-window infrastructure -- the bespoke 50-line
  popup frame and three associated globals (HDG_ExportReagents,
  HDG_ShowExportWindow, HDG_ReagentExportFrame) are gone.

* Refactor: privateDB.pendingCraftInfo (multi-craft tracking, used by
  RecipesTab when initiating a craft and by HDG_PowerCrafting's queue
  auto-decrement when crafts complete) initialised in HDG_PowerCrafting
  instead of the main file. Dead duplicate _runtime.pendingCraftInfo
  removed from the Store state defaults.

* Refactor: dead bridge functions HDG:RefreshUI, HDG:RefreshCraftingQueue,
  HDG:RefreshMaterials, HDG:RefreshLumberTracking, HDG:Toggle removed.
  Zero internal callers; aspirational "for legacy macros" comment.
  Macro authors should bind /hdg or /click an addon button instead.

* Refactor: HDG_RecipesTab.lua slimmed from 3876 to 1109 lines (-71%).
  Four self-contained chunks lifted out into their own modules; what
  remains is the recipe list (left column), the lifecycle methods
  (Init/Create/Refresh/Show/Hide) and the EventBus glue:
    - UI/Tabs/HDG_CraftDialog.lua (282 lines) -- the [Craft] button's
      confirmation modal (frame creation + Show/Execute). Internal
      caller updated to privateDB.HDG_CraftDialog.Show; no third-party
      hooks exist so the old HDG_RecipesTab.ShowCraftConfirmation /
      .ExecuteCraft surface was deleted, not aliased.
    - UI/Tabs/HDG_ProfessionSidebar.lua (380 lines) -- left rail of the
      Recipes tab: expansion-filter dropdown, "All Professions" button,
      per-profession buttons with collection + recipes-known badges +
      open-prof-window icon. Was HDG_RecipesTab:RefreshProfessionTabs
      and the local EnsureProfessionTabFrames; now exposes Init(frame)
      + Refresh(). HDG_UI.RefreshProfessionTabs delegates to the new
      module instead of RecipesTab.
    - UI/Tabs/HDG_QueuePanel.lua (917 lines) -- middle column of the
      Recipes tab: queue ScrollBox + char-grouping + expand/collapse
      subsidiary recipes + the embedded Lumber widget at the bottom of
      the panel. Was HDG_RecipesTab:CreateQueuePanel +
      :RefreshCraftingQueue + ~580 lines of element kinds, binders,
      DataProvider push helpers, plus several queue-only locals
      (OpenRecipeAndThen, IsPSLAvailable, GetQueueItemColor,
      GetProfessionForItem, expandedQueueItems,
      pendingTooltipRebuilds + GET_ITEM_INFO_RECEIVED listener,
      SUB_INDENT/SUB_HEIGHT). Exposes Init(frame), Create(), Refresh().
      HDG_UI.RefreshCraftingQueue delegates to the new module; the
      EventBus HDG_STATE_CHANGED handler that fans out queue refreshes
      now calls privateDB.HDG_QueuePanel.Refresh() directly.
    - UI/Tabs/HDG_MaterialsPanel.lua (1217 lines) -- right column of
      the Recipes tab: materials ScrollBox + Totals/By-Recipe sort
      toggle + Direct/Raw mode toggle + cost rollup + "Add All to
      Auctionator" CTA. Was HDG_RecipesTab:CreateMaterialsPanel +
      :RefreshMaterials + :AddAllMaterialsToAuctionator + 7 binders
      + 3 push helpers + the orphan UpdateCostDisplay local. Exposes
      Init(frame), Create(), Refresh(), AddAllToAuctionator().
      HDG_UI.RefreshMaterials and HDG_UI.AddAllMaterialsToAuctionator
      delegate to the new module. Stripping these helper sites also
      surfaced four genuinely-dead locals in HDG_RecipesTab
      (GetConfig, GetUIState, GetCraftingQueue, GetRecipeByItemID --
      now read only by the new sub-panels) which were removed.

* Refactor: helper de-duplication across the recipes-tab modules.
  CreatePanelHeader (the 22px textured strip + title FontString) was
  copy-pasted in three sub-panels after the split; lifted into
  HDG_UIHelpers.CreatePanelHeader and the three local copies removed
  (~90 lines of pure duplication gone). Three new read accessors on
  HDG.Store (:GetConfig, :GetUIState, :GetCraftingQueue) replace the
  hand-rolled "state and state.config and state.config[key]" walks
  that every UI module had been duplicating; combined with calling
  HDG.Store:Dispatch directly, the four recipes-tab modules dropped
  ~70 more lines of boilerplate Get/Set wrappers. CraftDialog: 282 ->
  269. QueuePanel: 917 -> 874. MaterialsPanel: 1217 -> 1166.
  RecipesTab: 1109 -> 1064. ConfigTab/DataTab/MogulTab finished in
  the same style: wrapper preambles dropped, callers use HDG.Store
  directly (-54 more lines, -2 unused-local lints).

* Refactor: new HDG_UIHelpers.CreateAtlasButton(parent, atlasBase,
  size, opts) factory for the "frame + Normal/Pushed/Disabled atlas"
  pattern that recurs ~30 times across the UI. Auto-suffixes the
  Pressed and Disabled variants from atlasBase by default; opts let
  callers override per-button. Retrofitted across the UI:
  DecorPreviewTab destroy/minus/plus buttons, VendorShoppingList
  cart-plus/cart-minus, TrainersTab + AchievementSection collapse
  arrows, ZoneMode gear + clear-X icons, AcquisitionTab vendor + item
  note pencils. Sites that don't fit (bind-time atlas swaps, custom
  suffix conventions like HouseTab's -default/-active, or icons whose
  Normal atlas is set later) left inline.

* Refactor: materials-panel toggles now use the canonical
  HDG_UIHelpers.CreateFilterButton / UpdateFilterButtonState helpers
  instead of inline backdrop+text-color juggling. Affects the Sort
  Mode (Totals / By Recipe) chip and the Direct / Raw mode chip-pair.
  Two side benefits: the active/inactive state colours now match
  every other filter chip in the addon (was using bespoke
  button_hover/panel + accent-border instead of the addon-wide
  button_active/button_inactive theme tokens), and the panel shed
  another ~56 lines (1166 -> 1110) of inline frame setup.

* Memory: feedback_no_defensive_or_cascades.md sharpened with
  Vamoose's directive "things set to 1 hide bugs" -- default to no
  `or N` defaults at internal boundaries; only keep them at genuine
  external boundaries (WoW API returns, optional user config).

## [2.42.1] (Released May 2026) -- "Materials counts + Faarden vendor data"

* Data: Faarden the Builder (Founder's Point) was missing 9 items in
  HDG_VendorDB. Faarden and "Len" Splinthoof at Razorwind Shores are
  paired vendors selling the same 35-item Stormwind line; the original
  scrape stopped at 26. Added: Sturdy Wooden Chair, Sturdy Wooden Bench,
  Reinforced Wooden Chest, Carved Wooden Bar Table, Large Covered Wooden
  Table, Carved Wooden Crate, Wooden Chamberstick, Large Sturdy Wooden
  Table, Tall Sturdy Wooden Chair. Verified against Wowhead.

* Fix: Required Materials list and recipe tooltip showed every reagent
  as 0/1 when adding from the Recipes tab (and other non-Mogul paths).
  Two reagent producers had drifted to different field names (`amount`
  vs `qty`) and the consumers only read `qty`, so non-Mogul queue items
  silently fell back to 1 of each. HDG_Data.InitializeDatabase now
  emits the canonical `qty` field.

* Fix: Acquire tab 3D previews could remain stuck on "Preview unavailable"
  on cold login if the housing catalog landed after HDG had already been
  opened. The HDG_COLLECTION_READY listener was rebuilding the row list
  but not re-running SelectItem, so the right-side preview model and
  "Also sells" gallery were left bound to the pre-catalog (nil) state.
  Listener now re-selects the current item with a forced gallery rebuild.

## [2.42.0] (Released May 2026) -- "Mogul Supply Impact + UX polish"

* Mogul tab -- Supply Impact: three-way mode toggle (Off / Smooth / Cap)
  controlling how the planner accounts for market saturation when the
  same recipe stacks. Off keeps the original "stack the highest-margin
  recipe" behaviour. Smooth applies a per-unit decay so each successive
  craft of the same recipe is worth less in the ranking, diversifying
  the plan on its own (default 7%). Cap is a hard ceiling per recipe;
  freed lumber redistributes to runners-up (default 10). Each mode has
  an inline editable value; changes apply 0.5s after typing settles, or
  immediately on Enter. Cap is implemented as a per-recipe upper-bound
  constraint in both the greedy and LP planners. Smooth's per-unit
  decay is non-linear so the LP planner falls back to greedy in that
  mode (LP button greys out with an explanatory tooltip line).

* Mogul tab -- House tab Velocity widget: counts only Learned entries
  from acquisition history. Previously a 65-craft Banded Barrel session
  read as 65 collection events when the collection only grew by 1.
  The number now reflects actual collection growth and House XP rate.

* Mogul tab -- layout: BEST PLAN heading replaced with the Supply
  Impact selector. Revenue and Net profit now share one line, anchored
  just above the column header strip. Crafts and lumber-used moved
  into the Plan section header line ("Plan -- N crafts, M lumber
  used"). Hairline divider under the toolbar separates controls from
  data. Cap-limited indicator appears on the lumber summary when a cap
  binds and lumber would otherwise go unspent.

* Mogul tab -- mats panel header: "MATS TO BUY" renamed to "Reagents
  to buy for complete plan". Selecting a single recipe row updates
  the header to "Reagents to buy for <recipe name>".

* Mogul tab -- "I'll buy mats from AH" checkbox replaced with a pill
  toggle matching the rest of the toolbar. "Planner:" label prefixes
  the Greedy/LP pair so the row reads as a single labelled group.
  Both hide in Collection mode (where they don't apply).

* Mogul tab -- Collection mode replaces the Supply Impact row with a
  title-styled "Best use of lumber for uncollected, crafted decor."

* Mogul tab -- icon swapped to Mobile-TreasureIcon (saturated when
  active, desaturated when not).

* Acquire tab -- "Group by zone" toggle removed; alphabetical sort is
  the only mode.

## [2.41.0] (Released May 2026) -- "Mogul tab + storage migration"

* House Editor: HDG no longer touches Blizzard's HouseEditorStoragePanel
  at all. Two attempts to inject a tab there (v2.39.0 and a 2026-05-08
  retry) both crashed Blizzard's Catalog tab via productInfo-nil races
  introduced in the 12.0.5 patch -- any participation in the storage
  panel's tab dispatch was sufficient to trigger the bug, even with no
  callbacks or catalog API calls of our own. Replaced with a small
  launcher button (HDG icon, anchored to UIParent's left edge by
  default, draggable) shown only while the housing editor is open;
  click to toggle the standalone HDG editor window. Zero AddNamedTab,
  zero SetTabCallback, zero hooksecurefunc, zero HookScript on any
  Blizzard panel.

* Mogul tab polish (2026-05-08): fix locale lookup so all UI strings
  resolve (was rendering raw keys like "MOGUL_HEADER_BEST_PLAN"); column
  layout (Qty / Crafter / Recipe / Lumber-each / gold-per-lumber /
  Revenue-Net / Expansion) with bordered + tinted header strip matching
  the scrollbox width below; in-list section dividers ("Plan -- craft
  these" / "Runners-up -- did not fit") with full-width accent
  underlines; vertical theme-accent bar on each plan row to mark active
  plan vs runner-ups; sortable plan rows (revenue desc) so greedy and LP
  outputs align row-for-row when they pick the same plan; click a row
  again to deselect (mats panel returns to plan-wide list); selection
  survives refresh when the same recipe is still picked; mats panel
  migrated to WowScrollBoxList (was clipping past ~6 entries with the
  flat anchor chain); mat rows are have/need StatusBars colored by
  progress (red/amber/green) with hover tooltips and AH-search /
  Auctionator-multi-search / Auctionator-list click handlers ported
  from MaterialsList; Send to Auctionator button moved to the action
  row alongside Send-entire-plan and Hide-runners-up so all primary
  actions sit in one strip; lumber budget panel at top-right of the
  frame replaces the single "Lumber: N" readout, showing all 12 tiers
  in two columns colored by expansion, with leftover-after-plan as
  "have - used [arrow] remaining" and green numbers on tiers the plan
  used; "Lumber-only / Lumber + mats" two-button toggle replaced with a
  single "I'll buy mats from AH" checkbox plus an explainer tooltip
  ("checked = rank by net profit including AH cost of mats you don't
  own; unchecked = rank by gross revenue, treats mats as free; owned
  mats are always free in the spend math regardless of mode");
  Greedy/LP buttons are blizz UIPanelButtonTemplate with auto-sized
  width and tooltips explaining the algorithm choice; "Hide candidates"
  renamed to "Hide runners-up" (and Show too) to match the section
  divider; mat cost shown in collection-mode summary so the player sees
  the gold required for non-owned reagents; collected/uncollected icon
  and expansion-color background tint on every plan row; row hover
  shows item tooltip + per-mat have/need + bestAlt; "Best on: <Alt>"
  moved from inline name suffix to its own Crafter column with subtle
  gold-accent text; the Crafter column shows the active player's name
  in active-char view too so the column is meaningful in both modes.

* Mogul algorithm: shipped an LP-relaxation alternative to the greedy
  planner. New modules/HDG_MogulLP.lua: pure-Lua tableau simplex with
  Bland's rule (cycle-safe), solves max profit s.t. per-tier lumber
  budgets, rounds down to integer crafts, then greedy-fills any
  leftover; collection mode delegates back to greedy. Greedy/LP toggle
  on the Mogul header lets players A/B compare. On typical single-tier
  housing-recipe data the two algorithms produce identical plans (LP
  relaxation collapses to the per-lumber greedy result); LP can win on
  contrived multi-tier or shared-mat scenarios. 6 LP tests covering
  empty input, single-tier parity with greedy, per-tier budget respect,
  multi-tier ranking, collection delegation, dispatcher routing.

* Mogul engine: standardised reagent-quantity field name to `qty`
  (previously some producers emitted `amount`, some `count`, some
  `qty`; consumers had defensive `or` cascades reading all three).
  Producer renames: HDG_PowerCrafting.normalizeReagents,
  HDG_PowerCrafting.BuildReagentToRecipesIndex, HDG_Data recipe
  iteration, HDG_GoblinTab queue insertion. Consumer cleanups across
  HDG_RecipesTab, HDG_LumberTracker, HDG_MaterialsList,
  HDG_PriceIntegration, HDG_DataTab (cascades stripped, dead defensive
  branches removed). Plan-row count renamed to `crafts`; shoppingList
  count renamed to `qty`. `lumberOnlyProfit`/`lumberPlusMatsProfit`
  fields renamed to `revenuePerCraft`/`netProfitPerCraft` (per-craft)
  and `revenue`/`netProfit` (totals) so user-facing labels read
  "Revenue (mats free)" and "Net profit (mats bought)" -- the old
  "lumber-only profit" name was confusing because the number is gross
  revenue, not actual profit.

* Mogul engine: multi-tier lumber ranking fix. Recipes that need 2+
  lumber tiers (rare in current data but possible) were under-ranked
  because the per-lumber profit divisor was the SUM of lumber tiers,
  while `lumberCap` correctly used the bottleneck tier. Engine now
  computes `bindingLumberQty = max(qty across tiers)` and uses it as
  the ranking divisor; `lumberCost` (sum) stays for display. Single-
  tier recipes are unaffected (max == sum); multi-tier recipes now
  rank by their actual binding constraint. New regression test in
  test_mogul.lua covers a 5-Sturdy + 5-Polished recipe vs a 6-Sturdy
  recipe scenario where the new ranking flips the plan to the more
  profitable choice.

* Mogul tab: account-view fix. Toggling between Active char and
  Account didn't change the candidate set because Refresh filtered to
  `knownByActive` regardless of view. Account view now correctly
  expands the plan to include alt-only recipes with the bestAlt tag
  visible in the Crafter column; owned mats and prices stay
  active-char-scoped (we can't see alt bags). Spec section 6 clarifies
  this is the intended scope.

* Mogul: defensive cascade cleanup. Per code review of the new module,
  removed multi-field-or fallbacks where the producer is now strict
  (`reagent.qty or reagent.amount or 1` style). These were silently
  papering over data bugs -- if a producer ever emits the wrong field,
  downstream math now errors loudly with `attempt to perform arithmetic
  on a nil value` instead of computing a wrong total with `or 1`.

* Goblin tab: lumber count for each row's required tier is now colored
  green when you have enough of that lumber for at least one craft of
  that recipe, dim grey otherwise. At-a-glance "can I craft this right
  now?" indicator in the same column that already showed the type.

* Vendor DB: Bel'ameth vendors Mythrin'dir (NPC 216284) and Ellandrieth
  (NPC 216285, sells Bel'ameth Barrel + ~7 other Bel'ameth-themed
  items) were tagged "Amirdrassil" with uiMapID 2239 because Blizzard's
  catalog inherits the parent zone. Pin landed on the Amirdrassil map
  and the shopping-list label sent players via the wrong portal.
  Updated to "Bel'ameth" with uiMapID 2369; coords are estimates
  pending in-game verification. Reported by Moondaze on Discord.

* MultiHouse widget: ADDON_ACTION_BLOCKED on Frame:Show() during
  tainted refresh paths. The card itself is a regular Frame but has a
  SecureActionButtonTemplate child (tpBtn), and recent WoW versions
  treat Frame:Show() on parents-of-secure-buttons as protected when
  the call stack is tainted. Switched the card visibility from
  Show()/Hide() to SetAlpha + EnableMouse (same pattern already used on
  the secure tpBtn for the same reason).

* Mogul tab: new craft optimizer that produces a planned recipe mix
  from your lumber stockpile. Two modes: Profit (greedy by per-lumber
  profit, mix emerges from owned-mat depletion; two columns Lumber-only
  and Lumber + mats) and Collection (cheapest-uncollected-first to
  maximize new appearances per lumber). Header toggles for mode / view /
  optimize and an editable lumber budget. Plan rows show
  "K x Recipe  L lumber/ea  +cashg / +marging" in a WowScrollBoxList;
  selecting a row reveals that recipe's mat list. Mats panel includes
  Send to Auctionator (creates a Housing Decor shopping list) and the
  action row has Send entire plan to crafting queue. Show all candidates
  appends dimmed runner-up rows. Account view tags rows with
  "Best on: <AltName>" when the active char doesn't know the recipe.
  Tab is a compact icon-only button next to Goblin. Pure-function
  engine in modules/HDG_Mogul.lua with 21 unit tests covering scoring,
  profit greedy-with-state, and collection ordering. Static panel
  (no event subscriptions); price freshness is owned by the Goblin
  tab's scan.

* HDG_LumberTracker: new public accessors GetTotalLumberCount and
  GetLumberIDs so other modules can read the lumber set without poking
  the file-local LUMBER_TYPES table.

* HDG_PowerCrafting: new public GetAllKnownDecorRecipes(viewMode) ->
  list of decor recipes the active char (viewMode = "char") or any alt
  ("account") knows, with knownByActive and bestAlt tags.

* Style Curator: new "Wishlist - Uncollected" virtual source in the
  source dropdown. Shows the catalog slice you don't yet own and lets
  you pre-file uncollected decor into your styles -- plan an Apothecary
  build before you have the pieces. Filings persist; once an item lands
  in your chest it's already filed under the styles you intended.
  Coverage bar is unaffected (still scoped to collected decor only).

* VendorResolver: pcall-wrap UnitGUID/strsplit probes (Method 1 + 2) to
  guard against the 12.0.5 secret-string taint when called from tainted
  call stacks (e.g. after teleporting via MultiHouse). Pre-fix, vendor
  name resolution could silently fail for the rest of the session.

* MultiHouse: defensive pcall around SetAttribute teleport bind. The
  outer InCombatLockdown guard handled the in-combat case; pcall covers
  the rare path where Bind is called from a tainted stack outside combat.
  Card stays stable on failure; next Refresh re-binds.

* Cockpit aggregator: gate the subscriber-error print behind the debug
  flag. Pre-fix, transient widget init errors during the cold-cache
  retry window at login could spam chat for all users.

* Cockpit aggregator: removed C_Timer-based 1-8s retry cascade. The
  HDG_COLLECTION_READY event fires when the catalog cache is warm and
  is already wired to RequestRebuild -- the cascade was redundant
  belt-and-suspenders that violated the no-UI-timers rule. Verified via
  cold-cache smoke test (full client restart) that the cockpit
  Decorator Profile populates correctly without the cascade.

* Style Curator: Coverage bar now reads "Coverage (collected): ..." to
  make the bar's scope unambiguous. Pre-fix, users filing uncollected
  items into styles via the new Wishlist source would see a stationary
  bar with no indication why.

* Shopping List: title summary now includes per-currency totals across
  the entire active list (gold + Hearthsteel + Kirin Tor tokens etc),
  not just per-zone. Saves the manual tallying before a vendor run.

## [2.40.0] (Released May 2026) — "Style Curator + Builder split, faster cold open"

* StylesTab refactor (plans/2026-05-04-stylestab-split.md):
  HDG_StylesTab.lua decomposed from a 2920-line monolith to a 1656-line
  orchestrator + a UI/Tabs/Styles/ folder of screen modules + a UI/Widgets/
  folder of cross-tab widgets. -1264 lines (-43%) extracted across 8 phases.

  - Phase 1: shared widget seam at UI/Widgets/ -- HDG_W_SegmentedChip +
    HDG_W_TypePill. Replaces previous inline implementations.

  - Phase 2: state extracted to UI/Tabs/Styles/HDG_ST_State.lua. Single
    source of truth for all Styles selectors (selectedStyle, selectedTier,
    collectionFilter, etc.) with named mutators (SelectTier, ResetForStyle,
    SetCollectionFilter, etc.). 162 references migrated. Legacy
    uncollectedOnly + collectedOnly boolean pair consolidated into
    State.collectionFilter ("all" / "have" / "need").

  - Phase 3a: ItemPanel extracted to UI/Tabs/Styles/HDG_ST_ItemPanel.lua.
    Owns the right-side panel widget; Build/Render/LoadModel/Show/Hide/
    GetFrame surface. Shims (RefreshItemDetail, LoadPreviewModel) forward.

  - Phase 3c: Landing data layer extracted to UI/Tabs/Styles/HDG_ST_Landing.lua.
    BuildData{ statsCache } returns the full landing row array
    (curated + filtered + shopping lists + snapshots + sessions + room
    concepts + collections). Widget creation stays in StylesTab.

  - Phase 3d: Detail screen progressively extracted to
    UI/Tabs/Styles/HDG_ST_Detail.lua across five sub-phases:
      3d-1: helpers + cell handlers (TIER_TOOLTIP_LABELS, OnCellEnter/
            OnCellLeave/OnCellClick, UpdateCellHighlights, HideFilterButtons,
            SortByDecorName).
      3d-2: shared flat-gallery renderer (RenderFlatGallery, used by both
            snapshot + shopping-list views).
      3d-3: Snapshot + ShoppingList render bodies (RenderSnapshot,
            RenderShoppingList).
      3d-4: Session render body (RenderSession).
      3d-5: Main detail render (Render -- the tier/themed/curated/collection
            branching with chip rendering + tier counts + filter loop +
            view-mode dispatch). Plus card-grid, item-list row, and item-list
            renderers; IsItemHidden, ItemHasRepRequirement, ItemCostsEndeavor,
            SOURCE_FILTER_DEFS, ConstructItemListRow.

  - Subtitle anchor fix: detailDesc now anchors to detailHeader's BOTTOMLEFT
    instead of the frame edge -- previously the subtitle hugged the panel
    border.

  Remaining for a future session:
    - CreateDetail widget construction (~250 lines)
    - CreateLanding widget construction (~190 lines)
    - Smart Set landing rows showing 0/0 + empty preview icons in some
      states -- transient bug we couldn't reliably reproduce; needs a
      focused session with the recipe captured.

* Style tab landing header reworded -- "Browse by Style (Beta - in development)"
  becomes "Style, On Purpose -- Drag, drop, and act like that was the plan."
  Beta marker dropped.

* Style tab detail view polish, curated cleanup pass:
  - Curated styles no longer show the Signature/Accent/Versatile/Clashing
    tier chips or the Great Hall/Kitchen/etc. room chips. Those filters
    belong to Smart Set / themed styles where items actually classify by
    tier or room; on a curated set they were always rendering "(0)".
  - New CURATED / SMART SET / SNAPSHOT / COLLECTION / THEMED type pill next
    to the title.
  - Subtitle now reads "<N> items" + optional description (replaces the
    standalone "Curated" line).
  - Have/Need/All segmented chip replaces the Uncollected + Collected
    checkbox pair.
  - List/Grid view toggle moved out of the chip rows into the top-right
    utility cluster next to Export.
  - Curated/collection/snapshot detail views drop ~54px of vertical chrome
    so the item grid starts higher.

* Fixed: empty rows appearing in Style detail grids when scrolling or
  switching styles. HDG_StyleCardRow's shared cell pool was re-parenting
  cells across recycled WowScrollBoxList rowFrames -- new rows would steal
  cells from earlier rows, leaving the earlier rows visually empty. Each
  rowFrame now owns its cells exclusively (no shared pool); ScrollBox's
  built-in rowFrame recycling handles virtualization. UpdateStyleCellHighlights
  rewritten to walk visible rowFrames via ForEachFrame instead of the
  retired pool.

* New shared widget folder UI/Widgets/. First two residents:
  - HDG_W_SegmentedChip (mutually-exclusive 3+ state chip control; powers
    the new Have/Need/All filter)
  - HDG_W_TypePill (small dim-uppercase header label; powers the new
    CURATED / SMART SET pill)
  Both designed for cross-tab reuse. Acquisition / Preview / Goblin filter
  bars are candidates for future migration.

* Fixed: legacy customStyles weren't being restored from SavedVariables on
  load, so the v1-collections migration ran with a nil source table and
  silently copied zero styles. Affected anyone whose save predated the
  v1-collections migration's first run (saves restored from backup, fresh
  installs that imported old data, etc.). Saves where state.collections
  was already populated were unaffected. Fix: load HDG_DB.customStyles +
  customStyleOrder into state.* before Migration.RunAll, mirroring the
  save-side preservation block.

* Data tab no longer spins up its own catalog searcher. The legacy refresh
  flow (TriggerCollectionSearch) created a CreateCatalogSearcher with
  SetOwnedOnly(false) + BasicDecor mode, but immediately filtered every
  result through HDG_Data.GetCatalog — which only carries owned rows — so
  the un-owned 4k+ entries were enumerated and discarded each click.
  Replaced with a synchronous BuildCollectionSnapshot that iterates
  HDG_Data.GetAllCatalog() directly. Refresh is instant, the panel
  auto-populates on tab open, and HDG_Data is once again the only owner of
  CreateCatalogSearcher in the addon. ~120 lines net deletion.

* Catalog Store-canonicalization complete (Steps 1-4). HDG.Store's
  state.collection.decorCatalog and state.collection.catalogByItem are now
  the single source of truth for catalog data; the module-local _catalog /
  _catalogByItem upvalues in HDG_Data have been retired. Saves ~1.5-2 MB of
  persistent duplication and eliminates the ~3-4 MB transient deep-copy
  spike that fired on every sweep. External call sites (Acquisition,
  Preview, Styles, HouseEditor, ZoneTracker, etc.) read through the same
  HDG_Data.GetCatalog / GetCatalogByItem / GetAllCatalog accessors as
  before — internal plumbing change, no behavioural impact. Mutators
  (sweep finalize, UpdateSingleEntry, InvalidateCollectionCache) write
  through Store directly with wipe-in-place semantics, preserving table
  identity for short-lived caller handles.

* Login no longer rebuilds the catalog. The deferred-eager verification
  sweep (kicked 0.5s after SavedVariables restore) was responsible for the
  ~85 MB cold-open memory spike: it re-read every catalog entry, re-built
  ~1,706 row tables, and re-populated variants to confirm what the persisted
  save almost always already had right. Replaced with a lightweight ID-only
  diff (VerifyOwnedSetIDsOnce) — a one-shot owned-only searcher enumerates
  current decorIDs, compares to persisted ownedDecorIDs, and patches ONLY
  the few that drifted via the existing UpdateSingleEntry path. No row reads
  or variant population unless drift is actually detected. Catches the rare
  cases (addon disabled mid-session, crash before save flushed, etc.) without
  the per-login ~30-50 MB allocation churn. Drift during normal play remains
  caught by HOUSING_STORAGE_ENTRY_UPDATED (per-entry) and HOUSING_STORAGE_UPDATED
  (bulk, fires on housing customize entry). Refresh button still does a full
  rebuild on demand.

* Zone scanner no longer triggers WarmCollectionCache at PLAYER_ENTERING_WORLD.
  Persisted ownership data already lives in HDG.Store from SavedVariables by
  the time PEW fires, so IsItemCollected / IsDecorCollected now fall back to
  Store directly when the module-local cache hasn't been warmed. Result: the
  addon does no eager work at login; the scanner answers from persisted state
  for users with saved data, and silently no-ops on cold-cold sessions (first
  install) where Store has nothing yet — they populate it the first time they
  open the HDG window. IsCollectionCacheWarmed accepts Store data as warmed.

* Power Crafting raw-material totals are correct again when a crafted
  sub-reagent is reached via two parent paths in the same recipe. The
  dependency-graph walker was incrementing the revisited node's quantity but
  skipping recursion into its children, so the second path's leaves were
  lost. Player-reported repro: Kirin Tor Skyline Banner (8 Spellweave + 8
  Moonshroud) was showing 80 Frostweave Cloth and 16 Infinite Dust; correct
  totals are 160 and 32. Any recipe that pulls the same crafted intermediate
  from multiple parents (Imbued Bolts, Heavy Borean Leather, etc.) was
  understated by the same factor.

* Projects → Architect: Plan mode is live. Mode pill (Reflect / Plan) on
  the canvas; Plan mode unlocks drag-to-reposition (snap-to-grid + footprint
  collision rejection), right-click rotate (cycles 0/90/180/270 quarter-
  turns), right-click context menu Remove (planned-only) / Reset position
  (captured), and a left-dock palette of all 17 shapes that spawns a fresh
  greenfield room on click. Manual cell positions persist via cell.locked
  and override the auto-layout for both Reflect rendering and the lower-
  floor backdrop. "Reset auto-layout" wipes locks for the current floor.

* Projects → Architect: manual room-connection assertion in Reflect. Click
  any open-door orb → context menu of compatible rooms (same floor, opposite
  cardinal, also unfilled). Right-click a room → Connections submenu showing
  each cardinal's state with Disconnect actions. Asserted/blocked records
  live in projects.connections[floorID]; _floorLayout seeds them before the
  cardinal-matching algorithm runs, so manual overrides always win. Closes
  the topology heuristic ceiling — players can hand-fix mistakes the
  algorithm makes on ambiguous-cardinal houses.

* Projects → Crates: Library + Stamp. CrateDetail gains "Save as template"
  (clones members + name into a new lib_<uuid> entry). RoomSidePanel gains
  "Stamp template" (context menu of every library entry grouped by source —
  My Templates / Curated). Click → mints a fresh crate cloned from the
  template into the current room, opens its detail. Curated content data
  file ships 7 starter templates (Vrykul Throne Hall, Cosy Hearthstone,
  Tavern Essentials, Library/Study, Garden Sanctum, Winter Chalet, Vrykul
  Armory) — seeded by an idempotent v3-curated-library migration that
  remembers player deletes via state.curatedSeeded[key].

* Projects → Crates: orphan handling. Re-capture no longer cascade-deletes
  crates whose room is removed; DeleteProjectRoom detaches them (parent=nil)
  and they surface in any RoomSidePanel under "Unrooted crates (N)" with
  per-row "Move here" buttons that adopt the orphan into the current room.
  Crate_ListOrphans + Crate_Reparent helpers added.

* Projects → Crates: real decor picker. New modal HDG_CratePicker.lua
  with sticky header, search box, status chips (Owned / Missing / Craftable
  / Vendor), top carousel (All + 6 Blizzard categories with progress bars +
  My Styles + Templates cards purple-tinted), sub-carousel (subcategories
  of active category with progress), virtualised row list with checkboxes,
  3D model preview pane, and footer (selected count / Add visible / Done).
  Styles and Templates cards swap the row list to a list-view mode that
  shows each entry with [All N] [Missing N] bulk-add buttons, normalising
  itemID-keyed Style members to decorIDs before adding to the crate. The
  generic horizontal carousel widget (HDG_Carousel) and pure filter
  primitives (HDG_DecorFilter) are factored as standalone modules so Style
  Creator can adopt them later. CrateDetail's "+ Add decor" button replaces
  the placeholder "by ID" text input.

* Projects → Crates: CrateDetail decor list virtualised via WowScrollBoxList
  (no more rows overflowing the panel on large crates). Each row leads with
  the decor's icon (resolved via C_Item.GetItemIconByID) and shows the
  catalog name with a hover tooltip. Translucent lighter-blue overlay panel
  (instead of opaque sidebar) so the canvas remains visible behind. HIGH
  strata so room buttons can't bleed through.

* Projects → Architect: Plan-mode budget impact preview. Rooms meter shows
  a translucent purple "planned" overlay on top of the actual spent bar;
  text suffix reads "→N (+M)" when over budget. Per-shape budget pulled
  from DB2 HouseRoom.WeightCost (closet=1, square_m=12, square_l=20,
  octagon_l=16, etc.) so totals match GetSpentPlacementBudget exactly.
  Decor count meter (GetNumDecorPlaced) added in Reflect, hidden in Plan.
  Floor + house room-count chip top of canvas.

* Projects → Architect: room-scoped Crates. Each room gains a Crates section
  in the right-side detail pane; "+ New crate" mints a path-keyed crate and
  opens a detail editor (rename, member list, "+ Add decor by ID", remove
  buttons). Crates persist via the new Collection_* API and survive reloads.
  Decor Preview rows now accept Ctrl+Right-click to drop the row's item into
  any crate via a context menu grouped by room. Plain right-click still
  toggles favorite — the existing UX is preserved.

* Style Curator + Smart Set Builder: cleaner split between the two surfaces.
  Style Creator is renamed Smart Set Builder and is now Smart-only — the
  Curated mode pill is gone, and new styles always start as smart filters.
  Curated style creation, editing, renaming, duplicating, and deleting all
  live in the Style Curator now (right-click any target row for the menu).
  Hero card subtitles on the Styles landing reframed to reflect the split.
  Existing curated styles still open in the legacy editor view from the
  landing list for backward compat, but the toggle is gone.

* Projects → Architect: clean rewrite of the room-layout pipeline. Pin-frame
  data → player-cardinals via a single N↔S flip in FP.facingToCardinal
  (Blizzard builds N→S internally but the editor view flips that axis on
  screen). Replaced the two-phase BFS+DFS, rotation deducer, and
  synthetic-door injection (~360 lines + a whole module) with a single-pass
  BFS that reads captured door multisets directly. Pin frames only emit
  internal connection doors and IsOccupiedDoor() honestly flags the
  connected ones — the earlier confusion was the missing axis flip, not a
  Blizzard bug. TopologyCapture now stores doorCardinals (every slot,
  drives orb rendering) and occupiedCardinals (real connections, drives
  BFS). Canvas anchors its host at the bottom so Entry sits at canvas south
  and rooms fan upward. CaptureAllFloors forces a Decorate→Layout toggle
  so pin frames re-emit on the first click; passive _onModeChanged
  early-returns during a sweep so the toggle can't race the capture.
  Removed: HDG_RotationDeducer, _preprocessImplicitDoors, the Entry-N
  hardcode override.

* Style Creator: new "Audit" mode lets you triage decor that isn't in any
  of your custom curated styles, fan items out into existing styles via
  instant-assign with an undo strip, and audit existing style contents.
  Filter the grid by Blizzard catalog category chips (Structural,
  Furnishings → Seating, etc.). Coverage progress bar tracks the
  shrinking gap as you triage. Multi-select via shift/ctrl/alt-click
  for bulk-add. Inline "+ New style" affordance creates a target style
  mid-session. (Synthea1979 request — for collections of 2000+ items
  where it's hard to spot what hasn't been categorised yet.)

* Note (root cause for v2.39.1): traced to BigWigsMods/WoWUI commit
  d0877949df, patch 12.0.5.67088 (2026-04-22). That patch added a new
  Blizzard_HousingMarketProductDisplay.lua and inserted a synchronous
  RestoreFilterAndFocusState call as the first line of
  HouseEditorStorageFrameMixin.OnTabChanged. RestoreFilterAndFocusState
  cascades into ScrollBox SetDataProvider → product card Init → calls
  CatalogShopUtil.GetProductInfo (async, returns nil before
  CATALOG_SHOP_DATA_REFRESH). The next ScrollBox Update runs Layout
  on the same card and indexes self.productInfo.catalogShopProductID
  on the nil. Any addon that holds a long-lived
  C_HousingCatalog.CreateCatalogSearcher delays the market fetch
  enough to expose this; bare client wins the race. This is a Blizzard
  bug — Layout/Init in the new mixin lack a nil guard. Re-enabling
  HDG's inline HE-storage-panel tab is gated on a Blizzard fix.
  Documented at Reference/HOUSING_CATALOG_API.md (Catalog Tab Gotcha
  section) and in the wow-api MCP under
  HouseEditorStorageFrameMixin.RestoreFilterAndFocusState,
  HousingMarketProductDisplayMixin, and
  CatalogShopDefaultProductCardMixin.Layout.

## [2.39.1] — Hotfix: House Editor Catalog tab errors

* Fix: opening the House Editor's Catalog (Market) tab spammed
  ADDON_ACTION_FORBIDDEN errors blaming HousingDecorGuide for calling
  C_CatalogShop.GetProductInfo. HDG never calls that API directly; the
  taint came from our wrapper around TabSystem:SetTabSelectedCallback,
  which inserted an HDG stack frame between Blizzard's tab-click path
  and the Market tab init. Removed the wrapper.

* Fix: removing the wrapper exposed a deeper interaction — the Catalog
  tab still crashed inside Blizzard's product card layout
  ("attempt to index field 'productInfo' (a nil value)"). The root
  interaction needs more diagnostic work; in the meantime the
  HE-storage-panel "HDG Styles" tab injection has been disabled
  entirely. HDG remains fully functional via its own window; you just
  lose the inline shortcut tab inside the House Editor's storage
  panel. This will be re-enabled once we've identified what's making
  Blizzard's market product fetch return nil productInfo while HDG is
  loaded.

## [2.39.0] (Released 2026-05-01) — "Reset Config + Recipe Knowledge"

* Fix: PowerCrafting PruneProfessionsDB Category A was matching housing
  decor recipes against HDG_ProfessionsDB by spellID, but ProfessionsDB
  is keyed by itemID. Match never succeeded, so EVERY housing decor
  recipe was being pruned out of the in-memory ProfessionsDB on load,
  collapsing the sub-recipe DAG (no crafted reagent chains, no "what
  produces this intermediate" lookups). Materials list and crafting
  readiness widgets that depend on the DAG now resolve correctly.

* Fix: PowerCrafting CanPlayerCraft always returned false. itemIDIndex
  stores the ProfessionsDB key (= itemID), but the function passed it
  straight to PlayerKnowsRecipeBySpellID — itemIDs and spell IDs occupy
  different numeric ranges. Now dereferences the entry and passes the
  real entry.recipeID. Restores correct results for any caller asking
  "can the player make this sub-component?"

* Fix: Acquire tab craftableByItem cache was storing the HDG_DecorDB
  table key (legacy decor record id) instead of the actual
  recipe.spellID, mirroring the same loop-variable shadowing bug as the
  Decor Preview tab. Symptom was latent (downstream uses are boolean
  ~= nil checks) but the value is now correct for any future consumer.

* Fix: Decor Preview craftable column was showing recipes you actually know
  as "no one knows it" (faint outline) for older expansions.
  decorToRecipeCache was storing the legacy decor record id from the
  HDG_DecorDB table key instead of the real recipe spellID field, so
  PlayerKnowsRecipeBySpellID was being queried with the wrong number and
  the persisted-cache lookup never matched. Recipes in your knownRecipes
  cache (Alts tab counts) now light up gold correctly across all
  expansions. Same fix applied to two other call sites using the same
  misleading loop variable.

* Fix: PlayerKnowsRecipeBySpellID now reads the persisted profession
  cache first (HDG_DB.characters[me].professions[*].knownRecipes) and
  falls back to live C_SpellBook.IsSpellKnown only as a pre-scan
  catch-net. The live API only sees recipes for the currently-slotted
  expansion profession, so older-expansion recipes returned false even
  when learned. The cache scan (run when the profession window opens)
  records every learned recipe across all expansions, so the cache is
  the authoritative answer once a scan has happened.

* New: Current house name shown right-aligned on the GRAND CURATOR
  title line of the Decorator Profile. Reads the active neighborhood
  from the MultiHouse cache (HDG_DB.account.houses) and tints the
  label by faction (Alliance blue / Horde red). Updates each refresh.

* Fix: GetCharactersWhoKnowRecipe had the same flaw as the
  PlayerKnowsRecipeBySpellID issue above — the CURRENT character was
  checked via live C_SpellBook.IsSpellKnown only, while alts correctly
  used the persisted cache. Result: "Recipe known by:" tooltips would
  list only your alts and omit YOU on older-expansion recipes you
  actually know. Now cache-first; live API is the pre-scan fallback.

* Fix: Find Lumber detection on the Alts tab top-right used the
  deprecated IsPlayerSpell global, which returns nil on retail.
  Replaced with the verified C_SpellBook.IsSpellKnown(1256697). The
  "Find Lumber known" indicator should now actually light up for
  characters that have learned it.

* Polish: Decor Preview "Craftable" column unified to a single icon
  family. The old mix of bright gold star / dim grey star / dim
  checkmark / bright red X was visually inverted from utility — the
  loudest icon (Red X for "not craftable") was the least actionable.
  Now: bright gold star = you know it, silver dim star = an alt knows
  it, faint outline star = recipe exists but no one knows it, empty
  cell = not a recipe (vendor / drop / event). Source category for
  non-craftables stays in the tooltip and Acquire tab. The check icon
  was also dropped — a check-mark for "recipe exists but you don't
  know it" was counter-intuitive (checks usually mean done). Tooltip
  legend updated to match.

* New: "Reset Config" button on the Appearance card — wipes
  HDG_DB.config and reloads from defaults via a confirm popup. Recovers
  from stale appearance/behaviour settings that can't be reached via
  normal UI controls (e.g. fontScale stuck non-zero from old builds, or
  legacy keys left behind by the HDG_Settings backward-compat proxy
  that cause text to render visibly wider than expected and overflow
  column widths). Shopping lists, characters, lumber map, custom
  styles, and House tab layout are preserved. Popup explains a /reload
  is sufficient in most cases; full relog only if anything looks off
  afterwards.

## [2.38.0] (Released April 2026) — "Cockpit: Patterns + Widgets + Polish"

* New: Decorator Profile composite widget — folds the old XPHero +
  DecoratorTitle + TrophyShelf hero band into one full-width card built
  around Blizzard's exact Housing Dashboard level ring (laurel wreath +
  radial XP sweep + leading-edge sparkle flipbook). Verbatim XML port of
  CurrentLevelFrame at native atlas sizes (256×158 host, 130×130 cooldown
  sweep at offset 8/-8, six leaf textures at native useAtlasSize positions
  — DO NOT scale, the radial fill and frame line up pixel-perfect at exact
  Blizzard dimensions). Sweep animates from empty → current XP over 1s
  with InOutQuartic easing on each tab open, replays on Show.
* New: Sticky header strip pinned to TOP of the House tab, above the
  scroll viewport — `Level N · X / Y XP · Slots O / M · Lumber count ·
  +collectible XP` always visible regardless of scroll position. Refreshes
  on the same Aggregator broadcast as the dashboard cards.
* New: Daily bestowed title rotation — 50 squirrel-given titles + Vamoose
  quips ("Twilight Court Architect — Sleeps with one eye open. The other
  is admiring the moonlight." etc.). Deterministic per-day so all alts
  see the same title; rolls at server reset. Persisted via
  HDG_DB.daily.bestowed = {date, index} for downstream rollover detection.
  Disconnected from collection stats — pure date-based rotation.
* New: `/hdg costtest` slash command — validates HDG_VendorDB against
  `entryInfo.sourceText` from C_HousingCatalog.GetCatalogEntryInfoByItem.
  Parses gold (`Cost: 50g`) and currency hyperlinks (`|Hcurrency:NNNN|h`)
  from sourceText, matches against our DB per (itemID, vendor, cid),
  reports per-currency totals (DB-uncoll vs API-uncoll, OK/!! markers)
  plus per-item mismatches and missing-in-DB lines. Output goes to a
  scrollable copy-paste dialog. Discovery: vendor cost lives in sourceText
  as parseable text, NOT as a structured field — Bliz API IS authoritative
  for most current items but UNDER-reports for older WoD-era items
  (sometimes drops AC component, sometimes shows wrong gold). Treat as
  "investigate" not "fix automatically."
* New: `/hdg decordump` (alias for `/hdg dump`) — restored layout-dump
  copy dialog after the v2.38a TestWindow surface retired.
  HDG_HT_LayoutDump module replaces HDG_HT_TestWindow.lua (fewer parallel
  renderers; one render path).
* Fix: HDG_VendorDB validation pass via /hdg costtest. 119 cost mismatches
  resolved across Voidlight Marl (~80 systematic 750→250 / 2500→500 /
  1500→150 drops on Khaz Algar housing vendors), Khaz Algar gold pricing
  (High Tides Ren / Xiao Dan / Len Splinthoof / Founder's Point pricing
  reshuffled). 7 vendor entries with missing currCost fields patched
  (Crafty Palu, Gabbun ×4, The Last Architect, Void Researcher Aemely).
* Fix: VendorDB data integrity — 3 Sin'dorei items (245284 Silvermoon
  Wooden Chair, 245330 Enchanted Blood Elven Candelabra, 251997 Sin'dorei
  Winged Chaise) were misassigned to Materialist Ophinell at Twilight
  Highlands with the wrong currency (Twilight's Blade Insignia 3319).
  Items moved to NEW vendor Dethelin (npcID 250982, Silvermoon City,
  Midnight) at correct Resonance Crystal prices (3000/3000/5000).
* Fix: VendorDB — Second Chair Pawdo (252312) retagged from Orgrimmar
  Classic Horde → Dornogal The War Within Neutral. Nightborne Lantern
  (247908) cost added at this vendor (30g + 50 Order Resources).
* Fix: VendorDB — 11 Apexis Crystal entries normalized from item-token
  format `{{"i",823,X}}` to currency format `{{"c",823,X}}` (Apexis
  Crystal is uniquely both itemID 823 AND currencyID 823; functionally
  equivalent but the validation tooling counts only the "c" form).
* Change: House tab source widgets retired — XPHero, DecoratorTitle, and
  the standalone TrophyShelf widget folded into Decorator Profile (style
  affinity remains as its own slim full-width card). HDG_HT_TestWindow.lua
  also retired (its parallel renderer was a v2.38a debug surface no longer
  needed). Old `/hdg dashboard` and `/hdg dump` slash handlers removed
  from /hdg surface (decordump and dump still work as aliases).
* Change: Design Mode no longer supports drag-to-reorder — reorder via
  the up/down arrows in the Customize picker instead. Resize handles
  (right-edge width snap, bottom-edge height) and the dimension-slider
  gear popover stay. Popover gains a "Reset" button per widget that
  clears that widget's saved overrides only. Font keys (titleFont,
  subFont, etc.) are hidden from the slider list — they are intentionally
  hardcoded for visual consistency and the sliders had no effect.
* Change: TrophyShelf gains optional `showHeader = false` dim — when
  hosted inside the composite, hides the "Trophy shelf X/Y" header.
  Also gains `iconDrop` dim controlling how far icons sit into the wood
  plank (used by composite to place trophies lower on the shelf).
* New: Top $/Lumber widget on House tab — third-width panel, top-5 craftable
  decor by gold-per-lumber, lumber-expansion-coloured names with $/lum chip,
  click row → Goblin tab. Pulls from HDG_GoblinTab profit data via a public
  `GetTopByLumberValue(n)` getter (lazy-computes on first use).
* New: Favorites system — right-click any row in Preview to toggle a star
  (auctionhouse-icon-favorite atlas, layered above row chrome), persists in
  `HDG_DB.favorites` keyed by itemID (survives catalog cache rebuilds).
  "Favorites" filter chip added to the All sub-tag row, after All Decor.
  Scrollable Favorites widget on House tab (mouse-wheel only, no scroll bar)
  — left-click row → Preview tab Favorites filter, right-click → unfavorite.
* New: Goblin tab crafting-queue awareness — two new mutually-exclusive
  filter checkboxes ("Queued Only", "Hide Queued") in the Goblin filter
  row, plus a 3px coloured stripe on the left edge of any row whose item
  is in your active crafting queue. Queue lookup is built once per filter
  pass keyed by both itemID and recipe spellID so the indicator catches
  rows added by either path.
* New: Default tab pin — right-click any tab button (or the title-bar
  chest level badge) to pin it as your default tab. The addon switches
  to the pinned tab on first main-frame show per session; right-click
  again to unpin. State lives at `HDG_DB.config.defaultTab`. Tooltip
  shows pinned/unpinned state and the right-click hint.
* Fix: Resolver and Customize picker now auto-append widgets that were added
  AFTER you last saved a layout order, so brand-new widgets appear in both
  the cockpit and the customise panel even when your SavedVar order predates
  them. New widgets land at the end of the list — use the up/down arrows or
  Reset to default to slot them naturally.
* Fix: Decor Currencies panel now colours Midnight currencies (Voidlight
  Marl, Brimming Arcana, Angler Pearls, Illusionary Coin, etc.) in the
  Midnight expansion colour. Earlier the heuristic picked the earliest
  vendor.exp seen, so any currency accepted by a Stormwind/Orgrimmar
  capital-city vendor got bucketed Classic. Explicit currency→expansion
  override added in HDG_ExpansionData for the 33xx Midnight block.
* Fix: HDG_VendorResolver pcall-hardened against 12.0.5 secret-string taint
  when resolving vendor/NPC names via C_TooltipInfo.GetHyperlink. The fault
  is on read/comparison of `tooltipData.lines[i].leftText`, not the call
  itself, so the entire probe is wrapped — falls back cleanly to cached DB
  names instead of cascading the error up through Preview tab tooltips.

* New widgets bound through Aggregator + Registry: A1 Capacity (with B4 Rooms
  sub-line), A2 NextRewards (async), A3 MultiHouse (with secure teleport
  buttons cribbed from VN), B1 HotPicks, C1 CraftableNow, C2 RecentActivity
  (driven by HDG_Settings.craftingHistory), C3 ThemedSets (top closest-to-
  complete from HDG_CollectionDefinitions), C4a LumberWallet + C4b
  DecorCurrency (split, currency IDs auto-extracted from HDG_VendorDB), D1
  persona line (folded into DecoratorTitle), D2 Records + DailyXPTracker
  (default-off until logs are dense enough), A4 Refund footer
* Extracted with v2.37 fidelity preserved: XP Hero (level + decor count +
  collectible-XP callout), DecoratorTitle (title + tier ladder), TrophyShelf
  (alpha-sorted uniques then prey, two-tone header, accent bar), CloseCards
  (smooth bars, yellow titles, "X / Y - N to go (P%)" stat format), Featured
  (now full-width with 4 weekly-rotated mini-features), Source/Expansion
  donuts (Source: % headline + count/total sub; Expansion: count + label;
  Expansion sort uses HDG_ExpansionData.EXPANSION_ORDER)
* New: Aggregator computes `housingNeed[currID]` — per-currency cost to buy
  every uncollected vendor decor, derived from HDG_VendorByItem index +
  VendorDB cost field. DecorCurrency chips render `have / needed` with green
  tint + ReadyCheck-Ready icon when sufficient
* New: chrome modes ("card" / "section" / "none") — the hero band renders
  flat with section dividers, donut/capacity/etc. keep card chrome. Cards
  paint at scheme.panel × 0.6 / scheme.border × 0.3 for v2.37-matching
  layered look. Cyan accent bars (2px) left of every section title.
* New: theme propagation across every cockpit widget — every fontstring goes
  through Theme.ApplyFont (user font + scale), every color reads scheme.text
  / accent / text_dim / success. Hardcoded RGB triplets eliminated except in
  Editor/Placeholder (debug surfaces).
* New: StyleAffinity collapsed to single inline horizontal row in the hero
  band with v2.37 tag-namespace filter (skipTagIDs from
  C_HousingCatalog.GetAllFilterTagGroups drops Expansion/Size groups so
  faction/style tags surface as the dominant aesthetic)
* New: SegmentedBar themed defaults (lit = scheme.success, unlit =
  scheme.border × 0.7), GaugeBar tier colors via scheme.success/warning/error
* New: `/hdg dump` slash command + copy dialog — multiline editbox with
  auto-select for layout dumps. Captures user picker reorderings as
  sequential integer `order` values for round-trip into source.
* New: 2-column Customize panel (was 1-column, 19 widgets fit cleanly now)
* New: `defaultEnabled` field on widget specs — three-state visibility so
  data-light widgets (Records) ship off by default
* New: `/hdg order` + `/run HDG_PrintOrder()` for quick order inspection
* House tab body NOT yet replaced — cockpit still lives only in
  `/hdg dashboard`. Real House tab integration arrives in next commit.

### v2.38a foundations (folded into 2.38.0)

* New: `/hdg dashboard` slash command opens a standalone layout test window
* New: full data-driven layout system (`HDG_HT_LayoutConfig`) with 17 placeholder
  widgets — single source of truth for all dashboard dimensions
* New: pure-math 3-column bin-packer (`HDG_HT_Layout`) with three discrete
  card widths (1/3, 2/3, Full); pixel-clean column math at 270/552/834
* New: Resolver (`HDG_HT_Resolver`) merges config defaults with SavedVar overrides
* New: slide-down customisation picker — toggle widgets on/off, change widths,
  reorder via ↑↓; state persists in `HDG_DB.houseTab.{enabled, order, width}`
* New: visual layout editor (Design Mode toggle) — drag-reorder cards, resize
  handles snap widths, gear-icon dimension popovers with live-preview sliders
* New: `/hdg layout dump` echoes the current effective LAYOUT_CONFIG to chat
  for graduating runtime tweaks back into the source file
* New: `HDG_HT_SegmentedBar` primitive (10-segment fillbar with `solid` and
  `blizzPip` styles) — built but not yet consumed; ready for v2.38b widgets
* Note: the real House tab remains unchanged in this release. v2.38b will
  introduce internal layout patterns and migrate widget rendering into the
  new system.

## [2.37.0] (Released April 2026)

### Added
- House tab redesigned as a Decorator Profile dashboard:
  - Tier-based decorator title using Blizzard's housing achievement names
    up to 500 (Score a Decor, Casual Collector, Well-Travelled Collection,
    Fully Furnished), then extended with Vamoose-original ranks (Decor
    Maven 750, Decor Master 1000, Grand Curator 1500, Legendary Decorator
    2000). Vamoose ranks are marked with an asterisk and footnote.
  - Progression line shows previous, current, and next rank with the
    exact item count to rank up.
  - Style fingerprint: top five Style/Faction tags from your collected
    items with collected count, total count, and completion %.
  - Closest-to-Complete cards: three subcategories ranked by smallest
    gap to 100%. Click jumps to the Preview tab.
  - Trophy shelf: collected unique-trophy items + Preyseeker hunter
    trophies (effigies and busts), uniques first then prey, with hover
    tooltips for each.
  - Featured of the Week: one item from your collection rotates each
    week. Shows model icon, name, source, and zone.
  - Source and Expansion donut charts: per-category breakdown built
    from 90 triangle wedges per donut for smooth edges, with masked
    circular hole. Source colours match the new palette.
  - Hero panel rebuilt with Blizzard's housing-dashboard fillbar
    atlases: chest-icon level badge, themed XP bar, level pip markers
    that gild as you cross thresholds, MAX/Next callouts.
- Title-bar level badge now animates: chest icon with the level number,
  with a sparkle flipbook celebration that plays three times on first
  open to draw attention to the click target. Hover tooltip says
  "Click for House Stats".
- Preview tab detail block reworked:
  - Big bold item name with horizontal divider underneath.
  - Expansion accent right-aligned on the title row in the expansion's
    own colour. Reads from the live in-game catalog tag so re-themed
    items get the correct expansion bucket.
  - Source line(s) consolidated. Primary source first; alternate source
    indented underneath with a curved arrow icon to chain them visually.
    Vendor name renders as a clickable cyan hyperlink that jumps to the
    matching Acquire row.
  - Vendor cost shown inline next to the vendor name with currency or
    item icons. Long currency names no longer overflow the line.
  - Cart buttons (add / remove) inline next to the vendor cost.
  - Combined Collected and Placement on a single row, mirrored on the
    Not Collected state.
  - First-acquisition XP bonus shown for uncollected items with the
    house-XP icon.
  - Stored count uses Blizzard's house-chest atlas next to the number.
  - Editable note panel on the right with subtle gold border and
    autosave on focus loss.
  - Palette icon (housing-dyable-palette-icon) appears next to the item
    name for dyeable items. Replaces the old Dyeable line.
  - Tags filtered to Style and Faction/Culture only. Drops Blizzard's
    noun-list junk like cup, cups, mug, mugs, tankard.
  - Source-type colours applied to gate chips on Acquire-row items.
- Source-type metadata unified into a single CONFIG.SOURCE_TYPES table.
  Each entry carries display name, short label, colour, atlas, view
  flags, acquirable flag, and synthetic flag in one place. Reputation,
  Endeavor, and Gold Only promoted to first-class synthetic source
  types so they're surfaced and coloured the same way as Blizzard's
  source types in dropdowns and stats.
- Preview tab destroyable indicator moved out of the row column and
  into the detail block as a small icon on the Collected line.

### Fixed
- Source breakdown for newly-added items (Void Elf Scribe's Desk,
  Decorative Dornogal Opal): items with empty AllDecorDB source data
  are now classified as Vendor at runtime if they exist in vendor
  data. Previously they showed up under Unknown.
- Expansion bucketing for items mistagged in AllDecorDB (Vanquisher
  Trophies). Now uses the live in-game data tags so the expansion
  matches Blizzard's filter UI exactly.
- Stored copy count now sums across base item + all dye variants. Was
  showing only the base count, often two or three lower than Blizzard's
  tooltip.
- House Level XP bar pip markers now render at every level boundary
  including the maximum level, gilding as you cross each threshold.
- Preview tab detail block correctly shows the size tag on the category
  line and the Style/Faction tags on the Tags line.

## [2.36.0] (Released April 2026)

### Added
- Dyed model preview: Preview tab's 3D model now renders with the actual
  dye colors applied for variant entries, matching Blizzard's housing
  catalog. Uses the new 12.0.5 SetGradientMaskWithDyes API on the model
  scene actor with per-channel dye color IDs from
  C_HousingCatalog.GetAllVariantInfosForEntry.
- Inline dye droplets on Preview tab list rows: dyed variants now show
  their dye colors as small droplets after the item name (replacing the
  "(Dyed)" text suffix). Visual matches Blizzard's catalog droplet style.
- House Editor variant cards:
  - Dyed-item indicator changed from a plain white droplet to Blizzard's
    "housing-dyable-palette-icon" atlas (small palette shape).
  - Dye swatches moved to TOP-RIGHT of the card, tightly stacked, using
    droplet-shaped atlas textures (dye-drop_32) tinted via SetVertexColor.
  - Mirrors Blizzard's HousingCatalogDyeDisplayMixin.
- Tooltip transparency for variant placed counts: Owned and Dyed variant
  cards now show the row-aggregate placed total ("N placed across all
  variants") with an explicit note that per-variant split isn't exposed
  by Blizzard's API. Replaces silent "0 placed" misattribution.
- Materials List bag chip icon swapped to "plunderstorm-icon-item" atlas
  (visual refresh, no behavioural change).
- Crafting Queue dropdown indicator (Recipes tab) swapped from yellow
  triangle (common-button-collapseExpand-up/-down) to the curved
  "common-icon-rotateright" atlas, with green tint when expanded. Avoids
  the yellow-triangle "warning indicator" misread reported by a player.

### Fixed
- 12.0.5 catalog searcher API: SetDistinctPerRecordID was hard-removed
  in 12.0.5, replaced by SetBaseVariantOnly (semantic inverse). The
  defensive `if searcher.X then` guard meant the old call silently
  no-op'd, leaving distinct-variant filtering broken since the patch.
  Now uses SetBaseVariantOnly(false) on 12.0.5+, falls back to legacy
  SetDistinctPerRecordID(true) on older builds.
- Materials List recipe popout anchor: clicking a material row no longer
  positions the recipe panel at the bottom-right of the screen. The Y
  offset was reading the row's content-frame Y (often -300 deep into a
  scroll), which combined with SetClampedToScreen pushed the popout off
  the materials window entirely. Now uses screen-relative offsets so the
  popout always lands directly to the right of the materials window,
  vertically aligned with the clicked row.
- Materials List row tooltip overlap: hovering a row no longer shows the
  item tooltip on top of the materials list. The default ANCHOR_TOPRIGHT
  positioned the tooltip at the row's top-right (inside the list).
  Tooltip now anchors to the right of the materials window (or to the
  right of the recipe popout if it's open) so it never covers list rows.
- Materials List resize tab: clicking-and-dragging the bottom resize tab
  no longer makes the window jump to full height before settling. Cause
  was StartSizing("BOTTOM") on a frame with a single non-top anchor —
  WoW had to compute the effective top edge on first drag, mis-snapping
  the height. Now pins TOPLEFT to current screen position before resize
  and persists the new anchor so position survives reload.
- Preview tab vendor tooltip: currency-priced items now show the actual
  currency name + icon + amount (e.g. "150 [icon] Voidlight Marl") on
  the "Available from vendor:" lines instead of the literal placeholder
  text "currency". Calls HDG_VendorResolver.GetCurrencyCost(itemID) once
  per tooltip and reuses the resolved tuple across all vendor rows,
  matching the pattern already used by the Acquisition tab.
- Alts tab Character Details: characters no longer show empty stub rows
  for every decor profession (Alchemy, Blacksmithing, Enchanting, etc.)
  with "Open a profession window..." prompts. CollectCharacterProfessions
  was unconditionally creating an entry in newProfessions for every
  decor-recipe-bearing profession, regardless of whether the character
  actually had it. Now only persists an entry when there's evidence the
  character owns the profession: it appears in GetProfessions() (prof1,
  prof2, cooking, archaeology, fishing slots), prior cached non-empty
  skill levels exist, or the character knows at least one decor recipe
  in that profession (the safety net for Cooking when GetProfessions
  returns nil for the cooking slot).
- Alts tab Character Details: gathering professions (Skinning, Herbalism,
  Mining) now appear under the character's row when owned. Loop now
  iterates the union of "professions with decor recipes" and
  "professions the character has per GetProfessions()", so gathering
  professions (which have no decor recipes and were previously skipped)
  are included whenever the character actually has them.
- Alts tab phantom collapse arrow: the yellow collapse/expand triangle
  no longer leaks onto per-character header rows. The "No Professions"
  section header was lazy-attaching a collapseArrow to a frame in the
  shared charHeaderPool; when ReleaseAll recycled that frame back to a
  per-character header, the arrow stayed visible (and clicking it
  toggled the No Professions section instead of doing anything
  character-related). Per-char header acquisition now hides any leaked
  collapseArrow, resets the label anchor, and clears the section
  OnMouseUp script. Section header path also now hides any leaked
  per-char hideBtn/deleteBtn for the inverse direction.

## [2.35.1] (Released April 2026)

### Added
- VendorDB: three new Midnight 12.0.5 decor vendors wired up:
  - Depthdiver Tu'nakit (Zul'Aman, Abyss Anglers) -- 6 decor
    items priced in Angler Pearls
  - Rae'ana (Silvermoon City, Ritual Sites) -- 6 decor items
    priced in Voidlight Marl, Renown 3 / Renown 7 gated
  - Disguised Decor Duel Vendor (Silvermoon City, Falconwing
    Square) -- 12 Sin'dorei / Decor Duel decor items priced
    in Illusionary Coins
- Ritual Sites added to the renown faction lookup so vendor
  rep gates display as "Renown 3" / "Renown 7" and check
  C_MajorFactions correctly.

### Changed
- Disambiguated the two Rae'ana NPCs in the vendor list:
  Dragonscale Expedition's Rae'ana now shows as "Rae'ana
  (Waking Shores)" and the new one as "Rae'ana (Silvermoon)".

## [2.35.0] (Released April 2026)

### Added
- Shopping List import: housing.wowdb.com builds can now be exported
  directly into HDG. Click "Export Shopping List" on any build at
  housing.wowdb.com, paste the string into HDG's Import dialog, and
  HDG handles the rest -- attribution banner, clickable build URL,
  and per-item quantities all populate from the header. No mode
  switch required.
- Shopping List import: auto-resolve missing vendors. When an imported
  entry has no vendor specified but the item is flagged as
  vendor-sourced in HDG's catalog, the importer now picks the first
  matching vendor from HDG's vendor index. External tools no longer
  need to know vendor IDs.
- Preview: new "Dyeable" category filter alongside "Dyed" -- shows
  every decor that can accept dyes (whether or not you own a dyed
  copy yet).
- Useful Collections: new "Trophies" pinned collection. Includes
  every unique-trophy decor and every Preyseeker effigy -- the rare
  trophies earned through hard PVE content (raids, dungeons, prey
  hunts).
- Trainers: Cost / Method column widened so longer cost strings
  ("150 Artisan Alchemist's Moxie + Voidlight Marl") fit on one
  line. Map All / Clear button widths fitted to label text.

### Changed
- Internal: housing-catalog access centralised. All UI surfaces
  (Acquire, Preview, Styles, House Editor, Data, zone scanner) now
  read from one persisted snapshot instead of calling Blizzard's
  catalog API directly. Restored from SavedVariables on /reload for
  instant first paint; rebuilt automatically on patch crossing.
  Background verification sweep confirms saved data on each
  window-open. Refresh button performs a full reset. Two redundant
  per-tab searchers and three per-tab catalog caches retired.
- Dye-variant ownership: players who only own dyed variants of a
  decor are now correctly flagged as collecting that decorID
  (previously the base entry's zero-count masked it). Dyed variants
  rebuilt via Blizzard's variant API after the 12.0.5 catalog API
  change removed subtypeIdentifier from searcher results -- the
  House Editor's per-variant cards (with mini dye swatches) work
  again, and clicking a variant card places that specific variant.
- Alts: profession-recipe tracking now scans by profession-with-decor
  list rather than the player's primary slot indexes. Cooking and
  other secondary professions are tracked even when not in the
  player's primary slots.
- Shopping List import: hint text updated to "Paste an HDG, Wowhead
  or housing.wowdb.com string".

## [2.34.0] (Released April 2026)

### Added
- Preview tab: new filter layout. The "All" category now has sub-tags
  (mutually exclusive radio) -- All Decor, Crafted, House XP. Default is
  "All Decor" (full catalog). "Crafted" restricts to craftable items from
  the recipe database. "House XP" shows only unowned items that will
  grant house XP on first acquisition (uses entryInfo.firstAcquisitionBonus
  > 0 and auto-hides unreleased items). Unknown and Stored remain on the
  header row as INDEPENDENT toggles so they compose with categories and
  tags (e.g. Unknown + Crafted + Alchemy = uncollected Alchemy recipes).
- Preview tab: new "Only Unreleased" toggle alongside "Hide Unreleased"
  for a sneak-peek view of upcoming decor items (items with a patch ver
  higher than the current client build). The two toggles are mutually
  exclusive.
- House Editor tab (injected inside Blizzard's HouseEditorStorageFrame):
  unique trophy items now show the trophy icon (house-chest-trophy-icon
  atlas) instead of a "1" quantity badge. Matches Blizzard's own catalog
  behaviour.
- Collection state now persists across /reload. The owned decor set is
  saved to SavedVariables after each update and restored on login, so
  tabs paint with last-known collected markers immediately instead of
  empty state for ~0.5s. A fresh sweep runs in parallel if stale. The
  Refresh button wipes the persisted store and rebuilds from scratch;
  all other SavedVariables (crafting/farming history, known recipes,
  custom styles, shopping lists, user notes, config) are untouched.
- HDG_ENTRY_UPDATED EventBus event (payload: decorID, itemID, isOwned,
  wasOwned, stored, placed, redeemable) fires on each per-entry change
  for future per-row UI consumers. Existing tabs continue to use the
  coalesced HDG_COLLECTION_READY broadcast.

### Changed
- Recipes tab: "Known" filter is now ACCOUNT-WIDE instead of current-
  character only. Shows recipes learned by any character on the account.
  Narrow to a single character via the profession tag. Thanks to Jack
  for the feedback -- this matches the workflow he outlined: Known +
  Expansion + Profession filters to quickly thin down the list for
  shopping queue planning.
- Collection detection rewritten to match Blizzard's canonical pattern
  (Blizzard_HousingDashboardCatalog.lua). HOUSING_STORAGE_UPDATED (bulk)
  runs a full arithmetic sweep; HOUSING_STORAGE_ENTRY_UPDATED (per-entry)
  patches a single decor via GetCatalogEntryInfo(entryID). Replaces the
  previous debounce / shrink-guard / retry machinery with an O(1)
  per-event path. Coalesced HDG_COLLECTION_READY (0.3s) keeps tab
  refreshes batched during 100-item acquisition bursts.

### Fixed
- CRITICAL: collection arithmetic was reading nonexistent fields. The
  sweep used info.totalNumStored / info.totalNumPlaced, but the real
  runtime fields (in-game verified and confirmed in
  Blizzard_HousingCatalogEntry.lua:437-438) are info.quantity /
  info.numPlaced. Items with no remainingRedeemable were silently
  invisible to the sweep -- most of a mature player's collection.
  Fixed in both the bulk sweep and per-entry paths.
- CatalogSearcher configured with correct method names. Previous code
  called SetStoredOnly(false) and SetBaseVariantOnly(true) -- neither
  method exists in Blizzard's searcher API; both silently no-op'd.
  Replaced with the canonical SetOwnedOnly(false) and
  SetDistinctPerRecordID(true). Similarly removed phantom
  SetIncludeMarketEntries calls from the Preview tab's own searcher.
- Preview tab "Loading catalog..." stuck state on cold login. The tab's
  persistent searcher kicked at window-open time before Blizzard's
  catalog had synced from the server; the callback never fired, the
  in-progress flag latched true, and subsequent HOUSING_STORAGE_UPDATED
  events couldn't retry. Fix: the storage event handler now re-kicks
  the searcher AND clears the stale in-progress flag, so when Blizzard
  reports storage ready the next RunSearch produces fresh results and
  the callback fires. After /reload the catalog was already cached so
  the bug only showed on cold login.
- Preview tab's variant-discovery searcher now uses
  SetDistinctPerRecordID(false) to return each dyed copy as a separate
  entry (matches Blizzard_HouseEditorStorageFrame storage-mode config).
- Lumber tracker in Recipes tab: "In Stock" column sometimes rendered
  the "have/needed" form instead of the collapsed single-count form
  on first window open, even for lumber types whose decor was fully
  collected. Fix: HDG_COLLECTION_READY handler also refreshes the
  embedded in-window tracker, not just the pinned widget.
- Eliminated 17 false positives from the firstAcquisitionBonus
  heuristic used in previous versions (Spring Blossom Pond, Lunar
  Celebrant's tea set items, Brown Paper Sack, and similar items that
  incorrectly showed as collected when they weren't).

### Removed
- HDG_Data.MarkDecorCollected and the HOUSE_DECOR_ADDED_TO_CHEST
  optimistic-write kludge. The shopping list now refreshes via the
  normal HDG_COLLECTION_READY chain (~300ms after the acquisition event
  fires). LumberTracker's event wiring already did the right thing.

## [2.33.0] (Released April 2026)

### Added
- Recipes tab: new expansion-filter dropdown above the profession list. Lists
  only expansions that have recipes in the DB, tinted with the expansion's
  canonical colour. Selection persists across /reload.
- Recipes tab: new "Known" toggle button added between "All" and "Ready",
  restricting the list to recipes the current character has already learned.
  Tri-state exclusive with "All" / "Ready"; selection persists across /reload.
  Big thanks to Jack for prototyping both filters in a community fork —
  these features are ported from his work.

### Fixed
- Lumber tracker in Recipes tab: "In Stock" column sometimes rendered the
  "have/needed" form instead of the collapsed single-count form on first
  window open, even for lumber types whose decor was fully collected. Root
  cause: the lumber tracker's HDG_COLLECTION_READY handler only refreshed
  the pinned widget, not the embedded in-window tracker. Switching tabs
  away and back masked the issue (RefreshLumberTracking fires on show).
  Fix: also call HDG_UI.RefreshLumberTracking() when the collection cache
  warms, so the embedded tracker re-renders with fresh collection state.

## [2.32.0] (Released April 2026)

### Fixed
- Cold-login collection state: every decor showed uncollected (red X, every
  style "0/N", every profession's decor count "0/N") until /reload. Reported
  2026-04-20. Root cause: the addon kicked off a "warm collection cache" pass
  1s after PLAYER_ENTERING_WORLD, but Blizzard's housing catalog isn't synced
  that early on cold login. The searcher returned 0 results and set the
  ownedSearchDone flag with empty data, locking every subsequent
  IsItemCollected call into "false" until a /reload (which fires the warm
  again with the catalog already cached locally) or a manual Refresh button
  press (which runs much later, when the catalog is ready). Fix: rip out the
  PEW eager warm and the layered retry/backoff hacks added during diagnosis,
  and instead run the same logic the Refresh button uses whenever the main
  window opens. By window-open time the catalog is reliably ready (same
  conditions under which Refresh has always worked). Window-open refresh and
  manual Refresh now share a single HDG_UI.RefreshAll(silent) function.
- Style tab now subscribes to HDG_COLLECTION_READY (parity with Recipes tab)
  so any async cache fill -- not just window-open -- re-renders the visible
  view with fresh stats.
- Refresh button now also re-renders the Style tab (was previously omitted).
- In-editor tab: storage count not refreshing after picking a decor back
  up to the chest (reported by px: place something, then delete it, the
  Storage count in the tooltip doesn't go back up). Root cause: we only
  rebuilt the catalog cache on place success/failure, customization, and
  storage-updated events; HOUSING_DECOR_REMOVED + HOUSE_DECOR_ADDED_TO_CHEST
  weren't wired. Now both events trigger a 0.2s-delayed cache rebuild
  (same pattern as dye changes, giving Blizzard's catalog time to update
  before we re-read).

### Added
- **Recent Activity tracker:** new mode in the in-editor HDG tab (Shift+Z >
  Storage panel > HDG > Recent) that records every decor placement and removal
  while you edit your house, grouped into "edit sessions." Cells use the
  Communities chat plus/minus atlases: a cyan + marks items you placed, a red
  - marks items you removed, and a cell with both badges means you placed and
  then picked it back up in the same session (dimmed). An `xN` badge counts
  repeated touches of the same decor. Hover any cell for the standard 3D model
  preview plus a session-scoped tooltip ("Placed 2m ago", "3 still placed of
  5 placed this session"). Left-click to place another copy from storage with
  the same ownership/indoor-outdoor checks as other modes. A +/- 10 stepper
  at the top of the sidebar lets you raise the per-house session cap (default
  10, soft warning at 200).
- **Recent section in the Styles tab:** the standalone HDG window now has a
  dedicated Recent section listing every recorded edit session in a sidebar.
  Clicking a session opens a read-only detail view with the same +/- timeline
  cells, so you can browse session history outside the editor.
- Built entirely on Blizzard housing events (taint-safe; no calls to the
  enumeration APIs that addons can't touch). Pure rearrange/move/dye sessions
  leave no SavedVariables trace.

### Changed
- HDG Styles tab migrated to modern WowScrollBoxList for landing rows, item
  list, and card grid. Card rendering centralized into a new
  HDG_StyleCardRow helper module that delegates to the existing gallery
  cell factory and layers Recent Activity overlays on top via optional
  fields. First-render times for large styles drop from hundreds of
  milliseconds to single-digit milliseconds; scroll is now natively
  virtualized. Tier headers in the landing view are click-to-toggle and
  persist their collapsed state.
- HDG in-editor tab (Shift+Z > Storage panel > HDG) sidebar and card grid
  migrated to modern WowScrollBoxList. The card grid now uses the same
  HDG_StyleCardRow helper as the standalone Style tab, extended with
  cellConstructor + cellBinder hooks so the in-editor cell variant (dye
  swatches, indoor/outdoor border, Recent +/- overlays) plugs into the
  shared virtualization path. Significant first-render speedup on large
  sessions and styles; scroll is now natively virtualized.

### Fixed
- HDG.Store:SaveToSavedVariables was silently dropping HDG_DB.recentActivity
  on every save (the rebuild used an explicit allowlist of keys, and the
  tracker's data wasn't on it). Recent Activity sessions now persist across
  reloads and logouts.

## [2.31.1] (Released April 2026)

### Changed
- Re-release of v2.31.0. The v2.31.0 build was stuck in CurseForge's
  moderation review queue and was not installable by users. No code or
  data changes from 2.31.0 — see the v2.31.0 notes below for the full
  change set.

## [2.31.0] (Released April 2026)

### Changed
- Styles tab first-open: StyleEngine:BuildCache() trimmed by ~30% (392ms -> ~270ms
  on M4 Pro; older hardware proportionally faster). Query/boost/anti facet arrays
  are now pre-compiled into {[val]=true} lookup sets on each style def, so
  ScoreItem's hot path (100k+ calls during cache build) uses O(1) set lookups
  instead of nested array scans. Pre-filtered validItemList skips redundant
  per-style HDG_AllDecorDB lookups.
- Decor Preview list migrated to modern WowScrollBoxList + DataProvider.
  Previously the tab created one persistent frame per filtered item (~1632
  frames), so every time previewPanel:Show() ran, Blizzard's native
  visibility cascade walked every row (~540ms per tab switch). ScrollBox
  virtualization keeps only ~20 viewport frames live; tab switches now
  complete in ~1-3ms (roughly 300x faster), memory drops by several MB,
  and scrolling is noticeably smoother. API patterns verified against
  Gethe/wow-ui-source (Blizzard_Communities, SharedXML/Scroll)
- Recipes tab recipe list migrated to WowScrollBoxList + DataProvider.
  Mixed element kinds (recipe row, inline profession header, tier header,
  spacer) share one virtualized pool via a variable-extent calculator.
  Hand-rolled recipeRowPool + tierHeaderPool + ad-hoc CreateFrame inline
  profession headers collapsed into a single Initialize+Bind pattern; the
  inline-header per-refresh CreateFrame churn is gone.
- Recipes tab materials list migrated to WowScrollBoxList + DataProvider.
  Seven element kinds (collapsible header for category/recipe/Intermediates,
  non-collapsible sub-header for ByRecipe category dividers, reagent row with
  progress StatusBar, intermediate parent row, indented intermediate child
  row, spacer, emptyState) share one virtualized pool via a variable-extent
  calculator. The three manual pools (matHeaderPool / matRowPool / matSubPool)
  and Acquire/Release helpers are gone. This retires the legacy CreateScrollPane
  helper — all three Recipes tab panels now construct WowScrollBoxList inline.
  Tab re-open (steady-state): ~107ms -> ~3.8ms.
- ScrollBox migrations now uniformly RetainScrollPosition on every refresh.
  Previously filter changes and mode toggles could kick the list back to top;
  now ScrollBox holds position and clamps to data bounds if the list shrinks.
- Recipes tab crafting queue migrated to WowScrollBoxList + DataProvider.
  Four element kinds (character header, item row, "Craft Order:" label,
  expanded craft-order step) share one virtualized pool; the three manual
  pools (queueHeaderPool / queueRowPool / queueSubPool) and their
  Acquire/Release helpers are gone. Expand/collapse of subsidiary recipes
  still rebuilds the full flat element list (cheap with native
  virtualization). HDG_UI.UpdateLumberLayout updated to reposition
  mainFrame.queueScrollBox (the old mainFrame.queueScroll field).
- Acquire tab (By Item + By Vendor) migrated to WowScrollBoxList +
  DataProvider with a variable-extent calculator to mix vendor headers,
  bundle headers (Shop), and indented item rows in a single virtualized
  list. The legacy manual virtual-scroll hack (UpdateVisibleItemRows +
  OnVerticalScroll hook + 200-item threshold) is gone; ScrollBox handles
  viewport recycling natively. The pooled row factories in HDG_AcqRows
  (CreateItemRow / CreateVendorHeaderRow) collapsed into Initialize+Bind
  renderers the ScrollBox calls per-row. Arrow-key navigation scrolls
  via scrollBox:ScrollToElementDataIndex against an index tracked during
  populate. Rows no longer draw 1px edge borders (BackdropTemplate is
  unavailable on bare ScrollBox-created frames; the Preview migration
  established the bg-texture-only pattern)

### Fixed
- Decor Preview: owned counts were stale for up to 5 minutes after buying or
  redeeming decor. HOUSING_STORAGE_UPDATED/HOUSING_STORAGE_ENTRY_UPDATED now
  invalidates the collected-decor cache in addition to the destroyable cache
- Decor Preview rows stuck on the question-mark icon until scrolled away: the
  async item-data path now invalidates the cached miss and refreshes the
  visible list on GET_ITEM_INFO_RECEIVED (previously fire-and-forget)
- Decor Preview name/icon lookups: GetCachedItemInfo now triggers
  RequestLoadItemDataByID on misses so uncached items eventually populate
- Recipes queue-item tooltip: extra reagent lines are now rebuilt on
  GET_ITEM_INFO_RECEIVED when the tooltip is still shown for the same row,
  replacing a 50ms race timer that could swallow cold-cache item data
- Recipes queue craft button: five C_Timer.After(0.1-0.3, ...) guesses around
  C_TradeSkillUI.OpenRecipe replaced with a single helper that waits on
  TRADE_SKILL_LIST_UPDATE (Blizzard's actual ready signal); 2s fallback for
  edge cases

### Changed
- Replaced three timer-based waits in the main event handler with event-driven
  patterns: HOUSE_DECOR_ADDED_TO_CHEST no longer schedules a 0.5s deferred
  RefreshUI (HOUSING_STORAGE_ENTRY_UPDATED drives it now, matching Blizzard's
  own UI); login pinned-window restores wait for BAG_UPDATE_DELAYED instead of
  0.5s/0.8s guesses. 5s fallback timer retained as a safety net.

### Added
- HDG_Debug.Timed(label, fn) helper: wraps a function and reports elapsed ms
  when debug mode is on (no-op otherwise). Uses GetTimePreciseSec so nested
  timers don't clobber each other. Wired into HDG_UI.UpdateTabs, the Decor
  Preview Show/Refresh/RefreshList path, and the Styles tab Show path so
  /hdgdebug on now prints per-stage tab-switch timing
- Debug on/off state persists across /reload via config.debugOnAtLoad, so
  investigation sessions survive a reload without re-running /hdgdebug on

### Fixed
- Materials panel now counts Midnight quality-variant reagents (e.g. Radiant
  Shard 243602/243603). Regenerated HDG_ProfessionsDB.lua from a fresh cross-
  guild scan so the variant cache picks up every Midnight reagent pair
- 8 reagents moved from Vendor to Crafted (Outsider's Provisions, Ghost Dye,
  Gilded Vial, Greater/Powerful Ghostly Spellthread, Prototype Barding
  Frameworks, Pebbled Rock Salts). Reported via Discord for Outsider's; the
  rest surfaced from the same audit

### Added
- HDG_ReagentsDB expanded to 2541 entries (+431 Midnight/TWW additions,
  including Midnight fishing catches, cooking vendor ingredients, and the new
  2-tier quality pairs)
- New "In-Game Shop" virtual vendor in the By Vendor view, grouping all
  Hearthsteel and real-money housing decor products in one place
- HDG_ShopDB.lua: seeded from a live C_CatalogShop capture with 36 housing
  items + 5 real bundles (Lush Garden Decor Pack, Spring Blossom Decor Pack,
  The Roofus Pack, Small Starter Decor Pack, Midnight Epic Edition). Each
  entry carries its C_CatalogShop productID for future live-price overlay
- HDG_VendorResolver synthesizes a virtual HDG_VendorDB entry (npcID=-9001)
  from HDG_ShopDB so existing By Vendor pipeline renders it unchanged
- Bundle grouping: items now sit under their bundle's inline header in the
  expanded shop view; solo items fall to the bottom. Bundle headers show
  localized price ("2500 [Hearthsteel icon]" or "$$$" for region-dependent
  real money until a live-overlay pass lands)
- Hearthsteel icon support: new "h" currency tuple type in VendorDB cost
  resolver, rendered inline via atlas `hearthsteel-icon-32x32`
- FormatCurrencyIcon helper: unified inline icon markup for both fileID and
  atlas-name sources
- Bundle-only items show "Bundle only" label instead of a price amount

### Changed
- HDG_AllDecorDB: 16 bundle-exclusive items (8 Midnight Epic edition decor,
  8 Roofus Pack items) re-tagged with sourceType=SHOP. Midnight items keep
  Dennia Silvertongue as an alt source (she stocks more after tier purchase)
- HDG_VendorDB header comment: noted hand-curated status and virtual vendor
  synthesis hook
- Wowhead NPC link button hidden for synthetic vendor IDs (< 10000000 upper
  cap on the guard at HDG_AcquisitionTab:1314)
- Silenced "HDG loaded" login chat message (shown only when debug mode is on)

## [2.30.9] - 2026-04-12

### Fixed
- House Editor tab: Fix dyed decor quantity display showing 0 undyed copies when dyed variants exist (double-subtraction of Blizzard-separated quantities)
- House Editor tab: Add "(Undyed)" label to base item cells when dyed variants are present for clarity
- House Editor tab: Tooltip now shows "Undyed" instead of "Owned" for base items with dyed variants
- House Editor tab: Use base entry ID for placement to improve undyed item placement order
- House Editor tab: Stay on HDG Styles tab after removing a placed item (Blizzard resets to Storage tab on any storage change; now intercepts the reset when HDG tab was active)
- House Editor tab: Register HOUSING_DECOR_CUSTOMIZATION_CHANGED event so dye operations update the grid
- House Editor tab: Release catalog searcher after callback to prevent memory leak
- House Editor tab: Nil catalog searcher reference on stale-generation exit path (was leaking the old reference when cache invalidated mid-scan)
- House Editor tab: Remove searcher:Release() calls -- method doesn't exist on catalog searcher userdata; nil the reference and let GC handle cleanup
- House Editor tab: Deduplicate CUSTOMIZATION_CHANGED + STORAGE_UPDATED double-rebuild (dye ops fire both events in same frame)
- House Editor tab: Add indoor/outdoor placement restriction check to dye-variant and base-entry click paths (was only checked in fallback path)
- House Editor tab: Improve qty<1 error message on pre-resolved entries to distinguish "all placed" from "unowned"
- Data: Fix OpenProfessionAtRecipe using removed BOOKTYPE_PROFESSION constant — use skillLine from GetProfessionInfo instead
- Data: Fix collection search watchdog not draining pending callbacks or firing HDG_COLLECTION_READY when it trips
- Vendor Shopping List: Fix pool-reuse race in async item load callbacks -- stale callback could overwrite a recycled row with wrong icon/name
- Styles Tab: Replace em-dash (U+2014) with ASCII dash in source detail text -- em-dash renders as box in WoW Latin fonts
- Acquisition Tab: Replace all em-dashes with ASCII dashes in help text, crafted source line, and cost summary
- Style Engine: Fix GetStyleStats returning wrong keys for thematic styles -- HouseEditorTab sidebar showed 0 items for all thematic styles; also skip _byItemID hash in count loop
- Vamoose Talking Head: Fix orphaned hide timer on rapid re-trigger -- second PlayTalkingHead during fade-out no longer gets hidden by the first timer
- UI: Clamp saved scale to 0.5-2.0 range to prevent collapsed frame from corrupt SavedVariables
- Fix GetBuildInfo crash when another addon clobbers the `Build` global -- use type check so we fall back to GetBuildInfo() gracefully

### Added
- Recipes Tab: Small profession icon button on each row for professions the character has -- click to open the profession window directly

## [2.30.8] - 2026-04-10

### Added
- AllDecorDB: 237 new items pre-loaded for Patch 12.0.5 (Lush Garden, Sin'dorei, seasonal, and more) — auto-hidden on live clients via version gating
- AllDecorDB: `ver` field — tracks which patch version each item was first seen in. Items from future patches are hidden under "Hide Unreleased" and automatically appear when the patch goes live. No addon update needed on patch day.
- Expansion Aliases: 21 missing CJK expansion display names (Korean, Simplified Chinese, Traditional Chinese) — fixes "Unrecognized expansion name" errors on Korean and Chinese clients for all expansions including Midnight
- TOC: 12.0.5 compatibility declared (120001, 120005)
- Data Pipeline: WowCodex decor scanner now fetches wago.tools HouseDecor DB2 — discovers items not yet in the Blizzard REST API
- Data Pipeline: ProfTools `/pt catcsv` now scans full Blizzard catalog (all decorIDs 1-20000) and saves to SavedVariables

### Fixed
- Expansion Data: Korean Midnight alias ("한밤") was missing — caused "Unrecognized expansion name" error on Korean clients

## [2.30.7] - 2026-04-08

### Fixed
- Zone Scanner: Squirrel alerts no longer fire false positives on login when the collection cache hasn't finished warming — now gates on IsCollectionCacheWarmed() before scanning

### Added
- AllDecorDB: 10 new items — 8 Paw Pal shop items (Dog House variants, Bed, Water Dish) and 2 Farstriders statues
- AllDecorDB: 48 Blizzard name corrections (painting titles now quoted, Loa titles now comma-separated)
- Data Pipeline: SHOP=12 source type added to match HDG_Config.lua

### Changed
- Data Pipeline: Restructured housingdecorguide-tools into pipeline-named folders (alldecor/, facetdb/)
- Data Pipeline: refresh_alldecordb.py now accepts WowCodex JSON (Blizzard REST API) as input
- Data Pipeline: Removed destructive build_all_decor_db.py and 30+ orphaned one-off scripts

## [2.30.6] - 2026-04-05

### Fixed
- Lumber Tracker: Denominator showed total lumber for ALL recipes instead of just uncollected ones — race condition where CalculateLumberNeeds ran before collection search completed on login, and HDG_LumberTracker never listened to HDG_COLLECTION_READY to recalculate
- Lumber Tracker: Collecting a new item mid-session now invalidates lumber needs cache (HOUSE_DECOR_ADDED_TO_CHEST handler)
- Recipes Tab: "Known by alts" now shown for professions the current character HAS but knows fewer recipes than an alt — previously only shown for professions the character didn't have at all
- Recipes Tab: Badge shows alt's recipe count in white when alt knows more (same visual treatment as professions the char doesn't have)
- Recipes Tab: Grand total recipe percentage now uses best count across current char + alts

### Added
- Goblin Tab: Small profession icon (atlas) shown before item name when Prof filter is set to "All"

## [2.30.5] - 2026-04-03

### Fixed
- Lumber Tracker: Embedded/pinned lumber display not refreshing after crafting a queued recipe — crafting queue dispatch only invalidated the cache but never triggered a UI redraw. Reverted broken inline cache rebuild in GetCachedLumberData and added explicit RefreshLumberTracking call after craft queue updates
- Zone Scanner: Fixed forward declaration of RefreshIfShowing to avoid nil reference

## [2.30.4] - 2026-03-30 (March 2026)

### Fixed
- Zone Scanner: All items showed as uncollected (0 collected) — ShowPopup was invalidating the collection cache then immediately rendering before the async catalog search could finish. Now waits for cache warmth or re-renders on HDG_COLLECTION_READY callback
- Zone Scanner: Eye toggle (show/hide collected) no longer wipes the collection cache unnecessarily

---

## [2.30.3] - 2026-03-25

### Refactored
- StylesTab: Landing page replaced with unified row list (44px rows with icon, name, description, 6 preview icons, count, progress bar, hover action buttons). Supports search and scales to 100s of styles
- StylesTab: Style Editor extracted to HDG_StylesEditor.lua (1,747 lines, 37% of original file)
- StylesTab: Removed separate card factories (CreateCard/CreateMinicard) and shopping list card renderer — one row type for all styles, collections, snapshots, and shopping lists
- Collection Detection: Replaced per-item CheckCollected/WarmCollectionCache system with catalog searcher (SetOwnedOnly) + placed-item sweep. Eliminates cache poisoning from early warm-up timing. Fixes ~10 previously miscounted items
- StyleEngine: GetStyleCollectionStats uses IsDecorCollected (decorID path) instead of IsItemCollected
- StyleEngine: Collection namePattern matching uses live Blizzard names from itemCache instead of static AllDecorDB.name

### Performance
- StyleEngine: Unified itemCache pre-computes all per-item data (name, icon, source, vendor flags, dye status) during BuildCache — StylesTab no longer calls Blizzard APIs during render
- StylesTab: Sort comparators use pre-built name lookup instead of O(N log N) GetDecorName API calls
- StylesTab: ItemHasRepRequirement / ItemCostsEndeavor read cached booleans instead of iterating VendorDB per item per refresh
- StylesTab: statsCache elevated to module-level with dirty flag — no longer recomputed on every collapse toggle or filter click
- StylesTab: Collapse state persisted only on toggle click, not on every RefreshLanding
- StylesTab: Card icon rendering reads from itemCache instead of pcall(GetCatalogEntryInfoByRecordID)
- HousingDecorGuide: CollectCharacterProfessions debounced (0.5s) on TRADE_SKILL_LIST_UPDATE — prevents 10-20x/sec dispatch storms when profession window is open
- HousingDecorGuide: Removed redundant HDG_UI.RefreshUI() after crafting queue Dispatch (EventBus subscriber already handles it)
- StylesTab: Row click updates highlights only (no full RefreshDetail) — module-scope ListRow_OnClick handler
- StylesTab: Gallery cell OnClick/OnEnter/OnLeave extracted to module-scope handlers (eliminates ~1,200 closure allocations per render)
- StylesTab: Tier tooltip labels table built once on first hover, not per-cell
- StylesTab: Gallery cell opts table allocated once, not per-cell
- StylesTab: ApplyFont only re-applied when theme scheme changes, not on every RenderItemList call
- StylesTab: Editor basket count tracked as integer (editorBasketCount) instead of pairs() iteration on every OnLeave
- StylesTab: Editor tier filter chip uses DebouncePreview instead of direct UpdateEditorPreview
- AltsTab: EventBus handlers defer Refresh() when tab is hidden (dirty flag, refreshes on Show)
- HDG_UI: Removed recipesTabDirty dead code (was set in 6 places, never read)
- UIHelpers: Added BACKDROP_FLAT constant, used in CreateFilterButton (eliminates per-call table allocation)
- UIHelpers: ClearScrollContent no longer orphans frames to WorldFrame (removed SetParent(nil) calls)

### Added
- Trainers Tab: "Midnight Recipe Sources" section — shows where to learn all 52 Midnight housing decor recipes, grouped by profession. Color-coded source types (vendor/trainer/drop/discovery/quest), NPC names, zones, costs, and Navigate button for vendors with known coordinates
- DecorDB: Recipe acquisition source data for all Midnight recipes (recipeSource table with type, NPC, zone, mapID, coords, cost, skill level)
- Style Editor: "Used in" indicator — items in other curated styles show a dot badge with tooltip listing style names (up to 5, then "+X more")
- Preview Tab: "Dyed" filter category to show only dyed variants
- Preview Tab: Dyed items show "(Dyed)" suffix and dye color names in detail panel (e.g. "Dyes: Horde Red")
- Preview Tab: Tags line no longer word-wraps
- House Editor: Dyed variants properly split into separate grid cells with dye-drop icon and color swatches
- House Editor: Dye color swatches (from C_DyeColor API) shown along top of dyed variant cells
- Collections: "Recently Learned" collection — de-duped items from acquisition history (chest additions only)
- Collections: Recently Learned + Dyeable pinned at top of collections list
- Acquisition Tab: Dyeable items now show dye icon badge in row names (wired to StyleEngine:IsDyeable)
- Acquisition Tab: "Dyeable: Yes" line now appears in vendor detail panel for dyeable items
- Styles Tab: Alphabetical sorting for My Styles, Snapshots, and Collections (case-insensitive)
- Styles Tab: Wowhead shopping lists show logo icon + clickable inline URL copy
- Styles Tab: Collection count (X/Y %) displayed next to search box

### Fixed
- Preview Tab: "Script ran too long" — filter state pre-computed once per refresh instead of per-item; lowered strings cached on item data
- Preview Tab: Dye variant search only checks dyeable items (canCustomize), not all owned items. Guard flag prevents duplicate appends
- House Editor: False dye swatches on non-dyeable items — now requires actual dye data (customizations/dyeIDs) before marking as dyed variant
- House Editor: catalogSearcher nil crash in async callback
- GoblinTab: UpdateTSMModeToggle nil from shadowed local variable declaration
- DataTab: LogAcquisition `state` nil global reference → `store:GetState()`
- StylesTab: GetStyleDef infinite recursion when StyleEngine is nil (returned nil instead of self-call)
- StylesTab: EditorAutoSave stored editorLockedItems by reference — opening a new style wiped previous styles' curated/locked items (shared-reference corruption)
- StylesTab: Final save for smart styles also stored lockedItems/removedItems by reference
- Store: SaveCustomStyle now deep-copies def to prevent any future reference-sharing bugs
- Store: Migration detects corrupted styles on load — auto-repairs smart styles (query intact), warns user about curated styles with duplicate item sets
- House Editor: Grid never refreshed on HOUSING_STORAGE_UPDATED (PopulateGrid called with no args)
- House Editor: IsIndoors() used for placement borders instead of C_Housing.IsInsideHouse() — showed wrong borders when opening editor from outdoors
- House Editor: SetTab override double-toggled Blizzard UI on HDG tab click (Hide then Show flicker)
- House Editor: Tab flicker after placement — Blizzard's OnShow calls SetTab(storageTabID) unconditionally; now intercepted synchronously in SetTab override
- House Editor: placedFromHDGTab never reset on placement cancel/failure — Storage tab permanently hijacked
- House Editor: Concurrent catalog searchers could stack with no cancel guard
- House Editor: Catalog searcher GC'd before async callback fired — catalogScanInFlight stuck true permanently
- House Editor: Cache rebuild gated on IsShown() — missed rebuilds when panel hidden during event sequence
- VendorResolver: Removed InvalidateCollectionCache on every zone change — was triggering full 1600-item catalog sweep per ZONE_CHANGED_NEW_AREA
- HDG_Data: MarkDecorCollected O(N) linear scan over AllDecorDB replaced with O(1) _decorToItem reverse lookup
- PowerCrafting: BuildReagentIndex reagentsArray built once per recipe instead of O(R^2) inside inner loop
- MaterialsList: Search OnTextChanged now debounced (0.25s) — was triggering full reagent scan per keystroke
- DataTab: LogCraftFromItemLink + LogAcquisition use Store:AddCraftingHistory instead of direct state mutation
- AcquisitionTab: Removed C_Timer.After(0) from Show/ShowByItem — synchronous refresh
- HouseTab: Removed C_Timer.After(0) from Show — synchronous UpdateXPBar/UpdateCollectionStats
- AcqRows: collapseBtn closure moved inside _handlersSet guard
- RecipesTab: Recipe row click/tooltip handlers set once via _handlersSet, data stored on btn
- RecipesTab: ResetRecipeRow clears _handlersSet flag instead of scripts (fixes click-to-queue regression)
- ThemeEngine: ApplyAtlasBackground C_Timer.After(0) replaced with OnSizeChanged hook; fixed OnSizeChanged args crash
- VendorResolver: SaveCache uses Store:SetVendorNameCache instead of direct state mutation
- UIHelpers: Extracted ApplyFilterButtonColors shared helper from Create/Update duplicate
- HDG_Data: PlayerHasProfession cached via playerProfessionSkillLines set, invalidated on TRADE_SKILL_LIST_UPDATE
- MaterialsList: Inline SetBackdrop table allocation replaced with lazy GetBackdropSolid() constant (7 sites)
- MaterialsList: Item counts cached on row at render, reused in OnEnter tooltip
- AchievementSection: Removed duplicate arrow OnClick handler (was firing double Relayout)
- RecipesTab: Tier header FontStrings now pooled via tierHeaderPool
- AltsTab: Triple GetState() collapsed to single local
- Framework: Dropdown popup rows pooled (reused across opens instead of unbounded frame creation)
- VendorShoppingList: Vendor + item row handlers set once via _handlersSet (eliminates ~200 closures per refresh)
- DecorPreviewTab: Fixed decorInfo scoping bug (was nil outside if block)
- LumberHUD: Blip recycling replaced O(N) scan + O(N) table.remove with single-pass compaction

### Refactored
- House Editor: Unified catalog cache replaces 5 separate caches/flags (dyeCache, catalogInfoCache, dirty flags, scan guard). Single owned-only catalog scan on tab show provides ownership, item info, and dye variants. Zero per-item API calls during style switching.
- House Editor: Generation counter on catalog cache drops stale async callbacks after invalidation
- House Editor: Merged duplicate GetCustomStyleSidebarItems/GetSnapshotSidebarItems into GetCustomStyleSidebarByFilter
- House Editor: MODE_CONFIG table replaces 5 near-identical RefreshCurrentMode branches
- House Editor: BLIZZARD_PANELS array replaces repeated Show/Hide calls in ShowHDGContent/HideHDGContent
- House Editor: Click handler unified — deduplicated StartPlacingNewDecor + placedFromHDGTab across base/dyed paths
- House Editor: Cached themes/collections sidebar lists (static data, built once)
- House Editor: Simplified IsItemOwned (removed unused decorID param), removed EnsureStyleCache wrapper, placeLabel logic
- House Editor: hookFrame unregisters ADDON_LOADED after first match
- House Editor: Extracted ProcessSearchEntry, ResolveItemDisplay, GridCell_OnClick from deep-nested loops — max 2 levels of nesting, zero per-cell closure allocation
- House Editor: PopulateGrid loop body reduced from ~130 lines to ~30 lines

### Removed
- Dead HDG_DyeData references in AcqRows, AcquisitionTab, DecorPreviewTab (module was never built)
- DecorPreviewTab: Removed non-functional dye swatch strip (HDG_DyeData.GetCategories never existed)
- StyleEngine: dyeableSet replaced by unified itemCache

---

## [2.30.1] - 2026-03-23

### Added
- Alts Tab: Delete character data button (trashcan icon next to each character name)
- Fixes realm transfer / rename duplicate issue — delete the stale entry to correct lumber and profession counts
- House Editor tab: Dyed item detection via catalog searcher scan
- House Editor tab: Dyed variants shown as separate grid cells with dye-drop icon and dye name label
- House Editor tab: Multi-channel dye names joined in label and tooltip (e.g. "Horde Red, Alliance Blue")
- House Editor tab: Tooltip shows "Dyes: ..." line on dyed variant cells
- House Editor tab: Clicking a dyed variant cell places the correct dyed copy (not a random base stack item)
- Preview tab: Improved dye detection with multi-signal check (subtypeIdentifier + customizations + dyeIDs)
- Useful Collections: 26 auto-resolved collection minicards on the Styles tab (Chairs, Tables, Plants, Dyeable, etc.)
- Reference docs: Verified dye API findings (HousingCatalogSearcher dye detection pattern, field types, entrySubtype values)

### Fixed
- House Editor tab: Grid qty not updating after placing items (was calling PopulateGrid with no args instead of RefreshCurrentMode)
- House Editor tab: Dye cache invalidated on HOUSING_STORAGE_UPDATED and placement events

---

## [2.30.0] - 2026-03-22 (March 2026)

### Added
- Style Creator: Curated mode — hand-pick exact items for a style without auto-scoring
- Style Creator: Smart/Curated toggle buttons in the editor top bar
- Style Creator: Search box for filtering items by name (curated mode)
- Style Creator: Add All button for bulk-adding visible items to basket
- Style Creator: Default name includes "(Curated)" suffix for curated styles
- Style Creator: Name auto-updates when toggling between Smart and Curated modes
- StyleEngine: FilterItemsByFacets for curated browse (AND across facets, OR within)
- StyleEngine: Curated cache, stats, and collection stats support
- Curated styles show in My Styles, House Editor, and detail view with Edit/Export/Delete
- Landing page card description shows "Curated" label for curated styles
- House Editor tab: Default mode changed to "Your Styles"
- House Editor tab: 3D hover preview on icon grid items (anchored outside panel)
- House Editor tab: Indoor/outdoor placement validation with user feedback messages
- House Editor tab: Gold-bordered HDG icon and title in tab header
- House Editor tab: Already-placed item detection with status message
- House Editor tab: StoragePanel OnShow hook restores tab state after item placement

### Fixed
- House Editor tab: Indoor/outdoor label showed "Indoor only" for items allowed both indoors and outdoors (Lua nil-ternary pattern bug)
- House Editor tab: InCombatLockdown guard on tab injection (prevents taint)
- House Editor tab: Tooltip name fallback used sourceType number instead of item name
- House Editor tab: Hover preview placeholder nil check
- House Editor tab: Grid refreshes on HOUSING_STORAGE_UPDATED (owned counts stay current)
- House Editor tab: Tooltip matches Blizzard format: "Owned: N (Placed: X, Storage: Y)"
- Style Creator: Curated styles no longer render empty in detail view (missing items.curated fallback)
- Style Creator: Clear All now properly clears curatedItems from working definition
- Style Creator: Export button hidden in curated mode (no serializer support yet)
- Style Creator: Duplicate of curated style preserves tier and curated items
- Style Creator: Collection cache pre-warmed on editor open (fixes missing items for some players)
- Landing page: Curated styles now appear under "My Styles" category
- Card icons: Curated styles show item preview strip (uses curated bucket)

### Changed
- Style Creator: New styles default to Curated mode
- Landing page: Removed Races, Moods, Classes, Expansions from category filter row
- House Editor tab: Icon grid backgrounds set to 90% opaque black
- House Editor tab: Fine-tuned RadioGroup and header positioning
- House Editor tab: Sidebar lists sorted alphabetically
- House Editor tab: BuildCache errors no longer silently swallowed

## [2.29.1] - 2026-03-19 (March 2026)

### Added
- Acquisition tab: Wowhead links on vendors and items — click to copy URL (includes utm_source=hdg tracking)
- Alts tab: Midnight profession thresholds for all 8 crafting professions

### Fixed
- Alts tab: Midnight expansion showing "No decor recipes" despite having recipes in DecorDB

## [2.29.0] - 2026-03-17 (March 2026)

### Added
- Acquisition tab: "Gold Only" source filter — shows items purchasable with gold only (no rep, currency, achievement, quest, promo, or race gates)

### Fixed
- Data: Fix coordinates for 13 Silvermoon City vendors (Wowhead audit — were using old map coordinates)

## [2.28.0] - 2026-03-15 (March 2026)

### Added
- Data: Add Pascal-K1N6 Mechagon vendor with 6 Junkyard Tinkering housing decor items and material costs
- Goblin tab: TSM price mode toggle (Server / Region) — switch between DBMinBuyout (server) and DBRegionSaleAvg (region) pricing
- Lumber Tracker: End Session button on the active farming row (red stop icon)

### Changed
- Data: Update Hesta Forlath vendor location to Silvermoon City (44.2, 62.7) and add Deed of Patronage note
- Goblin tab: Direct AH scan status now shows decor/reagent count breakdown
- Goblin tab: Item count moved to bottom status bar
- Goblin tab: Tighter expansion filter button spacing
- TSM integration: Changed from DBMarket to DBMinBuyout (server mode) for more accurate current pricing

### Fixed
- Data: Fix coordinates for 6 vendors (Craw MacGraw x/y swap, Maurice Essman, Woodsman Drake, Hoddruc Bladebender, Provisioner Thom, Hilseth Travelstride)
- Data: Fix mapID for Master Smith Burninate (Searing Gorge), Provisioner Vredigar (Ghostlands), Provisioner Aristta (Azure Span), Naynar (Harandar)
- Data: Fix Valdrakken mapID for Unatos, Provisioner Thom, Tethalash (2134 → 2112)
- Data: Relocate Captain Donald Adams from Orgrimmar to Undercity
- Data: Fix Arakkoan vendor price stubs — Ruuan the Seer, Shadow-Sage Brakoss, Ravenspeaker Skeega now show correct gold + Apexis Crystal costs
- Recipes tab: Hide "Add All to Auctionator" button when Auctionator not installed
- UI: Fix cooldown ring alignment on title bar

## [2.27.1] - 2026-03-12 (March 2026)

### Fixed
- Minimap button now correctly respects "Show Minimap Button" setting across
  reloads and relogs. LibDBIcon's hide flag is now synced with the HDG setting
  so the PLAYER_LOGIN handler no longer re-shows the button.

## [2.27.0] - 2026-03-12 (March 2026)

### Added
- Goblin tab: **Direct AH price source** — scans the Auction House directly
  using C_AuctionHouse browse queries. No TSM or Auctionator required.
  Browses all AH listings and filters locally for decor and reagent prices.
  Prices persist across reloads and sessions with cache age display.
- Goblin tab: price source selector with radio buttons (Direct / Auc / TSM).
  Unavailable sources are grayed out. Direct is always available.
- Goblin tab: "My Auctions" checkbox filters to items you have listed on the
  Auction House. Uses native C_AuctionHouse API to show listing status icons:
  green checkmark (listed above market), red X (being matched or undercut),
  and gold coin (sold, awaiting mailbox). Listed and sold counts display
  inline after the margin column. Auction data persists across reloads.
- Goblin tab: active sort column header now highlighted in accent color.
- Minimap button now uses LibDBIcon-1.0 for reliable positioning with all
  minimap replacement addons (SexyMap, BasicMinimap, etc.). Drag, lock, and
  shape detection are handled automatically.
- LibDataBroker-1.1 launcher object for external LDB display hosts.

- Config tab: Buy Me a Coffee link added to the Community card.

### Removed
- Goblin tab: "Hide Unprofitable" checkbox removed (sort by profit instead).

### Fixed
- Goblin tab: undercut detection now uses three states: green checkmark
  (cheapest), amber dot (matched price with LIFO risk), and red X (undercut).
  Previously same-price listings incorrectly showed as undercut.
- Silvermoon City vendors now appear in Zone Mode. MapID corrected to the
  Midnight-era Silvermoon (2393) and faction tag changed from Horde-only to
  Neutral, since Silvermoon is a shared city in Midnight.
- Minimap button no longer drifts or disappears when using SexyMap or other
  non-circular minimap shapes.

## [2.26.3] - 2026-03-11 (March 2026)

### Fixed
- Goblin tab: prices now auto-populate after an Auctionator scan completes.
  Previously the scan callback fired before Auctionator finished indexing,
  leaving all cost/sell/profit columns empty until switching tabs.
- Goblin tab: price source label now probes Auctionator for actual data when
  scan timestamp is unavailable, showing "Auctionator" instead of misleading
  "full scan needed" when prices exist.
- Materials list and vendor shopping list pin toggle now saves correctly.
  Pinned state was silently lost on each click.
- German locale file moved to correct Localization directory (was failing to
  load on startup).

## [2.26.2] - 2026-03-10 (March 2026)

### Added
- Zone popup: search bar filters vendors and items by name.
- Zone popup: eye toggle to show/hide collected items. Collected items
  appear dimmed with a checkmark badge, sorted below uncollected.
- Vendor counts in zone popup show uncollected/total format.
- Simply Adorned Vase and Flowers, Cuddly Alliance Blue Grrgle, and
  Cuddly Horde Red Grrgle added to Tuuran and Gabbi vendor inventories.

### Fixed
- Detail panel text colors: Cost, Profession, Expansion, Placement, and
  Promotional values now use theme text color instead of falling back to
  default after label reset.
- Blizzard "Shop" sourceText no longer appears redundantly on Promotion
  and Shop items in the detail panel.
- Zone popup timing: increased post-reload delay to 3s so housing catalog
  API has time to populate collection data. Manual opens also clear cache
  and invalidate collection state for fresh results.
- Simply Adorned Vase and Flowers reclassified from Shop to Promotional
  with Zillow ARG acquisition instructions.

## [2.26.1] - 2026-03-09 (March 2026)

### Added
- New "In-Game Shop" source type (SHOP) distinguishing shop-only items from
  promotional items that have vendor copies. 21 items reclassified including
  Spring Blossom Pack, Lush Garden Pack, Colorful Eggs, Doormats, and Plushies.
- Hearthsteel prices displayed in item detail panel for shop items. Shows cost
  in Hearthsteel currency or "Bundle only" for pack-exclusive items.
- "Shop" filter option in Acquire tab source dropdown.

### Fixed
- Collection detection now checks `remainingRedeemable` field from Blizzard API,
  fixing false-negative uncollected status for items stored but never placed.
- Zone Finder no longer directs players to vendors for shop-only items
  (Alliance/Horde Doormats removed from VendorDB).
- Horadric Cube correctly classified as Promotional (vendor copies available)
  instead of In-Game Shop.

## [2.26.0] - 2026-03-08 (March 2026)

### Added
- Custom chain link icon for URL buttons on shopping list cards and style cards.
- Style card attribution row highlights on hover when URL is present.

### Fixed
- Materials panel now correctly counts Dragonflight quality reagents (R1/R2/R3).
  Previously only the exact quality tier listed in the recipe was checked, so
  e.g. R1 Draconium Ore would show 0/10 when the recipe referenced R2.
  Quality variant cache is now bidirectional across all tiers.
- Collection detection consolidated into single CheckCollected() function.
  Vendor and Promotion items no longer trust firstAcquisitionBonus (fixes
  Grrgle dye variant false-positives). Removed redundant display-layer
  Promotion override in AcqRows.
- Styles Tab: Shopping list gallery now respects Collected/Uncollected filter
  checkboxes (was only filtering by search text).
- Styles Tab: Fixed taint error when clicking URL on shopping list cards.
  Replaced protected CopyToClipboard with EditBox popup (Ctrl+C to copy).
- Pin icon color now correctly shows yellow when pinned (was displaying
  gray due to blue channel always being 0.6).

### Changed
- Full localization: ~200 L["KEY"] entries wired across all UI files covering
  panel headers, button labels, filter checkboxes, status messages, tooltips,
  empty states, and dropdown labels. Translated to all 10 locale override files
  (deDE, esES, frFR, itIT, koKR, ptBR, ruRU, zhCN, zhTW).
- Config: Added CONFIG.COLORS palette (RGBA tuples for panels, text states,
  semantic status, faction backgrounds) with ~80 hardcoded colors migrated to
  constants across 7 files.

### Removed
- VendorResolver: Removed runtime vendor event handler and merchant currency
  scanning. All vendor names and currency costs are now in static VendorDB.
- PowerCrafting: Removed dead fallback code in AggregateRawMaterials that was
  unreachable when BuildDependencyGraph always returns a valid graph.
- Removed ~50 overcautious nil guards across 20+ files. TOC load order
  guarantees HDG.Store, HDG.Theme, and HDG_UIHelpers are always initialized
  before UI code runs.

## [2.25.0] - 2026-03-07 (March 2026)

### Added
- Styles Tab: New "Zandalari Creche" themed style -- a jungle nursery for
  young Zandalari trolls with plushies, loa totems, and tropical decor.
  Includes Toys & Plushies, Nap & Rest, Loa & Lessons, and Jungle Nursery
  subcategories.
- Styles Tab: "Collected" filter checkbox in detail view -- mutually exclusive
  with the existing Uncollected filter.
- Acquire Tab: Dyeable filter now works using AllDecorDB data (no longer
  requires Vamoose's Dye Studio to be installed).
- Config Tab: Community/Discord card moved to top of settings for visibility.

### Fixed
- Collection false-positives: vendor dye variants (like the Cuddly Grrgle
  plush series) no longer incorrectly show as collected. The itemID-based API
  returns unreliable bonus data for dye variants; collection now uses the
  accurate decorID-based API for the firstAcquisitionBonus check.
- Styles tab collection check now uses the centralized IsItemCollected()
  instead of an inline firstAcquisitionBonus check.
- Materials List now refreshes immediately when tracking or untracking a reagent.

### Changed
- Recipes tab materials: Shift-Click now tracks any reagent (was Ctrl-Click,
  gather-only). Works in both Direct and Raw material modes.
- Config Tab: Updated community message text across all 10 locales.
- Config Tab: Removed "Pin Radar to Tracker" option.

## [2.23.0] - 2026-03-05 (March 2026)

### Added
- House Tab: Two-column layout -- Collection by Source (left) and Collection by
  Expansion (right) side-by-side with fluid-width progress bars
- House Tab: Hero panel with backdrop, XP bar, and collection summary line
  showing total collected count, percentage, and XP available
- House Tab: Hover highlights on stat rows, green completion tint on 100% rows
- House Tab: Accent bars beside section headers for visual hierarchy

### Fixed
- AllDecorDB: Corrected expansion tags for 265 items that were showing as
  "Unknown" -- categorized by vendor zone, currency cost, and item source
- AllDecorDB: Remapped 178 items incorrectly tagged as "The Burning Crusade"
  to "Midnight" (TBC zones reused in Midnight expansion)

## [2.22.0] - 2026-03-04 (March 2026)

### Added
- Styles Tab: Tier section headers are now collapsible with arrow indicators
  -- click to expand/collapse; state persists across sessions; all sections
  default to collapsed on first use
- Styles Tab: "Shopping" category chip to filter the landing page to only
  shopping list cards
- Styles Tab: Shopping list cards rendered as snapshot-style cards with mini
  icon preview strip, attribution row, and source-appropriate big icon
- Styles Tab: Clicking a shopping list card opens a gallery detail view with
  3D decor previews, quantity badges, and collected checkmarks

### Changed
- Tooltip hook: Simplified housing decor reagent tag (removed per-profession
  breakdown, now shows just recipe count)

## [2.21.0] - 2026-03-03 (March 2026)

### Added
- Arrow key navigation in Preview, Acquire By Item, and Acquire By Vendor lists
  -- Up/Down to move selection, auto-scrolls to keep selected row visible
- Preview Tab (Stored mode): Vendor cost now shown below the destroy button for
  vendor-sold items (gold, currency, or token cost with vendor name)
- Alts Tab: Hide individual characters from the list using the eye icon next to
  their name -- hidden characters are filtered from view and the account summary;
  a "Hidden (N)" button appears to temporarily reveal them dimmed; preference
  persists across sessions (data collection continues normally on hidden characters)

### Changed
- New minimap icon and title bar artwork
- Alts Tab: Find Lumber status now right-aligned with icon after text
- Memory optimization: FacetDB freed after StyleEngine cache build (~1.5 MB saved)
- Memory optimization: ProfessionsDB pruned to housing-relevant recipes at runtime
  (~6-12 MB saved, 8,396 entries reduced to ~1,500)
- ProfessionsDB data file: stripped 8,267 empty `variants={}` entries (~330 KB saved)

### Fixed
- Goblin Tab: AH scan no longer gets permanently stuck on "Scanning..." if
  Auctionator's callback fails to fire (60s safety timeout)

## [2.20.0] - 2026-03-01 (March 2026)

### Fixed
- Minimap button no longer overlaps the minimap on non-default minimap sizes
  (now uses dynamic radius based on actual minimap dimensions)
- DecorDB: Corrected reagents for 7 Midnight recipes verified against Wowhead
  - Alchemy: Entropic Illuminant (wrong mote type + quantities),
    Haranir Preserving Agents (wrong mote type + quantity)
  - Blacksmithing: All 5 recipes used wrong reagent (Core Alloy -> Refulgent
    Copper Ingot) with incorrect quantities on 3 of them
- ReagentsDB: Added 39 missing Midnight reagents (17 Gathering, 18 Crafted,
  4 Vendor) -- PowerCrafting source labels and cost calculations now work for
  all Midnight housing decor recipes

## [2.19.0] - 2026-02-28 (February 2026)

### Fixed
- Preview Tab: Catalog search no longer gets permanently stuck at "Loading catalog..."
  (held strong reference to async searcher to prevent GC before callback; added 10s watchdog)

### Added
- Preview Tab: "Stored" filter toggle to show items with stored copies you can destroy
- Preview Tab: Stored count overlay on item icons, sorted by quantity when filter active
- Preview Tab: +/- quantity selector and "Destroy" button with confirmation dialog
- Preview Tab: Storage stats line showing owned count and stored totals
- Preview Tab: Auto-refresh on HOUSING_STORAGE_UPDATED/HOUSING_STORAGE_ENTRY_UPDATED events

### Improved
- Preview Tab: Performance overhaul -- memoized category/subcategory API lookups, font string
  pooling in info pane, single GetScheme() per row render, cached color prefixes, O(1) tag
  category lookups, O(1) item-by-decorID index, cached decorToRecipe map, shallow-copy sort
  to avoid mutating cache, skip redundant IsDecorCollected/GetCachedItemInfo calls per row

## [2.18.0] - 2026-02-28 (February 2026)

### Added
- Materials List: "All My Mats" browse mode shows every housing reagent you own across
  bags, bank, and warband bank, with search filtering and sort cycling (Name / Count / Recipes).
- Materials List: location chips on each row -- bag, bank, and warband atlas icons show
  where your materials are stored at a glance. Tooltip breaks down counts per location.
- Materials List: recipe pop-out panel. Click any reagent to see every recipe that uses it,
  sorted by craft readiness (100% ready recipes at top with green highlight). Shows
  owned/total mats indicator per recipe with color coding.
- Materials List: Shift-click any recipe in the pop-out to add it to the crafting queue
  with teal flash feedback.
- Reverse reagent index in PowerCrafting: maps reagent -> recipes for instant lookup.
- Craft readiness calculator: checks inventory against recipe requirements.

### Changed
- Materials List button in the main title bar now matches the Shopping List button style
  (atlas button with icon + "Materials" label) instead of a standalone icon.

## [2.17.0] - 2026-02-27 (February 2026)

### Added
- Acquisition tab: alt source chips now display for gate types (Achievement, Quest,
  Drop, Treasure, Craft, Profession, Promotion), not just Achievement and Quest.
- Source filters (Achievement, Quest, Treasure, Drop, Promotion) now also match items
  where the alt source matches, not just the primary source type.
- Data pipeline: enriched 445+ items with secondary acquisition sources parsed from
  Blizzard catalog sourceText. World Quest sources merged into Quest.

### Changed
- Chip architecture: AllDecorDB alt field is now the primary chip source; VendorDB
  gates (Rep/Quest/Achievement IDs) provide met/unmet coloring only.
- Data pipeline: vendor items with gate prerequisites (Achievement, Quest, Treasure)
  now correctly store Vendor as primary source and the gate as alt. Previously the
  gate was stored as primary, causing items to appear under the wrong filter.
- Removed "Vend" chip label -- Vendor is an acquisition method, not a gate.

### Fixed
- Gundargaz Grand Keg: corrected source type from Drop to Quest per Blizzard catalog.
- Promotion false-positive collection: items with Promotion as alt source (e.g. Cuddly
  Grrgles) now use strict quantity/placed check instead of firstAcquisitionBonus.
- Endeavor filter: fixed crash when VendorDB item entry has a quest ID instead of a
  costs table in field 5.

## [2.16.0] - 2026-02-26 (February 2026)

### Added
- Materials List: standalone floating window for crafting queue reagents, toggled
  from the title bar. Shows direct or raw materials, tracked reagents, estimated
  cost, AH search integration, and persists position/size across sessions.
- Shopping List: vertical resize grip -- drag the bottom edge to make the panel
  taller (height persists across sessions).
- Shopping List: collapsible zone and wish list headers -- click zone/wish list
  headers to collapse or expand their sections.
- Shopping List: shift-click non-crafted wish list items to navigate to the
  Acquire tab By Item view with that item selected (crafted items still add to
  crafting queue as before).
- Styles Tab: new "Kafa Shop" themed style template for coffee-house builds.

### Fixed
- Styles Tab: fixed 5 style templates (Rustic Tavern, Cozy Cottage, Feast Hall,
  Workshop, Sacred Shrine) showing 0/0 items due to multi-facet query scoring.
  Secondary query facets moved to boost where appropriate.
- Styles Tab: subcategory item counts now match card totals -- all 22 decor
  categories are covered by subcategory queries (no items lost to uncategorized).
- Styles Tab: Alliance and Horde faction styles now correctly populate (lowered
  minScore to accommodate proportional culture matching).
- Materials List: fixed Auctionator MultiSearch error when auction house is not
  open -- shift-click now checks AH state before calling the API.
- Materials List: fixed "Tracked Reagents" header and separator duplicating on
  each panel refresh (leaked textures/fontstrings now cached and reused).

## [2.15.1] - 2026-02-26 (February 2026)

### Added
- Config: Font Size +/- buttons to adjust all addon text size (-4 to +4 offset).

### Changed
- Crafting queue: left-click now opens the recipe in the profession window instead
  of removing items. Shift+left-click removes one (prevents accidental removal).
- Shopping List: world quest items now show as "Q" (quest) badge instead of "WQ".

### Fixed
- ReagentsDB: Legion Inscription pigments had wrong names -- itemID 129032 was
  labeled "Yseralline Seeds" (should be Roseate Pigment) and 129034 was labeled
  "Felwort" (should be Sallow Pigment). This caused wrong material names, wrong
  tooltips, and missing pigments in the Required Materials panel.
- ReagentsDB: Ghost Iron Bar was truncated to "Ghost Iron", causing Auctionator
  exact-search failures.
- ReagentsDB: 18 Essence/Eternal/Primal reagents had descriptive suffixes
  (e.g. "Eternal Life (drops from nature elementals)") baked into the item name,
  breaking AH searches and display text. Names now match in-game item names.
- Materials panel and Auctionator list now use WoW API item names instead of
  ReagentsDB names for display and search, preventing mismatches from data errors.
- Shopping List import: non-vendor items (drops, quests, crafted) now correctly
  land in the Wish List instead of creating "Unknown" vendor sections.

## [2.15.0] - 2026-02-25 (February 2026)

### Added
- Tab bar: all tabs now use Blizzard atlas icons with hover/active state changes,
  replacing the old texture-based icons. Each tab has a themed atlas matching its
  purpose (housing icon for Acquire, spellbook for Recipes, wax seal for Styles, etc).
- Export/Import dialog: wood frame border overlay matching the main window style.
- Export dialog factory (`UIHelpers.CreateExportDialog`) for consistent themed dialogs
  across all export windows.

### Changed
- ReagentsDB migrated to v3 table format: entries now store item names inline
  (`{"Source", "Name"}`) instead of in comments, enabling O(1) name lookups.
- Item name resolution (materials panel, tooltips, Auctionator export) now checks
  ReagentsDB and ProfessionsDB locally before falling back to WoW API cache.
- Tab bar: removed backdrop borders from all tab buttons for a cleaner look.
- Shopping List: export/import dialog titles now read "Export Shopping List" and
  "Import Shopping List" instead of generic titles.
- Shopping List: import dialog auto-closes after successful import with chat
  confirmation message.

### Fixed
- Lumber Tracker: pinned widget now detects zone changes and refreshes lumber type
  automatically instead of staying frozen on the previous zone's lumber.
- Lumber Tracker: pinned widget no longer shows stale data on login -- the 3-second
  inventory sync now forces a full re-render.
- Lumber Tracker: elapsed time and per-hour rate now tick every second during active
  farming sessions (was only updating on lumber collection).
- Lumber Radar: E and W cardinal labels were swapped on the compass display.
- Removed redundant focus widget (~155 lines) -- the pinned widget's collapse mode
  already handles single-row display during farming sessions.
- Lumber Tracker: coordinate saves now go through Store (Dispatch) so the radar
  sees freshly gathered nodes immediately instead of after reload.
- Lumber Tracker: raw materials calculation now iterates reagents consistently with
  direct materials (pairs vs ipairs), preventing silently skipped reagents.
- Lumber Radar: removed debug global leak (`_G.HDG_LumberHUD`).
- Removed ~120 lines of dead code: duplicate `GetCachedLumberData`, orphaned
  `CreateProgressBar`, unreachable embedded `Refresh()`, unused `GetFrame()`,
  duplicate progress color function.
- VendorDB: Added missing currency costs (Wowhead-verified) for 43+ vendor items across
  Order Resources (c:1220), War Resources (c:1560), Dragon Isles Supplies (c:2003),
  and Resonance Crystals (c:2815). Corrected gold prices for affected items.
- Adamantite Bar and other legacy reagents no longer show as "Item #XXXXX (unknown)"
  in materials panel -- PowerCrafting.GetItemName now checks ReagentsDB and ProfessionsDB.
- Sundries Merchant (Suramar): corrected prices from gold to Ancient Mana currency
  (currency 1155) with proper Nightfallen reputation standing requirements.
- Removed ~9 redundant C_Item.RequestLoadItemData / GetItemInfo API calls in RecipesTab,
  GoblinTab, and PowerCrafting where local DB data was already available.
- Removed dead RequestItemInfo function and unused ITEM_DATA_LOAD_RESULT handler from
  GoblinTab.

## [2.14.0] - 2026-02-24 (February 2026)

### Added
- Race-gated vendors: vendors restricted by race (e.g. Dark Iron Dwarf, Dwarf/Gnome)
  now show a "Race:" line with headshot icons and colored text (green if met, yellow
  if not). Item rows display a gate icon for race-locked vendors.
- Built-in vendor notes: VendorDB entries can include a `note` field with directions
  or tips. Shown in dim text when no user note is set; user notes still take priority.
- Plugger Spazzring: added Mole Machine directions as built-in vendor note.
- Shopping List: "Link" button on attribution banner to copy the source URL of
  imported lists.
- Shopping List: Race badge shown on items from race-gated vendors (alongside
  existing Rep/Quest/Achieve badges).
- Shopping List & Snapshot export: "Use Decor IDs" checkbox converts itemIDs to
  decorIDs for external sharing. Adds `idtype=decor` header.
- Import auto-detects decorID strings (ID < 100,000 or `idtype=decor` header) and
  resolves them to itemIDs via HDG_AllDecorDB reverse lookup.

### Fixed
- Plugger Spazzring: corrected zone (Searing Gorge), mapID (BRD entrance), and coords.
- San Redscale: corrected mapID from continent (870) to zone (371, The Jade Forest).
- Innkeeper Belm: marked as Dwarf/Gnome race-gated vendor.
- Shopping List: Bottom action buttons inset to clear wood frame corner decorations.

### Changed
- Snapshot export now uses unified `HDGVL:1:` format with `source=snapshot` header
  instead of legacy `HDG:2:` -- snapshots get author/date/desc/cost metadata for free.
- Snapshot export no longer emits `cost` header field; import no longer reads
  `totalPlacementCost`.

### Removed
- Legacy `HDG:2:` snapshot format (import and export).

## [2.13.0] - 2026-02-23 (February 2026)

### Added
- Shopping List: Multiple named lists -- create, rename, delete, and switch
  between separate shopping lists via the new list selector bar.
- Shopping List: Complete visual redesign -- housing wood frame border, dark
  Solarized panels, and bottom action bar matching the main HDG window style.
- Shopping List: Attribution banner shown when a list was imported from an
  external source.
- Shopping List: Import can now create a new list instead of merging into the
  current one (checkbox in import dialog).
- Shopping List: Empty state now shows a centered icon with helper text.
- Shopping List: Export/import now includes item quantities (backward compatible
  with old strings that omit qty).
- Shopping List: List selector dropdown with expand/collapse arrow indicator
  and larger + / gear buttons for better usability.

### Changed
- Shopping List: Removed Mats mode tab (materials already shown in the lumber
  tracker pinned widget). Shopping list is now a single flat view with no mode
  selector bar.
- Shopping List: Panel widened from 320px to 380px for better readability.
- Shopping List: Export and Import buttons moved to bottom action bar alongside
  Map All and Clear.
- Shopping List: Existing single-list data automatically migrates to the new
  multi-list format on first load.
- Shopping List: Extracted zone mode to HDG_ZoneMode.lua (~470 lines), reducing
  VendorShoppingList from 2515 to ~2113 lines with flat render functions.
- Lumber Tracker: Simplified CheckLumberChanges from 6-level nesting to 3-level
  by extracting helpers (ApplyAutoShowBehavior, TriggerLumberQuote,
  TriggerCollectionAnimation, RefreshVisibleWidget, SPEAKER_COLORS table).
- Lumber Tracker: DRYed reagent accumulator pattern with EnsureLumberEntry,
  EnsureReagentEntry, and AccumulateDirectMaterials shared helpers.
- Lumber Tracker: Split 325-line RefreshPinned monolith into orchestrator +
  RefreshPinnedLumberRows, RefreshPinnedMaterials, RefreshPinnedFooter.

### Fixed
- Shopping List: Gold and currency cost totals now correctly multiply by item
  quantity (previously showed unit price regardless of qty).
- Shopping List: Import capped at 500 entries to prevent freeze from oversized
  payloads.
- Shopping List: Skips async item load when icon/name already cached, reducing
  redundant ItemMixin allocations on every refresh.
- Shopping List: Fixed stale closure in list selector popup hover highlight.
- Lumber Tracker: Fixed pinned widget freeze where elapsed timer and per-hour
  rate stopped updating between collections (snapshot now includes farming
  session state + 1-second ticker keeps display live during active farming).
- Shopping List: Import EditBox now accepts paste (was silently rejecting due to
  missing EnableKeyboard/EnableMouse).
- Shopping List: Removed 255-character EditBox limit that truncated large lists.
- Shopping List: Export now includes wish list items (items without a vendor).
- Zone Scanner: Extracted to standalone lightweight popup (no longer part of
  shopping list). Shows vendor list with expand/collapse, Map All and Open
  List buttons, and gear icon for scanner settings.
- Zone Scanner: No longer shows unreleased items or "Loading..." flash;
  item cache is pre-warmed before the popup appears.
- Zone Scanner: Now fires on /reload (not just zone changes).
- Zone Scanner: Brightened all text and increased font sizes for better
  readability. Vendor item count now inline with name to avoid coord overlap.

## [2.12.0] - 2026-02-23 (February 2026)

### Added
- Lumber Tracker: Pinned tracker now shows all lumber rows during farming sessions,
  not just the active one. Active row stays expanded (62px) with session stats while
  other rows display compact (18px) with have/need counts. New collapse/expand button
  in the header toggles between full view and single-row focus. Preference persists
  across farming sessions.
- Lumber Tracker: Active farming row now shows achievement progress (e.g., "47/250")
  in the bottom-right corner when the lumber achievement isn't yet earned.

### Fixed
- Localization: Comprehensive expansion name alias audit across all 10 supported
  languages. Added missing ptBR aliases (Clássico, Terralém, Nortúndria, Pandária,
  Ilhas do Dragão, Terras Sombrias), added missing Italian Cataclisma variant.
  Fixes "Unrecognized expansion name" chat spam for non-English clients.

### Changed
- Lumber Tracker: Materials bag icon states swapped -- icon now appears bright/active
  when materials panel is hidden (click to show) and dim when already showing, matching
  conventional button affordance expectations.
- Acquisition Tab: Item row highlights now scoped by vendor -- selecting an item under
  one vendor no longer highlights the same item under other vendors.
- Acquisition Tab: Vendor detail panel now shows the correct vendor when clicking items,
  instead of defaulting to the first vendor alphabetically.

## [2.11.0] - 2026-02-22 (February 2026)

### Added
- Styles Tab: "Save Placed Decor" snapshot feature -- scans all placed decor
  (account-wide across all houses/plots) and saves a snapshot to the Styles tab.
  Snapshots appear in a new "Snapshots" category with placed count badges per item.
  Gallery view sorted by placed count. Supports export/import via HDG:2: encoded
  strings for sharing between players. Note: Blizzard restricts per-house placement
  data (GetAllPlacedDecor), so snapshots reflect account-wide placed totals.
- Localization: Split monolithic localization file into per-locale files (VN pattern).
  11 locale files under Localization/ folder with layout policy -- short labels
  (column headers, compact buttons) stay English to prevent layout overflow.
- Localization: Phase 1 wiring -- Acquisition, Styles, Recipes, and Config tabs
  now use L[] references for panel titles, button labels, status messages, and
  print feedback (~70 strings wired).
- Localization: Phase 2 wiring -- Goblin, Alts, Data, Trainers, and Decor Preview
  tabs now use L[] references for panel titles, print messages, status text,
  info labels, and error messages (~103 strings wired).
- Localization: Config tab high-priority strings wired -- Interface, Lumber Radar,
  Quotes, and Advanced card checkboxes/hints, waypoint dropdown options, and
  debug toggle chat messages (~35 CFG_* keys).
- Power Crafting: Queue expand now shows topologically-sorted craft order (leaf-first)
  instead of flat subsidiary list. Each step numbered, colored green if known or
  dim if unknown. Tooltips show profession, expansion, reagents, and "Known by" info.
- Power Crafting: Raw Materials intermediates section now shows known/unknown status
  per item with "(unknown)" suffix and "Known by" tooltip line.
- Power Crafting: Implemented CanPlayerCraft(itemID) -- checks if player knows the
  recipe for a given intermediate item via profession spell lookup.

### Changed
- Style Creator: Scoring engine rewritten with specificity-weighted matching.
  Partial chip matches are now weighted by how specific an item is to the queried
  facet -- specialist items (tagged for 1-2 values) score higher than generalist
  items (tagged for 8+ values), preventing generic structural pieces from
  dominating the Accent tier.
- Style Creator: Tier assignment uses semantic logic -- full facet match or
  strong partial (>50%) for Accent, negative score for Clashing, instead of
  fixed score thresholds.
- Style Creator: Mismatch penalty -- items with a different value for a queried
  facet are penalized toward Clashing instead of scoring as Versatile.

### Fixed
- DecorDB: Added missing Long Valdrakken Storage Crate (Dragon Isles Inscription).
- AllDecorDB: Fixed mislabeled entry -- itemID 253497 was "Rootbound Vat/Crafted"
  but is actually "Embroidered Sunfury Chair/Vendor". Filled in missing name/source
  for real Rootbound Vat (itemID 253506).
- Localization: Locale override setting now persists across /reload (was writing
  to transient memory instead of Store).
- Localization: Language dropdown items now have consistent text color on first
  display (was showing mixed white/gold before hover).
- Localization: "Language" card header and Auto locale option now use L[] refs.
- Localization: Phase 3 -- Profession filter buttons and "Uncollected" checkbox
  kept English per layout policy. Wired remaining visible strings: "Style" tab,
  "Professions" header, "Shopping List" button, "Est. Cost:" label, "Not Known"
  queue header, "(you)" marker, "Known by:" tooltip. Added TAB_STYLES,
  TAB_ACQUIRE, RECIPE_PROFESSIONS, RECIPE_EST_COST to all 10 locale files.
- Style Creator: Clicking a chip no longer resets the chip scroll position to top.
- Style Creator: Selected chips stay at top of list in stable alphabetical order
  instead of re-sorting on every toggle.

## [2.10.0] - 2026-02-21 (February 2026)
### Changed
- Style Creator: Redesigned as 4-column layout (Category | Chips | Pick List
  | Basket) replacing the old vertical stack. Category facets shown as vertical
  button list with active-chip badges. Tag chips scroll vertically with arrow
  navigation. Pick list uses 86px cells in a 4-column grid with tier filter
  strip. New basket column shows selected items with icons, names, remove
  buttons, and running placement cost total. Info bar displays item name, cost,
  and decor notes on hover. Score normalization makes tier classification
  subtractive -- each additional facet narrows results instead of inflating them.

### Added
- Themes: New "Colorblind Safe" theme with CVD-friendly palette (blue/teal/amber/pink
  instead of green/red). All semantic colors remain distinguishable across
  deuteranopia, protanopia, and tritanopia. Thanks to BaronKarza for the suggestion
  and testing.
- Themes: Standardized font sizes across all 13 themes for consistent text rendering.
- Alts Tab: Recipe completion pips are now theme-aware (use themed success/error
  colors instead of hardcoded green/red).
- Lumber Tracker: Unlearned lumber asterisks now display in red instead of dim
  gray for better visibility; green asterisks remain for unlocked lumber.
  Thanks to Boggle for the suggestion.
- Vendor Data: Added promo items to Gabbi (Orgrimmar) and Tuuran (Stormwind):
  Naturally Elegant Doormat, Sanctuary's Horadric Cube, Cuddly Green Grrgle.
  Updated Miniature Replica Dark Portal price to 1500g.

### Fixed
- Vendor Shopping List: Fixed crash when mapping waypoints for wish-list items
  that have no associated vendor (nil npcID guard).
- Vendor Shopping List: Fixed export serialization skipping entries without
  vendor data instead of concatenating nil.

## [2.9.0] - 2026-02-20 (February 2026)
### Added
- Data Tab: Housing Achievements section showing progress for all 30 housing
  achievements across three groups (11 Decor Collection, 7 Community Coupons,
  12 Lumber Harvesting). Three-tone progress bars use Blizzard skills bar
  textures: green base for completed milestones, gray fill for current progress,
  black for remaining. Groups auto-collapse when all achievements in the group
  are complete; manually collapsible at any time. Section live-refreshes on
  ACHIEVEMENT_EARNED. Achievement UI extracted into standalone
  HDG_AchievementSection.lua module. Tooltips show full achievement name and
  description.
- Fixed coupon achievement thresholds (corrected to 250/2000, not 100/2500).
- Cart Buttons: New atlas-based [+][-] cart buttons (128-RedButton-Cart-Add/Minus)
  with full Pressed/Highlight states. Add increments qty, Remove decrements.
  Remove button only visible when item is on the list.
  - Preview Tab info panel: cart buttons replace old text-only "Add to List" button
  - Acquisition Tab detail panel: cart buttons in bottom-right of item info area
    with live "N in cart" counter beneath
  - Shopping List: remove button upgraded from red "x" text to cart-minus atlas
- UI Polish: Replaced all text-based collapse/expand indicators across tabs with
  Blizzard common-button-collapseExpand atlas buttons (up/down with pressed/hover
  states). Affected areas:
  - Recipes Tab: queue row arrows, material category headers, per-recipe headers,
    and intermediates section headers
  - Acquisition Tab (By Vendor): vendor group header expand/collapse arrows
  - Alts Tab: section expand/collapse arrows
  - Trainers Tab: profession section expand/collapse arrows
  - Data Tab: achievement group expand/collapse arrows
  - Shopping List (List and Zone tabs): vendor row expand/collapse arrows
- Config Tab: Sliders reskinned with common-slider-thumb and common-slider-track
  atlas textures for a native Blizzard look
- Alts Tab: Added recipe completion pips to skill cells - small colored indicators
  show recipe learning status at a glance (green = all learned, orange = missing
  recipes). Recipe details also merged into skill cell tooltips. Legend updated
  with pip explanations.
- Shopping List: New "Mats" tab replaces "Style" tab - shows all crafting materials
  needed for items on your shopping list with have/needed counts, colored by
  completion status. Direct/Raw toggle switches between direct reagents and fully
  decomposed raw materials. Click rows to search the Auction House.
- Lumber Tracker: Materials header tooltip now points to Shopping List > Mats tab
- Lumber Tracker: Mounted harvesting achievement progress shown on each lumber row
  (green asterisk when unlocked, dim progress counter when in-progress) and in row
  tooltips with detailed progress or "Unlocked!" status
- Lumber Tracker: Achievement badge (X/12) in pinned widget header showing
  mounted-harvesting completion count at a glance (dim when incomplete, green
  when all 12 complete).
- Acquisition Tab: Achievement decor collected count appended to status bar when
  Achievement source filter is active.
- ExpansionData: Achievement data layer with IsHousingAchievement,
  GetDecorAchievementProgress, GetCouponAchievementProgress, and
  GetLumberAchievementSummary functions.

### Changed
- Data Tab: Reduced crafting history container height (150 to 100px) and farming
  history container height (250 to 110px) to reclaim vertical space for the new
  achievements section.
- Internal: Renamed crafting queue identifiers from "shoppingList" to "craftingQueue"
  across the entire codebase to avoid confusion with the Vendor Shopping List widget.
  Includes SavedVariables migration (existing queue items preserved automatically).

### Removed
- Shopping List: Removed Style Shopping List feature (style mode, style export/import,
  StylesTab add/remove integration). Style tracking is replaced by the Mats tab.

## [2.8.7] - 2026-02-19 (February 2026)
### Fixed
- LumberHUD: Reverted OnLocationAdded raise-to-front logic; restores original
  single-condition auto-show behaviour

## [2.8.6] - 2026-02-18 (February 2026)
### Changed
- Goblin Tab: "Only Known" / "Known by Alts" filters are now mutually exclusive
  (selecting one automatically deselects the other)
- Goblin Tab: Renamed filter checkboxes to "My Recipes" and "All Known Recipes"
  for clarity
- Added missing localization key CHECK_KNOWN_BY_ALTS (was always using hardcoded
  English fallback)

## [2.8.5] - 2026-02-18 (February 2026)
### Fixed
- Engineering Classic/Cataclysm Horde trainer Roxxik npcID corrected (3494 -> 11017)
- Alchemy MoP trainer Ni Gentlepaw npcID corrected (64071 -> 56777)
- Engineering WoD Horde trainer corrected to Nik Steelrings (npcID 87552, updated position)
- Alchemy WoD Horde trainer corrected to Joshua Alvarez (npcID 87542)
- Engineering BfA Horde trainer Shuga Blastcaps npcID corrected (122710 -> 131840)
- Alchemy BfA Horde trainer Clever Kumali position corrected (42.2, 38.0)
- Alchemy Dragonflight trainer Conflago npcID corrected (185548 -> 185545)
- Engineering Shadowlands trainer Machinist Au'gur position corrected (38.0, 44.7)
- Engineering Dragonflight trainer corrected to Clinkyclick Shatterboom (npcID 185548)
- Engineering TWW trainer Thermalseer Arhdas npcID corrected (217139 -> 219099)
- Leatherworking Classic/Cataclysm Horde trainer Karolek npcID corrected (7871 -> 3365)
- Leatherworking WoD Horde trainer corrected to Garm Gladestride (npcID 87549, updated position)
- Leatherworking Dragonflight trainer Hideshaper Koruz npcID corrected (185543 -> 185551)
- Leatherworking TWW trainer Marbb npcID corrected (217136 -> 219080)
- Blacksmithing WoD Horde trainer corrected to Nonn Threeratchet (npcID 87550)
- Blacksmithing BfA Horde trainer Forgemaster Zak'aal npcID corrected (127114 -> 127112)
- Blacksmithing Dragonflight trainer Metalshaper Kuroko npcID corrected (185542 -> 185546)
- Blacksmithing TWW trainer Darean npcID corrected (217138 -> 223644)

### Internal
- Replace O(n) HDG_DecorDB linear scan with lazy reverse index for profession lookup
- Eliminate double profession iteration in RefreshProfessionTabs
- Move OnEnter/OnLeave scripts to one-time init in EnsureProfessionTabFrames
- Replace 6 inline SetBackdrop blocks with ApplyBackdrop
- Simplify UpdateCraftableToggle, UpdateToggleAppearance, UpdateSortModeAppearance toggle helpers
- Remove dead code: ClearScrollContent wrapper, redundant GetScheme calls, C_Timer guard
- Refactor RecipesTab: extract business logic to HDG_Data and HDG_PowerCrafting modules
- Deduplicate tier bucketing, cost display, and GetScheme calls
- Pool recipe row frames and cache profession tab buttons to reduce frame churn
- Add per-refresh CanCraftRecipe cache for performance
- Add shared CreatePanelHeader() and CreateScrollPane() helpers, replacing 3 duplicate header bar blocks and 3 duplicate scroll frame blocks
- Hoist 7 redundant GetScheme() calls in CreateRecipePanel, CreateShoppingPanel, and CreateMaterialsPanel
- Extract RenderMaterialCategory() and RenderIntermediatesSection() from RefreshMaterials (471 -> 88 lines)
- Extract CreateCraftDialog() from ShowCraftConfirmation (238 -> 85 lines)
- Extract GroupShoppingByCharacter() and RenderShoppingItem() from RefreshShoppingList (434 -> 60 lines)
- RecipesTab reduced from 4,384 to 3,682 lines (-16%)

## [2.8.4] - 2026-02-17 (February 2026)
### Fixed
- **Preview tab: wrong item shown on click** — Clicking an item in the Decor
  Preview scroll list showed the wrong item's 3D model and info. Row pool
  recycling (LIFO) during Refresh() caused stale frame data references. Fixed
  by capturing item data before pool refresh

## [2.8.3] - 2026-02-16 (February 2026)
### Added
- **Shopping List button repositioned**: Moved Shopping List button from Acquire tab
  header to main title bar for global access across all tabs
- **Shopping/Wish List: all item types supported**: Shopping List now accepts all
  item types as a "Wish List" (crafted, drops, promo, shop items, etc.)
- **Shopping List: Wish List support for non-vendor items**: Shift-click now
  works on ALL items in the Acquisition tab and gallery view, not just vendor
  items. Items without an NPC vendor (crafted, AH-only, drops, etc.) are added
  to a "Wish List" section. Wish list allows duplicate items (e.g., multiple
  copies of the same decor)
- **Decor Preview tab: shift-click to Shopping List**: Added shift-click to add
  items from the Preview tab (priority: vendor list, crafting queue, wish list).
  Updated tooltip text to say "Shopping List" instead of "Crafting Queue"
- **Preview tab: Shift-Click to Shopping List**: Shift-Click in Preview tab now
  adds items directly to the Shopping/Wish List
- **Shopping List quantity tracking**: Shopping list items now track quantity with
  counter display (e.g., "3x Item Name"). Adding duplicate vendor items also
  increments the counter instead of creating a new entry
- **Style Editor: grid cell interactivity**: Left-click grid cells to lock/unlock
  items (pinned across tag refreshes). Right-click to remove items from preview.
  Shift-click to add items to vendor shopping list. Locked/removed items auto-save
  to custom style definition. Lock icon (bag lock atlas) shown on pinned cells
- **Shopping List: Shift-Click AH search**: Shift-click craftable items in the
  vendor or style shopping lists to search the Auction House (when AH is open)

### Changed
- **Config tab Appearance card**: Scale, Font, and Waypoints controls now use a
  horizontal layout instead of vertical stacking
- **Preview tab itemID resolution**: Now uses Blizzard catalog API directly
  instead of reverse lookup for more reliable item resolution

### Fixed
- **Dropdown persistence on tab switch**: Fixed dropdowns persisting on screen
  when switching tabs (tab bar clicks now route through SwitchTab)
- **Alts tab stale professions**: Profession cache now fully replaces on each
  scan, so dropped professions are properly removed instead of persisting
- **Nil guard on C_HousingCatalog fallback path**: Added API existence check
  on decorID-based collection lookup to prevent crash if API unavailable
- **GetScheme nil safety**: All UIHelpers color getters now guard against nil
  scheme during early initialization (GetBorderColor, GetActiveColor, etc.)
- **itemLoadTimes memory cleanup**: Unreleased item entries now pruned from
  tracking table to prevent unbounded growth
- **SavedVariables growth caps**: Auto-prune userNotes (500), vendorNotes (200),
  farmingHistory (100), characters (50) on load to prevent unbounded SV bloat
- **Combat taint guard**: CloseTradeSkill/HideUIPanel in craft-and-close timer
  now checks InCombatLockdown() to prevent "Interface action failed" errors
- **FormatWithCommas dedup**: Consolidated duplicate definitions from
  VendorResolver and PriceIntegration into single UIHelpers canonical function
- **GetProgressBarColor dedup**: Removed 3 duplicate local wrappers (HDG_UI,
  LumberTracker, RecipesTab), all callers now use UIHelpers.GetProgressBarColor
- **Theme color code helper dedup**: Removed ~60 local C_* wrapper functions
  across 14 files, all call sites now use HDG.Theme.C_*() directly
- **Row pool standardization**: Migrated 10 hand-rolled row pools across 6 files
  to shared UIHelpers.CreateRowPool() pattern, eliminating ~130 lines of boilerplate
- **SavedVariables validation**: Type-safe MergeTable rejects type-mismatched values,
  bounds clamping on config (scale, fontScale, bgOpacity, chattiness), activeTab
  whitelist, array sanitization for shopping/style/vendor/crafting/farming lists
- **Tab lifecycle standardization**: All 9 tabs now have Show/Hide methods;
  UpdateTabs delegates to module methods instead of reaching into frame internals
- Tome of Reliquary Insights now correctly listed under Legion (Return to Karazhan) instead of TBC Karazhan
- **Localization (zhCN)**: Added missing Shadowlands alias for Simplified Chinese clients

## [2.8.2] - 2026-02-15
### Added
- **Alts tab: collapsible unscanned section**: Characters without scanned skill
  data are grouped into a collapsible "Unscanned Characters" section at the
  bottom, collapsed by default to reduce clutter
- **Style Creator: click-to-shop**: Left-click grid items to add to shopping
  list (stacks multiples), right-click to remove, shift-click to select/inspect
- **Style Creator: smart defaults**: New styles auto-name as "CharName Style N",
  description auto-populates from Must Have tags as you select them
- **Style Creator: collected-only preview**: Editor preview grid now shows only
  collected items; unreleased items hidden. Note displayed next to title
- **Style tab: button tinting**: Tag buttons now show subtle green/yellow/red
  tint for Must Have/Prefer/Avoid states instead of small dot indicators
- **Style detail: Export button**: Custom styles now show an Export button in
  the detail/browse view for easy sharing
- **Style Editor: Freeform category**: Added 'Freeform' category tab that uses
  Blizzard's native housing catalog tags directly, plus 'Other' catch-all for
  untagged items. Tags sorted by expansion/race/size/style with pretty names
- **Style Editor: simplified interaction**: Tags now use a clean on/off toggle
  instead of the 3-state Must Have/Prefer/Avoid cycle. Facet tab row shows
  green tint when tags are selected. Clear All button resets all selections
- **Style Editor: onboarding help**: Preview area shows guidance text when no
  tags are selected, explaining how to build a style. Disappears on first click
- **Style Editor: expanded preview**: Preview gallery increased from 4 rows to
  20 rows (scrollable) to show more matching items
- **Browse by Style**: Beta label added to header
- **Squirrel zone alerts**: Two new squirrel talking head options in Shopping
  List config -- one for uncollected vendor items in the zone, one for shopping
  list items in the zone. 40 squirrel-persona quotes with chat output
- **Minimap right-click menu**: Right-click minimap button now shows a context
  menu with Lumber Tracker and Shopping List options (also applies to addon
  compartment and LDB launcher)
- **FacetDB subject enrichment**: All 1665 items classified into 173 subject
  terms (chair, fountain, statue, etc.) and 8 structural roles via keyword
  matching pipeline. Subject and structural_role facets now indexed by style
  engine for style matching queries

### Fixed
- **Goblin tab profit accuracy**: Vendor-exclusive reagent costs (Rot Resistant
  Cauldron, Crystalforged Cauldron, etc.) now included in profit calculations.
  Price lookup falls back to ReagentsDB vendor prices when TSM/Auctionator
  have no data for vendor-only items
- **ReagentsDB vendor tagging**: 83 reagents retagged from "Gathering" to
  "Vendor:price" with correct copper amounts from Blizzard DB2 data (threads,
  dyes, fluxes, vials, cauldrons, and other vendor-sold crafting materials)
- **TomTom waypoint clearing**: Clear Pins button now correctly removes
  TomTom waypoints (fixed hash table iteration for newer TomTom versions)
- **Map crash on invalid zones**: Fixed error when mapping vendors in zones
  not yet recognized by the client (mapID validation in ZonePctToMap)
- **Housing Theme readability**: Changed recipe known text color from Solarized
  Orange to Blizzard Gold for better contrast and readability
- **Recipes tab price data**: Fixed "No price data" showing in By Recipe sort
  mode when TSM/Auctionator is installed and has pricing data
- **Vendor DB renown requirements**: Fixed 5 Dragonscale Expedition items using
  old standing IDs instead of correct renown ranks
- **Vendor DB reputation standings**: Fixed off-by-1 standing requirements for
  Blackwater Cartel, Bilgewater Cartel, and Darkfuse Solutions items
- **Trainer DB NPC fixes**: Fixed Inscription trainer Jo'mah using wrong NPC ID
  (was showing Thoth); fixed Shattrath Inscription trainer (was Nemiha/wrong ID,
  now Recorder Lidio)
- **Trainer DB coordinates**: Fixed Tailoring trainer Magar coordinates in
  Orgrimmar
- **Vendor DB renown fix**: Fixed Reliquary Telescope renown requirement
  (was 6, now 24)

## [2.8.1] - 2026-02-15
### Added
- **Native Waypoint Support**: TomTom is no longer required for waypoints
  - Blizzard's built-in waypoint + super-tracking used by default
  - TomTom still supported and preferred when installed (configurable)
  - New "Waypoint System" dropdown in Settings: Auto / Blizzard Native / TomTom Only
  - Custom map pins for multi-vendor routes via MapCanvas DataProvider
  - Acquisition tab "Navigate" button sets waypoint + super-tracks destination
  - Vendor Shopping List and Trainers tab use the same unified system
- **LibDataBroker support**: HDG now registers as an LDB launcher -- appears
  automatically in Bazooka, Titan Panel, ChocolateBar, and other LDB display addons
  (no embedded libraries; uses LDB if already loaded by another addon)
- **`/hdg reset` command**: Emergency window reset -- clears saved position and
  forces the main window to screen center (for users whose window moved off-screen)
- **Vendor map pin atlas**: Map pins for vendor waypoints now use the
  housing-map-plot-occupied atlas for better visibility
- **Travel hints**: When navigating to vendors in other expansions, shows
  portal/travel directions in chat to help you get there

### Fixed
- **Native waypoint map pins**: Fixed crash caused by incorrect
  CreateUnsecuredRegionPoolInstance signature

## [2.8.0] - 2026-02-14
### Added
- **Custom Styles**: Create your own style definitions with hand-picked facet tags
  - Style Creator editor: pick Room, Mood, Material, Color, Culture and more
  - 4-state tag cycle: Must Have (green), Prefer (yellow), Avoid (red), Off
  - Live preview shows item counts and sample icons as you build
  - Icon picker (20 presets) and color picker (12 presets)
  - Up to 50 custom styles, persisted across sessions
- **Import/Export**: Share styles as encoded strings (HDG:1:... format)
  - Export from right-click context menu or Style Creator
  - Import via button on Styles landing page
- **Context Menu**: Right-click any style card for Duplicate/Edit/Delete/Export
- **My Styles** tier on landing page with "+ New Style" card
- "Style Creator" and "Import" buttons on Styles tab header
- **Style Shopping List**: Track uncollected items per style in the Shopping List widget
  - New "Style" tab in the Shopping List alongside List, Zone, Config
  - Items grouped by style with expand/collapse headers and collected/total counts
  - "Add All to Style List" button in style detail view header
  - Shift-Click items in gallery or list view to add individually
  - Source badge (Vendor, Craft, Q, etc) on each item row
  - Collected items highlighted in green; remove button per item
  - Persists across sessions via SavedVariables

### Fixed
- **Vendor DB**: Alliance "High Tides" Ren (Founder's Point) -- added 23 missing items (37->60)
- **Vendor DB**: Alliance "Len" Splinthoof (Founder's Point) -- added 10 missing items (17->26), removed 1 incorrect
- **Vendor DB**: Alliance "Yen" Malone (Founder's Point) -- replaced incorrect Horde inventory with correct 33 Alliance items
- **Vendor DB**: Horde "High Tides" Ren (Razorwind Shores) -- added 25 missing items, fixed 7 prices (30->53)
- **Vendor DB**: Horde "Yen" Malone (Razorwind Shores) -- added 5 missing Garden Clusters, removed 4 incorrect entries
- **Localization**: Acquire tab vendor NPC names now resolve via WoW API for localized display on non-English clients (previously hardcoded English)
- **Localization**: Added missing expansion aliases for Classic (all non-English clients) so profession skill points display correctly on the Alts tab
- **Localization (zhCN)**: Updated Simplified Chinese translations from community contributor (sgswdzgr) -- improved lumber terminology, addon name handling, added minimap/compartment strings

===============================================================================
Vamoose's Housing Decor Helper - Version 2.7.0 (February 2026)
===============================================================================

TAB BAR
=======
* Replaced 8 custom TGA tab textures with unified icon+text buttons using WoW
  built-in icons. All 9 tabs now fully respond to theme changes.
* Active tab shows accent-colored 2px underline bar and tinted backdrop.
* Config and Data tabs are now compact icon-only buttons with tooltips.
* Hover state brightens inactive tabs using theme panel color.

STYLES TAB (NEW)
================
* V2 Faceted Style System — replaced monolithic keyword/tag-based classification
  with faceted query engine. Each item has up to 19 independent facets (category,
  colors, materials, culture, mood, room, condition, formality, motifs, etc.)
  Styles are now "saved queries" over facets. New HDG_FacetDB.lua (1705 items).
  Room taxonomy expanded from 7 to 20 rooms. All public StyleEngine APIs preserved.
* 14 persona-driven style definitions across 3 tiers:
  - Room Concepts (10): Rustic Tavern, Cozy Cottage, Arcane Study, Feast Hall,
    Workshop, Sacred Shrine, Garden Retreat, War Camp, Seafarer's Haven, Dark Sanctum
  - Themed (2): Witch's Den, Tribal Lodge
  - Faction (2): Alliance, Horde
  Each style has richer descriptions, refined query/boost/anti scoring, and
  fixed vocabulary values (removed invalid condition/color references).
* Card/gallery grid view — toggle between list and 3D card grid using Blizzard's
  native catalog card atlas textures with static ModelScene thumbnails. Cell
  pooling for efficient reuse. Uncollected items show actor desaturation.
* Category switcher tabs (All/Races/Moods/Classes/Expansions/Thematic) on the
  landing page to filter styles by category.
* Mini icon preview strip on each card shows up to 6 item icons from the style's
  signature tier. Collected items saturated, uncollected desaturated at 50% alpha.
* Completion percentage shown in count text (e.g. "59/68 (86%)").
  100% complete styles get a gold border on their card.
* Landing page cards show real collection progress (X / Y collected) with
  accurate progress bar fill based on 1st Order items.
* 3D model preview in detail panel — select an item to see a rotatable, zoomable
  ModelScene preview (drag to rotate, scroll to zoom, right-click to reset).
* Room subcategory filter in detail view: toggle buttons for All, Great Hall,
  Kitchen, Study, Bedroom, Garden, Workshop, and Trophy rooms.
* "Hide Unreleased" filter checkbox (default ON) — hides unreleased/datamined
  items from the item list.
* "Neutral" tier — items with no style relationship now get their own bucket.
  Tier order: 1st Order > 2nd Order > Neutral > Clash.
* Thematic Collections — 6 subcategory-based styles: Outdoors & Garden, Forest
  Retreat, Coastal & Beach, Farmstead, Zen Garden, Training Grounds. Shows
  subcategory buttons instead of harmony tiers, with source-type filter buttons.
* Generic subcategory system — any style definition with a `subcategories` field
  automatically uses subcategory buttons and keyword-based classification.
* Pre-computed thematic assignments from Blizzard dataTagsByID dump — O(1) lookup
  with runtime keyword fallback. Eliminates false positives from short substring
  matches.
* Quantity badge on gallery cells — Blizzard-style owned count at BOTTOMRIGHT.
* Data-mined harmony/clash lists — rebuilt all 42 style relationships from 1,662
  vision-classified item co-occurrences, replacing hand-authored lists.
* List view and detail panel show "+ Vendor" suffix on source labels for items
  with both a primary source and a vendor source.

ACQUISITION TAB
===============
* 3D preview rebuilt as a replica of Blizzard's HousingModelPreview — atlas
  background, item name + collected checkmark overlay, placement cost, storage
  counts, decorative corbels, and ModelSceneControlFrame (zoom/rotate/reset).
  Camera uses native PanningModelSceneMixin instead of custom handlers.
* Vendor "Also sells" gallery now uses Blizzard atlas-card style with quantity
  badges. Shift-click gallery cells to add items to the Shopping List.
* Source text in detail panel now filters out the selected vendor's block, Cost:,
  and Faction: lines to avoid duplicating info shown in the detail header.

GOBLIN TAB
==========
* Auctionator scan UX overhaul: scan status is now a clear state machine with
  distinct visual states for idle, scanning, complete, cooldown, and AH closed.
* Animated "Scanning..." indicator with cycling dots shows scan is in progress.
* Green "Updated!" flash for 3 seconds after scan completes, then shows freshness.
* Price freshness text upgraded to normal font size with color-coded age
  (green <1h, yellow <24h, red >24h, red "No AH data" if never scanned).
* Scan button text now context-aware: "Scan", "Open AH", or "Cooldown".
* Tooltip rewritten per state: explains what scan does when ready, tells you to
  visit an auctioneer when AH is closed, shows Auctionator's cooldown timer.
* 60-second freshness ticker auto-updates the time display without manual refresh.

ALTS TAB
========
* Find Lumber indicator on each character header row (spell icon + status text).
  Shows "Find Lumber known" (green), "Find Lumber not learned" (red), or
  "Log in to check" (dim) for alts not yet cached with the updated addon.
* Uses IsPlayerSpell(1256697) -- data populates as each alt logs in.

IMPROVEMENTS
============
* 3D decor preview extracted into reusable factory (HDG_UIHelpers.CreateDecorPreview).
  Acquisition, Decor Preview, and Styles tabs now share the same Blizzard-style
  atlas preview with PanningModelSceneMixin, ModelSceneControlFrame, and corbels.
* Shared gallery cell factory (HDG_UIHelpers) — Styles and Acquisition tabs share
  a single cell creation + pooling codebase for atlas-card grids.
* Memory chart window (/hdgdebug mem) — 5-minute scrolling area chart showing
  addon memory usage over time, with auto-scaling Y-axis and peak tracking.
* VendorResolver: Fixed reputation standing display — STANDING_NAMES now uses
  Blizzard's 1-based reaction IDs (8=Exalted).

PERFORMANCE
===========
* Fixed memory leak in pinned lumber tracker — row frames now pooled and reused.
* Cached shopping list and profession lumber calculations — only recalculated
  when shopping list or recipes change, not on every bag event.
* Early-exit in RefreshPinned when lumber counts haven't changed.
* Optimized lumber radar render loop — ~4x reduction in GC pressure via reused
  Vector2D, cached coordinates, localized math, numeric for loops.

DATABASE
========
* Added Sanctuary's Horadric Cube (In-Game Shop).
* Updated Beloved Lion Plushie and Beloved Wolf Plushie source to In-Game Shop.
* VendorDB: Added 15 missing vendor sources (10 new vendors: Drac Roughcut,
  Master Smith Burninate, Woodsman Drake, Maurice Essman, Fiona, Willard
  Harrington, Brave Tuho, Maybell Maclure-Stonefield, Hoddruc Bladebender,
  Provisioner Thom; plus items added to Gina Mudclaw, Ellandrieth, Caspian,
  Delphine). Added 6 missing items to Arcanist Peroleth, 7 to Second Chair
  Pawdo, 2 to Ripley Kiefer/Lord Candren, 1 to Sergeant Crowler.
* VendorDB: Fixed wrong coordinates for 17 vendors (Captain Donald Adams,
  Captain Lancy Revshon, Captain Stonehelm, Gabbi, Lonalo, Second Chair Pawdo,
  Stone Guard Nargol, Tuuran, Sage Whiteheart, Silvrath, Tethalash, Unatos,
  Auditor Balwurz x/y swap, Garnett, Chachi the Artiste mapID, Shredz the
  Scrapper, Street Food Vendor). Fixed mapID for Gabbi/Second Chair Pawdo
  (Kalimdor->Orgrimmar) and Gabbun (2272->2214).
* VendorDB: Fixed 12 expansion misclassifications — 11 Undermine/K'aresh
  vendors incorrectly tagged as Midnight (now The War Within), Moon Priestess
  Lasara corrected from TWW to Dragonflight.
* VendorDB: Fixed Lifecaller Tzadrak vendor name (was Caretaker Azkra).
* VendorDB: Fixed costs — Cendvin currency 100->75, Gina Mudclaw 4 items
  rep level 5->8 (Good Friend).
* VendorDB: Removed 3 items vendors no longer sell (Replica Acherus Soul
  Forge from Caydori Brightstar, Replica Tome of Fel Secrets from
  Quartermaster Ozorg, Skyhorn Eagle Kite from Ransa Greyfeather).
* VendorDB: Added Gundargaz Grand Keg (253172) to Chert.
* VendorDB: Fixed costs for BfA War Resources vendors (Provisioner Mukra,
  T'lama, Pearl Barlow, Janey Forrest, MOTHER), removed duplicate vendor
  Dershway the Triggered, removed 7 incorrectly listed Alliance items from
  Sergeant Grimjaw.
* VendorDB: Fixed 6 Legion class hall vendor mapIDs -- Kelsey Steelspark,
  Meridelle Lightspark, Quartermaster Durnolf, Toraan the Revered, Flamesmith
  Lanying, Quartermaster Ozorg all pointed to wrong instance maps.
* VendorDB: Fixed Provisioner Aristta Mysterious Fragments cost (7000->4000).
* VendorDB: Fixed Stacks Topskimmer -- removed non-sold achievement item
  (257353), added Counterfeit Dark Heart (267265) at 15,000 Resonance Crystals.
* VendorDB: Fixed Edwin Harly expansion tag (Cataclysm->Classic, NPC added
  in patch 1.11.1).
* VendorDB: Extended item format with quest gate [6] and achievement gate [7]
  fields. Added RENOWN_FACTIONS lookup table to distinguish renown from
  traditional rep standings (DF + TWW factions).
* VendorDB: Added quest/renown/achievement gates for 15 vendors (88 items):
  Auditor Balwurz (renown + quest), Chert (quest + renown), Stacks Topskimmer
  (renown + quest + achieve), Om'sirik (renown), MOTHER (achieve), Blair Bass
  (quest), Berazus (quest), Ta'sam (quest), Jocenna (7 quest gates + painting
  rep fix), Trader Caerel (8 quest gates), Ellandrieth (3 quest gates),
  Arcanist Peroleth (10 quest/achieve gates), T'lama (14 quest/achieve gates).
* VendorDB: Fixed Garnett -- corrected cost from 10g to Resonance Crystals
  (450-900 RC per item), added quest/achievement gates for all 7 items.
* DecorDB: Fixed Pandaren Stone Post itemID (247729->247728) -- was pointing
  to vendor version instead of crafted version.
* AllDecorDB: Fixed Kotmogu items sourceType to Achievement, fixed Architect's
  Drafting Table to Vendor, fixed 3 Brawler's Guild vendor references.
* TrainersDB: Fixed 15 incorrect NPC IDs across Cooking, Tailoring, Enchanting,
  Alchemy, Engineering. Thanks to Tzunamis for the report!
* Thanks to keeperharvest for the detailed vendor audit!
* Vendor display pipeline: wired quest/achievement gates through all UI layers.
  Acquire tab detail panel shows "Quest: name" and "Achievement: name" lines
  with green/orange met/unmet coloring. Preview tab tooltip shows quest/achieve
  requirements indented under vendor. Acquire row icons reflect combined gate
  status (rep + quest + achieve). Shopping list badge shows "Quest"/"Achieve"
  label where applicable.
* Fixed renown detection -- was using minRep > 8 heuristic which misread low
  renown levels (e.g. Cartels of Undermine renown 5 as "Friendly"). Now uses
  RENOWN_FACTIONS lookup table for correct "Renown N" display and meeting check.

BUG FIXES
=========
* Fixed Alts tab legend colors not matching cell colors — legend now uses
  theme-aware C_Accent/C_Warning/C_Dim instead of hardcoded hex colors.
  Thanks to Gnuclear Gnome for the report!
* Fixed Alts tab crash on expansion #12 (Midnight) — EXPANSION_SLOTS bumped
  from 11 to 12.
* Fixed incorrect vendor coordinates for Om'sirik — corrected to 40.6, 29.0
  in Tazavesh.

===============================================================================
Vamoose's Housing Decor Helper - Version 2.6.4 (February 2026)
===============================================================================

BUG FIXES
=========
* Fixed collection status showing red X for items the player has collected but
  no longer has copies in stock — now uses firstAcquisitionBonus to detect
  appearance unlocks (affects both IsItemCollected and IsDecorCollected)

IMPROVEMENTS
============
* Lumber tracker column headers renamed: "Needed" → "Queue", "In Stock" →
  "Uncollected" for clarity (pinned tracker and Recipes tab)
* Right-click minimap icon now toggles the pinned lumber tracker standalone
* Added "Pin Radar to Tracker" option in Config — anchors radar HUD below the
  lumber tracker so they move together

===============================================================================
Vamoose's Housing Decor Helper - Version 2.6.3 (February 2026)
===============================================================================

DATABASE
========
* Extended unreleased item detection to cover additional Midnight zones:
  Harandar, Arcantina, Voidstorm, Masters' Perch, The Voidspire, The Blinding
  Vale, Voidscar Arena, The Dreamrift, Zul'Aman, Murder Row, Windrunner Spire,
  Nexus-Point Xenas, Magisters' Terrace, Seat of the Triumvirate, Slayer's
  Rise, and Midnight Delves (Shadow Enclave, Collegiate Calamity)
* Marked 392 total unreleased items with future timestamps (up from 274)
* Fixed Alliance/Horde Doormat source — reclassified from vendor to In-Game
  Shop (source type 10) and future-dated
* Hide Unreleased filter now also filters items named "Unreleased" by the
  Blizzard API

===============================================================================
Vamoose's Housing Decor Helper - Version 2.6.2 (February 2026)
===============================================================================

NEW FEATURES
============
* Added "Hide Unreleased" checkbox to Acquisition and Preview tabs — filters
  out datamined items not yet obtainable in-game (on by default)
* Unreleased detection: zero-cost vendor items, items not in AllDecorDB, and
  future-timestamped items (Silvermoon/Eversong revamp, Midnight professions)
* Added /hdgdebug scan command — scans the Blizzard catalog API for items
  missing from AllDecorDB and outputs them in copy-paste DB format

DATABASE
========
* Added 14 new items to AllDecorDB (1704 total items tracked)
* Marked 260 unreleased items with future timestamps (Silvermoon City revamp,
  Eversong Woods revamp, Midnight profession recipes)
* Fixed "Glorious Pendant of Rukhmar" source — now correctly listed as
  Achievement (Secrets of Skettis) instead of Vendor-only
* Fixed vendor price for Duskcaller Erthix item (was 100,000g, corrected to 10g)
* Fixed Velerd (Dornogal) items — Deephaul Crystal and Earthen Contender's
  Target now correctly listed as Honor currency instead of 10g

BUG FIXES
=========
* Fixed debug mode not persisting across sessions — config checkbox saved to
  HDG_DB but the debug guard was reading from HDG_Settings
* Fixed /hdgdebug scan source classification — Lua pattern used invalid +?
  syntax (regex non-greedy), changed to proper greedy + match

===============================================================================
Vamoose's Housing Decor Helper - Version 2.6.1 (February 2026)
===============================================================================

COMPATIBILITY
=============
* Updated for WoW 12.0.1 (Midnight Patch 1)

===============================================================================
Vamoose's Housing Decor Helper - Version 2.6.0 (February 2026)
===============================================================================

NEW FEATURES
============
* NEW: Vendor Shopping List — bookmark vendor items for shopping trips
  - Shift-click items or vendor headers in Acquisition tab to add to list
  - "List" button in Acquisition tab header toggles the shopping list widget
  - Items grouped by zone → vendor → item with gold costs and rep badges
  - Remove individual items (X button) or clear the entire list
  - "Map Waypoints" button drops TomTom waypoints for all listed vendors
  - Click any vendor row to set a single TomTom waypoint
  - List persists across sessions via SavedVariables
* NEW: Zone Scanner — auto-detects vendors with uncollected items in your zone
  - "Zone" tab in the shopping list widget shows current zone vendors
  - Shift-click items/vendors in Zone view to add them to your manual list
  - Optional auto-open on zone change (disabled by default)
  - Optional notification sound on auto-open (disabled by default)
  - Config tab within the widget for zone scanner settings
IMPROVEMENTS
============
* IMPROVED: Dye Studio closes on Escape key press
* IMPROVED: Acquisition tab — "Acquisition Source" shortened to "Source",
  "Unc" spelled out as "Uncollected"
* IMPROVED: UI polish — buttons, tab toggles, checkboxes, and dropdown
  scrollbars now use native WoW atlas textures for a cleaner look

BUG FIXES
=========
* FIXED: Korean, Chinese, and Russian locale users now see proper font rendering
  — non-Latin locales use WoW's built-in locale-appropriate font instead of
  Expressway (which lacks CJK/Cyrillic glyphs)
* FIXED: Dyeable filter in Acquisition tab now works immediately on login
  (persisted cache loads at startup instead of waiting for Dye Studio init)

===============================================================================
Vamoose's Housing Decor Helper - Version 2.5.0 (Released February 2026)
===============================================================================

NEW FEATURES
============
* NEW: User Notes — Attach personal text notes to any decor item
  - Pencil icon + note text in the item header panel (visible for all item types)
  - Click to add/edit via popup editor (up to 200 characters)
  - Notes persist across sessions (account-wide in SavedVariables)
  - [N] badge indicator on item rows in the list view for annotated items
  - "Export Notes" button in Acquisition tab title bar — opens copy-friendly
    text window with all notes, item names, and timestamps
* NEW: Dye Studio — Complete overhaul of the dye browser
  - Rainbow spectrum title bar and "Vamoose's Dye Studio" branding
  - Three browse modes: Category (Blizzard groupings), Color (hue-based),
    and Theme (23 curated palettes like Alliance, Horde, class themes)
  - Custom Palettes — Create, rename, delete, and share your own dye palettes
    with import/export via encoded strings (up to 20 palettes, 20 dyes each)
  - Live Dyeing — "Replace Blizzard UI" checkbox auto-opens Dye Studio when
    editing decor in your house; click dyes for instant in-place preview
  - Dye slot bar shows all slots on the selected decor for quick slot switching
  - Color group classification (RGB→HSV) auto-sorts 62 dyes into 12 hue families
  - Sidebar filter buttons with color-coded swatches for quick navigation
  - Palette detail strip shows all dyes in a custom palette with color swatches
* NEW: Dye Studio button in HDG title bar (rainbow 2x3 swatch grid icon)
  - Hover tooltip shows colorful rainbow bar and feature summary
* NEW: `/hdg dyes` slash command to toggle the Dye Studio

PERFORMANCE
===========
* OPTIMIZED: Acquisition tab filter rebuilds no longer call Blizzard API for
  uncollected items — negative collection results now cached with generation
  counter (eliminates 1,000+ API calls per filter change)
* OPTIMIZED: Search filtering uses pre-lowercased item name cache instead of
  per-item string allocation on every keystroke
* OPTIMIZED: DNT/AUTOGEN items filtered at build time instead of per-filter-pass
* OPTIMIZED: Removed redundant sourceInfo/vendorInfo/vendorItemCost cache tables
  — reads directly from AllDecorDB and VendorDB (faster BuildCaches, less GC)
* OPTIMIZED: Sort comparators hoisted to module level (no closure allocation)
* OPTIMIZED: Theme/scheme cached per refresh batch instead of per-row lookup
* OPTIMIZED: Preview tab dye swatches use pre-computed category ownership cache
  instead of per-dye iteration on every item selection (60-80 calls → 10 lookups)
* OPTIMIZED: Removed dead O(n) ProfessionsDB scan in PowerCrafting item name
  resolution (was iterating 8,000+ entries with no possible match)

IMPROVEMENTS
============
* IMPROVED: Acquisition tab virtual scrolling for large item lists (>200 rows)
  — only creates visible rows + buffer, rebuilds on scroll for smooth performance
* IMPROVED: "Dyeable" checkbox re-enabled in Acquisition tab filters
* IMPROVED: Expansion filter dropdown now color-codes expansion names
* IMPROVED: Zone, Faction, and Source filter dropdowns highlight active selection
* IMPROVED: Non-vendor items now resolve expansion from recipe or AllDecorDB data
* IMPROVED: Dropdown widget supports `colorFn` callback for per-item text coloring
* IMPROVED: Dye Panel help popup with colored keywords and left-aligned layout

DATA UPDATES
============
* UPDATED: VendorDB — Fixed Stormshield/Warspear vendor mapIDs (588→622/624),
  Frostwall (588→590), K'aresh (0→2552) coordinates
* UPDATED: VendorDB — Added currency costs for Garrison, Legion class hall,
  Midnight, and Undermine vendors
* UPDATED: VendorDB — Fixed bogus 20000 copper on class hall vendors
* UPDATED: VendorDB — Removed incorrectly listed items (Bob's crafted item,
  misplaced Kelsey Steelspark items)
* UPDATED: AllDecorDB — Comprehensive data refresh (2,885 lines changed)

BUG FIXES
=========
* FIXED: Combat taint error from UnitGUID "secret value" in TWW 12.0+ when
  targeting vendors — VendorResolver now pcall-guards strsplit on GUID and
  defers PLAYER_TARGET_CHANGED processing to break the hardware-input taint chain
* FIXED: Frame strata lowered from HIGH to MEDIUM for main window, floating
  widgets, and teal buttons to reduce taint propagation surface
* FIXED: FloatingWidget close button using deprecated `button` scheme key
  instead of `button_normal` (caused nil color error on some themes)
* FIXED: C_DyeColor API name corrected (was C_HousingDyeColor)

===============================================================================
Vamoose's Housing Decor Helper - Version 2.4.0 (February 2026)
===============================================================================

NEW FEATURES
============
* NEW: Acquisition Tab - Vendor Shopping Guide
  - New "Acquire" tab between Preview and Trainers
  - Two views: "By Vendor" (browse vendors by zone) and "By Item" (flat
    alphabetical list of all 1,646 acquirable items)
  - Left panel: Searchable item list with Expansion, Zone, Reputation, and
    Source dropdown filters, "Uncollected only" and "Endeavor" toggles
  - Right panel: Vendor info (name, zone, coords, faction/rep), 3D model
    gallery of vendor stock, item details with price and "Other Vendors" list
  - "Set Waypoint" (TomTom) and "Show on Map" buttons for navigation
  - "Map All" button drops TomTom waypoints for all vendors matching filters

* NEW: Acquisition Tab - All Source Types
  - Master AllDecorDB of all 1,690 housing decor items with source classification
  - Vendor items (1,060): full vendor details, prices, rep requirements
  - Achievement items (121): shows achievement name and completion status
  - Quest items (110) and World Quest items (93): shows quest name and zone
  - Drop items (68): shows dungeon/source name
  - Crafted items (310): shows profession, expansion, and reagent list with
    "Add to Crafting Queue" button (same workflow as Preview and Goblin tabs)
  - Treasure (3) and Promotion (17) items also included
  - Source icons in rows: achievement crest, quest bang, crosshair, anvil,
    loot sparkle, crafting orders icon
  - Done/Incomplete status for all non-vendor source types
  - Source filter dropdown: All, Vendor, Achievement, Quest, Drop, Crafted,
    Treasure, Promotion

* NEW: "How to Use" Guide Panel
  - In-app guide shown on the right panel before any item is selected
  - Covers Getting Started, Common Use Cases, Views, Filters, and Map All
  - Explains all row icons (collected, rep status, faction) and source icons
  - "How to Use" button in header bar toggles guide visibility at any time
  - Guide text rebuilds dynamically to match active theme colors

* NEW: Preview Tab - "Find Vendor" button
  - Non-crafted vendor items now show a "Find Vendor" button in the info pane
  - Clicking navigates to the Acquisition tab and pre-selects that item

* NEW: Data Tab - Decor Collection Statistics
  - New "Decor Collection" section below Farming History
  - Summary stats: Unique items owned, items in storage, items placed
  - Top 5 category breakdown with item counts
  - "Refresh" and "Export CSV" buttons

IMPROVEMENTS
============
* IMPROVED: Preview tab vendor tooltips now show faction/reputation requirements
* IMPROVED: Reputation filter correctly excludes non-vendor items
* IMPROVED: Zone and Expansion filters properly skip non-vendor items
  - Non-vendor items only respond to Source, Search, and Uncollected filters
* IMPROVED: Acquisition Tab defaults to "By Vendor" view

PERFORMANCE
===========
* OPTIMIZED: Acquisition tab opens instantly (deferred list build to next frame)
  - Collection status lazy-cached on demand by IsItemCollected()
* OPTIMIZED: Row/cell pool acquisition O(n) → O(1) via free-list stacks
* OPTIMIZED: Vendor inventory cost summary uses pre-built lookup table
* OPTIMIZED: Gallery cells no longer flash 2D icon before 3D model loads

BUG FIXES
=========
* FIXED: Vendor coordinates — Converted 90 vendors from world-space to
  zone-percentage coordinates. Waypoints now work for Stormwind, Orgrimmar,
  Silvermoon City, Ironforge, Valdrakken, Dornogal, and all other previously
  broken locations.
* FIXED: Coordinate validation prevents waypoint crashes from out-of-range coords
* FIXED: "Also sells" gallery not updating when switching vendors in By Vendor view
* FIXED: Lumber farming sessions not detecting after zone transitions
* FIXED: Lumber session tracking robustness (timer guards, lazy init fallback)
* FIXED: Vendor button frame leak in item detail panel (now pooled)
* FIXED: "...and N more" label FontString leaked on every item selection
* FIXED: Stale theme colors in vendor button hover handlers
* FIXED: "attempt to index field 'collectedIcon'" crash in expansion grouping
* FIXED: Clicking item in vendor gallery switched to wrong vendor

DATA QUALITY
============
* ADDED: AllDecorDB — master database of all 1,690 housing decor items
  - 12 source types: Unknown, Achievement, Quest, World Quest, Drop, Vendor,
    Crafted, Learned, Gathering, Treasure, Promotion, Profession
* ADDED: 96 new vendor items from Blizzard catalog cross-reference
  - Added items from 38 new vendors across all expansions
  - VendorDB now covers 1,211 items (was 964)
* ADDED: 228 alternate vendor entries for existing items
  - Items now show all vendors that sell them
* REMOVED: 105 quest-only items from VendorDB (confirmed as quest rewards)
* UPDATED: 15 Mechagon items with correct vendor/zone data

===============================================================================
Vamoose's Housing Decor Helper - Version 2.2.2 (Released February 2026)
===============================================================================

BUG FIXES
=========
* FIXED: BfA professions not showing for Horde characters on German clients
  - Root cause: German WoW uses "Zandalar" (place name) instead of "Zandalari"
    (demonym) for Horde profession expansion identifiers
  - Added "Zandalar" to BfA locale aliases in HDG_ExpansionData.lua
  - Alliance ("Kul Tiras") was unaffected as spelling matches across locales

* FIXED: Lumber tracker not working after zone transitions (Dorn, Pandaria, etc.)
  - Root cause: C_Map.GetBestMapForUnit("player") returns nil briefly during
    zone transitions, causing lumber tracking to silently fail
  - Added ZONE_CHANGED_NEW_AREA event handler with 0.5s delay to allow map
    data to stabilize before refreshing tracker
  - Lumber HUD now clears cached blip positions on zone change for recalculation

* FIXED: Lorewalker's Bookcase (MoP Inscription) showing wrong item
  - Root cause: Database had incorrect itemID (258147) which belongs to vendor
    item "Empty Lorewalker's Bookcase" instead of crafted version
  - Corrected itemID to 247669 (crafted Lorewalker's Bookcase)
  - Thanks to user report for identifying this data error

NEW FEATURES
============
* Added Debug Mode as a config option (Config > Advanced)
  - Debug commands (/hdgdebug) are now gated behind a setting (off by default)
  - Can also toggle via /hdgdebug unlock without opening the config UI
  - Useful for troubleshooting data issues without cluttering normal usage

===============================================================================
Vamoose's Housing Decor Helper - Version 2.2.1 (Released February 2026)
===============================================================================

BUG FIXES
=========
* FIXED: Compatibility with Vamoose's Endeavors addon - HDG no longer shows as
  empty white box when both addons are loaded
  - Root cause: Shared theme system overwrote HDG-specific themes (HDGDefault)
  - Fix: HDG now preserves its own themes when merging shared color schemes
* FIXED: Lumber coordinates performance degradation after extended farming
  - Root cause: lumberCoordinates table grew unbounded, causing O(n) work per HUD frame
  - Added MAX_LUMBER_COORDINATES = 500 limit with efficient batch pruning
  - Migration (v3) prunes existing bloated SavedVariables on login

IMPROVEMENTS
============
* CHANGED: Simplified Lumber Tracker UI
  - Removed title click to show focus tracker (title now decorative only)
  - Removed Reset Session button from lumber rows
  - X (End Session) button is now the only way to end a farming session

THEME ADJUSTMENTS
=================
* CHANGED: HDGDefault "success" color from bright green to muted teal (#429A91)
  - Better visual harmony with HDG's teal accent palette

===============================================================================
Vamoose's Housing Decor Helper - Version 2.2.0 (Released January 2026)
===============================================================================

THEME SYSTEM
============
* NEW: "Housing" theme with wood panel backgrounds and decorative foliage
* NEW: HDGDefault theme matching original addon styling
* NEW: Theme selector button in title bar - switch between Housing, HDGDefault, Solarized, Midnight
* NEW: Live theme switching without reload
* NEW: Wood sign backgrounds for section headers in Housing theme
* NEW: Animated foliage decorations around titles in Housing theme

UI ARCHITECTURE REFACTOR
========================
* NEW: HDG.UI:TabPanel() factory method for standardized tab content panels
* NEW: TAB_PANEL constants in HDG_Config.lua for consistent layout values
* NEW: HeaderTitle and SectionHeader skinners in ThemeEngine
* NEW: StyleHeaderTitle() for panel header bars with wood sign backgrounds
* NEW: AddFoliageDecorations() for section titles with decorative foliage
* IMPROVED: AltsTab refactored to use new TabPanel factory pattern
* IMPROVED: Title textures (title1, title2) now display correctly for all themes
* IMPROVED: Title z-ordering fixed - renders above wood border in Housing theme

GOBLIN TAB
==========
* NEW: CSV Export button - exports all profit analysis data
* NEW: Export includes all columns: Name, ItemID, Profession, Expansion, Quality,
       LumberType, LumberQty, LumberValuePer, LumberValueTotal, MaterialCost,
       SellPrice, Profit, Margin%, RegionAvg, TSMMargin%, KnownByPlayer,
       KnownByAlts, PriceSource
* NEW: Gold values formatted as gold.silver.copper (e.g., 123.45.67)
* NEW: Export button uses housing-neighborhood-invite-icon atlas
* FIXED: Auctionator scan button no longer shows "Cooldown" when AH first opened
* FIXED: Scan button re-checks availability on each click

LUMBER TRACKER
==============
* IMPROVED: Reset Session button now saves current session to history before starting fresh
  - Farming stats are preserved in Data tab's Farming History
  - Confirmation message shows collected count before resetting

DATA TAB
========
* IMPROVED: Decor Crafting and Farming History tables now use full scroll region width
  - Column widths optimized for ~760px usable space
  - All columns use SetWordWrap(false) to prevent text layout issues

BUG FIXES
=========
* FIXED: Smoke Lamp recipe now displays correct name (was showing "Schematic: Thalassian Competitor's Plate Guard")
  - Corrected itemID in DecorDB from 257408 to 257406
* FIXED: House level/XP display moved up 2 pixels for better alignment

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.8 (Released January 2026)
===============================================================================

DATABASE UPDATE
===============
* NEW: Added 2 new TBC Alchemy housing decor recipes:
  - Arakkoan Alchemist's Bottle (recipeID: 1273064)
  - Arakkoan Alchemist's Concoction (recipeID: 1273070)
  - Both items added to HDG_ProfessionsDB and HDG_DecorDB

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.7 (Released January 2026)
===============================================================================

MIDNIGHT (12.0) COMPATIBILITY
=============================
* FIXED: Updated deprecated API calls for WoW 12.0 compatibility:
  - IsPlayerSpell → C_SpellBook.IsSpellKnown (recipe knowledge checks)
  - GetItemInfo → C_Item.GetItemInfo (item data lookups)
  - GetItemQualityColor → C_Item.GetItemQualityColor (quality colors)
  - GetCoinTextureString → C_CurrencyInfo.GetCoinTextureString (gold display)
* FIXED: Collection mode (Decor Preview tab) now works in 12.0
  - C_HousingCatalog searcher calls wrapped in pcall for error protection
* FIXED: Profession filter in Collection mode now properly filters items
  - Non-craftable catalog items no longer pass through when profession selected

LUMBER RADAR
============
* FIXED: Radar auto-closes when farming session ends

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.6 (Released January 2026)
===============================================================================

LOCALIZATION FIXES
==================
* FIXED: Non-English clients missing expansion skills in Alts tab
  - GetExpansionFromSkill() now checks apiTags array for localized names
  - Added support for all 9 languages: DE, ES, FR, IT, RU, KO, ZH
  - German users can now see Scherbenwelt (TBC), Nordend (WotLK), etc.
  - Spanish users can see Terrallende (TBC), Rasganorte (WotLK), etc.

CONFIG TAB REORGANIZATION
=========================
* NEW: Two-column grid layout with General (left) and Lumber Tracking (right)
* NEW: Teal section headers for visual organization
* NEW: Row 1: Show Minimap Button | Auto-Enable Lumber Tracker
* NEW: Row 2: Show in Addon Compartment | Auto-Show Lumber Radar
* NEW: Row 3: Show Profession Window Buttons | Radar Scale slider (0.5x-2.5x)
* NEW: Row 4: Pin Lumber Tracker | Radar FPS slider (10-30 fps)
* NEW: Consistent 38px row spacing with hint text below each option
* NEW: "Farming & Crafting Quotes" section with streamlined layout:
  - Enable Quotes (master toggle)
  - Only print quotes to chat (NEW - disables talking head, keeps chat output)
  - Lumber Quotes
  - Chattiness slider (aligned under Lumber Quotes label)
  - Craft Quotes
* IMPROVED: Hint text clarified (e.g., "Floating widget - also via pin button")

BUG FIXES
=========
* FIXED: Manually crafting decor no longer closes profession window
  - Window only closes if craft was initiated from addon UI
* IMPROVED: Chattiness slider personality text with Vamoose's recommendations

DOCUMENTATION
=============
* IMPROVED: How-to Guide updated with Lumber Radar tips about efficient small routes

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.5 (Released January 2026)
===============================================================================

MAJOR FEATURE: LUMBER RADAR HUD
===============================
* NEW: Temporal radar showing recent lumber gathering locations
* NEW: Circular radar with player at center - blips positioned by distance and bearing
* NEW: Distance rings at 150y and 300y with yard labels
* NEW: Blip colors show respawn status:
  - Red = just cut, don't return yet
  - Yellow = respawning soon
  - Green = ready to harvest again
* NEW: Blip size scales with distance (larger = closer)
* NEW: Auto-shows when gathering lumber, toggle with /lumberhud
* NEW: Draggable positioning saved to SavedVariables
* NEW: Green radar styling with circular background and distance rings
* NEW: Radar Scale slider (0.5x - 2.5x) in Config tab
* NEW: Radar Framerate slider (10-30 fps) in Config tab
* NEW: Distance calibration matches TomTom/HereBeDragons accuracy
  - Uses C_Map.GetWorldPosFromMapPos for true yard calculations

MAIN WINDOW
===========
* NEW: House level and experience display in bottom right
  - Shows "House Level 5 (Max)   7540 / 3700 XP" format
  - Uses async C_Housing API with proper event handling
  - Refreshes when player learns new decor items

MATERIALS PANEL
===============
* NEW: "Add All to Auctionator" now subtracts materials you already have
  - Only searches for quantities you actually need
* IMPROVED: Tooltip clarifies that it replaces the existing Auctionator shopping list

CRAFT CONFIRMATION DIALOG
=========================
* NEW: "Keep profession window open" checkbox option
  - Setting persists account-wide
* FIXED: +/- buttons and "Max N" now appear correctly
  - Was checking queued amount instead of craftable materials

LUMBER TRACKER
==============
* NEW: Trade lumber tracking - prevents false farming sessions
  - Added TRADE_SHOW/TRADE_CLOSED event handling
  - Multi-account users can trade lumber without triggering quotes/sessions
* NEW: Lumber coordinate tracking - saves player position when gathering
  - Stores mapID, x/y coordinates, zone, timestamp per gather
  - Data persisted for radar and future route analysis

BUG FIXES
=========
* FIXED: Craft quotes now respect chattiness=0 setting
  - Added chattiness > 0 check before showing quotes

IMPROVEMENTS
============
* IMPROVED: How-to Guide updated with Lumber Radar HUD documentation

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.4 (Released January 2026)
===============================================================================

ACCOUNT-WIDE LUMBER TRACKING
============================
* NEW: Lumber tracker now sums inventory across ALL characters
* NEW: Warband Bank shown as separate line (counted once, not per-character)
* NEW: Tooltip shows breakdown: each character's personal count + Warband Bank
* FIXED: No more double-counting shared Warband Bank items

TALKING HEAD QUOTE SYSTEM
=========================
* NEW: Talking head quotes appear while farming lumber
* NEW: 20 Shaman (Vamoose) quotes per lumber type - spiritual wisdom
* NEW: 10 Goblin (Gazlowe) quotes per lumber type - profit-focused humor
* NEW: 10 Squirrel quotes per lumber type - angry eviction protests
* NEW: Squirrel speaker with brown squirrel model, "[Squirrel]" in brown in chat
* NEW: Craft quotes when crafting decor - profession-specific with famous NPC speakers:
  - Marin Noggenfogger (Alchemy), Magni Bronzebeard (Blacksmithing), Nomi (Cooking)
  - Kalecgos (Enchanting), Trade Prince Gazlowe (Engineering), Lorewalker Cho (Inscription)
  - Haris Pilton (Jewelcrafting), Hemet Nesingwary (Leatherworking), First Arcanist Thalyssra (Tailoring)
* NEW: Expansion-specific quotes matching the recipe's expansion
* NEW: Chattiness slider in Config tab (1-99, higher = less frequent)
* NEW: Custom talking head frame with animated 3D models

BUG FIXES
=========
* FIXED: Collection status not updating after collecting items
  - Only cache positive results to avoid stale negatives when Blizzard API is slow
  - Note: If refresh button doesn't work, a /reload may be needed due to API delays
* FIXED: Quality variant material counting now includes all tiers (R1 + R2 + R3)
  - Materials like "Oil of Beledar's Grace" now count all quality variants in inventory
  - New GetItemCountWithVariants() function sums base item + all quality tiers

-------------------------------------------------------------------------------

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.3 (Released January 2026)
===============================================================================

MAJOR FEATURE: LOCALIZATION
===========================
* NEW: Full localization framework with 215+ translated UI strings
* NEW: 9 languages supported: Spanish, Portuguese, German, French, Italian,
       Russian, Korean, Simplified Chinese, Traditional Chinese
* NEW: Locale override dropdown in Config tab - choose your preferred language
* NOTE: Addon UI text is translated; item/recipe names come from WoW client

NEW FEATURES
============

Alts Tab - Skills/Recipes Toggle
--------------------------------
* NEW: Two-button toggle to switch between Skills and Recipes view modes
* NEW: Recipes mode shows known/total decor recipes per profession/expansion
* NEW: Account Summary aggregates best known count across ALL characters
* NEW: Color coding: Gray=none known, Yellow=partial, Teal=all known
* NEW: Uses stored knownRecipes data - open profession windows to scan

History Click-to-Preview
------------------------
* NEW: Click on crafted items in history navigates to Preview tab with 3D model
* NEW: Click on learned items (acquired decor) also works
* NEW: Hover shows teal highlight and "Click to preview" tooltip
* FIXED: 3D preview now works on first click after reload

Trainers Tab
------------
* NEW: Shows character name who knows most decor recipes in profession header

Compatibility
-------------
* FIXED: Square minimap compatibility (SexyMap, BasicMinimap, etc.)
* NEW: Addon Compartment support (Blizzard minimap drawer integration)

UI Improvements
---------------
* NEW: Crafting Queue shows item count in title "(N items)"
* FIXED: Goblin tab layout - price source text above scan button (was overlapping)
* FIXED: "Script ran too long" error when adding all 242 items from Preview tab

Code Quality
------------
* Deduplication Phase 1-5: Consolidated color constants, collection checks,
  filter button factory, character key, and materials processing functions
* Reduced ~200 lines of duplicated code across modules

---

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.1 (Released January 2026)
===============================================================================

NEW FEATURES
============

TSM Integration Enhancements
----------------------------
* NEW: Price addon toggle in Goblin tab - switch between TSM and Auctionator
* NEW: Region Avg column (TSM only) - shows regional average sale price
* NEW: TSM % column (TSM only) - margin calculated using Region Avg price

Goblin Tab Enhancements
-----------------------
* NEW: Search box - filter decor items by name in Goblin tab
* NEW: Lumber inventory count - shows available lumber next to lumber type name

Lumber Tracker Enhancements
---------------------------
* NEW: Focus mode - when farming starts, hides other lumber rows to focus on active item

Gathering Tracker
-----------------
* NEW: Trackable reagents - ctrl-click any material to add to tracking
* NEW: Remove from tracking - right-click tracked items to remove them
* NEW: Tracked reagents appear in pinned lumber widget alongside lumber

Help Button & How-to Guide
--------------------------
* NEW: Help button (?) in title bar next to refresh button
* NEW: Clicking help button opens Config tab with comprehensive How-to Guide
* NEW: How-to Guide covers all tabs with detailed feature explanations
* NEW: Guide includes keyboard shortcuts and interaction tips

BUG FIXES
=========

* FIXED: Footer text ("Vamoose says...") being overlapped by panels
* FIXED: Panel height calculation now properly accounts for banner and tab spacing

---

===============================================================================
Vamoose's Housing Decor Helper - Version 2.1.0 (Released January 2026)
===============================================================================

NEW FEATURES
============

Goblin Mode - Profit Analysis Tab
---------------------------------
* NEW: "Goblin" tab for profit analysis on all housing decor items
* NEW: Shows Sell Price, Material Cost, Profit, and Margin for every item
* NEW: Lumber Value Analysis - implied gold value per lumber when crafting
* NEW: Total Lumber Value column - per lumber value times lumber qty per craft
* NEW: Items color-coded by expansion for easy identification
* NEW: Sortable columns - click any header to sort ascending/descending
* NEW: Sort indicator via text color (white = active sort, gold = inactive)
* NEW: Profession and Expansion filter dropdowns
* NEW: "Hide unprofitable" checkbox to filter negative-margin items
* NEW: "Only known (this char)" checkbox to show only recipes you know
* NEW: Item count shows filtered/total (e.g., "125 / 243 items")
* NEW: Click row to expand material breakdown (Direct vs Raw costs)
* NEW: Ctrl-click to add item to crafting queue
* NEW: Shift-click to search AH for item (when AH is open)
* NEW: Auctionator "Scan AH" button integration with cooldown tracking
* NEW: TSM/Auctionator price source indicator

UI/UX Improvements
------------------
* NEW: Custom goblin tab button texture
* IMPROVED: Item cache auto-refresh in expansion panel (no more "Item #XXXXX")
* IMPROVED: Expansion panel shows both Direct Materials and Raw Materials totals

Data Updates
------------
* UPDATED: Database refresh with latest profession recipes

---

===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.9 (Released January 2026)
===============================================================================

DATA FIXES
==========

Raw Materials Quality Variant Deduplication
-------------------------------------------
* FIXED: TWW/DF quality variants (T1/T2/T3) no longer appear as separate items
* FIXED: Raw materials quantities now correctly sum across multiple craft paths
* NEW: Automatic deduplication by item name (groups quality tiers together)
* NEW: Consecutive ID detection for items with placeholder names (T1, T1+1, T1+2)
* NOTE: Quality variants are alternatives - only the base tier quantity is shown

Finishing Reagent Filtering
---------------------------
* ADDED: Lesser Illustrious Insight (191526) marked as "Ignore" in reagent database
* This DF finishing reagent/embellishment no longer appears in raw materials lists


---

===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.8 (Released January 2026)
===============================================================================

NEW FEATURES
============

Power Crafting (Raw Materials View)
-----------------------------------
* NEW: HDG_PowerCrafting.lua module for DAG-based recipe resolution
* NEW: "Direct | Raw" toggle in Required Materials header
* NEW: Raw mode expands crafted reagents to base materials (what you actually need)
* NEW: Dependency graph builder with circular dependency detection
* NEW: Topological sort for proper crafting order (leaf nodes first)
* Supports recursive resolution up to 10 levels deep

Midnight Expansion Support
--------------------------
* NEW: Added Midnight expansion to expansion data
* NEW: Added Thalassian Lumber (item 256963) for Midnight
* NEW: Lumber tracker now supports 12 lumber types (Classic through Midnight)

Auctionator Shopping List Quantities
-------------------------------------
* NEW: "Add All to Auctionator" button now includes quantities for each material
* NEW: Uses Auctionator API v1 ConvertToSearchString for proper quantity encoding
* NEW: Shopping list shows exact amounts needed (e.g., "Bismuth x15" instead of just "Bismuth")
* NEW: Graceful fallback to item names only if quantity API unavailable

IMPROVEMENTS
============

Code Cleanup
------------
* REMOVED: Legacy CRAFTED_RECIPES hardcoded table (~220 lines) from HDG_PowerCrafting.lua
* IMPROVED: HDG_ProfessionsDB is now the single source of truth for crafted reagent recipes

Dynamic Lumber Tracker Layout
-----------------------------
* IMPROVED: Lumber tracker heights now calculate dynamically based on lumber count
* IMPROVED: Adding new expansions/lumber types no longer requires manual height adjustments
* IMPROVED: Embedded and pinned lumber widgets both scale automatically
* IMPROVED: Smaller header font in embedded lumber panel for better fit

Crafting UI Enhancements
------------------------
* NEW: Craft confirmation dialog with quantity selector (+/- buttons)
* NEW: "Craft N" button updates dynamically as you adjust quantity
* NEW: "Max N" button to craft all queued items at once
* NEW: Craft button shows craftable count in shopping list
* NEW: Multi-craft support - profession window stays open for sequential crafts
* FIXED: Shopping list now properly decrements when crafting completes
* IMPROVED: Tooltip positioning (cursor at bottom-left, not obscuring content)

Release Pipeline Automation
---------------------------
* NEW: Wago.io automatic upload on release
* NEW: CurseForge description auto-update from Curseforge_Description.md
* NEW: Wago.io description auto-update from Curseforge_Description.md
* NEW: Separate workflow for manual description-only updates

---

===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.7 (Released January 2026)
===============================================================================

NEW FEATURES
============

Recipe Search Box
-----------------
* NEW: Search box in Recipes tab to filter recipes by name
* NEW: Real-time filtering as you type
* NEW: Clear button (X) to reset search
* NEW: Works with profession and "All | Ready" filters

Search Materials Toggle (+Mats)
-------------------------------
* NEW: "+Mats" checkbox to extend search to reagent names
* NEW: Search "bismuth" to find recipes using Bismuth
* NEW: Toggleable to avoid clutter in normal searches

Uncollected Only Toggle
-----------------------
* NEW: "Uncollected" checkbox in Recipes tab
* NEW: Hides recipes for decor you already own
* NEW: Persisted to SavedVariables across sessions

Collection Progress (Preview Tab)
---------------------------------
* NEW: Shows "X / Y (Z%)" collection progress in header
* NEW: Color-coded: Green (100%), Yellow (50%+), White (<50%)
* NEW: Updates dynamically with current filter results

Crafting Queue Grouped by Character
-----------------------------------
* NEW: Crafting queue items sorted by who can craft them
* NEW: Current character's craftable items appear first
* NEW: Section headers show "CharName - RealmName" for each crafter
* NEW: "(you)" indicator in gold next to current character's section
* NEW: "Not Known" section for recipes no alts can craft
* NEW: Profession icons (14x14) next to each item in queue

Decor Acquisition History
-------------------------
* NEW: Tracks when decor is learned (added to collection), not just crafted
* NEW: Source column shows "Crafted" (teal) or "Learned" (gold)
* NEW: Renamed section to "Decor Crafting / Acquisition History"
* NEW: CSV export includes Source column

Per-Character Profession Memory
-------------------------------
* NEW: Each character remembers their last selected profession tab
* NEW: Switching characters restores their profession selection
* NEW: No more resetting to "All" when logging between alts

Auto-Refresh Alts Tab
---------------------
* NEW: Alts tab refreshes when profession window opens
* NEW: 0.3s delay ensures profession data is loaded
* NEW: Keeps alt profession data current without manual refresh

UI IMPROVEMENTS
===============

* IMPROVED: Expansion background colors now consistent in All and Ready modes
* IMPROVED: Unknown recipe text lighter gray (#909090) for better readability
* IMPROVED: Tooltip async loading fixed - no more double-hover needed

DATA UPDATES
============

* ADDED: 50+ new reagent IDs for Dragonflight & TWW expansions
  - Ores: Bismuth, Aqirite, Ironclaw Ore, Draconium Ore
  - Hides: Carapace-Backed Hide, Sporecoated Hide, Stormcharged Leather, etc.
  - Gems: Queen's Ruby, Mystic Sapphire, Vibrant Emerald, Illimited Diamond, etc.
  - Inks: Shadow Ink, Apricate Ink, Blazing Ink, Flourishing Ink, etc.
  - Cloth: Weavercloth Bolt, Duskweave, Weavercloth
  - Alloys: Core Alloy, Charged Alloy, Primal Molten Alloy
  - Engineering: Handful of Bismuth Bolts, Whimsical Wiring, Gyrating Gear, etc.
  - Alchemy: Slumbering Soul Serum, Harmonious Horticulture, Oil of Beledar's Grace
* FIXED: Corrected item IDs for Dragonflight Inscription inks (Blazing, Flourishing, Serene)
* FIXED: Corrected Illimited Diamond item ID (192869)
* FIXED: Corrected Harmonious Horticulture item ID (212563)

CODE CLEANUP
============

* REMOVED: Compact mode dead code (lumber widget only has embedded/pinned modes)
* MOVED: Crafting history functions from HDG_ConfigTab to HDG_DataTab
* FIXED: Orphaned progress bar code removed

UPDATES
=======

* UPDATED: Discord invite link changed to https://discord.gg/RWZaxJaHFP


===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.6 (Released January 2026)
===============================================================================

BUG FIXES
=========

* FIXED: Lumber farming no longer starts when receiving lumber from mail or bank
  - Only tracks actual gathering/farming, not withdrawing stored lumber
  - Prevents false farming sessions when checking mailbox or bank
* FIXED: Alts tab now shows all expansion skill levels correctly
  - Fixed expansion names stored as API names (Outland, Northrend, Dragon Isles)
  - Now properly normalizes to display names (TBC, WotLK, Dragonflight, etc.)
  - Existing data automatically migrated on character login


===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.5 (Released January 2026)
===============================================================================

NEW FEATURES
============

Lumber Farming Session Tracker
------------------------------
* NEW: Active farming stats when collecting lumber - gold/yellow row highlight
* NEW: Shows "Collected this session" count with live updates
* NEW: Rate per hour calculation displayed in real-time
* NEW: Current zone tracking for each session
* NEW: 3-phase collection animation (white flash -> gold settle -> normal)
* NEW: "End Session" button for manual session termination
* NEW: Session summary printed to chat when ending

Farming History (Data Tab)
--------------------------
* NEW: Farming sessions saved to Data tab history
* NEW: Upsert pattern - updates existing session as you continue farming
* NEW: Columns: Date/Time, Lumber, Collected, Rate/hr, Duration, Zone, Character
* NEW: CSV export includes all farming session data
* NEW: Character-realm tracking for all farming sessions

Crafting History Price Tracking
-------------------------------
* NEW: Stores AH price at time of crafting (from TSM/Auctionator)
* NEW: Stores total material cost at time of crafting
* NEW: "Price" column shows item market value
* NEW: Hover tooltip shows: Item Value, Material Cost, Profit/Loss, Price Source
* NEW: Sortable by Price column
* NEW: CSV export includes ItemPrice, MaterialCost, PriceSource columns

Profession Window Integration
-----------------------------
* NEW: "Filter Decor" button in profession window - filters to House Decor recipes
* NEW: Teal-themed buttons matching addon style
* NEW: "/hdg decor" slash command for text-based decor filtering
* NEW: Config toggle to show/hide profession window buttons

UI IMPROVEMENTS
===============

* NEW: Custom title banner with Vamoose logo image
* IMPROVED: Data tab columns reorganized and spaced for readability
* IMPROVED: Farming history Character column at end with more width
* IMPROVED: Price tooltip title clarified as "AH Price at Time of Crafting"

BUG FIXES
=========

* FIXED: Alts tab expansion order fallback using correct display names
* FIXED: Shadowlands Alchemy threshold corrected (was 140, now 80)


===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.4 (Released January 2026)
===============================================================================

BUG FIXES
=========

* FIXED: Decor Preview column alignment - header icons now align with list icons
* FIXED: Lumber tracker materials panel crash when price addon name is nil
* FIXED: Pinned lumber widget now appears above main window close button (DIALOG strata)

UI IMPROVEMENTS
===============

* IMPROVED: Preview tab status columns moved closer to scrollbar for more name space
* IMPROVED: Column right margin reduced from 8px to 2px for tighter layout


===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.3 (Released January 2026)
===============================================================================

NEW FEATURES
============

Crafting History Enhancements
-----------------------------
* NEW: Clickable items in crafting history - click to preview in Decor Preview tab
* NEW: Sortable columns - click Time, Item, or Character headers to sort
* NEW: Sort direction indicator arrows (ascending/descending)
* NEW: Character-Realm display shows full realm name for all entries

BUG FIXES
=========

* FIXED: OpenRecipe now calls twice with 0.2s delay for reliable profession window opening
* FIXED: Crafting history now uses TRADE_SKILL_ITEM_CRAFTED_RESULT event for accurate tracking
* FIXED: Sort arrows now use TGA texture instead of unicode characters

CODE QUALITY
============

* NEW: PreviewByItemID function for cross-tab navigation from crafting history
* IMPROVED: Sort arrows rendered as flippable TGA texture (textures/sort-arrow.tga)
* IMPROVED: Crafting history module reference corrected (HDG_DecorPreview)


===============================================================================
Vamoose's Housing Decor Helper - Version 2.0.2 (Released January 2026)
===============================================================================

NEW FEATURES
============

Discord Button
--------------
* NEW: Discord button in title bar (blurple "D" button)
* NEW: Click to copy invite link to clipboard
* NEW: Hover tooltip shows Discord invite URL

Contributors Section
--------------------
* NEW: "Special Thanks" section at bottom of Config tab
* NEW: Credits: Abased, Rylls, Jonnyne, JodouKast

Footer Enhancement
------------------
* NEW: Random Orc quotes in footer (Shaman blue color)
* NEW: Quotes change on each /reload or login

BUG FIXES
=========

* FIXED: Visual corruption when minimizing from Trainers tab
* FIXED: Visual corruption when minimizing from Config tab
* FIXED: Crafting Queue clear button not responding to clicks
* FIXED: Crash on first load with old SavedVariables (crafting history)
* FIXED: Decor Preview row pooling causing overlapping/corrupted text

CODE QUALITY
============

* IMPROVED: Removed duplicate GetExpansionColor from TrainersTab
* IMPROVED: Removed duplicate TEXT_COLORS from UIHelpers
* IMPROVED: Centralized expansion color lookup (supports abbreviations)
* IMPROVED: Centralized tooltip anchor configuration (CONFIG.TOOLTIP_ANCHOR)
* IMPROVED: Row pooling lifecycle properly tracks all rows in activeRows
* IMPROVED: DB_VERSION incremented to force SavedVariables refresh


===============================================================================
Version 2.0.1 (Released January 2026)
===============================================================================

NEW FEATURES
============

Lumber Tracker Pinned Mode
--------------------------
* NEW: Pin button to keep compact lumber tracker open independently
* NEW: Custom pin icon shows active/inactive state
* NEW: Pinned tracker auto-shows on login
* NEW: Persists across sessions via SavedVariables

IMPROVEMENTS
============

Decor Preview Tab
-----------------
* IMPROVED: Full 3D rotation - drag vertically to tilt model up/down
* IMPROVED: Controls hint updated to show "Drag to rotate (H+V)"

Trainer Locations
-----------------
* IMPROVED: Cross-checked all coordinates against VamooseDB
* IMPROVED: Fixed 13+ incorrect trainer locations
* IMPROVED: Updated Dragonflight trainer coordinates (Valdrakken)
* IMPROVED: Updated TWW trainer coordinates (Dornogal)
* IMPROVED: "Both" faction now shows "A/H" instead of "B" for clarity

BUG FIXES
=========
* FIXED: Compact mode now works from any tab (not just Recipes)
* FIXED: Pin button tooltip updates dynamically on click


===============================================================================
Version 2.0.0 (Released January 2026)
===============================================================================

NEW FEATURES
============

Multi-Character Profession Tracking
-----------------------------------
* NEW: Alts Tab - View account-wide profession skills at a glance
* NEW: Account Summary grid showing best skill per profession/expansion
* NEW: Color-coded skill levels (White=no data, Yellow=below threshold, Teal=ready)
* NEW: "Known by: AltName" shown on recipe tooltips when alt can craft
* NEW: Alt recipe counts shown in grey for professions you don't have
* NEW: BfA expansion normalizes Kul Tiran (Alliance) / Zandalari (Horde)

Catalog Browser (Decor Preview Tab)
------------------------------------
* NEW: "Collection" toggle shows ALL housing decor from the game catalog
* NEW: Browse every decor item in the game, not just craftable recipes
* NEW: Uses Blizzard's C_HousingCatalog API for complete catalog data
* NEW: Filters out room structures (shows only placeable decor)
* NEW: Item counter shows total items in current filtered view
* NEW: Non-craftable items show icon/name from game API
* NEW: "Uncollected" toggle filters to items you don't own yet
* NEW: Segmented toggle button design matching tab styling

Tag Filter System (Decor Preview Tab)
-------------------------------------
* NEW: Two-row filter UI with category and tag buttons
* NEW: Filter categories: Sizes, Factions, Styles, Expansions, Other
* NEW: 64 unique tags extracted from game data
* NEW: Single-select filtering (one tag at a time)
* NEW: "Filter:" and "Tags:" labels for clarity
* NEW: `/hdg tags` command dumps all tags with counts

UI IMPROVEMENTS
===============

Profession Tab Badges
---------------------
* NEW: Dual badges showing recipes known (teal) + decor collected (gold)
* NEW: Header row with book/crate icons
* NEW: Professions you don't have show "--" for recipe count
* NEW: Detailed tooltip showing missing items list

Terminology Updates
-------------------
* RENAMED: "Shopping List" is now "Crafting Queue" throughout the addon
* RENAMED: "Materials Needed" is now "Required Materials" throughout the addon

Visual Polish
-------------
* IMPROVED: Minimalist scrollbars (slim thumb, no arrows, subtle teal)
* IMPROVED: Panel headers have lighter background than list body
* IMPROVED: Craftable button redesigned as segmented [All | Ready] toggle
* IMPROVED: Craftable button state now persists across reloads
* IMPROVED: Material percentage calculation is now quantity-weighted
* IMPROVED: Minimap icon positioned outside minimap border

Code Quality
------------
* IMPROVED: Data files renamed for consistency (HDG_DecorDB, HDG_ReagentsDB, HDG_TrainersDB)
* IMPROVED: Consolidated NormalizeExpansionName function
* IMPROVED: Profession threshold data in HDG_ProfessionThresholds.lua
* FIXED: 0% items no longer shown in What Can I Craft mode

PLANNED (Future Versions)
=========================

* Power Crafting - DAG-based recursive recipe resolution
* Project Manager - Named groups with gold budgeting
* Wowhead Links - Click to open item/recipe pages


===============================================================================
Version: 1.9.5 (Released January 2026)
===============================================================================

[Released on CurseForge]

NEW FEATURES
============

"What Can I Craft?" Mode
------------------------
* NEW: Toggle button to filter recipes by material availability
* NEW: Recipes organized into tiers based on material percentage:
  - Ready to Craft (100%) - Have all materials
  - Almost Ready (75-99%)
  - Halfway There (50-74%)
  - Need Materials (<50%)
* NEW: Shows material % for professions you don't have (grayed out)
* NEW: Shows all recipes for professions you have but haven't learned yet

Crafting History Log
--------------------
* NEW: Account-wide crafting history in Config tab
* NEW: Tracks what decor items you craft and when
* NEW: Stores up to 100 entries (newest first)
* NEW: Clear History button to reset

Estimated Material Costs
------------------------
* NEW: Materials panel shows estimated total cost
* NEW: Integrates with TSM and Auctionator for price data
* NEW: Shows "Have all materials!" when complete
* NEW: Per-material cost breakdown in tooltips

Profession Window Integration
-----------------------------
* NEW: "Decor Guide" button appears in Blizzard's profession UI
* NEW: Opens addon filtered to the current profession
* NEW: Only shows for professions with decor recipes

UI IMPROVEMENTS
===============

Tab Button Styling
------------------
* IMPROVED: Inactive tabs now have subtle teal tint (brand consistency)
* IMPROVED: Tab icons keep full color but reduced opacity when inactive
* IMPROVED: Hover state brightens tabs and icons
* IMPROVED: Teal border on all tabs (brighter when active)

Visual Consistency
------------------
* IMPROVED: Cool white (#e2e8f0) applied across all tabs
* IMPROVED: Recipe rows have expansion-based background colors
* IMPROVED: Fancy title bar with colored "Vamoose's" accent
* IMPROVED: Material categories renamed to "From Vendor", "From Gathering / AH"

Config Tab
----------
* IMPROVED: Added minimap button show/hide toggle
* IMPROVED: Removed icon picker (simplified)
* IMPROVED: Cleaner layout with crafting history section

Crafting Queue
--------------
* IMPROVED: Left-click decrements quantity by 1
* IMPROVED: Right-click removes entire stack
* IMPROVED: More intuitive for crafting items one at a time

BUG FIXES
=========

* FIXED: Title bar now dynamically pulls version from TOC metadata
* FIXED: Reagent database audited - TWW, DF, SL modified crafting slots fixed
* FIXED: Added missing reagents (Gilded Vial, Slumbering Soul Serum, etc.)

CODE IMPROVEMENTS
=================

* NEW: HDG_UIHelpers.lua module for centralized UI utilities
* NEW: Centralized TEXT_COLORS and CONFIG.PADDING/SIZES constants
* MOVED: validate.lua and deploy.sh to utilities/ directory
* REMOVED: Deprecated textures/README.md and QUICK_START.txt


===============================================================================
Previous Version: 1.9.4
===============================================================================

BUG FIXES
=========

Auction House Integration - Fixed
----------------------------------
* FIXED: Shift-click materials to search Auction House now works properly
* FIXED: Right-click to add materials to search list now functional
* NEW: Auctionator integration fully implemented with API v1
* NEW: TSM (TradeSkillMaster) integration added as fallback/alternative
* IMPROVED: Click instructions now shown in material tooltips

Auctionator Integration
------------------------
* Shift-click material → Search Auction House via Auctionator.API.v1.MultiSearch
* Right-click material → Add to Auctionator search list
* Automatic detection of Auctionator addon
* Graceful fallback if addon not installed

TSM Integration (NEW)
---------------------
* Shift-click material → Opens TSM and searches Auction House (if Auctionator not available)
* Right-click material → Add to TSM search list with needed quantity
* Ctrl-click material → Show TSM market price (DBMarket)
* Full TSM_API integration for price checking and shopping

UI IMPROVEMENTS
===============

Complete UI Styling Overhaul - Slate/Teal Theme
------------------------------------------------
* NEW: Modern flat design with unified "Slate/Teal" color scheme
* NEW: Dark teal accent color (#1d4e4f) for all buttons and active tabs
* NEW: Clean white text without shadows/outlines throughout interface
* IMPROVED: Progress bars now use consistent dark teal (#2C7A7B) with opacity variations
* IMPROVED: Removed all black background borders for cleaner look
* IMPROVED: Updated profession progress text to use clean white

Progress Bar Text Overlap - Fixed
----------------------------------
* FIXED: Progress bar text no longer overlaps with percentage
* FIXED: "Collected:" header position adjusted to fit properly
* FIXED: Progress bars moved further right to prevent overlap
* IMPROVED: Clean text layout across all progress indicators

Window Position Persistence
----------------------------
* IMPROVED: Window position now properly saves and restores between sessions
* FIXED: Position saved on window move/drag
* FIXED: Position restored on addon load

Technical Details
-----------------
* Major UI code refactoring for v1.9.5 preparation
* Improved frame creation and management
* Better separation of concerns between modules


===============================================================================
Version: 1.9.3
===============================================================================

* Initial release on CurseForge
* Support for all 9 professions with housing decor recipes
* Crafting queue functionality
* Material tracking with have/need counts
* Minimap button with customizable icon
* Trainer locations for all expansions
* 3D model preview for decor items
