local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

local RequireApi = INTERNAL_API.LIDCOUNCIL_RequireApi_Impl
local ResolveOptionalApiFunction = INTERNAL_API.LIDCOUNCIL_ResolveOptionalApiFunction_Impl
local BindMouseWheelScroll = INTERNAL_API.LIDCOUNCIL_BindMouseWheelScroll_Impl
local CreateAboutFAQSection = INTERNAL_API.LIDCOUNCIL_CreateAboutFAQSection_Impl
local CreateAboutUtilitySections = INTERNAL_API.LIDCOUNCIL_CreateAboutUtilitySections_Impl
if type(RequireApi) ~= "function"
  or type(ResolveOptionalApiFunction) ~= "function"
  or type(BindMouseWheelScroll) ~= "function"
  or type(CreateAboutFAQSection) ~= "function"
  or type(CreateAboutUtilitySections) ~= "function" then
  error("LidCouncil missing about page helpers.")
end

local Print = RequireApi("LIDCOUNCIL_Print", _G.LIDCOUNCIL_Print)
local ApplyFrameSkin = RequireApi("LIDCOUNCIL_ApplyFrameSkin", _G.LIDCOUNCIL_ApplyFrameSkin)
local MakeYellowSubHeader = RequireApi("LIDCOUNCIL_MakeYellowSubHeader", _G.LIDCOUNCIL_MakeYellowSubHeader)
local ShowErrorLogWindow = RequireApi("LIDCOUNCIL_ShowErrorLogWindow", _G.LIDCOUNCIL_ShowErrorLogWindow)
local ShowSilentLogWindow = RequireApi("LIDCOUNCIL_ShowSilentLogWindow", _G.LIDCOUNCIL_ShowSilentLogWindow)
local RootDB = RequireApi("LIDCOUNCIL_RootDB", _G.LIDCOUNCIL_RootDB)
local CreateLootProfile = RequireApi("LIDCOUNCIL_CreateLootProfile", _G.LIDCOUNCIL_CreateLootProfile)
local DeleteLootProfile = RequireApi("LIDCOUNCIL_DeleteLootProfile", _G.LIDCOUNCIL_DeleteLootProfile)
local GetLootProfileAccessInfo = RequireApi("LIDCOUNCIL_GetLootProfileAccessInfo", _G.LIDCOUNCIL_GetLootProfileAccessInfo)
local RepairSimulationProfileOwnership = RequireApi("LIDCOUNCIL_RepairSimulationProfileOwnership")
local SetLootProfileEnabled = RequireApi("LIDCOUNCIL_SetLootProfileEnabled", _G.LIDCOUNCIL_SetLootProfileEnabled)
local GetActiveLootSession = RequireApi("LIDCOUNCIL_GetActiveLootSession", _G.LIDCOUNCIL_GetActiveLootSession)
local GetLiveLootRuntimeDiagnostics = ResolveOptionalApiFunction("LIDCOUNCIL_GetLiveLootRuntimeDiagnostics")
local GetEditorThemePalette = type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function" and INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl or nil

local function GetAboutTitleColor()
  local palette = GetEditorThemePalette and GetEditorThemePalette() or nil
  local color = type(palette) == "table" and palette.aboutTitle or nil
  if type(color) ~= "table" then
    color = { 0.6588, 0.4784, 0.9098, 1.0 }
  end
  return color[1] or 0.6588, color[2] or 0.4784, color[3] or 0.9098, color[4] or 1.0
end

local function SafeHookScript(frame, scriptName, handler)
  if frame and type(frame.HookScript) == "function" and type(handler) == "function" then
    pcall(frame.HookScript, frame, scriptName, handler)
  end
end

local function BuildAboutPage(editor, aboutPage)
  if not editor or not aboutPage then return end

  local function StyleAboutTitle(fs)
    if not fs then return end
    local r, g, b, a = GetAboutTitleColor()
    fs:SetTextColor(r, g, b, a)
  end

  local function MakeAboutTitle(parent, text, x, y)
    local title = MakeYellowSubHeader(parent, text, x or 0, y or 0)
    StyleAboutTitle(title)
    return title
  end

  local aboutNavBg = CreateFrame("Frame", nil, aboutPage, "BackdropTemplate")
  aboutNavBg:SetPoint("TOPLEFT", 0, -44)
  aboutNavBg:SetPoint("BOTTOMLEFT", 0, 0)
  aboutNavBg:SetWidth(240)
  ApplyFrameSkin(aboutNavBg)
  editor.aboutNavBg = aboutNavBg

  local aboutRightBg = CreateFrame("Frame", nil, aboutPage, "BackdropTemplate")
  aboutRightBg:SetPoint("TOPLEFT", aboutNavBg, "TOPRIGHT", 12, 0)
  aboutRightBg:SetPoint("BOTTOMRIGHT", 0, 0)
  ApplyFrameSkin(aboutRightBg)
  aboutRightBg:SetClipsChildren(true)
  editor.aboutRightBg = aboutRightBg

  local aboutScroll = CreateFrame("ScrollFrame", nil, aboutRightBg, "UIPanelScrollFrameTemplate")
  aboutScroll:SetPoint("TOPLEFT", 18, -12)
  aboutScroll:SetPoint("BOTTOMRIGHT", -28, 12)
  BindMouseWheelScroll(aboutScroll)
  editor.aboutScroll = aboutScroll

  local aboutNavLoadedBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavLoadedBtn:SetSize(200, 20)
  aboutNavLoadedBtn:SetPoint("TOPLEFT", 6, -18)
  aboutNavLoadedBtn:SetText("Loaded Components")
  editor.aboutNavLoadedBtn = aboutNavLoadedBtn

  local aboutNavErrorsBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavErrorsBtn:SetSize(200, 20)
  aboutNavErrorsBtn:SetPoint("TOPLEFT", 6, -44)
  aboutNavErrorsBtn:SetText("Errors")
  editor.aboutNavErrorsBtn = aboutNavErrorsBtn

  local aboutNavSilentBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavSilentBtn:SetSize(200, 20)
  aboutNavSilentBtn:SetPoint("TOPLEFT", 6, -70)
  aboutNavSilentBtn:SetText("Silent Errors")
  editor.aboutNavSilentBtn = aboutNavSilentBtn

  local aboutNavUpdatesBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavUpdatesBtn:SetSize(200, 20)
  aboutNavUpdatesBtn:SetPoint("TOPLEFT", 6, -96)
  aboutNavUpdatesBtn:SetText("Changelog")
  editor.aboutNavUpdatesBtn = aboutNavUpdatesBtn

  local aboutNavFaqBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavFaqBtn:SetSize(200, 20)
  aboutNavFaqBtn:SetPoint("TOPLEFT", 6, -122)
  aboutNavFaqBtn:SetText("FAQ")
  editor.aboutNavFaqBtn = aboutNavFaqBtn

  local aboutNavCreditsBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavCreditsBtn:SetSize(200, 20)
  aboutNavCreditsBtn:SetPoint("TOPLEFT", 6, -148)
  aboutNavCreditsBtn:SetText("Credits")
  editor.aboutNavCreditsBtn = aboutNavCreditsBtn

  local aboutNavStressBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavStressBtn:SetSize(200, 20)
  aboutNavStressBtn:SetPoint("TOPLEFT", 6, -174)
  aboutNavStressBtn:SetText("Stresstest")
  editor.aboutNavStressBtn = aboutNavStressBtn

  local aboutNavTutorialImagesBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavTutorialImagesBtn:SetSize(200, 20)
  aboutNavTutorialImagesBtn:SetPoint("TOPLEFT", 6, -200)
  aboutNavTutorialImagesBtn:SetText("Disable Tutorial Images")
  editor.aboutNavTutorialImagesBtn = aboutNavTutorialImagesBtn

  local aboutNavDeveloperBtn = CreateFrame("Button", nil, aboutNavBg, "UIPanelButtonTemplate")
  aboutNavDeveloperBtn:SetSize(200, 20)
  aboutNavDeveloperBtn:SetPoint("TOPLEFT", 6, -226)
  aboutNavDeveloperBtn:SetText("Developer Mode")
  editor.aboutNavDeveloperBtn = aboutNavDeveloperBtn

  local aboutContent = CreateFrame("Frame", nil, aboutScroll)
  aboutContent:SetSize(1, 1)
  aboutScroll:SetScrollChild(aboutContent)
  editor.aboutContent = aboutContent

  local function SetAboutContentHeight(h)
    if not aboutContent then return end
    local minH = (aboutScroll and aboutScroll.GetHeight and aboutScroll:GetHeight()) or 1
    if type(h) ~= "number" then h = minH end
    if h < minH then h = minH end
    aboutContent:SetHeight(h)
    if aboutScroll and aboutScroll.UpdateScrollChildRect then aboutScroll:UpdateScrollChildRect() end
  end
  editor.SetAboutContentHeight = SetAboutContentHeight

  aboutScroll:SetScript("OnSizeChanged", function(self)
    local w = self:GetWidth() - 28
    if w < 1 then w = 1 end
    aboutContent:SetWidth(w)
    if editor and editor.UpdateAboutOverviewLayout then editor:UpdateAboutOverviewLayout() end
    if editor and editor.UpdateAboutUpdatesLayout then editor:UpdateAboutUpdatesLayout() end
    if editor and editor.UpdateAboutFAQLayout then editor:UpdateAboutFAQLayout() end
    if editor and editor.UpdateAboutCreditsLayout then editor:UpdateAboutCreditsLayout() end
    if editor and editor.UpdateAboutStressLayout then editor:UpdateAboutStressLayout() end
    if editor and editor.UpdateAboutTutorialImagesLayout then editor:UpdateAboutTutorialImagesLayout() end
    if editor and editor.UpdateAboutDeveloperLayout then editor:UpdateAboutDeveloperLayout() end
    if self.UpdateScrollChildRect then self:UpdateScrollChildRect() end
  end)

  local aboutOverview = CreateFrame("Frame", nil, aboutContent)
  aboutOverview:SetPoint("TOPLEFT", 0, 0)
  aboutOverview:SetPoint("BOTTOMRIGHT", 0, 0)
  editor.aboutOverview = aboutOverview

  local aboutMeta = aboutOverview:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutMeta:SetPoint("TOPLEFT", 0, 0)
  aboutMeta:SetWidth(520)
  aboutMeta:SetJustifyH("LEFT")
  aboutMeta:SetText("")
  editor.aboutMeta = aboutMeta

  local aboutDesc = aboutOverview:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutDesc:SetPoint("TOPLEFT", 0, -60)
  aboutDesc:SetWidth(560)
  aboutDesc:SetJustifyH("LEFT")
  aboutDesc:SetText("")
  editor.aboutDesc = aboutDesc

  local aboutUpdateNewsBtn = CreateFrame("Button", nil, aboutOverview, "UIPanelButtonTemplate")
  aboutUpdateNewsBtn:SetSize(170, 22)
  aboutUpdateNewsBtn:SetPoint("TOPLEFT", aboutDesc, "BOTTOMLEFT", 0, -12)
  aboutUpdateNewsBtn:SetText("Show Update News")
  aboutUpdateNewsBtn:SetScript("OnClick", function()
    local showFn = ResolveOptionalApiFunction("LIDCOUNCIL_ShowUpdateNews")
    if showFn then
      showFn()
    elseif Print then
      Print("Update News is currently unavailable.")
    end
  end)
  editor.aboutUpdateNewsBtn = aboutUpdateNewsBtn

  local aboutLogo = aboutOverview:CreateTexture(nil, "ARTWORK")
  aboutLogo:SetSize(140, 140)
  aboutLogo:SetPoint("TOPRIGHT", -8, -8)
  aboutLogo:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\About_Lid.tga")
  editor.aboutLogo = aboutLogo

  local function UpdateAboutOverviewLayout()
    if not aboutContent or not aboutMeta or not aboutDesc then return end
    if editor and editor.aboutSection and editor.aboutSection ~= "Overview" then return end
    local contentW = aboutContent:GetWidth() or 0
    local logoW = 140
    local pad = 20
    local textW = contentW - logoW - pad
    if textW < 200 then textW = 200 end
    aboutMeta:SetWidth(textW)
    aboutDesc:SetWidth(textW)
    local metaH = aboutMeta.GetStringHeight and aboutMeta:GetStringHeight() or 0
    local descH = aboutDesc.GetStringHeight and aboutDesc:GetStringHeight() or 0
    local buttonH = 0
    if aboutUpdateNewsBtn and aboutUpdateNewsBtn:IsShown() then
      buttonH = (aboutUpdateNewsBtn:GetHeight() or 0) + 18
    end
    local totalH = 60 + descH + buttonH + 40
    if metaH > 0 then
      totalH = metaH + 20 + descH + buttonH + 40
    end
    if editor and editor.SetAboutContentHeight then
      editor:SetAboutContentHeight(math.max(520, math.floor(totalH)))
    end
  end
  editor.UpdateAboutOverviewLayout = UpdateAboutOverviewLayout
  SafeHookScript(aboutContent, "OnSizeChanged", UpdateAboutOverviewLayout)
  UpdateAboutOverviewLayout()
  SafeHookScript(aboutOverview, "OnShow", UpdateAboutOverviewLayout)

  local aboutLoaded = CreateFrame("Frame", nil, aboutContent)
  aboutLoaded:SetAllPoints(aboutContent)
  aboutLoaded:Hide()
  editor.aboutLoaded = aboutLoaded

  local infoLabel = MakeAboutTitle(aboutLoaded, "Loaded Components", 0, 0)

  local aboutDetails = aboutLoaded:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutDetails:SetPoint("TOPLEFT", infoLabel, "BOTTOMLEFT", 0, -6)
  aboutDetails:SetWidth(560)
  aboutDetails:SetJustifyH("LEFT")
  aboutDetails:SetText("")
  editor.aboutDetails = aboutDetails

  local aboutErrorsFrame = CreateFrame("Frame", nil, aboutContent)
  aboutErrorsFrame:SetAllPoints(aboutContent)
  aboutErrorsFrame:Hide()
  editor.aboutErrorsFrame = aboutErrorsFrame

  local errLabel = MakeAboutTitle(aboutErrorsFrame, "Errors", 0, 0)

  local statusIcon = aboutErrorsFrame:CreateTexture(nil, "ARTWORK")
  statusIcon:SetSize(18, 18)
  statusIcon:SetPoint("TOPLEFT", errLabel, "BOTTOMLEFT", 0, -10)
  editor.aboutStatusIcon = statusIcon

  local statusText = aboutErrorsFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  statusText:SetPoint("LEFT", statusIcon, "RIGHT", 6, 0)
  statusText:SetText("")
  editor.aboutStatusText = statusText

  local aboutErrors = aboutErrorsFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutErrors:SetPoint("TOPLEFT", statusIcon, "BOTTOMLEFT", 0, -10)
  aboutErrors:SetWidth(560)
  aboutErrors:SetJustifyH("LEFT")
  aboutErrors:SetText("")
  editor.aboutErrors = aboutErrors

  local errorLogBtn = CreateFrame("Button", nil, aboutErrorsFrame, "UIPanelButtonTemplate")
  errorLogBtn:SetSize(120, 20)
  errorLogBtn:SetPoint("TOPLEFT", aboutErrors, "BOTTOMLEFT", 0, -8)
  errorLogBtn:SetText("ErrorLog")
  errorLogBtn:SetScript("OnClick", function()
    ShowErrorLogWindow()
  end)
  editor.errorLogBtn = errorLogBtn

  local aboutSilentFrame = CreateFrame("Frame", nil, aboutContent)
  aboutSilentFrame:SetAllPoints(aboutContent)
  aboutSilentFrame:Hide()
  editor.aboutSilentFrame = aboutSilentFrame

  local silentLabel = MakeAboutTitle(aboutSilentFrame, "Silent Errors", 0, 0)

  local aboutSilent = aboutSilentFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutSilent:SetPoint("TOPLEFT", silentLabel, "BOTTOMLEFT", 0, -4)
  aboutSilent:SetWidth(560)
  aboutSilent:SetJustifyH("LEFT")
  aboutSilent:SetText("")
  editor.aboutSilent = aboutSilent

  local silentLogBtn = CreateFrame("Button", nil, aboutSilentFrame, "UIPanelButtonTemplate")
  silentLogBtn:SetSize(140, 20)
  silentLogBtn:SetPoint("TOPLEFT", aboutSilent, "BOTTOMLEFT", 0, -8)
  silentLogBtn:SetText("SilentErrorLog")
  silentLogBtn:SetScript("OnClick", function()
    ShowSilentLogWindow()
  end)
  editor.silentLogBtn = silentLogBtn

  local aboutUpdatesFrame = CreateFrame("Frame", nil, aboutContent)
  aboutUpdatesFrame:SetAllPoints(aboutContent)
  aboutUpdatesFrame:Hide()
  editor.aboutUpdatesFrame = aboutUpdatesFrame

  local updatesHeader = MakeAboutTitle(aboutUpdatesFrame, "Changelog", 0, 0)

  local aboutUpdates = aboutUpdatesFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  aboutUpdates:SetPoint("TOPLEFT", updatesHeader, "BOTTOMLEFT", 0, -4)
  aboutUpdates:SetWidth(560)
  aboutUpdates:SetJustifyH("LEFT")
  aboutUpdates:SetText("")
  aboutUpdates:Hide()
  editor.aboutUpdates = aboutUpdates

  local updatesContainer = CreateFrame("Frame", nil, aboutUpdatesFrame)
  updatesContainer:SetPoint("TOPLEFT", updatesHeader, "BOTTOMLEFT", 0, -8)
  updatesContainer:SetPoint("TOPRIGHT", aboutUpdatesFrame, "TOPRIGHT", -10, -8)
  updatesContainer:SetHeight(10)
  editor.aboutUpdatesContainer = updatesContainer

  local CHANGELOG_ENTRIES = {
    {
      version = "Version 0.9.2 [ALPHA]",
      sections = {
        { title = "Sync Optimizations", bullets = {
            "Added queued profile and member sync traffic to reduce addon-message bursts in larger raid groups",
            "Added smaller profile delta updates for supported profile-setting and permission changes",
            "Added per-domain checksums for Settings, Permissions, and Loot / Session Data sync comparison",
            "Added profile-delta acknowledgement and recovery handling so missed or mismatched updates request a full host refresh",
        } },
        { title = "Workflow Finalizing", bullets = {
            "Refined Prepare Session and Start Session into the intended host-authoritative raid workflow",
            "Improved live-sync coverage for Loot List edits, member updates, role changes, and profile changes during sessions",
            "Improved recovery options for stale joined members, late joiners, and shared profile refreshes",
        } },
        { title = "Alpha Test Preparation", bullets = {
            "Updated tutorial and sync workflow documentation to match the current behavior",
            "Polished button styling, backup controls, and Sync List presentation for clearer testing feedback",
            "Prepared version 0.9 as the next alpha candidate for real raid-scale validation",
        } },
      },
    },
    {
      version = "Version 0.8 [ALPHA]",
      sections = {
        { title = "Alpha Hardening", bullets = {
            "Stabilized the loot-profile, session, and runtime flow for broader real-group testing",
            "Polished the major LidCouncil editor pages into a cohesive end-to-end workflow",
            "Prepared the addon for the first real-environment alpha phase",
        } },
        { title = "Roll Setup", bullets = {
            "Added a template selector in Profile -> Roll Settings",
            "Added the Default WoW Template with Need, Greed, and Pass",
            "Added the LidCouncil Template with preset priority, icon, color, point-detail, and category rules",
        } },
        { title = "Diagnostics / Review", bullets = {
            "Expanded the About section into a real project review area with changelog, FAQ, credits, stress tools, and developer utilities",
            "Refined sync review and runtime visibility so shared-profile and board issues can be checked before live usage",
            "Completed the latest round of editor layout and workflow cleanup before alpha testing",
        } },
        { title = "Sync Optimization", bullets = {
            "Added persisted checksum and patch baselines so repeated host/member comparisons can reload precise repair context faster",
            "Added manual Run Recommended Repair suggestions, repair history, and one-step host undo support for recent shared-profile applies",
            "Expanded selective repair from domain scopes down to leaf scopes, nested preview rows, and compact conflict-row repair transfers where supported",
        } },
      },
    },
    {
      version = "Version 0.7",
      sections = {
        { title = "Simulation Profile", bullets = {
            "Added the dedicated Simulation profile workflow for testing without touching normal raid data",
            "Added local role overrides for Master, Session Host, Council Member, and Raider",
            "Connected the simulation rights matrix to the active Council Settings policy",
        } },
        { title = "Preview Tools", bullets = {
            "Added preview roll popups for testing roll choices outside a real raid environment",
            "Added preview live-board generation for host-side assignment testing",
            "Added simulation board history and award-testing flows",
        } },
        { title = "Real Session Test Flows", bullets = {
            "Added real-session simulation items that can be pushed into an active session",
            "Ensured real simulations update the Live Board without writing Loot List points",
            "Added clear/reset support for simulation content during repeated tests",
        } },
      },
    },
    {
      version = "Version 0.6",
      sections = {
        { title = "Shared Profile Sync", bullets = {
            "Added shared profile identity, clone tracking, and profile lineage handling",
            "Added revision tracking for Settings, Permissions, and Loot / Session Data",
            "Added full shared-profile snapshot export and import for session sync",
        } },
        { title = "Automatic Session Sync", bullets = {
            "Added join-time comparison between host and member shared copies",
            "Added automatic host snapshot delivery for missing or older joined copies",
            "Added automatic sync for member status, Auto Pass, roll choices, votes, awards, unassigns, and active board state",
        } },
        { title = "Manual Recovery", bullets = {
            "Added Push Host Repair for host-driven shared-profile refreshes",
            "Added Preview Member Repair and Pull Member Repair for member-copy review and recovery",
            "Added Send Board Sync for live-board recovery after reloads, UI errors, or crashes",
        } },
      },
    },
    {
      version = "Version 0.5",
      sections = {
        { title = "Role System", bullets = {
            "Established the Master, Session Host, Council Member, and Raider role model",
            "Added role-specific access checks across profile settings, session controls, live-board actions, and Loot List editing",
            "Added profile member role assignment directly inside the Council Settings section",
        } },
        { title = "Council Settings", bullets = {
            "Added grouped Council and Raider member overviews on the profile page",
            "Added editable permission policy rows for Session Host, Council, and Raider roles",
            "Added reset-to-default permission handling for quickly restoring the base policy",
        } },
        { title = "Rights Matrix", bullets = {
            "Added locked rights for critical permissions that must not be removed from required roles",
            "Added dedicated control over raid settings, roll settings, point settings, voting, assigning loot, and Loot List editing",
            "Added clearer rights feedback in the editor when access to a feature is blocked",
        } },
      },
    },
    {
      version = "Version 0.4",
      sections = {
        { title = "Loot List", bullets = {
            "Added the main Loot List page with summary columns for sessions, items, points, BiS, Off-Spec, and Transmog",
            "Added grouped Loot List navigation for roster organization",
            "Added list-only and detailed Loot List viewing modes",
        } },
        { title = "Character Data", bullets = {
            "Added Loot List Details with character summaries, loot history, and session statistics",
            "Added manual points management for raid corrections and special cases",
            "Added Main / Alt linking and personal notes per character",
        } },
        { title = "Point / Roll Rules", bullets = {
            "Added editable roll options with description, icon, color, point-detail behavior, and popup category",
            "Added LidTable and Custom point modes for profile-specific scoring systems",
            "Added item-level and item-specific point rule support with import/export and profile-copy workflows",
        } },
      },
    },
    {
      version = "Version 0.3",
      sections = {
        { title = "Session Flow", bullets = {
            "Added Start Session, join handling, late-invite support, and session shutdown flow",
            "Added session membership tracking with host, joined members, and status handling",
            "Added the basis for running a shared LidCouncil session across a group or raid",
        } },
        { title = "Session Views", bullets = {
            "Added the Current Session overview with member sync state, live-board status, and session cards",
            "Added Session History with participants, host/source details, and result summaries",
            "Added the Personal Auto Pass page for joined-member loot-roll behavior",
        } },
        { title = "Live Roll Runtime", bullets = {
            "Added the LidCouncil roll popup flow for joined members",
            "Added the host-side Live Board runtime with active items, votes, and assignment actions",
            "Added live-board history persistence for tracking current session state over time",
        } },
      },
    },
    {
      version = "Version 0.2",
      sections = {
        { title = "Loot Profiles", bullets = {
            "Added the main loot-profile system with create, copy, delete, activate, and deactivate actions",
            "Added grouped profile navigation inside the editor",
            "Added dedicated profile pages for raid, roll, point, and member data",
        } },
        { title = "Profile Presentation", bullets = {
            "Added profile hero cards, summary blocks, and profile statistics on the main profile page",
            "Added profile-member displays for master, council, and raider overview",
            "Added profile-specific raid context for season and raid selection",
        } },
        { title = "Profile Workflows", bullets = {
            "Added roll-setting and point-setting import/export between profiles",
            "Added profile-copy and identity foundations used later by the shared-profile systems",
            "Established the per-profile storage model that drives sessions, Loot List data, and live runtime",
        } },
      },
    },
    {
      version = "Version 0.1",
      sections = {
        { title = "Core Foundation", bullets = {
            "Created the LidCouncil addon shell, saved-variable structure, and internal API registry",
            "Established the split core/editor/runtime architecture used by the rest of the addon",
            "Laid the groundwork for loot profiles, sessions, runtime boards, and editor-driven configuration",
        } },
        { title = "Editor Framework", bullets = {
            "Built the main editor window, frame shell, page navigation, themed layout, and persistent window state",
            "Added reusable UI helpers such as floating windows, popup dialogs, and the custom dropdown system",
            "Created the page scaffolding for About, Profiles, Loot Profiles, Loot Session, Loot List, and Live Board",
        } },
        { title = "Project Structure", bullets = {
            "Defined the main LidCouncil sections and their page flow inside one unified editor",
            "Prepared the addon for feature-specific submodules instead of one monolithic file",
            "Set up the base environment for the later rights, sync, simulation, and alpha-hardening milestones",
        } },
      },
    },
  }

  local updatesLines = {}
  local updatesDividers = {}

  local function GetUpdatesLine(index)
    local fs = updatesLines[index]
    if not fs then
      fs = updatesContainer:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      fs:SetJustifyH("LEFT")
      updatesLines[index] = fs
    end
    return fs
  end

  local function GetUpdatesDivider(index)
    local tx = updatesDividers[index]
    if not tx then
      tx = updatesContainer:CreateTexture(nil, "ARTWORK")
      tx:SetColorTexture(1, 1, 1, 0.14)
      tx:SetHeight(1)
      updatesDividers[index] = tx
    end
    return tx
  end

  local function HideUnusedUpdates(fromLine, fromDivider)
    for i = fromLine, #updatesLines do updatesLines[i]:Hide() end
    for i = fromDivider, #updatesDividers do updatesDividers[i]:Hide() end
  end

  local function UpdateChangelogText()
    local width = (aboutContent:GetWidth() or 560) - 14
    if width < 220 then width = 220 end
    local lineIndex, dividerIndex, y = 1, 1, 0

    for _, entry in ipairs(CHANGELOG_ENTRIES) do
      local divider = GetUpdatesDivider(dividerIndex); dividerIndex = dividerIndex + 1
      divider:ClearAllPoints()
      divider:SetPoint("TOPLEFT", updatesContainer, "TOPLEFT", 0, y)
      divider:SetWidth(width)
      divider:Show()
      y = y - 12

      local versionLine = GetUpdatesLine(lineIndex); lineIndex = lineIndex + 1
      versionLine:ClearAllPoints()
      versionLine:SetPoint("TOPLEFT", updatesContainer, "TOPLEFT", 0, y)
      versionLine:SetWidth(width)
      versionLine:SetText(entry.version or "")
      local vf, _, vflags = versionLine:GetFont()
      versionLine:SetFont(vf, 16, vflags)
      do
        local r, g, b, a = GetAboutTitleColor()
        versionLine:SetTextColor(r, g, b, a)
      end
      versionLine:Show()
      y = y - (versionLine:GetStringHeight() + 8)

      for _, note in ipairs(entry.notes or {}) do
        local noteLine = GetUpdatesLine(lineIndex); lineIndex = lineIndex + 1
        noteLine:ClearAllPoints()
        noteLine:SetPoint("TOPLEFT", updatesContainer, "TOPLEFT", 8, y)
        noteLine:SetWidth(width - 8)
        noteLine:SetText(string.char(226, 128, 162) .. " " .. tostring(note))
        local nf, _, nflags = noteLine:GetFont()
        noteLine:SetFont(nf, 13, nflags)
        noteLine:SetTextColor(0.9, 0.9, 0.9, 1)
        noteLine:Show()
        y = y - (noteLine:GetStringHeight() + 2)
      end

      for _, section in ipairs(entry.sections or {}) do
        local sectionLine = GetUpdatesLine(lineIndex); lineIndex = lineIndex + 1
        sectionLine:ClearAllPoints()
        sectionLine:SetPoint("TOPLEFT", updatesContainer, "TOPLEFT", 0, y)
        sectionLine:SetWidth(width)
        sectionLine:SetText(section.title or "")
        local sf, _, sflags = sectionLine:GetFont()
        sectionLine:SetFont(sf, 14, sflags)
        do
          local r, g, b, a = GetAboutTitleColor()
          sectionLine:SetTextColor(r, g, b, a)
        end
        sectionLine:Show()
        y = y - (sectionLine:GetStringHeight() + 4)

        for _, bulletText in ipairs(section.bullets or {}) do
          local bulletLine = GetUpdatesLine(lineIndex); lineIndex = lineIndex + 1
          bulletLine:ClearAllPoints()
          bulletLine:SetPoint("TOPLEFT", updatesContainer, "TOPLEFT", 8, y)
          bulletLine:SetWidth(width - 8)
          bulletLine:SetText(string.char(226, 128, 162) .. " " .. tostring(bulletText))
          local bf, _, bflags = bulletLine:GetFont()
          bulletLine:SetFont(bf, 13, bflags)
          bulletLine:SetTextColor(0.9, 0.9, 0.9, 1)
          bulletLine:Show()
          y = y - (bulletLine:GetStringHeight() + 2)
        end
        y = y - 6
      end
      y = y - 8
    end

    HideUnusedUpdates(lineIndex, dividerIndex)
    updatesContainer:SetHeight(math.max(40, -y + 6))
  end

  local function UpdateAboutUpdatesLayout()
    if not aboutContent or not updatesContainer then return end
    if editor and editor.aboutSection and editor.aboutSection ~= "Updates" then return end
    UpdateChangelogText()
    local h = updatesContainer:GetHeight() or 400
    if editor and editor.SetAboutContentHeight then
      editor:SetAboutContentHeight(math.max(520, math.floor(h + 140)))
    end
  end
  editor.UpdateAboutUpdatesLayout = UpdateAboutUpdatesLayout
  SafeHookScript(aboutUpdatesFrame, "OnShow", UpdateAboutUpdatesLayout)
  SafeHookScript(aboutContent, "OnSizeChanged", UpdateAboutUpdatesLayout)

  CreateAboutFAQSection(editor, aboutContent, {
    MakeAboutTitle = MakeAboutTitle,
    SafeHookScript = SafeHookScript,
    GetTitleColor = GetAboutTitleColor,
  })

  CreateAboutUtilitySections(editor, aboutContent, {
    MakeAboutTitle = MakeAboutTitle,
    MakeYellowSubHeader = MakeYellowSubHeader,
    RootDB = RootDB,
    Print = Print,
    CreateLootProfile = CreateLootProfile,
    DeleteLootProfile = DeleteLootProfile,
    GetLootProfileAccessInfo = GetLootProfileAccessInfo,
    RepairSimulationProfileOwnership = RepairSimulationProfileOwnership,
    SetLootProfileEnabled = SetLootProfileEnabled,
    GetActiveLootSession = GetActiveLootSession,
    GetRuntimeDiagnostics = GetLiveLootRuntimeDiagnostics,
    SafeHookScript = SafeHookScript,
    GetTitleColor = GetAboutTitleColor,
  })

  function editor:ShowAboutSection(which)
    self.aboutSection = which or "Overview"
    if self.aboutOverview then self.aboutOverview:SetShown(self.aboutSection == "Overview") end
    if self.aboutLoaded then self.aboutLoaded:SetShown(self.aboutSection == "Loaded") end
    if self.aboutErrorsFrame then self.aboutErrorsFrame:SetShown(self.aboutSection == "Errors") end
    if self.aboutSilentFrame then self.aboutSilentFrame:SetShown(self.aboutSection == "Silent") end
    if self.aboutUpdatesFrame then self.aboutUpdatesFrame:SetShown(self.aboutSection == "Updates") end
    if self.aboutFAQFrame then self.aboutFAQFrame:SetShown(self.aboutSection == "FAQ") end
    if self.aboutCreditsFrame then self.aboutCreditsFrame:SetShown(self.aboutSection == "Credits") end
    if self.aboutStressFrame then self.aboutStressFrame:SetShown(self.aboutSection == "Stresstest") end
    if self.aboutTutorialImagesFrame then self.aboutTutorialImagesFrame:SetShown(self.aboutSection == "TutorialImages") end
    if self.aboutDeveloperFrame then self.aboutDeveloperFrame:SetShown(self.aboutSection == "Developer") end

    if self.aboutSection == "Updates" and self.UpdateAboutUpdatesLayout then
      self:UpdateAboutUpdatesLayout()
    end
    if self.aboutSection == "Overview" and self.UpdateAboutOverviewLayout then
      self:UpdateAboutOverviewLayout()
    end
    if self.aboutSection == "FAQ" then
      if self.UpdateFAQText then self:UpdateFAQText() end
      if self.UpdateAboutFAQLayout then self:UpdateAboutFAQLayout() end
    end
    if self.aboutSection == "Credits" and self.UpdateAboutCreditsLayout then
      self:UpdateAboutCreditsLayout()
    end
    if self.aboutSection == "Stresstest" and self.UpdateAboutStressLayout then
      self:UpdateAboutStressLayout()
    end
    if self.aboutSection == "TutorialImages" then
      if self.RefreshTutorialImagesSection then self:RefreshTutorialImagesSection() end
      if self.UpdateAboutTutorialImagesLayout then self:UpdateAboutTutorialImagesLayout() end
    end
    if self.aboutSection == "Developer" then
      if self.RefreshDeveloperSection then self:RefreshDeveloperSection() end
      if self.UpdateAboutDeveloperLayout then self:UpdateAboutDeveloperLayout() end
    end
  end

  aboutNavLoadedBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Loaded") end
  end)
  aboutNavErrorsBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Errors") end
  end)
  aboutNavSilentBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Silent") end
  end)
  aboutNavUpdatesBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Updates") end
  end)
  aboutNavFaqBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("FAQ") end
  end)
  aboutNavCreditsBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Credits") end
  end)
  aboutNavStressBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Stresstest") end
  end)
  aboutNavTutorialImagesBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("TutorialImages") end
  end)
  aboutNavDeveloperBtn:SetScript("OnClick", function()
    if editor and editor.ShowAboutSection then editor:ShowAboutSection("Developer") end
  end)
end

INTERNAL_API.LIDCOUNCIL_BuildAboutPage_Impl = BuildAboutPage
