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

INTERNAL_API.LIDCOUNCIL_CreateLootBoardScaffoldHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local ApplyFrameSkin = deps.ApplyFrameSkin
  local ResolveOptionalFunction = deps.ResolveOptionalFunction
  local BindPopupBoardDragScripts = deps.BindPopupBoardDragScripts
  local ApplyPopupBoardResizeLimits = deps.ApplyPopupBoardResizeLimits
  local RaisePopupFrameAboveEditor = deps.RaisePopupFrameAboveEditor
  local ApplyBoardButtonStyle = deps.ApplyBoardButtonStyle
  local ApplyBoardSectionSkin = deps.ApplyBoardSectionSkin
  local StartPopupBoardResize = deps.StartPopupBoardResize
  local StopPopupBoardResize = deps.StopPopupBoardResize
  local ShowBoardItemTooltip = deps.ShowBoardItemTooltip
  local HideBoardItemTooltip = deps.HideBoardItemTooltip
  local TrimText = deps.TrimText
  local DEFAULT_POPUP_BOARD_WIDTH = tonumber(deps.DEFAULT_POPUP_BOARD_WIDTH) or 760
  local DEFAULT_POPUP_BOARD_HEIGHT = tonumber(deps.DEFAULT_POPUP_BOARD_HEIGHT) or 560
  local OPTIONAL_MEMBER_COLUMNS = {
    { key = "items", label = "Items", tooltip = "Received items" },
    { key = "offspec", label = "OS", tooltip = "Off-Spec items" },
    { key = "transmog", label = "TM", tooltip = "Transmog items" },
    { key = "disenchant", label = "DE", tooltip = "Disenchant items" },
    { key = "total", label = "Points", tooltip = "Total points" },
    { key = "bis", label = "BiS", tooltip = "Best in Slot items" },
  }

  local function CreateBoardFrameScaffold(callbacks)
    callbacks = type(callbacks) == "table" and callbacks or {}
    local BuildBoardHeaderButton = callbacks.BuildBoardHeaderButton

    local frame = CreateFrame("Frame", "LIDCOUNCIL_LiveLootBoard", UIParent, "BackdropTemplate")
    frame:SetSize(DEFAULT_POPUP_BOARD_WIDTH, DEFAULT_POPUP_BOARD_HEIGHT)
    frame:SetPoint("CENTER", 0, 40)
    frame:SetFrameStrata("FULLSCREEN_DIALOG")
    frame:SetMovable(true)
    frame:SetResizable(true)
    frame:SetToplevel(true)
    frame:EnableMouse(true)
    if type(BindPopupBoardDragScripts) == "function" then
      BindPopupBoardDragScripts(frame)
    end
    if type(ApplyPopupBoardResizeLimits) == "function" then
      ApplyPopupBoardResizeLimits(frame)
    end
    if type(ApplyFrameSkin) == "function" then
      ApplyFrameSkin(frame)
    end
    frame:HookScript("OnShow", function(self)
      if not self.__embeddedParent and type(RaisePopupFrameAboveEditor) == "function" then
        RaisePopupFrameAboveEditor(self, "FULLSCREEN_DIALOG")
      end
    end)
    frame:Hide()

    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 16, -14)
    title:SetJustifyH("LEFT")
    title:SetText("LidCouncil Live Board")
    frame.title = title
    local titleWidth = math.max(160, math.ceil((title.GetStringWidth and title:GetStringWidth()) or 180))

    local note = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    note:SetPoint("TOPLEFT", 16, -38)
    note:SetWidth(724)
    note:SetJustifyH("LEFT")
    note:SetText("Live loot selection board for the session host.")
    frame.note = note

    local closeBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    closeBtn:SetSize(70, 22)
    closeBtn:SetPoint("TOPRIGHT", -16, -12)
    closeBtn:SetText("Close")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(closeBtn)
    end
    if type(callbacks.OnClose) == "function" then
      closeBtn:SetScript("OnClick", function()
        callbacks.OnClose(frame)
      end)
    end
    frame.closeBtn = closeBtn

    local collapseBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    collapseBtn:SetSize(74, 22)
    collapseBtn:SetPoint("TOPLEFT", 16 + titleWidth + 12, -12)
    collapseBtn:SetText("Collapse")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(collapseBtn)
    end
    if type(callbacks.OnCollapse) == "function" then
      collapseBtn:SetScript("OnClick", function()
        callbacks.OnCollapse(frame)
      end)
    end
    frame.collapseBtn = collapseBtn

    local boardSyncBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    boardSyncBtn:SetSize(116, 22)
    boardSyncBtn:SetPoint("LEFT", collapseBtn, "RIGHT", 8, 0)
    boardSyncBtn:SetText("Send Board Sync")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(boardSyncBtn)
    end
    if type(callbacks.OnSendBoardSync) == "function" then
      boardSyncBtn:SetScript("OnClick", function()
        callbacks.OnSendBoardSync(frame)
      end)
    end
    frame.boardSyncBtn = boardSyncBtn

    local tradeHelperBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    tradeHelperBtn:SetSize(104, 22)
    tradeHelperBtn:SetPoint("LEFT", boardSyncBtn, "RIGHT", 8, 0)
    tradeHelperBtn:SetText("Trade Helper")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(tradeHelperBtn)
    end
    if type(callbacks.OnTradeHelper) == "function" then
      tradeHelperBtn:SetScript("OnClick", function()
        callbacks.OnTradeHelper(frame)
      end)
    end
    frame.tradeHelperBtn = tradeHelperBtn

    local itemsPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(itemsPanel)
    end
    frame.itemsPanel = itemsPanel

    local selectionPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(selectionPanel)
    end
    frame.selectionPanel = selectionPanel

    local assignmentPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(assignmentPanel)
    end
    frame.assignmentPanel = assignmentPanel

    local membersPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(membersPanel)
    end
    frame.membersPanel = membersPanel

    local leftHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    leftHeader:SetPoint("TOPLEFT", 18, -72)
    leftHeader:SetText("Dropped Items")
    frame.leftHeader = leftHeader

    local assignedHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    assignedHeader:SetPoint("TOPLEFT", 18, -120)
    assignedHeader:SetText("Assigned Items")
    assignedHeader:Hide()
    frame.assignedHeader = assignedHeader

    local tradedHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    tradedHeader:SetPoint("TOPLEFT", 18, -148)
    tradedHeader:SetText("Traded Items")
    tradedHeader:Hide()
    frame.tradedHeader = tradedHeader

    local rightHeader = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    rightHeader:SetPoint("TOPLEFT", 268, -72)
    rightHeader:SetText("Selections")
    frame.rightHeader = rightHeader

    local memberSectionTitle = membersPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    memberSectionTitle:SetPoint("TOPLEFT", 268, -292)
    memberSectionTitle:SetText("Table Overview")
    frame.memberSectionTitle = memberSectionTitle

    local memberColumnToggleFrame = CreateFrame("Frame", nil, membersPanel)
    memberColumnToggleFrame:SetSize(470, 22)
    frame.memberColumnToggleFrame = memberColumnToggleFrame
    frame.memberColumnToggles = {}
    for index, column in ipairs(OPTIONAL_MEMBER_COLUMNS) do
      local check = CreateFrame("CheckButton", nil, memberColumnToggleFrame, "UICheckButtonTemplate")
      check:SetSize(20, 20)
      check.__columnKey = column.key
      check.__columnLabel = column.label
      check.__tooltipText = column.tooltip
      local text = check:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      text:SetPoint("LEFT", check, "RIGHT", -1, 0)
      text:SetText(column.label)
      check.text = text
      check:SetScript("OnClick", function(self)
        if type(callbacks.OnToggleMemberColumn) == "function" then
          callbacks.OnToggleMemberColumn(frame, self.__columnKey, self:GetChecked() and true or false)
        end
      end)
      check:SetScript("OnEnter", function(self)
        if type(GameTooltip) == "table" and TrimText(self.__tooltipText) ~= "" then
          GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
          GameTooltip:SetText(tostring(self.__tooltipText), 1.00, 0.92, 0.35, 1.00, true)
          GameTooltip:Show()
        end
      end)
      check:SetScript("OnLeave", function()
        if type(GameTooltip) == "table" then
          GameTooltip:Hide()
        end
      end)
      frame.memberColumnToggles[index] = check
    end

    frame.itemButtons = {}
    for i = 1, 14 do
      local button = CreateFrame("Button", nil, itemsPanel)
      button:SetSize(220, 22)
      button:SetPoint("TOPLEFT", 16, -76 - (i * 24))
      button:EnableMouse(true)
      local bg = button:CreateTexture(nil, "BACKGROUND")
      bg:SetAllPoints(true)
      bg:SetTexture("Interface\\Buttons\\WHITE8x8")
      bg:SetVertexColor(0.09, 0.08, 0.10, 0.92)
      button.__bg = bg
      local highlight = button:CreateTexture(nil, "ARTWORK")
      highlight:SetAllPoints(true)
      highlight:SetTexture("Interface\\Buttons\\WHITE8x8")
      highlight:SetVertexColor(0.90, 0.74, 0.18, 0.12)
      highlight:Hide()
      button.__highlight = highlight
      local itemIcon = button:CreateTexture(nil, "ARTWORK")
      itemIcon:SetSize(16, 16)
      itemIcon:SetPoint("LEFT", 6, 0)
      button.itemIcon = itemIcon
      local itemText = button:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      itemText:SetPoint("LEFT", button, "LEFT", 28, 0)
      itemText:SetPoint("RIGHT", button, "RIGHT", -6, 0)
      itemText:SetJustifyH("LEFT")
      button.itemText = itemText
      if type(callbacks.OnItemEnter) == "function" then
        button:SetScript("OnEnter", function(self)
          callbacks.OnItemEnter(frame, self)
        end)
      end
      if type(callbacks.OnItemLeave) == "function" then
        button:SetScript("OnLeave", function(self)
          callbacks.OnItemLeave(frame, self)
        end)
      end
      if type(callbacks.OnItemClick) == "function" then
        button:SetScript("OnClick", function(self)
          callbacks.OnItemClick(frame, self)
        end)
      end
      button:Hide()
      frame.itemButtons[i] = button
    end

    local resizeHandle = CreateFrame("Button", nil, frame)
    resizeHandle:SetSize(16, 16)
    resizeHandle:SetPoint("BOTTOMRIGHT", -6, 6)
    resizeHandle:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
    resizeHandle:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeHandle:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
    resizeHandle:RegisterForDrag("LeftButton")
    if type(callbacks.OnResizeStart) == "function" then
      resizeHandle:SetScript("OnDragStart", function(self)
        callbacks.OnResizeStart(frame, self)
      end)
    elseif type(StartPopupBoardResize) == "function" then
      resizeHandle:SetScript("OnDragStart", function(self)
        StartPopupBoardResize(frame, self)
      end)
    end
    if type(callbacks.OnResizeStop) == "function" then
      resizeHandle:SetScript("OnDragStop", function(self)
        callbacks.OnResizeStop(frame, self)
      end)
      resizeHandle:SetScript("OnMouseUp", function(self)
        callbacks.OnResizeStop(frame, self)
      end)
    elseif type(StopPopupBoardResize) == "function" then
      resizeHandle:SetScript("OnDragStop", function(self)
        StopPopupBoardResize(frame, self)
      end)
      resizeHandle:SetScript("OnMouseUp", function(self)
        StopPopupBoardResize(frame, self)
      end)
    end
    frame.resizeHandle = resizeHandle

    local detailIcon = selectionPanel:CreateTexture(nil, "ARTWORK")
    detailIcon:SetSize(32, 32)
    detailIcon:SetPoint("TOPLEFT", 268, -92)
    frame.detailIcon = detailIcon

    local detailTooltipButton = CreateFrame("Button", nil, selectionPanel)
    detailTooltipButton:SetPoint("TOPLEFT", detailIcon, "TOPLEFT", 0, 0)
    detailTooltipButton:SetSize(32, 32)
    detailTooltipButton:EnableMouse(false)
    detailTooltipButton:SetScript("OnEnter", function(self)
      if type(ShowBoardItemTooltip) == "function" then
        ShowBoardItemTooltip(self)
      end
    end)
    detailTooltipButton:SetScript("OnLeave", function()
      if type(HideBoardItemTooltip) == "function" then
        HideBoardItemTooltip()
      end
    end)
    frame.detailTooltipButton = detailTooltipButton

    local detailTitle = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    detailTitle:SetPoint("TOPLEFT", detailIcon, "TOPRIGHT", 10, -2)
    detailTitle:SetWidth(430)
    detailTitle:SetJustifyH("LEFT")
    frame.detailTitle = detailTitle

    local detailMeta = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    detailMeta:SetPoint("TOPLEFT", detailIcon, "BOTTOMLEFT", 0, -10)
    detailMeta:SetWidth(470)
    detailMeta:SetJustifyH("LEFT")
    frame.detailMeta = detailMeta

    local assignHeader = assignmentPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    assignHeader:SetPoint("TOPLEFT", 268, -158)
    assignHeader:SetText("Assignment")
    frame.assignHeader = assignHeader

    local assignTarget = assignmentPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    assignTarget:SetPoint("TOPLEFT", 268, -182)
    assignTarget:SetWidth(466)
    assignTarget:SetJustifyH("LEFT")
    if assignTarget.SetWordWrap then
      assignTarget:SetWordWrap(true)
    end
    assignTarget:SetText("")
    frame.assignTarget = assignTarget

    local createCustomDropdown = type(ResolveOptionalFunction) == "function" and ResolveOptionalFunction("LIDCOUNCIL_CreateCustomDropdownControl") or nil
    if type(createCustomDropdown) == "function" then
      local assignDropdown = createCustomDropdown(rawget(_G, "LIDCOUNCIL_Editor"), assignmentPanel, {
        width = 280,
        text = "Select session member",
      })
      assignDropdown:SetPoint("TOPLEFT", 268, -230)
      frame.assignDropdown = assignDropdown
    end

    local prevAssignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    prevAssignBtn:SetSize(70, 22)
    prevAssignBtn:SetPoint("TOPLEFT", 268, -208)
    prevAssignBtn:SetText("Prev")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(prevAssignBtn)
    end
    prevAssignBtn:Hide()
    if type(callbacks.OnPrevAssign) == "function" then
      prevAssignBtn:SetScript("OnClick", function()
        callbacks.OnPrevAssign(frame)
      end)
    end
    frame.prevAssignBtn = prevAssignBtn

    local nextAssignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    nextAssignBtn:SetSize(70, 22)
    nextAssignBtn:SetPoint("LEFT", prevAssignBtn, "RIGHT", 8, 0)
    nextAssignBtn:SetText("Next")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(nextAssignBtn)
    end
    nextAssignBtn:Hide()
    if type(callbacks.OnNextAssign) == "function" then
      nextAssignBtn:SetScript("OnClick", function()
        callbacks.OnNextAssign(frame)
      end)
    end
    frame.nextAssignBtn = nextAssignBtn

    local assignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    assignBtn:SetSize(150, 22)
    if frame.assignDropdown then
      assignBtn:SetPoint("LEFT", frame.assignDropdown, "RIGHT", 12, 0)
    else
      assignBtn:SetPoint("TOPLEFT", 268, -230)
    end
    assignBtn:SetText("Assign Item")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(assignBtn)
    end
    if type(callbacks.OnAssign) == "function" then
      assignBtn:SetScript("OnClick", function()
        callbacks.OnAssign(frame)
      end)
    end
    frame.assignBtn = assignBtn

    local voteBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    voteBtn:SetSize(70, 22)
    voteBtn:SetPoint("TOPLEFT", 268, -238)
    voteBtn:SetText("Vote")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(voteBtn)
    end
    voteBtn:Hide()
    if type(callbacks.OnVote) == "function" then
      voteBtn:SetScript("OnClick", function()
        callbacks.OnVote(frame)
      end)
    end
    frame.voteBtn = voteBtn

    local unassignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    unassignBtn:SetSize(86, 22)
    unassignBtn:SetPoint("TOPLEFT", 268, -116)
    unassignBtn:SetText("Unassign")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(unassignBtn)
    end
    if type(callbacks.OnUnassign) == "function" then
      unassignBtn:SetScript("OnClick", function()
        callbacks.OnUnassign(frame)
      end)
    end
    frame.unassignBtn = unassignBtn

    local changeRollBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    changeRollBtn:SetSize(96, 22)
    changeRollBtn:SetPoint("LEFT", unassignBtn, "RIGHT", 10, 0)
    changeRollBtn:SetText("Change Roll")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(changeRollBtn)
    end
    if type(callbacks.OnChangeRoll) == "function" then
      changeRollBtn:SetScript("OnClick", function()
        callbacks.OnChangeRoll(frame)
      end)
    end
    frame.changeRollBtn = changeRollBtn

    local awardStatusBox = CreateFrame("Frame", nil, assignmentPanel, "BackdropTemplate")
    if type(ApplyFrameSkin) == "function" then
      ApplyFrameSkin(awardStatusBox)
    end
    if awardStatusBox.SetBackdropColor then
      awardStatusBox:SetBackdropColor(0.07, 0.08, 0.11, 0.94)
    end
    if awardStatusBox.SetFrameLevel and assignmentPanel.GetFrameLevel then
      awardStatusBox:SetFrameLevel((assignmentPanel:GetFrameLevel() or 1) + 1)
    end
    awardStatusBox:Hide()
    frame.awardStatusBox = awardStatusBox

    local awardStatus = awardStatusBox:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    awardStatus:SetPoint("TOPLEFT", awardStatusBox, "TOPLEFT", 8, -7)
    awardStatus:SetWidth(450)
    awardStatus:SetJustifyH("LEFT")
    awardStatus:SetJustifyV("TOP")
    if awardStatus.SetWordWrap then
      awardStatus:SetWordWrap(true)
    end
    awardStatus:SetText("")
    frame.awardStatus = awardStatus

    local memberHeader = CreateFrame("Frame", nil, membersPanel)
    memberHeader:SetPoint("TOPLEFT", 268, -292)
    memberHeader:SetSize(470, 18)
    frame.memberHeader = memberHeader

    local function MakeMemberHeader(parent, textValue, x, width, justify, sortKey, tooltipText)
      local widget
      if type(BuildBoardHeaderButton) == "function" and ((type(TrimText) == "function" and (TrimText(sortKey) ~= "" or TrimText(tooltipText) ~= "")) or type(TrimText) ~= "function") then
        widget = BuildBoardHeaderButton(frame, parent, textValue, sortKey, tooltipText or "", width, justify or "LEFT")
      else
        widget = parent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        widget:SetWidth(width)
        widget:SetJustifyH(justify or "LEFT")
        widget:SetText(textValue)
      end
      widget:SetPoint("LEFT", x, 0)
      return widget
    end

    frame.memberHeaderName = MakeMemberHeader(memberHeader, "Raider", 8, 240, "LEFT", "name", "Character-Realm")
    frame.memberHeaderRoll = MakeMemberHeader(memberHeader, "Roll", 252, 110, "LEFT", "roll", "Selected roll option")
    frame.memberHeaderDice = MakeMemberHeader(memberHeader, "Dice", 366, 42, "RIGHT", "dice", "Dice roll (1-100)")
    frame.memberHeaderItems = MakeMemberHeader(memberHeader, "Items", 410, 38, "RIGHT", "items", "Received items")
    frame.memberHeaderOffSpec = MakeMemberHeader(memberHeader, "OS", 454, 28, "RIGHT", "offspec", "Off-Spec items")
    frame.memberHeaderTransmog = MakeMemberHeader(memberHeader, "TM", 488, 28, "RIGHT", "transmog", "Transmog items")
    frame.memberHeaderDisenchant = MakeMemberHeader(memberHeader, "DE", 522, 28, "RIGHT", "disenchant", "Disenchant items")
    frame.memberHeaderTotal = MakeMemberHeader(memberHeader, "Pts", 556, 52, "RIGHT", "total", "Total Points")
    frame.memberHeaderBis = MakeMemberHeader(memberHeader, "BiS", 614, 32, "RIGHT", "bis", "Received Best in Slot items")
    frame.memberHeaderState = MakeMemberHeader(memberHeader, "State", 510, 62, "LEFT", "state", "Roll state")
    frame.memberHeaderVote = MakeMemberHeader(memberHeader, "Vote", 576, 50, "LEFT", "", "Cast or clear your vote")
    frame.memberHeaderVotes = MakeMemberHeader(memberHeader, "Votes", 630, 32, "RIGHT", "votes", "Number of votes")
    frame.__memberSortKey = "roll"
    frame.__memberSortDescending = false

    local memberScroll = CreateFrame("ScrollFrame", nil, membersPanel, "UIPanelScrollFrameTemplate")
    memberScroll:SetPoint("TOPLEFT", 268, -312)
    memberScroll:SetPoint("BOTTOMRIGHT", -24, 42)
    frame.memberListScroll = memberScroll

    local memberContent = CreateFrame("Frame", nil, memberScroll)
    memberContent:SetSize(500, 1)
    memberScroll:SetScrollChild(memberContent)
    frame.memberListContent = memberContent

    return frame
  end

  return {
    CreateBoardFrameScaffold = CreateBoardFrameScaffold,
  }
end
