# Changelog

## 0.9.3.1-alpha

### Added
- Central crew-presence cache (`modules/presence.lua`), independent from keystone data: known roster characters are observed through the local login, readable C_Club state, and received TOAST/LibKS messages. The account-wide cache distinguishes online/recent, previously seen, and never seen without persisting an unreliable offline claim.
- Existing key `lastSeen` observations migrate once into the presence cache, preserving known status after upgrading without requiring a SavedVariables reset.
- Dashboard activity recap with `This Week`, `30 Days`, and `This Season` views for Most Active players and leaderboard-eligible Top Climbers, sourced entirely from the normalized bot export.
- Dashboard community shortcut beside Discord, plus consistent copy popups with automatic text selection and a clear Ctrl+C instruction.
- Deterministic bundled TOAST font objects across Dashboard, Leaderboard, Trends, welcome, and key UI, preventing user font replacements from breaking spacing or overflowing controls.
- Trends fixed time viewports: `7D`, `4W`, `8W`, `16W`, and `ALL`, selectable by click or throttled mouse wheel. Presets that cannot crop the available crew history stay visible but disabled and are skipped during wheel navigation.

### Changed
- Dashboard Status Report and Your Progress now share one compact overview card with aligned identity, ranking, delta, and passive summary rows.
- The addon now consumes the normalized trends export through a dedicated compatibility layer, keeping generated data immutable and presentation logic separate.
- Leaderboard status dots, View Crew status, My Crew online highlighting, key-row live ordering, and the Dashboard online count now use the shared presence resolver. Keystone timestamps remain the source only for key freshness, age labels, and key diagnostics.
- Failed, unavailable, empty, or combat-blocked C_Club reads no longer replace the current session map with an offline result; Away and Busy club states count as live presence alongside Online.
- Trends now uses a higher window stratum than Dashboard and Leaderboard, so the focused analysis view always stays on top when windows overlap.
- Trends viewport presets count backward from the latest real crew observation while active forecasts may extend the domain to the right; `8W` is the default only when it is meaningfully smaller than `ALL`.
- Trends y-axis now uses only values visible inside the active time viewport. Selecting a character excludes other crew lines from the vertical domain while retaining every explicitly checked benchmark, forecast, and estimated range for comparison.
- Trends crew rendering now adapts PCHIP sampling density to visible pixel length, preventing WoW from dropping subpixel line fragments on short intervals such as a one-day +16 RIO change.

### Internal
- Trends viewport rendering clips crew, benchmark, forecast, range-band, marker, and hover geometry to the visible plot; viewport-edge y-values use the same PCHIP interpolation as the rendered crew curve.

## 0.9.3.0-alpha

### Added
- Local M+ score observation (`modules/scores.lua`): reads the logged-in character's current score (`C_ChallengeMode.GetOverallDungeonScore()`) and season (`C_MythicPlus.GetCurrentSeason()`) defensively — combat-gated, `pcall`'d, secret-value-checked before any comparison, NaN/negative rejected — and caches it account-wide in `TOAST_DB.scoreObservations`, so a score seen on one character stays visible after relogging to another. The cache never regresses within a known season and replaces unconditionally on a season change.
- Central character-score resolver, `TOAST.ResolveCharacterScore(name, realm)`: picks the single best-known score for any character from four sources — local observation, `members.lua`, `leaderboard.lua`, `trends.lua` — with deterministic precedence (a current-season self-observation is authoritative when at least as new as the rest; otherwise newest date, then highest score, then self > members > leaderboard > trends on ties). Pure — never reads the WoW API or writes SavedVariables.
- `TOAST.GetResolvedLeaderboardSnapshot()`: the locally best-known leaderboard ordering, re-sorted by resolved score instead of the bot-generated `entry.rank`/`entry.rio`, with lazy session-only lookup indexes.
- Trends, Status Report, My Crew, View Crew, Your Progress, and the visible Leaderboard all now display the resolver's score instead of reading `entry.rio`/generated data directly, so a score change (locally observed or from a fresher bot export) shows consistently everywhere. Your Progress and the Leaderboard reorder immediately when a resolved score overtakes a neighbour, instead of waiting on the next bot export.
- Resilient-key badge in "Current SEAMEN Keys": shows the leaderboard Resi column's wordmark whenever a character's current broadcast key is at or below their resilience floor (`members.lua`'s `resi` field), in a fixed dedicated column so it never shifts with dungeon-label length.

### Changed
- Trends crew lines: switched from Catmull-Rom to shape-preserving PCHIP (Fritsch-Carlson) Hermite interpolation in real data-space (calendar days × RIO score), removing the overshoot/dip/reversal artifacts the old curve could show on near-flat score changes, and no longer breaking on a missing weekly value.
- Trends: forecast range-band alpha raised, with a screen-space visibility floor for very thin band strips; historical benchmark points now have hover targets sharing one tooltip with forecast points (Actual vs Projected).
- Your Progress (Dashboard): Next/Behind rows now share one vertical centerline per row instead of top-aligning a 20px icon to text, and prefix icon/label/name spacing follows the addon-wide identity convention instead of fixed columns.
- Trends button (Dashboard) icon is desaturated and tinted muted gold instead of untinted, since it's navigation, not a live-status indicator.
- Dashboard footer's static member count is now muted neutral text instead of teal; crew-online and keys-spotted counts stay teal since those are actual live status.
- Leaderboard alternating-row background changed from a blue tint to a neutral low-alpha white overlay.

### Internal
- Leaderboard rows now carry permanent per-row state (`r.entry`, `r.rankFS`, `r.rioFS`, `r.isEven`, `r.restBg`) instead of assuming `rows[i] == TOAST.leaderboard[i]`; `ApplyFilters`/`RefreshKeyColumn`/`RefreshStatusDots` all switched to `r.entry`. Zebra striping is re-derived from each row's actual visible (filtered) position, not just the unfiltered resolved order.
- `ShowLeaderboard()` is now the only path that builds the Leaderboard frame, sequenced `RefreshOwnScore` → build (if needed) → refresh resolved rows → show; `/lb` no longer builds the frame independently.
- Trends' character-line click hit-test extracted into a shared helper so historical benchmark hover targets can delegate through it.

## 0.9.2.6-alpha

### Added
- Trends: the four benchmark toggles (previously visual-only placeholders) now render real data. Checking one shows its historical series from `data/benchmarks.lua` as a solid, straight-segment line (no smoothing, no daily point markers — these are measurements) on a true calendar-date x-axis shared with crew snapshots, instead of the old evenly-spaced week index.
- Trends: a checked benchmark with a ready forecast (`data/forecasts.lua`) extends the date domain through its forecast horizon and continues past the historical line as a dashed projection (same color, no point markers), anchored from the latest actual observation through each daily projected value. Unchecking the last visible forecast contracts the domain back.
- Trends: one shared "FORECAST" boundary marker (muted gold, low alpha) at the actual/forecast transition date, and invisible hover targets on forecast points with a dedicated tooltip (benchmark, date, projected value, and an "Estimated range: low - high" line when the forecast point has valid bounds).
- Trends: checking a benchmark with a ready forecast shows a subtle "Estimated range" band for the last-checked (or currently hovered) benchmark — only ever one band at a time, even with several forecasts checked; hovering another checked+ready toggle previews its band without disturbing the persistent selection or moving the y-axis.
- Trends: "LB AVG" toggle now shows the SMN Discord-prefix icon + "AVG" instead of literal text, using the addon's standard prefix-icon spacing (20x20, 0px icon-to-label gap).

### Changed
- Trends: benchmark/forecast colors centralized in one muted gold-neutral palette (`BENCHMARK_COLORS`), tunable in one place; checkbox fill/border/checkmark use each benchmark's own color when checked, label text stays neutral.
- Trends: y-axis domain now also folds in every checked+available benchmark's visible values (historical and forecast, including valid low/high), so it never jumps just from hovering or refocusing which benchmark's range band is shown.

### Internal
- Trends: all x-axis positioning (crew, benchmark, forecast) now goes through pure calendar-date arithmetic (Howard Hinnant days-from-civil, no `os.date`/locale dependency) instead of index-based spacing.
- Trends: benchmark lines, forecast lines, forecast hover targets, the range band, and the boundary marker each use their own pooled region set, reused/hidden across refreshes like the existing crew-series pools — nothing is recreated or leaked on repeated toggling.
- Trends: toggle checked state and the persistent/hovered range-band focus are in-memory only, never written to SavedVariables.

## 0.9.2.5-alpha

### Added
- New TOAST Trends window (`modules/trends_view.lua`): smoothed per-character RIO progression chart (Catmull-Rom interpolated curve, breaking across any missing tracked week instead of interpolating over the gap) with a compact legend that grows from 2 to 5 visible rows before scrolling.
- Trends: click a legend row or click directly on a graph line (distance-to-segment hit-testing against the actual rendered curve, not just the raw data points) to persistently select a character — dims every other series' line and points. Clicking the same selection again, or clicking empty plot space, clears it back to the default view where every character is shown equally (no character is focused automatically).
- Trends: custom hover tooltip (never `GameTooltip`) on each data point showing character, week, RIO, and weekly gain.
- Trends: legend header benchmark toolbar — LB AVG, KEY ENJOYER, 1% CUTOFF, 0.1% CUTOFF — a horizontally centered row of independently clickable gold checkboxes. Currently visual-only placeholders for planned future benchmark lines (leaderboard average, the "Key Enjoyer" Top 10 RIO threshold, Raider.IO EU seasonal title cutoffs); toggling them doesn't affect the graph yet.
- Dashboard's Trends icon and the Trends window's own DASHBOARD/LEADERBOARD header buttons cross-navigate the same way the dashboard and leaderboard windows already do each other (left-click switches, right-click opens alongside).

### Changed
- "Data updated" timestamp shown in Trends now reflects Amsterdam local time (CET/CEST, DST-aware) instead of raw UTC — generated by the bot, not the addon.

### Internal
- Trends window height is fully derived: plot height, legend row count, and header height all flow through one `CalculateFrameHeight()` formula, so the window is only ever as tall as its actual content needs, never a fixed size that leaves dead space for a small crew.

## 0.9.2.4-alpha

### Added
- Guild-wide key discovery (whispers on login + periodic refresh) now reaches alts of leaderboard players too, not just their main character, via a new `GetLeaderboardTargets()` that matches on shared Discord ID (comms.lua).
- Dashboard "Current SEAMEN Keys" card now also surfaces keys from leaderboard players' alts, deduplicated per Discord ID (keeps whichever character was seen most recently).
- Alt-aware online status: if a player's own listed character isn't online but one of their alts is, the leaderboard status dot, "View Crew" popup, and "My Crew" card all reflect that, via a new `TOAST.RefreshOnlineStatus()` / `TOAST._onlineCharByDiscordId` mapping.
- Right-click "Invite" on a leaderboard row now invites whichever character is actually online, if that's an alt rather than the listed character.
- "View Crew" popup: the online character in the group is now highlighted (gold row tint + left accent bar), and a status dot next to the Discord name shows whether anyone in the group is currently online.
- Leaderboard: dedicated fixed-width status-marker column between the rank number and the Discord identity group, so the online/known dot no longer shifts the prefix icon and always reserves its own space, shown or not.

### Changed
- Unified "prefix icon → prefix label → Discord name" spacing (0px, then 4px, relatively anchored) across the leaderboard, dashboard Status Report card, My Crew, View Crew popup, and Current Keys card — previously each used different fixed-column offsets that drifted depending on prefix label width.
- Unified character-realm display everywhere: class-colored name followed by "-Realm" in #CCCCCC, as a single string, matching the leaderboard's existing format. Previously View Crew and My Crew used a separate white-at-50%-alpha realm column, and the Status Report tile colored the whole "-Realm" suffix in the class color instead of just the name.
- Unified role icon (20px) and prefix icon (20px) sizes across the leaderboard rows, dashboard Status Report, My Crew, View Crew popup, and Current Keys card.
- `DUNGEON_SHORT` dungeon-name abbreviation table centralized as `TOAST.DUNGEON_SHORT` in core.lua instead of being duplicated in comms.lua and keys.lua.
- LibKS key updates now always overwrite the stored key instead of only storing it the first time, so key changes broadcast via LibKS are actually picked up.

### Internal
- `RecognizePlayer()` and `GetLeaderboardTargets()` in comms.lua now use a cached name→member lookup instead of scanning `TOAST.members` on every call.
- Leaderboard's `RefreshStatusDots()` now looks up each row's leaderboard entry by index (`r.index`) instead of a linear per-row name search across the whole leaderboard.
- Deduplicated the identical `ITEM_CHANGED`/`ITEM_PUSH` keystone-change handling in comms.lua into a single `CheckKeyUpdate()` helper.

## 0.9.2.3-alpha

### Added
- Leaderboard: clickable column-header filters for Role (HEAL/TANK/DPS), Discord prefix (cycles TIDE/SMN/CPT), and Key level minimum (cycles 15+/18+/20+/22+), combined with the existing search box via AND logic.
- Leaderboard: "Reset" affordance next to the search box, shown only while a column filter is active, clears all column filters and the search text in one click.
- Leaderboard: gold underline marks the active/hovered filter on each header (Role icons, Discord prefix, Key), sized to the actual icon/label content rather than spanning the full column.
- Dashboard and leaderboard windows now remember their position across `/reload` (saved to `TOAST_DB.windowPos`) instead of always reopening centered.
- Right-click on the DASHBOARD/LEADERBOARD header buttons opens the other window without closing the current one, so both can be open side by side.

### Changed
- Leaderboard: Role column header icons enlarged (14px → 20px) and repositioned to align with the row role icons directly below them; unselected role icons dim only once a role filter is active, otherwise all three read normally.
- Leaderboard: RIO column recentered to sit at the exact horizontal midpoint between the Role icon group and the Resi column, and switched from right- to center-aligned to match its header.
- Dashboard header rebuilt to match the leaderboard's structure: banner/logo/title now live on a dedicated draggable header child frame (dragging is scoped to the header band, not the whole window), with the same elevated-frame fix for the gold top accent so the banner texture can't draw over it.
- Dashboard's top accent line and header medallion size now match the leaderboard's (2px / 32px) instead of being slightly thinner/smaller.
- The LEADERBOARD button moved from inside the "Your Progress" card to the header (top-right), mirroring the leaderboard's DASHBOARD button placement; both cross-navigation buttons are now the same width (90px) and use matching all-caps labels.
- "My Crew" card row context menu trimmed to just Copy Name (Invite/Whisper removed); the separate "View Crew" popup menu is unaffected.
- "View Crew" popup: Discord rank now sits on the same row as the Discord name, right-aligned, instead of on its own line below; popup header height shrunk to match.

### Fixed
- Leaderboard: clicking an already-active role filter a second time failed to clear it, caused by the classic Lua `cond and nil or x` idiom collapsing back to `x` whenever the "true" branch evaluates to `nil`; replaced with an explicit if/else.

## 0.9.2.2-alpha

### Changed
- Dashboard "Your Status" card redesigned into a compact "Status Report" Player Card: title row, "Ahoy!" greeting with Discord prefix/name, character-realm line, and an at-a-glance chip row (rank, RIO, resi, key).
- Removed the developer-style status badges (Recognized / In TIDE and Crew / Key shared, key-sharing ON/OFF, last-broadcast line) from the main card view.
- Technical diagnostics (recognized/community/leaderboard/roster status, key-sharing state, last broadcast, detected key, addon version) are now available via a subtle "?" hover tooltip in the card's top-right corner instead of cluttering the main view.
- Player Card now has the same gold top accent and title styling as the dashboard's other cards.

### Fixed
- Dashboard and welcome-screen header banner occasionally failing to load: replaced the uncompressed `tentakel_2.tga` asset with a losslessly re-encoded PNG (2.0MB → 957KB), matching the format already used reliably by the leaderboard banner.

### Internal
- Split `BuildDashboard()` in `dashboard.lua` into per-card builder functions (`BuildCardA`, `BuildMyCrewCard`, `BuildCardB`, `BuildCardC`, `BuildFooter`) to fix a Lua 5.1 60-upvalue-per-function limit that was breaking the addon on load.
