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 shared = INTERNAL_API.LIDCOUNCIL_LootRuntimeUiShared_Impl
if type(shared) ~= "table" then
  error("LidCouncil missing loot runtime UI shared helpers.")
end

local GetActiveLootSession = shared.GetActiveLootSession
local GetLootProfileAccessInfo = shared.GetLootProfileAccessInfo
local GetLootProfileAccessInfoForRole = shared.GetLootProfileAccessInfoForRole
local ResolveLootPointValue = shared.ResolveLootPointValue
local ResolveLootAwardOutcome = shared.ResolveLootAwardOutcome
local ApplyFrameSkin = shared.ApplyFrameSkin
local SendSessionComm = shared.SendSessionComm
local BroadcastAuthoritativeChoice = shared.BroadcastAuthoritativeChoice
local ResolveOptionalFunction = shared.ResolveOptionalFunction
local Print = shared.Print
local NOTE_ICON_TEXTURE = shared.NOTE_ICON_TEXTURE
local RuntimeState = shared.RuntimeState
local UIState = shared.UIState
local TrimText = shared.TrimText
local IsRealSimulationItemKey = shared.IsRealSimulationItemKey
local NormalizeSelectionNote = shared.NormalizeSelectionNote
local RefreshEditor = shared.RefreshEditor
local WrapColor = shared.WrapColor
local BuildMemberDisplayText = shared.BuildMemberDisplayText
local GetSelfKey = shared.GetSelfKey
local IsSelfHost = shared.IsSelfHost
local GetBroadcastDistribution = shared.GetBroadcastDistribution
local EnsurePreviewBoardContext = shared.EnsurePreviewBoardContext
local ResolveLootLedgerTotals = shared.ResolveLootLedgerTotals
local ClearRuntimeState = shared.ClearRuntimeState
local EnsureRuntimeSession = shared.EnsureRuntimeSession
local EnsureSelectedMember = shared.EnsureSelectedMember
local CycleSelectedMember = shared.CycleSelectedMember
local BuildAwardNote = shared.BuildAwardNote
local RemoveAwardFromEntry = shared.RemoveAwardFromEntry
local ApplyAwardMessage = shared.ApplyAwardMessage
local RefreshBoardAndEditor = shared.RefreshBoardAndEditor
local GetLiveLootBoardSummary = shared.GetLiveLootBoardSummary
local BuildPreviewBoardState = shared.BuildPreviewBoardState
local GetSelectionPriority = shared.GetSelectionPriority
local FormatSelectionLabel = shared.FormatSelectionLabel
local EnsurePreviewSelectedMember = shared.EnsurePreviewSelectedMember
local ResolveRollOptions = shared.ResolveRollOptions
local RecordChoice = shared.RecordChoice
local RecordLootVoteStat = shared.RecordLootVoteStat
local ResolveSessionUnit = shared.ResolveSessionUnit
local SendAwardPacket = shared.SendAwardPacket
local ResolveOptionIconTexture = shared.ResolveOptionIconTexture
local PersistRuntimeBoardHistory = shared.PersistRuntimeBoardHistory

local function GetSessionCommProfileName(activeSession, fallbackProfileName)
  return TrimText(type(activeSession) == "table" and activeSession.remoteProfileName) ~= ""
    and TrimText(activeSession.remoteProfileName)
    or TrimText(fallbackProfileName)
end

local function CountPendingTradeAssignments()
  local pendingCount = 0
  for _, itemKey in ipairs(RuntimeState.itemOrder or {}) do
    local entry = type(RuntimeState.items) == "table" and RuntimeState.items[itemKey] or nil
    local entryKey = TrimText(type(entry) == "table" and (entry.key or itemKey) or itemKey)
    if type(entry) == "table"
      and entry.awardedAt
      and TrimText(entry.awardedTo) ~= ""
      and not IsRealSimulationItemKey(entryKey)
      and string.upper(TrimText(entry.tradeState)) ~= "TRADED" then
      pendingCount = pendingCount + 1
    end
  end
  return pendingCount
end

local OPTIONAL_BOARD_COLUMN_DEFAULTS = {
  items = false,
  offspec = false,
  transmog = false,
  disenchant = false,
  total = true,
  bis = true,
  dice = true,
}
local OPTIONAL_BOARD_COLUMN_KEYS = {
  items = true,
  offspec = true,
  transmog = true,
  disenchant = true,
  total = true,
  bis = true,
  dice = true,
}

local function GetRootUiSettings()
  local rootProvider = rawget(_G, "LIDCOUNCIL_RootDB")
  local root = type(rootProvider) == "function" and rootProvider() or nil
  if type(root) ~= "table" then
    return nil
  end
  root.ui = type(root.ui) == "table" and root.ui or {}
  return root.ui
end

local function EnsureBoardColumnVisibility()
  local ui = GetRootUiSettings()
  local columns = ui and ui.liveBoardColumns or UIState.boardColumnVisibility
  columns = type(columns) == "table" and columns or {}
  for key, defaultValue in pairs(OPTIONAL_BOARD_COLUMN_DEFAULTS) do
    if columns[key] == nil then
      columns[key] = defaultValue and true or false
    else
      columns[key] = columns[key] and true or false
    end
  end
  local removeKeys = {}
  for key in pairs(columns) do
    if not OPTIONAL_BOARD_COLUMN_KEYS[key] then
      removeKeys[#removeKeys + 1] = key
    end
  end
  for _, key in ipairs(removeKeys) do
    columns[key] = nil
  end
  if ui then
    ui.liveBoardColumns = columns
  end
  UIState.boardColumnVisibility = columns
  return columns
end

local function RefreshBoardColumnToggles(frame)
  if not frame then
    return
  end
  local columns = EnsureBoardColumnVisibility()
  for _, check in ipairs(frame.memberColumnToggles or {}) do
    local key = TrimText(check.__columnKey)
    if check.SetChecked then
      check:SetChecked(columns[key] == true)
    end
  end
end

local function ApplyBoardColumnVisibility(frame)
  if not frame then
    return
  end
  local columns = EnsureBoardColumnVisibility()
  frame.__memberColumnVisibility = columns
  local sortKey = TrimText(frame.__memberSortKey)
  if OPTIONAL_BOARD_COLUMN_KEYS[sortKey] and columns[sortKey] ~= true then
    frame.__memberSortKey = "roll"
    frame.__memberSortDescending = false
  end
  RefreshBoardColumnToggles(frame)
end

local function SetBoardColumnVisibility(frame, key, visible)
  local resolvedKey = TrimText(key)
  if not OPTIONAL_BOARD_COLUMN_KEYS[resolvedKey] then
    return
  end
  local columns = EnsureBoardColumnVisibility()
  columns[resolvedKey] = visible and true or false
  local ui = GetRootUiSettings()
  if ui then
    ui.liveBoardColumns = columns
  end
  UIState.boardColumnVisibility = columns
  ApplyBoardColumnVisibility(frame)
end
local CyclePreviewSelectedMember = shared.CyclePreviewSelectedMember
local ApplySimulationAward = shared.ApplySimulationAward
local GetBoardPreviewState = shared.GetBoardPreviewState
local SetBoardPreviewState = shared.SetBoardPreviewState
local PersistBoardState = shared.PersistBoardState
local GetEntryVoteTargetForVoter = shared.GetEntryVoteTargetForVoter
local SetEntryVoteTarget = shared.SetEntryVoteTarget
local GetEntryVoteVoterKeys = shared.GetEntryVoteVoterKeys
local GetEntryVoteCount = shared.GetEntryVoteCount
local RenderAuthoritativeItemTooltip = shared.RenderAuthoritativeItemTooltip
local ResolveRuntimeItemDisplayText = shared.ResolveRuntimeItemDisplayText
local RaisePopupFrameAboveEditor
local ApplyPopupBoardResizeLimits
local CapturePopupBoardGeometry
local ApplyPopupBoardGeometry
local EnforcePopupBoardMinimumSize
local StartPopupBoardResize
local StopPopupBoardResize
local BindPopupBoardDragScripts
local ApplyBoardSectionSkin
local ApplyBoardButtonStyle
local ApplyPopupBoardLayout
local ApplyEmbeddedBoardLayout
local SetBoardCollapsed
local LayoutBoardFrame
local SetBoardSelectedMember
local ShowSelectionNotePopup
local HideBoardItemTooltip
local ShowBoardItemTooltip
local ApplyBoardMemberRowLayout
local RefreshBoardHeaderSortState
local BuildBoardHeaderButton
local ResolveEntryVotedKey
local ToggleBoardVoteForMember
local EnsureBoardMemberRows
local UpdateBoardMemberRows
local ResolveBoardMemberTotalPoints
local ResolveBoardProjectedPoints
local BuildAwardStatusDetail
local SetBoardItemButtonState
local BuildBoardItemButtonTitle
local SelectNextUnawardedBoardItem
local RenderBoardItemButtons
local RenderPreviewBoard
local SetBoardAwardStatus
local CountPendingBoardSelections
local CreateBoardFrameScaffold
local OpenChangeRollPopup
local OpenTradeHelperPopup

local function CanSelfAssignLiveBoard(activeSession, profileName)
  if not activeSession or not IsSelfHost(activeSession) then
    return false
  end
  if type(InCombatLockdown) == "function" and InCombatLockdown() then
    return false
  end
  local resolvedProfileName = TrimText(profileName ~= "" and profileName or (type(activeSession) == "table" and activeSession.profileName) or RuntimeState.profileName)
  if type(GetLootProfileAccessInfo) == "function" then
    local access = GetLootProfileAccessInfo(resolvedProfileName)
    if resolvedProfileName == "Simulation" then
      return type(access) == "table" and access.canAssignLoot and true or false
    end
    if type(access) == "table" and access.canTransferMaster then
      return access.canAssignLoot and true or false
    end
  end
  if type(GetLootProfileAccessInfoForRole) == "function" then
    local hostAccess = GetLootProfileAccessInfoForRole(resolvedProfileName, "SESSION_HOST")
    return type(hostAccess) == "table" and hostAccess.canAssignLoot and true or false
  end
  return false
end

local function IsManualVisibleBoardEntry(entry)
  return string.upper(TrimText(type(entry) == "table" and entry.distributionMode or "")) == "MANUAL_VISIBLE"
end

local function GetSimulationPreviewAccess(preview)
  if not preview or not preview.isSimulation or type(GetLootProfileAccessInfo) ~= "function" then
    return nil
  end
  local profileName = TrimText(preview.profileName)
  if profileName == "" then
    profileName = "Simulation"
  end
  local rootProvider = rawget(_G, "LIDCOUNCIL_RootDB")
  local root = type(rootProvider) == "function" and rootProvider() or nil
  if type(root) == "table" and (type(root.profiles) ~= "table" or type(root.profiles[profileName]) ~= "table") then
    return nil
  end
  local access = GetLootProfileAccessInfo(profileName)
  if type(access) ~= "table" then
    return nil
  end
  return access
end

local function CanSelfVoteSimulationPreview(preview)
  local access = GetSimulationPreviewAccess(preview)
  return type(access) == "table" and access.canOpenLiveBoard and access.canVote and true or false
end

local function CanSelfAssignSimulationPreview(preview)
  local access = GetSimulationPreviewAccess(preview)
  if type(access) == "table" then
    return access.canAssignLoot and true or false
  end
  return false
end

local DEFAULT_POPUP_BOARD_WIDTH = 780
local DEFAULT_POPUP_BOARD_HEIGHT = 560
local MIN_POPUP_BOARD_WIDTH = 780
local MIN_POPUP_BOARD_HEIGHT = 500

local CreateLootBoardLayoutHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardLayoutHelpers_Impl
if type(CreateLootBoardLayoutHelpers) ~= "function" then
  error("LidCouncil missing loot board layout helpers.")
end

local boardLayoutHelpers = CreateLootBoardLayoutHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  WrapColor = WrapColor,
  TrimText = TrimText,
  UIState = UIState,
  GetLiveLootBoardSummary = GetLiveLootBoardSummary,
  GetApplyBoardMemberRowLayout = function()
    return ApplyBoardMemberRowLayout
  end,
  DEFAULT_POPUP_BOARD_WIDTH = DEFAULT_POPUP_BOARD_WIDTH,
  DEFAULT_POPUP_BOARD_HEIGHT = DEFAULT_POPUP_BOARD_HEIGHT,
  MIN_POPUP_BOARD_WIDTH = MIN_POPUP_BOARD_WIDTH,
  MIN_POPUP_BOARD_HEIGHT = MIN_POPUP_BOARD_HEIGHT,
})

RaisePopupFrameAboveEditor = boardLayoutHelpers.RaisePopupFrameAboveEditor
ApplyPopupBoardResizeLimits = boardLayoutHelpers.ApplyPopupBoardResizeLimits
CapturePopupBoardGeometry = boardLayoutHelpers.CapturePopupBoardGeometry
ApplyPopupBoardGeometry = boardLayoutHelpers.ApplyPopupBoardGeometry
EnforcePopupBoardMinimumSize = boardLayoutHelpers.EnforcePopupBoardMinimumSize
StartPopupBoardResize = boardLayoutHelpers.StartPopupBoardResize
StopPopupBoardResize = boardLayoutHelpers.StopPopupBoardResize
BindPopupBoardDragScripts = boardLayoutHelpers.BindPopupBoardDragScripts
ApplyBoardSectionSkin = boardLayoutHelpers.ApplyBoardSectionSkin
ApplyBoardButtonStyle = boardLayoutHelpers.ApplyBoardButtonStyle
ApplyPopupBoardLayout = boardLayoutHelpers.ApplyPopupBoardLayout
ApplyEmbeddedBoardLayout = boardLayoutHelpers.ApplyEmbeddedBoardLayout
SetBoardCollapsed = boardLayoutHelpers.SetBoardCollapsed
LayoutBoardFrame = boardLayoutHelpers.LayoutBoardFrame

local CreateLootBoardActionHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardActionHelpers_Impl
if type(CreateLootBoardActionHelpers) ~= "function" then
  error("LidCouncil missing loot board action helpers.")
end

local boardActionHelpers = CreateLootBoardActionHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyBoardButtonStyle = ApplyBoardButtonStyle,
  BuildMemberDisplayText = BuildMemberDisplayText,
  GetActiveLootSession = GetActiveLootSession,
  IsSelfHost = IsSelfHost,
  CanSelfAssignLiveBoard = CanSelfAssignLiveBoard,
  EnsureRuntimeSession = EnsureRuntimeSession,
  ResolveRollOptions = ResolveRollOptions,
  RecordChoice = RecordChoice,
  SendSessionComm = SendSessionComm,
  BroadcastAuthoritativeChoice = BroadcastAuthoritativeChoice,
  GetBroadcastDistribution = GetBroadcastDistribution,
  GetSessionCommProfileName = GetSessionCommProfileName,
  ResolveSessionUnit = ResolveSessionUnit,
  RefreshBoardAndEditor = RefreshBoardAndEditor,
  PersistRuntimeBoardHistory = PersistRuntimeBoardHistory,
  RuntimeState = RuntimeState,
  ResolveRuntimeItemDisplayText = ResolveRuntimeItemDisplayText,
  TrimText = TrimText,
  ResolveOptionIconTexture = ResolveOptionIconTexture,
  GetSelfKey = GetSelfKey,
  Print = Print,
})

OpenChangeRollPopup = boardActionHelpers.OpenChangeRollPopup
OpenTradeHelperPopup = boardActionHelpers.OpenTradeHelperPopup

local CreateLootBoardOverlayHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardOverlayHelpers_Impl
if type(CreateLootBoardOverlayHelpers) ~= "function" then
  error("LidCouncil missing loot board overlay helpers.")
end

local boardOverlayHelpers = CreateLootBoardOverlayHelpers({
  UIState = UIState,
  ApplyFrameSkin = ApplyFrameSkin,
  RaisePopupFrameAboveEditor = RaisePopupFrameAboveEditor,
  ApplyBoardButtonStyle = ApplyBoardButtonStyle,
  NormalizeSelectionNote = NormalizeSelectionNote,
  WrapColor = WrapColor,
  TrimText = TrimText,
  RenderAuthoritativeItemTooltip = RenderAuthoritativeItemTooltip,
})

ShowSelectionNotePopup = boardOverlayHelpers.ShowSelectionNotePopup
HideBoardItemTooltip = boardOverlayHelpers.HideBoardItemTooltip
ShowBoardItemTooltip = boardOverlayHelpers.ShowBoardItemTooltip

local CreateLootBoardScaffoldHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardScaffoldHelpers_Impl
if type(CreateLootBoardScaffoldHelpers) ~= "function" then
  error("LidCouncil missing loot board scaffold helpers.")
end

local boardScaffoldHelpers = CreateLootBoardScaffoldHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  ResolveOptionalFunction = ResolveOptionalFunction,
  BindPopupBoardDragScripts = BindPopupBoardDragScripts,
  ApplyPopupBoardResizeLimits = ApplyPopupBoardResizeLimits,
  RaisePopupFrameAboveEditor = RaisePopupFrameAboveEditor,
  ApplyBoardButtonStyle = ApplyBoardButtonStyle,
  ApplyBoardSectionSkin = ApplyBoardSectionSkin,
  StartPopupBoardResize = StartPopupBoardResize,
  StopPopupBoardResize = StopPopupBoardResize,
  ShowBoardItemTooltip = ShowBoardItemTooltip,
  HideBoardItemTooltip = HideBoardItemTooltip,
  TrimText = TrimText,
  DEFAULT_POPUP_BOARD_WIDTH = DEFAULT_POPUP_BOARD_WIDTH,
  DEFAULT_POPUP_BOARD_HEIGHT = DEFAULT_POPUP_BOARD_HEIGHT,
})

CreateBoardFrameScaffold = boardScaffoldHelpers.CreateBoardFrameScaffold

local CreateLootBoardRowHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardRowHelpers_Impl
if type(CreateLootBoardRowHelpers) ~= "function" then
  error("LidCouncil missing loot board row helpers.")
end

local boardRowHelpers = CreateLootBoardRowHelpers({
  TrimText = TrimText,
  GetEntryVoteTargetForVoter = GetEntryVoteTargetForVoter,
  GetEntryVoteVoterKeys = GetEntryVoteVoterKeys,
  GetEntryVoteCount = GetEntryVoteCount,
  GetSelfKey = GetSelfKey,
  GetBoardPreviewState = GetBoardPreviewState,
  PersistBoardState = PersistBoardState,
  GetActiveLootSession = GetActiveLootSession,
  EnsureRuntimeSession = EnsureRuntimeSession,
  RuntimeState = RuntimeState,
  SetEntryVoteTarget = SetEntryVoteTarget,
  GetBroadcastDistribution = GetBroadcastDistribution,
  SendSessionComm = SendSessionComm,
  NormalizeSelectionNote = NormalizeSelectionNote,
  BuildMemberDisplayText = BuildMemberDisplayText,
  FormatSelectionLabel = FormatSelectionLabel,
  GetLootProfileAccessInfo = GetLootProfileAccessInfo,
  ResolveRollOptions = ResolveRollOptions,
  RecordLootVoteStat = RecordLootVoteStat,
  IsRealSimulationItemKey = IsRealSimulationItemKey,
  IsSelfHost = IsSelfHost,
  Print = Print,
  RefreshBoardAndEditor = RefreshBoardAndEditor,
  NOTE_ICON_TEXTURE = NOTE_ICON_TEXTURE,
  GetShowSelectionNotePopup = function()
    return ShowSelectionNotePopup
  end,
  GetSetBoardSelectedMember = function()
    return SetBoardSelectedMember
  end,
  ApplyBoardButtonStyle = ApplyBoardButtonStyle,
})

RefreshBoardHeaderSortState = boardRowHelpers.RefreshBoardHeaderSortState
BuildBoardHeaderButton = boardRowHelpers.BuildBoardHeaderButton
ResolveEntryVotedKey = boardRowHelpers.ResolveEntryVotedKey
ToggleBoardVoteForMember = boardRowHelpers.ToggleBoardVoteForMember
ApplyBoardMemberRowLayout = boardRowHelpers.ApplyBoardMemberRowLayout
EnsureBoardMemberRows = boardRowHelpers.EnsureBoardMemberRows
ResolveBoardMemberTotalPoints = boardRowHelpers.ResolveBoardMemberTotalPoints
UpdateBoardMemberRows = boardRowHelpers.UpdateBoardMemberRows

SetBoardSelectedMember = function(frame, memberKey)
  if not frame then
    return
  end

  local preview = frame.__previewState
  if type(preview) == "table" and preview.isSimulation then
    preview.selectedMemberKey = memberKey
  else
    RuntimeState.selectedMemberKey = memberKey
  end

  if frame.RefreshBoard then
    frame:RefreshBoard()
  end
end

local function UpdateAssignDropdown(frame, rows, selectedRow, emptyText)
  if not frame or not frame.assignDropdown then
    return
  end

  local fallbackText = tostring(emptyText or "Select session member")
  frame.__assignRows = rows or {}
  frame.__assignSelectedKey = selectedRow and selectedRow.key or nil
  frame.assignDropdown:SetSelectedValue(frame.__assignSelectedKey)
  frame.assignDropdown:SetText(selectedRow and BuildMemberDisplayText(selectedRow, { iconSize = 14 }) or fallbackText)
  frame.assignDropdown:SetMenuBuilder(function()
    local entries = {}
    for _, row in ipairs(frame.__assignRows or {}) do
      entries[#entries + 1] = {
        text = BuildMemberDisplayText(row, { iconSize = 14 }) .. " - " .. FormatSelectionLabel(row.selection),
        checked = frame.__assignSelectedKey == row.key,
        func = function()
          SetBoardSelectedMember(frame, row.key)
        end,
      }
    end
    if #entries == 0 then
      entries[1] = {
        text = fallbackText,
        disabled = true,
        notCheckable = true,
      }
    end
    return {
      width = 320,
      entries = entries,
    }
  end)
end

local function BuildAssignmentTargetText(selectedRow, selectionLabel, fallbackText)
  local prefix = "|cffb9c2d0Recipient:|r "
  if type(selectedRow) == "table" then
    local recipient = TrimText(selectedRow.name or selectedRow.key)
    if recipient == "" then
      recipient = "?"
    end
    if selectedRow.isHost then
      recipient = recipient .. " [Host]"
    end
    local selection = TrimText(selectionLabel)
    if selection == "" then
      selection = "Pending"
    end
    return prefix .. recipient .. " | " .. selection
  end

  return prefix .. tostring(fallbackText or "None selected")
end

SetBoardAwardStatus = function(frame, tone, headline, detail)
  if not frame then
    return
  end

  local titleText = TrimText(headline)
  local detailText = TrimText(detail)
  local readinessText = frame.assignmentReadiness
  local readinessTint = frame.assignmentReadinessTint
  local readinessBorder = frame.assignmentReadinessBorder

  if titleText == "" and detailText == "" then
    if readinessText then
      readinessText:SetText("")
      readinessText:Hide()
    end
    if readinessTint then
      readinessTint:SetVertexColor(0, 0, 0, 0)
    end
    for _, edge in ipairs(readinessBorder or {}) do
      edge:SetVertexColor(0.55, 0.55, 0.60, 0.72)
    end
    return
  end

  local titleColor = { 0.82, 0.82, 0.86 }
  if tone == "success" then
    titleColor = { 0.22, 0.88, 0.32 }
  elseif tone == "complete" then
    titleColor = { 0.42, 0.92, 0.56 }
  elseif tone == "ready" then
    titleColor = { 0.42, 0.92, 0.56 }
  elseif tone == "warning" then
    titleColor = { 1.00, 0.72, 0.22 }
  elseif tone == "projected" then
    titleColor = { 0.95, 0.82, 0.22 }
  elseif tone == "waiting" then
    titleColor = { 1.00, 0.72, 0.22 }
  end

  if readinessText then
    local statusText = titleText
    if detailText ~= "" then
      statusText = statusText .. " | " .. detailText
    end
    readinessText:SetText(statusText)
    readinessText:SetTextColor(titleColor[1], titleColor[2], titleColor[3], 1)
    readinessText:Show()
  end

  local borderColor = { 0.55, 0.55, 0.60, 0.72 }
  local tintColor = { 0, 0, 0, 0 }
  if tone == "complete" then
    borderColor = { 0.24, 0.82, 0.40, 0.96 }
    tintColor = { 0.05, 0.20, 0.10, 0.18 }
  end
  if readinessTint then
    readinessTint:SetVertexColor(tintColor[1], tintColor[2], tintColor[3], tintColor[4])
  end
  for _, edge in ipairs(readinessBorder or {}) do
    edge:SetVertexColor(borderColor[1], borderColor[2], borderColor[3], borderColor[4])
  end

end

CountPendingBoardSelections = function(rows)
  local pendingCount = 0
  local resolvedCount = 0
  for _, row in ipairs(rows or {}) do
    local selectionKey = string.lower(TrimText(row and row.selection and (row.selection.optionKey or row.selection.label) or "pending"))
    if selectionKey == "" or selectionKey == "pending" then
      pendingCount = pendingCount + 1
    else
      resolvedCount = resolvedCount + 1
    end
  end
  return pendingCount, resolvedCount
end

local CreateLootBoardRenderHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootBoardRenderHelpers_Impl
if type(CreateLootBoardRenderHelpers) ~= "function" then
  error("LidCouncil missing loot board render helpers.")
end

local boardRenderHelpers = CreateLootBoardRenderHelpers({
  TrimText = TrimText,
  ResolveLootAwardOutcome = ResolveLootAwardOutcome,
  ResolveLootPointValue = ResolveLootPointValue,
  GetBoardPreviewState = GetBoardPreviewState,
  EnsurePreviewBoardContext = EnsurePreviewBoardContext,
  ResolveLootLedgerTotals = ResolveLootLedgerTotals,
  EnsurePreviewSelectedMember = EnsurePreviewSelectedMember,
  FormatSelectionLabel = FormatSelectionLabel,
  BuildMemberDisplayText = BuildMemberDisplayText,
  GetEntryVoteTargetForVoter = GetEntryVoteTargetForVoter,
  GetSelfKey = GetSelfKey,
  IsRealSimulationItemKey = IsRealSimulationItemKey,
  UpdateBoardMemberRows = UpdateBoardMemberRows,
  ResolveEntryVotedKey = ResolveEntryVotedKey,
  CountPendingBoardSelections = CountPendingBoardSelections,
  SetBoardAwardStatus = SetBoardAwardStatus,
  UpdateAssignDropdown = UpdateAssignDropdown,
  BuildAssignmentTargetText = BuildAssignmentTargetText,
  GetLootProfileAccessInfo = GetLootProfileAccessInfo,
  RefreshBoardHeaderSortState = RefreshBoardHeaderSortState,
  RuntimeState = RuntimeState,
  ResolveRuntimeItemDisplayText = ResolveRuntimeItemDisplayText,
})

ResolveBoardProjectedPoints = boardRenderHelpers.ResolveBoardProjectedPoints
BuildAwardStatusDetail = boardRenderHelpers.BuildAwardStatusDetail
SetBoardItemButtonState = boardRenderHelpers.SetBoardItemButtonState
BuildBoardItemButtonTitle = boardRenderHelpers.BuildBoardItemButtonTitle
SelectNextUnawardedBoardItem = boardRenderHelpers.SelectNextUnawardedBoardItem
RenderBoardItemButtons = boardRenderHelpers.RenderBoardItemButtons
RenderPreviewBoard = boardRenderHelpers.RenderPreviewBoard

local function SetLiveBoardDetailTooltipState(frame, entry, itemKey)
  local button = frame and frame.detailTooltipButton or nil
  if not button then
    return
  end
  local hasEntry = type(entry) == "table"
  button.__itemTooltipLink = hasEntry and entry.link or nil
  button.__itemTooltipItemID = hasEntry and (entry.itemID or entry.link) or nil
  button.__itemTooltipName = hasEntry and (entry.name or itemKey) or itemKey
  button.__itemTooltipItemLevel = hasEntry and tonumber(entry.itemLevel) or nil
  local hasTooltip = hasEntry
    and (TrimText(button.__itemTooltipLink) ~= "" or button.__itemTooltipItemID ~= nil or TrimText(button.__itemTooltipName) ~= "")
  if button.EnableMouse then
    button:EnableMouse(hasTooltip and true or false)
  end
end

-- CreateBoardFrame wires a large UI surface and therefore touches many helpers.
-- Keep those dependencies behind one private bundle so the factory remains below
-- Lua's per-function upvalue limit without changing any board callback behavior.
local BoardFrameDeps = {
  ApplyAwardMessage = ApplyAwardMessage,
  ApplyBoardColumnVisibility = ApplyBoardColumnVisibility,
  ApplySimulationAward = ApplySimulationAward,
  BuildAssignmentTargetText = BuildAssignmentTargetText,
  BuildAwardNote = BuildAwardNote,
  BuildAwardStatusDetail = BuildAwardStatusDetail,
  BuildBoardHeaderButton = BuildBoardHeaderButton,
  CanSelfAssignLiveBoard = CanSelfAssignLiveBoard,
  CanSelfAssignSimulationPreview = CanSelfAssignSimulationPreview,
  CanSelfVoteSimulationPreview = CanSelfVoteSimulationPreview,
  CapturePopupBoardGeometry = CapturePopupBoardGeometry,
  CountPendingBoardSelections = CountPendingBoardSelections,
  CountPendingTradeAssignments = CountPendingTradeAssignments,
  CreateBoardFrameScaffold = CreateBoardFrameScaffold,
  CyclePreviewSelectedMember = CyclePreviewSelectedMember,
  CycleSelectedMember = CycleSelectedMember,
  EnforcePopupBoardMinimumSize = EnforcePopupBoardMinimumSize,
  EnsurePreviewSelectedMember = EnsurePreviewSelectedMember,
  EnsureRuntimeSession = EnsureRuntimeSession,
  EnsureSelectedMember = EnsureSelectedMember,
  FormatSelectionLabel = FormatSelectionLabel,
  GetActiveLootSession = GetActiveLootSession,
  GetBoardPreviewState = GetBoardPreviewState,
  GetBroadcastDistribution = GetBroadcastDistribution,
  GetSelfKey = GetSelfKey,
  GetSessionCommProfileName = GetSessionCommProfileName,
  HideBoardItemTooltip = HideBoardItemTooltip,
  INTERNAL_API = INTERNAL_API,
  IsManualVisibleBoardEntry = IsManualVisibleBoardEntry,
  IsRealSimulationItemKey = IsRealSimulationItemKey,
  LayoutBoardFrame = LayoutBoardFrame,
  OpenChangeRollPopup = OpenChangeRollPopup,
  OpenTradeHelperPopup = OpenTradeHelperPopup,
  PersistBoardState = PersistBoardState,
  Print = Print,
  RefreshBoardAndEditor = RefreshBoardAndEditor,
  RefreshBoardHeaderSortState = RefreshBoardHeaderSortState,
  RefreshEditor = RefreshEditor,
  RemoveAwardFromEntry = RemoveAwardFromEntry,
  RenderBoardItemButtons = RenderBoardItemButtons,
  RenderPreviewBoard = RenderPreviewBoard,
  ResolveBoardProjectedPoints = ResolveBoardProjectedPoints,
  ResolveEntryVotedKey = ResolveEntryVotedKey,
  ResolveLootLedgerTotals = ResolveLootLedgerTotals,
  ResolveOptionalFunction = ResolveOptionalFunction,
  ResolveRuntimeItemDisplayText = ResolveRuntimeItemDisplayText,
  RuntimeState = RuntimeState,
  SelectNextUnawardedBoardItem = SelectNextUnawardedBoardItem,
  SendAwardPacket = SendAwardPacket,
  SendSessionComm = SendSessionComm,
  SetBoardAwardStatus = SetBoardAwardStatus,
  SetBoardCollapsed = SetBoardCollapsed,
  SetBoardColumnVisibility = SetBoardColumnVisibility,
  SetLiveBoardDetailTooltipState = SetLiveBoardDetailTooltipState,
  ShowBoardItemTooltip = ShowBoardItemTooltip,
  StartPopupBoardResize = StartPopupBoardResize,
  StopPopupBoardResize = StopPopupBoardResize,
  ToggleBoardVoteForMember = ToggleBoardVoteForMember,
  TrimText = TrimText,
  UIState = UIState,
  UpdateAssignDropdown = UpdateAssignDropdown,
  UpdateBoardMemberRows = UpdateBoardMemberRows,
}

local function CreateBoardFrame()
  local D = BoardFrameDeps
  local ApplyAwardMessage = D.ApplyAwardMessage
  local ApplyBoardColumnVisibility = D.ApplyBoardColumnVisibility
  local ApplySimulationAward = D.ApplySimulationAward
  local BuildAssignmentTargetText = D.BuildAssignmentTargetText
  local BuildAwardNote = D.BuildAwardNote
  local BuildAwardStatusDetail = D.BuildAwardStatusDetail
  local BuildBoardHeaderButton = D.BuildBoardHeaderButton
  local CanSelfAssignLiveBoard = D.CanSelfAssignLiveBoard
  local CanSelfAssignSimulationPreview = D.CanSelfAssignSimulationPreview
  local CanSelfVoteSimulationPreview = D.CanSelfVoteSimulationPreview
  local CapturePopupBoardGeometry = D.CapturePopupBoardGeometry
  local CountPendingBoardSelections = D.CountPendingBoardSelections
  local CountPendingTradeAssignments = D.CountPendingTradeAssignments
  local CreateBoardFrameScaffold = D.CreateBoardFrameScaffold
  local CyclePreviewSelectedMember = D.CyclePreviewSelectedMember
  local CycleSelectedMember = D.CycleSelectedMember
  local EnforcePopupBoardMinimumSize = D.EnforcePopupBoardMinimumSize
  local EnsurePreviewSelectedMember = D.EnsurePreviewSelectedMember
  local EnsureRuntimeSession = D.EnsureRuntimeSession
  local EnsureSelectedMember = D.EnsureSelectedMember
  local FormatSelectionLabel = D.FormatSelectionLabel
  local GetActiveLootSession = D.GetActiveLootSession
  local GetBoardPreviewState = D.GetBoardPreviewState
  local GetBroadcastDistribution = D.GetBroadcastDistribution
  local GetSelfKey = D.GetSelfKey
  local GetSessionCommProfileName = D.GetSessionCommProfileName
  local HideBoardItemTooltip = D.HideBoardItemTooltip
  local INTERNAL_API = D.INTERNAL_API
  local IsManualVisibleBoardEntry = D.IsManualVisibleBoardEntry
  local IsRealSimulationItemKey = D.IsRealSimulationItemKey
  local LayoutBoardFrame = D.LayoutBoardFrame
  local OpenChangeRollPopup = D.OpenChangeRollPopup
  local OpenTradeHelperPopup = D.OpenTradeHelperPopup
  local PersistBoardState = D.PersistBoardState
  local Print = D.Print
  local RefreshBoardAndEditor = D.RefreshBoardAndEditor
  local RefreshBoardHeaderSortState = D.RefreshBoardHeaderSortState
  local RefreshEditor = D.RefreshEditor
  local RemoveAwardFromEntry = D.RemoveAwardFromEntry
  local RenderBoardItemButtons = D.RenderBoardItemButtons
  local RenderPreviewBoard = D.RenderPreviewBoard
  local ResolveBoardProjectedPoints = D.ResolveBoardProjectedPoints
  local ResolveEntryVotedKey = D.ResolveEntryVotedKey
  local ResolveLootLedgerTotals = D.ResolveLootLedgerTotals
  local ResolveOptionalFunction = D.ResolveOptionalFunction
  local ResolveRuntimeItemDisplayText = D.ResolveRuntimeItemDisplayText
  local RuntimeState = D.RuntimeState
  local SelectNextUnawardedBoardItem = D.SelectNextUnawardedBoardItem
  local SendAwardPacket = D.SendAwardPacket
  local SendSessionComm = D.SendSessionComm
  local SetBoardAwardStatus = D.SetBoardAwardStatus
  local SetBoardCollapsed = D.SetBoardCollapsed
  local SetBoardColumnVisibility = D.SetBoardColumnVisibility
  local SetLiveBoardDetailTooltipState = D.SetLiveBoardDetailTooltipState
  local ShowBoardItemTooltip = D.ShowBoardItemTooltip
  local StartPopupBoardResize = D.StartPopupBoardResize
  local StopPopupBoardResize = D.StopPopupBoardResize
  local ToggleBoardVoteForMember = D.ToggleBoardVoteForMember
  local TrimText = D.TrimText
  local UIState = D.UIState
  local UpdateAssignDropdown = D.UpdateAssignDropdown
  local UpdateBoardMemberRows = D.UpdateBoardMemberRows

  if UIState.boardFrame then
    return UIState.boardFrame
  end

  local frame
  frame = CreateBoardFrameScaffold({
    BuildBoardHeaderButton = BuildBoardHeaderButton,
    OnClose = function(currentFrame)
      if UIState.choicePopup and not GetActiveLootSession() then
        UIState.choicePopup:Hide()
      end
      currentFrame:Hide()
      RefreshEditor()
    end,
    OnCollapse = function(currentFrame)
      local nextCollapsed = not UIState.collapsed
      SetBoardCollapsed(currentFrame, nextCollapsed)
      if not nextCollapsed and currentFrame.RefreshBoard then
        currentFrame:RefreshBoard()
      end
    end,
    OnSendBoardSync = function(currentFrame)
      if currentFrame and currentFrame.boardSyncBtn and currentFrame.boardSyncBtn.__lidBoardSyncCooldown then
        return
      end
      local sendBoardSync = ResolveOptionalFunction("LIDCOUNCIL_SendActiveLiveBoardSyncFlow")
      local sentOk = false
      local sentCount = 0
      if type(sendBoardSync) == "function" then
        sentOk, sentCount = sendBoardSync()
      end
      local syncButton = currentFrame and currentFrame.boardSyncBtn or nil
      if syncButton and type(C_Timer) == "table" and type(C_Timer.After) == "function" then
        local feedbackToken = (tonumber(syncButton.__lidBoardFeedbackToken) or 0) + 1
        syncButton.__lidBoardFeedbackToken = feedbackToken
        if sentOk then
          syncButton.__lidBoardSyncCooldown = true
          syncButton:Disable()
          syncButton:SetText("Sent: " .. tostring(tonumber(sentCount) or 0))
        else
          syncButton:SetText("Not sent")
        end
        C_Timer.After(2, function()
          if syncButton.__lidBoardFeedbackToken == feedbackToken then
            syncButton.__lidBoardSyncCooldown = nil
            syncButton:SetText("Sync Board")
            if currentFrame and currentFrame.RefreshBoard then
              currentFrame:RefreshBoard()
            end
          end
        end)
      end
      if currentFrame and currentFrame.RefreshBoard then
        currentFrame:RefreshBoard()
      end
    end,
    OnTradeHelper = function(currentFrame)
      if type(OpenTradeHelperPopup) == "function" then
        OpenTradeHelperPopup(currentFrame)
      end
    end,
    OnToggleMemberColumn = function(currentFrame, columnKey, visible)
      SetBoardColumnVisibility(currentFrame, columnKey, visible)
      if currentFrame and currentFrame.RefreshBoard then
        currentFrame:RefreshBoard()
      end
    end,
    OnItemEnter = function(_, button)
      if button.__highlight then
        button.__highlight:Show()
        button.__highlight:SetVertexColor(0.90, 0.74, 0.18, button.__itemSelected and 0.20 or 0.12)
      end
      ShowBoardItemTooltip(button)
    end,
    OnItemLeave = function(_, button)
      if button.__highlight and not button.__itemSelected then
        button.__highlight:Hide()
      elseif button.__highlight then
        button.__highlight:Show()
        button.__highlight:SetVertexColor(0.90, 0.74, 0.18, 0.20)
      end
      HideBoardItemTooltip()
    end,
    OnItemClick = function(currentFrame, button)
      local preview = currentFrame.__previewState
      if preview then
        preview.selectedItemKey = button.__itemKey
        if currentFrame.RefreshBoard then
          currentFrame:RefreshBoard()
        end
        if preview.isSimulation then
          local openSimulationChoicePopup = INTERNAL_API.LIDCOUNCIL_OpenSimulationChoicePopup_Impl
          if type(openSimulationChoicePopup) == "function" then
            local entry = preview.items and preview.items[button.__itemKey] or nil
            local selfSelection = entry and entry.selections and entry.selections[preview.selfKey or ""] or nil
            local pending = string.lower(TrimText(selfSelection and (selfSelection.optionKey or selfSelection.label) or "pending")) == "pending"
            if pending and not (entry and entry.awardedAt) then
              openSimulationChoicePopup(preview, button.__itemKey)
            end
          end
        end
      else
        RuntimeState.selectedItemKey = button.__itemKey
        if currentFrame.RefreshBoard then
          currentFrame:RefreshBoard()
        end
      end
    end,
    OnResizeStart = function(currentFrame, resizeHandle)
      StartPopupBoardResize(currentFrame, resizeHandle)
    end,
    OnResizeStop = function(currentFrame, resizeHandle)
      StopPopupBoardResize(currentFrame, resizeHandle)
    end,
    OnPrevAssign = function(currentFrame)
      local preview = currentFrame.__previewState
      if preview and preview.isSimulation then
        if not CanSelfAssignSimulationPreview(preview) then
          return
        end
        local entry = preview.items and preview.items[preview.selectedItemKey] or nil
        if entry then
          CyclePreviewSelectedMember(preview, entry, -1)
          currentFrame:RefreshBoard()
        end
        return
      end

      local activeSession, profileName = GetActiveLootSession()
      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      if activeSession and entry then
        EnsureRuntimeSession(activeSession, profileName)
        CycleSelectedMember(activeSession, entry, -1)
        currentFrame:RefreshBoard()
      end
    end,
    OnNextAssign = function(currentFrame)
      local preview = currentFrame.__previewState
      if preview and preview.isSimulation then
        if not CanSelfAssignSimulationPreview(preview) then
          return
        end
        local entry = preview.items and preview.items[preview.selectedItemKey] or nil
        if entry then
          CyclePreviewSelectedMember(preview, entry, 1)
          currentFrame:RefreshBoard()
        end
        return
      end

      local activeSession, profileName = GetActiveLootSession()
      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      if activeSession and entry then
        EnsureRuntimeSession(activeSession, profileName)
        CycleSelectedMember(activeSession, entry, 1)
        currentFrame:RefreshBoard()
      end
    end,
    OnAssign = function(currentFrame)
      local preview = currentFrame.__previewState
      if preview and preview.isSimulation then
        if not CanSelfAssignSimulationPreview(preview) then
          return
        end
        local entry = preview.items and preview.items[preview.selectedItemKey] or nil
        if not entry or entry.awardedAt then
          return
        end
        local _, selectedMember = EnsurePreviewSelectedMember(preview, entry)
        if not selectedMember or TrimText(selectedMember.key) == "" then
          return
        end
        if ApplySimulationAward(preview, entry, selectedMember.key) then
          preview.selectedItemKey = SelectNextUnawardedBoardItem(preview.itemOrder, preview.items, preview.selectedItemKey)
          PersistBoardState(currentFrame)
          currentFrame:RefreshBoard()
          RefreshEditor()
        end
        return
      end

      local activeSession, profileName = GetActiveLootSession()
      if not activeSession or not CanSelfAssignLiveBoard(activeSession, profileName) then
        return
      end
      if not EnsureRuntimeSession(activeSession, profileName) then
        return
      end

      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      if not entry or entry.awardedAt then
        return
      end

      local _, selectedMember = EnsureSelectedMember(activeSession, entry)
      if not selectedMember or TrimText(selectedMember.key) == "" then
        return
      end

      local itemName = type(ResolveRuntimeItemDisplayText) == "function"
        and ResolveRuntimeItemDisplayText(entry, entry.key)
        or (entry.name or entry.key)
      local itemLevel = tonumber(entry.itemLevel)
      local points = ResolveBoardProjectedPoints(profileName, activeSession, entry, selectedMember.key)
      entry.projectedPoints = points
      local note = BuildAwardNote(entry, activeSession)
      local awardChangedAt = (type(GetServerTime) == "function" and GetServerTime()) or (time and time() or 0)
      local ok = ApplyAwardMessage(entry.key, selectedMember.key, itemName, itemLevel, points, note, activeSession, profileName, awardChangedAt)
      if not ok then
        return
      end

      local distribution = GetBroadcastDistribution()
      if distribution and type(SendAwardPacket) == "function" then
        local awardSent, awardSendReason = SendAwardPacket(
          distribution,
          nil,
          activeSession.id,
          GetSessionCommProfileName(activeSession, profileName),
          entry.key,
          selectedMember.key,
          itemName,
          itemLevel or "",
          points,
          note,
          awardChangedAt
        )

        local recipientKey = TrimText(selectedMember.key)
        local selfKey = TrimText(GetSelfKey())
        if awardSent and recipientKey ~= "" and string.lower(recipientKey) ~= string.lower(selfKey) then
          RuntimeState.pendingAwardReceipts = type(RuntimeState.pendingAwardReceipts) == "table"
            and RuntimeState.pendingAwardReceipts
            or {}
          local receiptKey = string.lower(tostring(activeSession.id or ""))
            .. "\031" .. string.lower(TrimText(entry.key))
            .. "\031" .. string.lower(recipientKey)
            .. "\031" .. tostring(awardChangedAt)
          local receipt = {
            sessionId = tostring(activeSession.id or ""),
            profileName = GetSessionCommProfileName(activeSession, profileName),
            memberKey = recipientKey,
            itemKey = TrimText(entry.key),
            itemName = itemName,
            itemLevel = itemLevel,
            points = points,
            note = note,
            changedAt = awardChangedAt,
            attempts = 0,
            state = "waiting",
          }
          RuntimeState.pendingAwardReceipts[receiptKey] = receipt

          local function MarkAwardReceiptUnconfirmed()
            if RuntimeState.pendingAwardReceipts[receiptKey] ~= receipt or receipt.state ~= "waiting" then
              return
            end
            receipt.state = "unconfirmed"
            RuntimeState.lastAwardReceipt = {
              sessionId = receipt.sessionId,
              itemKey = receipt.itemKey,
              memberKey = receipt.memberKey,
              changedAt = receipt.changedAt,
              state = receipt.state,
              attempts = receipt.attempts,
            }
            if type(Print) == "function" then
              Print("Award delivery to " .. receipt.memberKey .. " was not confirmed. It will reconcile during board sync.")
            end
          end

          local function SendAwardReceiptRetry()
            if RuntimeState.pendingAwardReceipts[receiptKey] ~= receipt or receipt.state ~= "waiting" then
              return
            end
            local retrySession = GetActiveLootSession()
            local retryEntry = RuntimeState.items[receipt.itemKey]
            if type(retrySession) ~= "table"
              or tostring(retrySession.id or "") ~= receipt.sessionId
              or not retryEntry
              or string.lower(TrimText(retryEntry.awardedTo)) ~= string.lower(receipt.memberKey)
              or tonumber(retryEntry.awardUpdatedAt or retryEntry.awardedAt) ~= receipt.changedAt
            then
              RuntimeState.pendingAwardReceipts[receiptKey] = nil
              return
            end

            SendAwardPacket(
              "WHISPER",
              receipt.memberKey,
              receipt.sessionId,
              receipt.profileName,
              receipt.itemKey,
              receipt.memberKey,
              receipt.itemName,
              receipt.itemLevel or "",
              receipt.points,
              receipt.note,
              receipt.changedAt
            )
            receipt.attempts = math.max(0, tonumber(receipt.attempts) or 0) + 1
            local retryDelays = { 1.5, 3, 6, 8 }
            local retryDelay = retryDelays[math.min(#retryDelays, receipt.attempts)]
            if type(C_Timer) == "table" and type(C_Timer.After) == "function" then
              C_Timer.After(retryDelay, function()
                if (tonumber(receipt.attempts) or 0) >= #retryDelays then
                  MarkAwardReceiptUnconfirmed()
                else
                  SendAwardReceiptRetry()
                end
              end)
            else
              MarkAwardReceiptUnconfirmed()
            end
          end

          if type(C_Timer) == "table" and type(C_Timer.After) == "function" then
            C_Timer.After(1.5, SendAwardReceiptRetry)
          else
            MarkAwardReceiptUnconfirmed()
          end
        elseif not awardSent and type(Print) == "function" then
          Print(
            "Award delivery could not be queued ("
              .. tostring(awardSendReason or "payload rejected")
              .. "). The next board sync will reconcile it."
          )
        end
      end
      RuntimeState.selectedItemKey = SelectNextUnawardedBoardItem(RuntimeState.itemOrder, RuntimeState.items, RuntimeState.selectedItemKey)
      RefreshBoardAndEditor({
        reason = "award",
        itemKey = entry.key,
      })
    end,
    OnVote = function(currentFrame)
      local preview = GetBoardPreviewState(currentFrame)
      if preview and preview.isSimulation then
        if not CanSelfVoteSimulationPreview(preview) then
          return
        end
        local entry = preview.items and preview.items[preview.selectedItemKey] or nil
        local selectedMember = nil
        if entry then
          local _, resolvedSelectedMember = EnsurePreviewSelectedMember(preview, entry)
          selectedMember = resolvedSelectedMember
        end
        if not entry or not selectedMember or TrimText(selectedMember.key) == "" or entry.awardedAt then
          return
        end
        ToggleBoardVoteForMember(currentFrame, selectedMember.key)
        return
      end

      local activeSession, profileName = GetActiveLootSession()
      if not activeSession or not EnsureRuntimeSession(activeSession, profileName) then
        return
      end
      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      local selectedMember = nil
      if entry then
        local _, resolvedSelectedMember = EnsureSelectedMember(activeSession, entry)
        selectedMember = resolvedSelectedMember
      end
      if not entry or not selectedMember or TrimText(selectedMember.key) == "" or entry.awardedAt then
        return
      end
      ToggleBoardVoteForMember(currentFrame, selectedMember.key)
    end,
    OnChangeRoll = function(currentFrame)
      local activeSession, profileName = GetActiveLootSession()
      if not activeSession or not CanSelfAssignLiveBoard(activeSession, profileName) then
        return
      end
      if not EnsureRuntimeSession(activeSession, profileName) then
        return
      end
      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      if not entry or entry.awardedAt then
        return
      end
      local _, selectedMember = EnsureSelectedMember(activeSession, entry)
      if not selectedMember or TrimText(selectedMember.key) == "" then
        return
      end
      if type(OpenChangeRollPopup) == "function" then
        OpenChangeRollPopup(currentFrame, entry, selectedMember.key)
      end
    end,
    OnUnassign = function(currentFrame)
      local preview = GetBoardPreviewState(currentFrame)
      if preview and preview.isSimulation then
        if not CanSelfAssignSimulationPreview(preview) then
          return
        end
        local entry = preview.items and preview.items[preview.selectedItemKey] or nil
        if not entry or not entry.awardedAt then
          return
        end
        local ok = RemoveAwardFromEntry(preview.profileName, entry)
        if not ok then
          return
        end
      PersistBoardState(currentFrame)
      currentFrame:RefreshBoard()
      RefreshEditor()
      return
      end

      local activeSession, profileName = GetActiveLootSession()
      if not activeSession or not EnsureRuntimeSession(activeSession, profileName) then
        return
      end
      if not CanSelfAssignLiveBoard(activeSession, profileName) then
        return
      end
      local entry = RuntimeState.items[RuntimeState.selectedItemKey]
      if not entry or not entry.awardedAt then
        return
      end
      local awardChangedAt = (type(GetServerTime) == "function" and GetServerTime()) or (time and time() or 0)
      local ok = RemoveAwardFromEntry(profileName, entry, awardChangedAt)
      if not ok then
        return
      end
      local distribution = GetBroadcastDistribution()
      if distribution and type(SendSessionComm) == "function" then
        SendSessionComm(
          "UNASSIGN",
          distribution,
          nil,
          activeSession.id,
          GetSessionCommProfileName(activeSession, profileName),
          entry.key,
          awardChangedAt
        )
      end
      PersistBoardState(currentFrame)
      RefreshBoardAndEditor({
        reason = "unassign",
        itemKey = entry.key,
      })
    end,
  })
  ApplyBoardColumnVisibility(frame)
  RefreshBoardHeaderSortState(frame)

  function frame:RefreshBoard()
    -- Resolve diagnostics here so CreateBoardFrame does not capture additional
    -- upvalues beyond WoW Lua's constructor limit.
    local performanceApi = rawget(_G, "LIDCOUNCIL_API")
    local performanceInternal = type(performanceApi) == "table" and type(performanceApi.__internal) == "table"
      and performanceApi.__internal
      or nil
    local function BeginBoardPerformanceSample(metricName)
      local beginSample = type(performanceInternal) == "table"
        and performanceInternal.LIDCOUNCIL_BeginSyncPerformanceSample_Impl
        or nil
      if type(beginSample) == "function" then
        return beginSample(metricName, 1)
      end
      return nil
    end
    local function RecordBoardPerformanceSample(metricName, startedAt, metadata)
      local recordSample = type(performanceInternal) == "table"
        and performanceInternal.LIDCOUNCIL_RecordSyncPerformance_Impl
        or nil
      if type(recordSample) == "function" then
        recordSample(metricName, startedAt, metadata)
      end
    end
    local refreshStartedAt = BeginBoardPerformanceSample("live_board_refresh_total")
    local phaseStartedAt = BeginBoardPerformanceSample("live_board_refresh_layout")
    ApplyBoardColumnVisibility(self)
    LayoutBoardFrame(self)
    RefreshBoardHeaderSortState(self)
    RecordBoardPerformanceSample("live_board_refresh_layout", phaseStartedAt)
    if self.boardSyncBtn then
      self.boardSyncBtn:Disable()
    end
    if self.tradeHelperBtn then
      self.tradeHelperBtn:Disable()
    end
    if self.tradeHelperBadge then
      self.tradeHelperBadge:Hide()
    end
    if RenderPreviewBoard(self) then
      if UIState.collapsed then
        SetBoardCollapsed(self, true)
      end
      return
    end
    local activeSession, profileName = GetActiveLootSession()
    if not activeSession or not EnsureRuntimeSession(activeSession, profileName) then
      self.note:SetText("No active LidCouncil session is currently running.")
      if self.leftHeader then
        self.leftHeader:SetText("Dropped Items (0)")
      end
      if self.assignedHeader then
        self.assignedHeader:SetText("Assigned Items (0)")
      end
      if self.tradedHeader then
        self.tradedHeader:SetText("Traded Items (0)")
      end
      for _, button in ipairs(self.itemButtons or {}) do
        button:Hide()
        button.__itemKey = nil
        button.__itemListOffsetY = nil
      end
      self.__assignedHeaderOffsetY = nil
      if self.assignedHeader then
        self.assignedHeader:Hide()
      end
      self.__tradedHeaderOffsetY = nil
      if self.tradedHeader then
        self.tradedHeader:Hide()
      end
      self.detailIcon:SetTexture(nil)
      SetLiveBoardDetailTooltipState(self, nil, "")
      self.detailTitle:SetText("")
      self.detailMeta:SetText("")
      self.assignTarget:SetText("")
      SetBoardAwardStatus(self)
      UpdateBoardMemberRows(self, {}, nil, nil, nil, nil)
      UpdateAssignDropdown(self, {}, nil, "No active session")
      self.prevAssignBtn:Hide()
      self.prevAssignBtn:Disable()
      self.nextAssignBtn:Hide()
      self.nextAssignBtn:Disable()
      self.assignBtn:Disable()
      self.voteBtn:Disable()
      self.unassignBtn:Disable()
      self.unassignBtn:Hide()
      self.__showUnassignBtn = false
      if self.changeRollBtn then
        self.changeRollBtn:Disable()
        self.changeRollBtn:Hide()
        self.__showChangeRollBtn = false
      end
      if UIState.collapsed then
        SetBoardCollapsed(self, true)
      end
      return
    end

    if not CanSelfAssignLiveBoard(activeSession, profileName) then
      self.note:SetText("Council members can review the Live Board and cast votes here. Only the session host can assign or unassign items.")
    else
      self.note:SetText("Live loot selection and assignment board for the session host. Awarding an item here applies points into the Loot List for the whole session.")
    end
    if self.boardSyncBtn then
      if CanSelfAssignLiveBoard(activeSession, profileName) and not self.boardSyncBtn.__lidBoardSyncCooldown then
        self.boardSyncBtn:Enable()
      else
        self.boardSyncBtn:Disable()
      end
    end
    if self.tradeHelperBtn then
      if CanSelfAssignLiveBoard(activeSession, profileName) then
        self.tradeHelperBtn:Enable()
      else
        self.tradeHelperBtn:Disable()
      end
    end
    if self.tradeHelperBadge then
      local pendingTradeCount = CountPendingTradeAssignments()
      self.tradeHelperBadge:SetShown(CanSelfAssignLiveBoard(activeSession, profileName) and pendingTradeCount > 0)
      if pendingTradeCount > 0 and self.tradeHelperBadge.text then
        self.tradeHelperBadge.text:SetText(tostring(pendingTradeCount))
      end
    end

    phaseStartedAt = BeginBoardPerformanceSample("live_board_refresh_items")
    RenderBoardItemButtons(self, RuntimeState.itemOrder, RuntimeState.items, RuntimeState.selectedItemKey)
    RecordBoardPerformanceSample("live_board_refresh_items", phaseStartedAt, {
      itemCount = #(RuntimeState.itemOrder or {}),
    })

    local selected = RuntimeState.items[RuntimeState.selectedItemKey]
    if not selected and #RuntimeState.itemOrder > 0 then
      RuntimeState.selectedItemKey = RuntimeState.itemOrder[#RuntimeState.itemOrder]
      selected = RuntimeState.items[RuntimeState.selectedItemKey]
    end
    if not selected then
      self.detailIcon:SetTexture(nil)
      SetLiveBoardDetailTooltipState(self, nil, "")
      self.detailTitle:SetText("No tracked loot items yet.")
      self.detailMeta:SetText("")
      self.assignTarget:SetText("")
      SetBoardAwardStatus(self)
      UpdateBoardMemberRows(self, {}, nil, nil, nil, nil)
      UpdateAssignDropdown(self, {}, nil, "No tracked items")
      self.prevAssignBtn:Hide()
      self.prevAssignBtn:Disable()
      self.nextAssignBtn:Hide()
      self.nextAssignBtn:Disable()
      self.assignBtn:Disable()
      self.voteBtn:Disable()
      self.unassignBtn:Disable()
      self.unassignBtn:Hide()
      self.__showUnassignBtn = false
      if self.changeRollBtn then
        self.changeRollBtn:Disable()
        self.changeRollBtn:Hide()
        self.__showChangeRollBtn = false
      end
      if UIState.collapsed then
        SetBoardCollapsed(self, true)
      end
      return
    end

    self.detailIcon:SetTexture(selected.icon)
    SetLiveBoardDetailTooltipState(self, selected, RuntimeState.selectedItemKey)
    local isRealSimulationItem = IsRealSimulationItemKey(selected.key)
    self.detailTitle:SetText(type(ResolveRuntimeItemDisplayText) == "function"
      and ResolveRuntimeItemDisplayText(selected, selected.key)
      or (selected.name or selected.key))
    local detailMetaLabel = isRealSimulationItem and "Real Simulation - points will not be saved" or ("Item Key: " .. tostring(selected.key))
    if isRealSimulationItem then
      local sourceParts = {}
      if TrimText(selected.instanceName) ~= "" then
        sourceParts[#sourceParts + 1] = tostring(selected.instanceName)
      end
      if TrimText(selected.encounterName) ~= "" then
        sourceParts[#sourceParts + 1] = tostring(selected.encounterName)
      end
      if #sourceParts > 0 then
        detailMetaLabel = detailMetaLabel .. " | " .. table.concat(sourceParts, " / ")
      end
    end
    self.detailMeta:SetText(
      string.format(
        "%s%s",
        detailMetaLabel,
        selected.itemLevel and (" | Item Level: " .. tostring(selected.itemLevel)) or ""
      )
    )

    local memberRows, selectedMember = EnsureSelectedMember(activeSession, selected)
    phaseStartedAt = BeginBoardPerformanceSample("live_board_refresh_ledger")
    local totalsByCharacter = ResolveLootLedgerTotals(profileName)
    RecordBoardPerformanceSample("live_board_refresh_ledger", phaseStartedAt, {
      memberCount = #memberRows,
    })

    if IsManualVisibleBoardEntry(selected) then
      self.assignTarget:SetText(BuildAssignmentTargetText(nil, nil, "Non-council visibility only"))
    elseif selectedMember then
      local selection = selectedMember.selection or (selected.selections and selected.selections[selectedMember.key] or nil)
      local selectionLabel = FormatSelectionLabel(selection)
      self.assignTarget:SetText(BuildAssignmentTargetText(selectedMember, selectionLabel))
    else
      self.assignTarget:SetText(BuildAssignmentTargetText(nil, nil, "None selected"))
    end
    local pendingRollCount, resolvedRollCount = CountPendingBoardSelections(memberRows)

    if IsManualVisibleBoardEntry(selected) then
      SetBoardAwardStatus(
        self,
        "success",
        "Non-Council Item",
        BuildAwardStatusDetail(profileName, selected)
      )
    elseif selected.awardedAt and selected.awardedTo then
      SetBoardAwardStatus(
        self,
        "complete",
        "Award Complete",
        BuildAwardStatusDetail(profileName, selected)
      )
    else
      local projectedPoints = ResolveBoardProjectedPoints(profileName, activeSession, selected, selectedMember and selectedMember.key or nil)
      selected.projectedPoints = projectedPoints
      if pendingRollCount > 0 then
        SetBoardAwardStatus(
          self,
          "warning",
          "Responses pending",
          isRealSimulationItem
            and string.format("%d pending.", pendingRollCount)
            or string.format(
              "%d pending | Projected award: %d point(s).",
              pendingRollCount,
              projectedPoints
            )
        )
      else
        SetBoardAwardStatus(
          self,
          "ready",
          "All responses received",
          isRealSimulationItem
            and ""
            or string.format("Projected award: %d point(s).", projectedPoints)
        )
      end
    end

    phaseStartedAt = BeginBoardPerformanceSample("live_board_refresh_members")
    UpdateBoardMemberRows(self, memberRows, RuntimeState.selectedMemberKey, totalsByCharacter, ResolveEntryVotedKey(selected), selected.awardedTo, selected)
    UpdateAssignDropdown(
      self,
      memberRows,
      selectedMember,
      IsManualVisibleBoardEntry(selected) and "Non-council visibility only" or (pendingRollCount > 0 and "Await rolls" or "Select session member")
    )
    RecordBoardPerformanceSample("live_board_refresh_members", phaseStartedAt, {
      memberCount = #memberRows,
    })
    if not CanSelfAssignLiveBoard(activeSession, profileName) or selected.awardedAt or not selectedMember or IsManualVisibleBoardEntry(selected) then
      self.assignBtn:Disable()
    else
      self.assignBtn:Enable()
    end
    if #memberRows > 1 and CanSelfAssignLiveBoard(activeSession, profileName) then
      self.prevAssignBtn:Hide()
      self.prevAssignBtn:Disable()
      self.nextAssignBtn:Hide()
      self.nextAssignBtn:Disable()
    else
      self.prevAssignBtn:Hide()
      self.prevAssignBtn:Disable()
      self.nextAssignBtn:Hide()
      self.nextAssignBtn:Disable()
    end
    if self.voteBtn then
      self.voteBtn:Hide()
    end
    local canUnassign = selected.awardedAt and CanSelfAssignLiveBoard(activeSession, profileName) and not IsManualVisibleBoardEntry(selected)
    self.__showUnassignBtn = canUnassign
    self.unassignBtn:SetShown(canUnassign)
    if canUnassign then
      self.unassignBtn:Enable()
    else
      self.unassignBtn:Disable()
    end
    if self.changeRollBtn then
      local canChangeRoll = CanSelfAssignLiveBoard(activeSession, profileName) and selectedMember and not selected.awardedAt and not IsManualVisibleBoardEntry(selected)
      self.__showChangeRollBtn = canChangeRoll
      self.changeRollBtn:SetShown(canChangeRoll)
      if canChangeRoll then
        self.changeRollBtn:Enable()
      else
        self.changeRollBtn:Disable()
      end
    end
    if UIState.collapsed then
      SetBoardCollapsed(self, true)
    end
    if IsManualVisibleBoardEntry(selected) then
      self.assignBtn:SetText("Non-Council Item")
    elseif selected.awardedAt then
      self.assignBtn:SetText("Item Awarded")
    else
      self.assignBtn:SetText("Assign Item")
    end
    RecordBoardPerformanceSample("live_board_refresh_total", refreshStartedAt, {
      itemCount = #(RuntimeState.itemOrder or {}),
      memberCount = #memberRows,
    })
  end

  frame:HookScript("OnSizeChanged", function(self)
    if self.__resizing then
      return
    end
    if EnforcePopupBoardMinimumSize(self) then
      return
    end
    if not self.__embeddedParent and not UIState.collapsed then
      CapturePopupBoardGeometry(self)
    end
    if self.__embeddedParent or not UIState.collapsed then
      LayoutBoardFrame(self)
    end
  end)
  frame:HookScript("OnHide", function(self)
    if self.__resizing then
      StopPopupBoardResize(self, self.resizeHandle)
    end
  end)

  LayoutBoardFrame(frame)
  UIState.boardFrame = frame
  return frame
end

local function OpenLiveLootBoard()
  local frame = CreateBoardFrame()
  ApplyPopupBoardLayout(frame)
  frame.__previewState = GetBoardPreviewState(frame)
  frame:Show()
  frame:RefreshBoard()
  SetBoardCollapsed(frame, UIState.collapsed)
end

local function CloseLiveLootBoard()
  if UIState.boardFrame then
    UIState.boardFrame:Hide()
  end
end

local function AttachLiveLootBoard(parent)
  local performanceApi = rawget(_G, "LIDCOUNCIL_API")
  local performanceInternal = type(performanceApi) == "table" and type(performanceApi.__internal) == "table"
    and performanceApi.__internal
    or nil
  local function BeginBoardPerformanceSample(metricName)
    local beginSample = type(performanceInternal) == "table"
      and performanceInternal.LIDCOUNCIL_BeginSyncPerformanceSample_Impl
      or nil
    if type(beginSample) == "function" then
      return beginSample(metricName, 1)
    end
    return nil
  end
  local function RecordBoardPerformanceSample(metricName, startedAt, metadata)
    local recordSample = type(performanceInternal) == "table"
      and performanceInternal.LIDCOUNCIL_RecordSyncPerformance_Impl
      or nil
    if type(recordSample) == "function" then
      recordSample(metricName, startedAt, metadata)
    end
  end
  local attachStartedAt = BeginBoardPerformanceSample("live_board_attach_total")
  local frame = CreateBoardFrame()
  frame.__previewState = GetBoardPreviewState(frame)
  local phaseStartedAt = BeginBoardPerformanceSample("live_board_attach_layout")
  ApplyEmbeddedBoardLayout(frame, parent)
  frame:Show()
  RecordBoardPerformanceSample("live_board_attach_layout", phaseStartedAt)
  phaseStartedAt = BeginBoardPerformanceSample("live_board_attach_render")
  frame:RefreshBoard()
  RecordBoardPerformanceSample("live_board_attach_render", phaseStartedAt)
  phaseStartedAt = BeginBoardPerformanceSample("live_board_attach_finalize")
  SetBoardCollapsed(frame, false)
  RecordBoardPerformanceSample("live_board_attach_finalize", phaseStartedAt)
  RecordBoardPerformanceSample("live_board_attach_total", attachStartedAt)
end

local function PopoutLiveLootBoard()
  local frame = CreateBoardFrame()
  ApplyPopupBoardLayout(frame)
  frame.__previewState = GetBoardPreviewState(frame)
  frame:Show()
  frame:RefreshBoard()
  SetBoardCollapsed(frame, UIState.collapsed)
end

local function PreviewLiveLootBoard(profileName)
  local frame = CreateBoardFrame()
  ApplyPopupBoardLayout(frame)
  SetBoardPreviewState(frame, BuildPreviewBoardState(profileName))
  PersistBoardState(frame)
  frame:Show()
  frame:RefreshBoard()
  SetBoardCollapsed(frame, false)
end

local function RefreshLiveLootBoard()
  local frame = UIState.boardFrame
  if frame and frame.RefreshBoard then
    frame.__previewState = GetBoardPreviewState(frame)
    frame:RefreshBoard()
    return true
  end
  return false
end

INTERNAL_API.LIDCOUNCIL_CreateBoardFrame_Impl = CreateBoardFrame
INTERNAL_API.LIDCOUNCIL_ApplyPopupBoardLayout_Impl = ApplyPopupBoardLayout
INTERNAL_API.LIDCOUNCIL_ApplyEmbeddedBoardLayout_Impl = ApplyEmbeddedBoardLayout
INTERNAL_API.LIDCOUNCIL_SetBoardCollapsed_Impl = SetBoardCollapsed
INTERNAL_API.LIDCOUNCIL_OpenLiveLootBoard_Impl = OpenLiveLootBoard
INTERNAL_API.LIDCOUNCIL_CloseLiveLootBoard_Impl = CloseLiveLootBoard
INTERNAL_API.LIDCOUNCIL_AttachLiveLootBoard_Impl = AttachLiveLootBoard
INTERNAL_API.LIDCOUNCIL_PopoutLiveLootBoard_Impl = PopoutLiveLootBoard
INTERNAL_API.LIDCOUNCIL_PreviewLiveLootBoard_Impl = PreviewLiveLootBoard
INTERNAL_API.LIDCOUNCIL_RefreshLiveLootBoard_Impl = RefreshLiveLootBoard
