<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://nssportwiki.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuild_bracket%2FRender</id>
	<title>Module:Build bracket/Render - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://nssportwiki.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuild_bracket%2FRender"/>
	<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Render&amp;action=history"/>
	<updated>2026-08-15T12:25:09Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.40.1</generator>
	<entry>
		<id>https://nssportwiki.com/index.php?title=Module:Build_bracket/Render&amp;diff=76406&amp;oldid=prev</id>
		<title>Osarius: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Render&amp;diff=76406&amp;oldid=prev"/>
		<updated>2026-07-24T10:50:37Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en-GB&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:50, 24 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en-GB&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Osarius</name></author>
	</entry>
	<entry>
		<id>https://nssportwiki.com/index.php?title=Module:Build_bracket/Render&amp;diff=76405&amp;oldid=prev</id>
		<title>wikipedia&gt;Pbrks: fix whitespace issue</title>
		<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Render&amp;diff=76405&amp;oldid=prev"/>
		<updated>2025-08-19T12:54:18Z</updated>

		<summary type="html">&lt;p&gt;fix whitespace issue&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local Render = {}&lt;br /&gt;
&lt;br /&gt;
-- ================================&lt;br /&gt;
-- 1) MODULE STATE &amp;amp; BIND INJECTS&lt;br /&gt;
-- ================================&lt;br /&gt;
-- Upvalues bound in buildTable(...)&lt;br /&gt;
local state, config, Helpers, StateChecks&lt;br /&gt;
&lt;br /&gt;
-- Local stdlib aliases&lt;br /&gt;
local t_insert = table.insert&lt;br /&gt;
&lt;br /&gt;
-- Helper/function locals (set during bind)&lt;br /&gt;
local isempty, notempty, cellBorder, unboldParenthetical&lt;br /&gt;
local showSeeds, teamLegs, roundIsEmpty, defaultHeaderText, isBlankEntry&lt;br /&gt;
&lt;br /&gt;
-- =========================&lt;br /&gt;
-- 2) CORE &amp;lt;td&amp;gt; CONSTRUCTOR&lt;br /&gt;
-- =========================&lt;br /&gt;
local function Cell(tbl, j, i, opts)&lt;br /&gt;
    opts = opts or {}&lt;br /&gt;
    local cell = tbl:tag(&amp;quot;td&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    -- classes/attributes&lt;br /&gt;
    if opts.classes then&lt;br /&gt;
        for _, c in ipairs(opts.classes) do&lt;br /&gt;
            cell:addClass(c)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if opts.colspan and opts.colspan ~= 1 then&lt;br /&gt;
        cell:attr(&amp;quot;colspan&amp;quot;, opts.colspan)&lt;br /&gt;
    end&lt;br /&gt;
    if opts.rowspan and opts.rowspan ~= 1 then&lt;br /&gt;
        cell:attr(&amp;quot;rowspan&amp;quot;, opts.rowspan)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- styling&lt;br /&gt;
    if opts.borderWidth then&lt;br /&gt;
        cell:css(&amp;quot;border-width&amp;quot;, cellBorder(opts.borderWidth))&lt;br /&gt;
    end&lt;br /&gt;
    if opts.weight == &amp;quot;bold&amp;quot; then&lt;br /&gt;
        cell:css(&amp;quot;font-weight&amp;quot;, &amp;quot;bold&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
    if opts.bg then&lt;br /&gt;
        cell:css(&amp;quot;background&amp;quot;, opts.bg)&lt;br /&gt;
    end&lt;br /&gt;
    if opts.color then&lt;br /&gt;
        cell:css(&amp;quot;color&amp;quot;, opts.color)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- alignment helpers&lt;br /&gt;
    if opts.align == &amp;quot;center&amp;quot; then&lt;br /&gt;
        cell:addClass(&amp;quot;brk-center&amp;quot;)&lt;br /&gt;
    elseif opts.align == &amp;quot;right&amp;quot; then&lt;br /&gt;
        cell:css(&amp;quot;text-align&amp;quot;, &amp;quot;right&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if opts.text then&lt;br /&gt;
        cell:wikitext(opts.text)&lt;br /&gt;
    end&lt;br /&gt;
    return cell&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- =====================================&lt;br /&gt;
-- 3) ENTRY SIZING (computed per-round)&lt;br /&gt;
-- =====================================&lt;br /&gt;
local entryColspan = nil&lt;br /&gt;
local function getEntryColspan(j)&lt;br /&gt;
    return entryColspan and entryColspan[j] or 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ==========================&lt;br /&gt;
-- 4) TEAM / SCORE CELLS&lt;br /&gt;
-- ==========================&lt;br /&gt;
local function teamCell(tbl, k, j, i, l, colspan)&lt;br /&gt;
    local classes = {&amp;quot;brk-td&amp;quot;, &amp;quot;brk-b&amp;quot;, (k == &amp;quot;seed&amp;quot;) and &amp;quot;brk-bgD&amp;quot; or &amp;quot;brk-bgL&amp;quot;}&lt;br /&gt;
    if k == &amp;quot;seed&amp;quot; or k == &amp;quot;score&amp;quot; then&lt;br /&gt;
        classes[#classes + 1] = &amp;quot;brk-center&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- strict bolding&lt;br /&gt;
    local weightFlag&lt;br /&gt;
    if k == &amp;quot;team&amp;quot; then&lt;br /&gt;
        if state.entries[j][i].weight == &amp;quot;bold&amp;quot; then&lt;br /&gt;
            weightFlag = &amp;quot;bold&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    elseif k == &amp;quot;score&amp;quot; and l ~= nil then&lt;br /&gt;
        local sc = state.entries[j][i].score&lt;br /&gt;
        if sc and sc.weight and sc.weight[l] == &amp;quot;bold&amp;quot; then&lt;br /&gt;
            weightFlag = &amp;quot;bold&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local legs = teamLegs(j, i)&lt;br /&gt;
    local opts = {&lt;br /&gt;
        classes = classes,&lt;br /&gt;
        colspan = colspan,&lt;br /&gt;
        rowspan = 2,&lt;br /&gt;
        borderWidth = {0, 0, 1, 1},&lt;br /&gt;
        weight = weightFlag -- &amp;#039;bold&amp;#039; or nil&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    -- borders&lt;br /&gt;
    if k == &amp;quot;team&amp;quot; and legs == 0 then&lt;br /&gt;
        opts.borderWidth[2] = 1&lt;br /&gt;
    end&lt;br /&gt;
    if state.entries[j][i].position == &amp;quot;top&amp;quot; then&lt;br /&gt;
        opts.borderWidth[1] = 1&lt;br /&gt;
    end&lt;br /&gt;
    if l == legs or l == &amp;quot;agg&amp;quot; or k == &amp;quot;seed&amp;quot; then&lt;br /&gt;
        opts.borderWidth[2] = 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- text&lt;br /&gt;
    local function tostr(x)&lt;br /&gt;
        return (x == nil) and &amp;quot;&amp;quot; or tostring(x)&lt;br /&gt;
    end&lt;br /&gt;
    if l == nil then&lt;br /&gt;
        opts.text = unboldParenthetical(tostr(state.entries[j][i][k]))&lt;br /&gt;
    else&lt;br /&gt;
        local v = state.entries[j][i][k] and state.entries[j][i][k][l]&lt;br /&gt;
        opts.text = tostr(v)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- ensure seeds inherit team bold without affecting score logic&lt;br /&gt;
    if k == &amp;quot;seed&amp;quot; and state.entries[j][i] and state.entries[j][i].weight == &amp;quot;bold&amp;quot; then&lt;br /&gt;
        opts.weight = opts.weight or &amp;quot;bold&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    return Cell(tbl, j, i, opts)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ======================================&lt;br /&gt;
-- 5) NIL/BLANK ENTRY HANDLING PER CELL&lt;br /&gt;
-- ======================================&lt;br /&gt;
local function handleEmptyOrNilEntry(tbl, j, i, R)&lt;br /&gt;
    local entry_colspan = getEntryColspan(j)&lt;br /&gt;
    local col = state.entries[j] or {}&lt;br /&gt;
&lt;br /&gt;
    -- nil entry: optionally emit spanning blank to keep grid intact&lt;br /&gt;
    if col[i] == nil then&lt;br /&gt;
        if col[i - 1] ~= nil or i == 1 then&lt;br /&gt;
            local rowspan, row = 0, i&lt;br /&gt;
            repeat&lt;br /&gt;
                rowspan = rowspan + 1&lt;br /&gt;
                row = row + 1&lt;br /&gt;
            until col[row] ~= nil or row &amp;gt; R&lt;br /&gt;
            Cell(tbl, j, i, {rowspan = rowspan, colspan = entry_colspan})&lt;br /&gt;
            return true&lt;br /&gt;
        else&lt;br /&gt;
            return true -- intentionally omitted cell&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if col[i][&amp;quot;ctype&amp;quot;] == &amp;quot;blank&amp;quot; then&lt;br /&gt;
        return true&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ============================&lt;br /&gt;
-- 6) ENTRY INSERTORS (ctype)&lt;br /&gt;
-- ============================&lt;br /&gt;
-- 6.1 Header&lt;br /&gt;
local function insertHeader(tbl, j, i, entry)&lt;br /&gt;
    local byesJ = state.byes[j]&lt;br /&gt;
    local hideJ = state.hide[j]&lt;br /&gt;
    local entry_colspan = getEntryColspan(j)&lt;br /&gt;
&lt;br /&gt;
    if (byesJ and byesJ[entry.headerindex] and roundIsEmpty(j, i)) or (hideJ and hideJ[entry.headerindex]) then&lt;br /&gt;
        return Cell(tbl, j, i, {rowspan = 2, colspan = entry_colspan})&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if isempty(entry.header) then&lt;br /&gt;
        entry.header = defaultHeaderText(j, entry.headerindex)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local classes = {&amp;quot;brk-td&amp;quot;, &amp;quot;brk-b&amp;quot;, &amp;quot;brk-center&amp;quot;}&lt;br /&gt;
    local useCustomShade = entry.shade_is_rd and not isempty(entry.shade)&lt;br /&gt;
    if not useCustomShade then&lt;br /&gt;
        t_insert(classes, &amp;quot;brk-bgD&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local cellOpts = {&lt;br /&gt;
        rowspan = 2,&lt;br /&gt;
        colspan = entry_colspan,&lt;br /&gt;
        text = entry.header,&lt;br /&gt;
        classes = classes,&lt;br /&gt;
        borderWidth = {1, 1, 1, 1}&lt;br /&gt;
    }&lt;br /&gt;
    if useCustomShade then&lt;br /&gt;
        cellOpts.bg = entry.shade&lt;br /&gt;
    end&lt;br /&gt;
    return Cell(tbl, j, i, cellOpts)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- 6.2 Team (+seed/+scores/+agg)&lt;br /&gt;
local function insertTeam(tbl, j, i, entry)&lt;br /&gt;
    local byesJ = state.byes[j]&lt;br /&gt;
    local hideJ = state.hide[j]&lt;br /&gt;
    local entry_colspan = getEntryColspan(j)&lt;br /&gt;
    local maxlegs = state.maxlegs[j] or 1&lt;br /&gt;
    local legs = teamLegs(j, i)&lt;br /&gt;
    local team_colspan = maxlegs - legs + 1&lt;br /&gt;
&lt;br /&gt;
    -- bye/hidden → reserve footprint&lt;br /&gt;
    if ((byesJ and byesJ[entry.headerindex]) and isBlankEntry(j, i)) or (hideJ and hideJ[entry.headerindex]) then&lt;br /&gt;
        return Cell(tbl, j, i, {rowspan = 2, colspan = entry_colspan})&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if config.aggregate and legs == 1 and maxlegs &amp;gt; 1 then&lt;br /&gt;
        team_colspan = team_colspan + 1&lt;br /&gt;
    end&lt;br /&gt;
    if maxlegs == 0 then&lt;br /&gt;
        team_colspan = team_colspan + 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- seed&lt;br /&gt;
    if config.seeds then&lt;br /&gt;
        if showSeeds(j, i) == true then&lt;br /&gt;
            teamCell(tbl, &amp;quot;seed&amp;quot;, j, i)&lt;br /&gt;
        else&lt;br /&gt;
            team_colspan = team_colspan + 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- team name&lt;br /&gt;
    teamCell(tbl, &amp;quot;team&amp;quot;, j, i, nil, team_colspan)&lt;br /&gt;
&lt;br /&gt;
    -- scores&lt;br /&gt;
    for l = 1, legs do&lt;br /&gt;
        teamCell(tbl, &amp;quot;score&amp;quot;, j, i, l)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- aggregate&lt;br /&gt;
    if config.aggregate and legs &amp;gt; 1 then&lt;br /&gt;
        teamCell(tbl, &amp;quot;score&amp;quot;, j, i, &amp;quot;agg&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- 6.3 Text&lt;br /&gt;
local function insertText(tbl, j, i, entry)&lt;br /&gt;
    Cell(tbl, j, i, {rowspan = 2, colspan = getEntryColspan(j), text = entry.text})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- 6.4 Group (spans columns)&lt;br /&gt;
local function insertGroup(tbl, j, i, entry)&lt;br /&gt;
    local span = state.entries[j][i].colspan or 1&lt;br /&gt;
    local colspan = 0&lt;br /&gt;
&lt;br /&gt;
    -- sum entry widths per column&lt;br /&gt;
    for m = j, j + span - 1 do&lt;br /&gt;
        colspan = colspan + state.maxlegs[m] + 2&lt;br /&gt;
        if not config.seeds then&lt;br /&gt;
            colspan = colspan - 1&lt;br /&gt;
        end&lt;br /&gt;
        if (config.aggregate and state.maxlegs[m] &amp;gt; 1) or state.maxlegs[m] == 0 then&lt;br /&gt;
            colspan = colspan + 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- add path columns between rounds&lt;br /&gt;
    for m = j, j + span - 2 do&lt;br /&gt;
        colspan = colspan + (state.hascross[m] and 3 or 2)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return Cell(tbl, j, i, {rowspan = 2, colspan = colspan, classes = {&amp;quot;brk-center&amp;quot;}, text = entry.group or &amp;quot;&amp;quot;})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- 6.5 Line&lt;br /&gt;
local function insertLine(tbl, j, i, entry)&lt;br /&gt;
    local entry_colspan = getEntryColspan(j)&lt;br /&gt;
&lt;br /&gt;
    local borderWidth = {0, 0, 0, 0}&lt;br /&gt;
    if entry.borderWidth then&lt;br /&gt;
        borderWidth = entry.borderWidth&lt;br /&gt;
    else&lt;br /&gt;
        -- derive from left path column&lt;br /&gt;
        local wantTop = entry.border == &amp;quot;top&amp;quot; or entry.border == &amp;quot;both&amp;quot;&lt;br /&gt;
        local wantBottom = (entry.border == nil) or entry.border == &amp;quot;bottom&amp;quot; or entry.border == &amp;quot;both&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if wantBottom and state.pathCell[j - 1] and state.pathCell[j - 1][i + 1] then&lt;br /&gt;
            borderWidth[3] = 2 * (state.pathCell[j - 1][i + 1][3][1][3] or 0)&lt;br /&gt;
        end&lt;br /&gt;
        if wantTop and state.pathCell[j - 1] and state.pathCell[j - 1][i] then&lt;br /&gt;
            borderWidth[1] = 2 * (state.pathCell[j - 1][i][3][1][1] or 0)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local cell = Cell(tbl, j, i, {rowspan = 2, colspan = entry_colspan, text = entry.text, borderWidth = borderWidth})&lt;br /&gt;
    cell:addClass(&amp;quot;brk-line&amp;quot;)&lt;br /&gt;
    if entry.color then&lt;br /&gt;
        cell:css(&amp;quot;border-color&amp;quot;, entry.color)&lt;br /&gt;
    end&lt;br /&gt;
    return cell&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local INSERTORS = {&lt;br /&gt;
    header = insertHeader,&lt;br /&gt;
    team = insertTeam,&lt;br /&gt;
    text = insertText,&lt;br /&gt;
    group = insertGroup,&lt;br /&gt;
    line = insertLine&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function insertEntry(tbl, j, i, R)&lt;br /&gt;
    if handleEmptyOrNilEntry(tbl, j, i, R) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
    local entry = state.entries[j][i]&lt;br /&gt;
    if not entry then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
    local fn = INSERTORS[entry.ctype]&lt;br /&gt;
    if fn then&lt;br /&gt;
        return fn(tbl, j, i, entry)&lt;br /&gt;
    end&lt;br /&gt;
    return Cell(tbl, j, i, {rowspan = 2, colspan = getEntryColspan(j)})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ===================================&lt;br /&gt;
-- 7) PATH CELL EMITTERS (between RDs)&lt;br /&gt;
-- ===================================&lt;br /&gt;
-- Always emit the correct number of &amp;lt;td&amp;gt;s:&lt;br /&gt;
-- - 2 lanes when no cross (k=1,3)&lt;br /&gt;
-- - 3 lanes when cross (k=1,2,3). The center lane (k=2) is skipped only if no cross.&lt;br /&gt;
local function generatePathCell(tbl, j, i, k, bg, rowspan)&lt;br /&gt;
    if not state.hascross[j] and k == 2 then&lt;br /&gt;
        return&lt;br /&gt;
    end -- keep table aligned&lt;br /&gt;
&lt;br /&gt;
    local colData = state.pathCell[j][i][k]&lt;br /&gt;
    local borders = (colData and colData[1]) or {0, 0, 0, 0}&lt;br /&gt;
    local color = (colData and colData.color) or &amp;quot;transparent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    local cell = tbl:tag(&amp;quot;td&amp;quot;)&lt;br /&gt;
    if rowspan and rowspan ~= 1 then&lt;br /&gt;
        cell:attr(&amp;quot;rowspan&amp;quot;, rowspan)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if k == 2 and state.hascross[j] and notempty(bg) then&lt;br /&gt;
        cell:css(&amp;quot;background&amp;quot;, bg):css(&amp;quot;transform&amp;quot;, &amp;quot;translate(-1px)&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if borders[1] ~= 0 or borders[2] ~= 0 or borders[3] ~= 0 or borders[4] ~= 0 then&lt;br /&gt;
        cell:css(&amp;quot;border&amp;quot;, &amp;quot;solid &amp;quot; .. color):css(&lt;br /&gt;
            &amp;quot;border-width&amp;quot;,&lt;br /&gt;
            (2 * borders[1]) ..&lt;br /&gt;
                &amp;quot;px &amp;quot; .. (2 * borders[2]) .. &amp;quot;px &amp;quot; .. (2 * borders[3]) .. &amp;quot;px &amp;quot; .. (2 * borders[4]) .. &amp;quot;px&amp;quot;&lt;br /&gt;
        )&lt;br /&gt;
    end&lt;br /&gt;
    return cell&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function insertPath(tbl, j, i, R)&lt;br /&gt;
    if state.skipPath[j][i] then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local colspan, rowspan = 2, 1&lt;br /&gt;
    local bg = &amp;quot;&amp;quot;&lt;br /&gt;
    local cross = {&amp;quot;&amp;quot;, &amp;quot;&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    local Pj = state.pathCell[j]&lt;br /&gt;
    local Xj = state.crossCell[j]&lt;br /&gt;
    local SPj = state.skipPath[j]&lt;br /&gt;
&lt;br /&gt;
    -- vertical merge: extend rowspan down while borders repeat identically&lt;br /&gt;
    if i &amp;lt; R then&lt;br /&gt;
        local function sameBorders(a)&lt;br /&gt;
            if a &amp;gt; R - 1 or SPj[a] then&lt;br /&gt;
                return false&lt;br /&gt;
            end&lt;br /&gt;
            local pi, pa = Pj[i], Pj[a]&lt;br /&gt;
            for k = 1, 3 do&lt;br /&gt;
                local bi, ba = pi[k][1], pa[k][1]&lt;br /&gt;
                if bi[1] ~= ba[1] or bi[2] ~= ba[2] or bi[3] ~= ba[3] or bi[4] ~= ba[4] then&lt;br /&gt;
                    return false&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
            return true&lt;br /&gt;
        end&lt;br /&gt;
        if sameBorders(i) then&lt;br /&gt;
            local row = i&lt;br /&gt;
            repeat&lt;br /&gt;
                if row ~= i and sameBorders(row) then&lt;br /&gt;
                    SPj[row] = true&lt;br /&gt;
                end&lt;br /&gt;
                rowspan = rowspan + 1&lt;br /&gt;
                row = row + 1&lt;br /&gt;
            until row &amp;gt; R or not sameBorders(row)&lt;br /&gt;
            rowspan = rowspan - 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- avoid double-emitting cross rows (previous row already spans)&lt;br /&gt;
    if&lt;br /&gt;
        i &amp;gt; 1 and Xj[i - 1] and&lt;br /&gt;
            ((Xj[i - 1].left and Xj[i - 1].left[1] == 1) or (Xj[i - 1].right and Xj[i - 1].right[1] == 1))&lt;br /&gt;
     then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- cross visuals&lt;br /&gt;
    if state.hascross[j] then&lt;br /&gt;
        colspan = 3&lt;br /&gt;
        if Xj[i].left[1] == 1 or Xj[i].right[1] == 1 then&lt;br /&gt;
            rowspan = 2&lt;br /&gt;
            if Xj[i].left[1] == 1 then&lt;br /&gt;
                cross[1] =&lt;br /&gt;
                    &amp;quot;linear-gradient(to top right, transparent calc(50% - 1px),&amp;quot; ..&lt;br /&gt;
                    Xj[i].left[2] ..&lt;br /&gt;
                        &amp;quot; calc(50% - 1px),&amp;quot; .. Xj[i].left[2] .. &amp;quot; calc(50% + 1px), transparent calc(50% + 1px))&amp;quot;&lt;br /&gt;
            end&lt;br /&gt;
            if Xj[i].right[1] == 1 then&lt;br /&gt;
                cross[2] =&lt;br /&gt;
                    &amp;quot;linear-gradient(to bottom right, transparent calc(50% - 1px),&amp;quot; ..&lt;br /&gt;
                    Xj[i].right[2] ..&lt;br /&gt;
                        &amp;quot; calc(50% - 1px),&amp;quot; .. Xj[i].right[2] .. &amp;quot; calc(50% + 1px), transparent calc(50% + 1px))&amp;quot;&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if notempty(cross[1]) and notempty(cross[2]) then&lt;br /&gt;
            cross[1] = cross[1] .. &amp;quot;,&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
        bg = cross[1] .. cross[2]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- emit L | (CENTER) | R cells&lt;br /&gt;
    for k = 1, 3 do&lt;br /&gt;
        generatePathCell(tbl, j, i, k, bg, rowspan)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- =========================================&lt;br /&gt;
-- 8) INVISIBLE SCAFFOLDING (LEGACY COMPAT)&lt;br /&gt;
-- =========================================&lt;br /&gt;
local function emitRowHeight(tr, rowHeightPx) -- left height cell per data row&lt;br /&gt;
    tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;height&amp;quot;, rowHeightPx)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- widths row: fixes widths for seed/team/score(+agg) and path columns&lt;br /&gt;
local function emitWidthsRow(tbl, MINC, C, seedW, teamW, scoreW, aggW, pathW, leftPad, rightPad, crossW, crossPad)&lt;br /&gt;
    tbl:tag(&amp;quot;tr&amp;quot;):css(&amp;quot;visibility&amp;quot;, &amp;quot;collapse&amp;quot;) -- spacer&lt;br /&gt;
&lt;br /&gt;
    local tr = tbl:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
    tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, &amp;quot;1px&amp;quot;) -- tiny leading gutter&lt;br /&gt;
&lt;br /&gt;
    for j = MINC, C do&lt;br /&gt;
        if config.seeds then&lt;br /&gt;
            tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, seedW)&lt;br /&gt;
        end&lt;br /&gt;
        tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, teamW)&lt;br /&gt;
&lt;br /&gt;
        local maxlegs = (state.maxlegs and state.maxlegs[j]) or 1&lt;br /&gt;
        if maxlegs &amp;lt;= 0 then&lt;br /&gt;
            tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, scoreW) -- legacy extra column when maxlegs == 0&lt;br /&gt;
        else&lt;br /&gt;
            for _ = 1, maxlegs do&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, scoreW)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if config.aggregate and maxlegs &amp;gt; 1 then&lt;br /&gt;
            tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, aggW)&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        if j &amp;lt; C then&lt;br /&gt;
            if state.hascross and state.hascross[j] then&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, pathW):css(&amp;quot;padding-left&amp;quot;, leftPad) -- L&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, crossW):css(&amp;quot;padding-left&amp;quot;, crossPad) -- CENTER&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, pathW):css(&amp;quot;padding-right&amp;quot;, rightPad) -- R&lt;br /&gt;
            else&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, pathW):css(&amp;quot;padding-left&amp;quot;, leftPad) -- L&lt;br /&gt;
                tr:tag(&amp;quot;td&amp;quot;):css(&amp;quot;width&amp;quot;, pathW):css(&amp;quot;padding-right&amp;quot;, rightPad) -- R&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ==============================&lt;br /&gt;
-- 9) PUBLIC: BUILD THE TABLE&lt;br /&gt;
-- ==============================&lt;br /&gt;
function Render.buildTable(frame, _state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    -- Bind upvalues&lt;br /&gt;
    state, config, Helpers, StateChecks = _state, _config, _Helpers, _StateChecks&lt;br /&gt;
&lt;br /&gt;
    -- Helpers&lt;br /&gt;
    isempty, notempty = Helpers.isempty, Helpers.notempty&lt;br /&gt;
    cellBorder = Helpers.cellBorder&lt;br /&gt;
    unboldParenthetical = Helpers.unboldParenthetical&lt;br /&gt;
&lt;br /&gt;
    -- State checks&lt;br /&gt;
    showSeeds = StateChecks.showSeeds&lt;br /&gt;
    teamLegs = StateChecks.teamLegs&lt;br /&gt;
    roundIsEmpty = StateChecks.roundIsEmpty&lt;br /&gt;
    defaultHeaderText = StateChecks.defaultHeaderText&lt;br /&gt;
    isBlankEntry = StateChecks.isBlankEntry&lt;br /&gt;
&lt;br /&gt;
    -- Hot locals&lt;br /&gt;
    local MINC, C = config.minc, config.c&lt;br /&gt;
    local R0 = tonumber(config.r) or 0&lt;br /&gt;
    local entries = state.entries&lt;br /&gt;
    local pathCell = state.pathCell&lt;br /&gt;
    local crossCell = state.crossCell&lt;br /&gt;
    local hide = state.hide or {}&lt;br /&gt;
    local byes = state.byes or {}&lt;br /&gt;
    local maxlegsArr = state.maxlegs or {}&lt;br /&gt;
    local hascross = state.hascross or {}&lt;br /&gt;
&lt;br /&gt;
    -- Respect explicit |rows=|&lt;br /&gt;
    local userRowsArg = config._fargs and config._fargs.rows&lt;br /&gt;
&lt;br /&gt;
    -- Is this entry visibly rendered&lt;br /&gt;
    local function entryIsVisible(j, i)&lt;br /&gt;
        local col = entries[j]&lt;br /&gt;
        local e = col and col[i]&lt;br /&gt;
        if not e then&lt;br /&gt;
            return false&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        local ct = e.ctype&lt;br /&gt;
        local hidx = e.headerindex&lt;br /&gt;
        local hid = (hide[j] and hide[j][hidx]) or false&lt;br /&gt;
        if hid then&lt;br /&gt;
            return false&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        if ct == &amp;quot;team&amp;quot; then&lt;br /&gt;
            local bye = (byes[j] and byes[j][hidx]) or false&lt;br /&gt;
            if bye and isBlankEntry(j, i) then&lt;br /&gt;
                return false&lt;br /&gt;
            end&lt;br /&gt;
            return true&lt;br /&gt;
        elseif ct == &amp;quot;header&amp;quot; then&lt;br /&gt;
            local bye = (byes[j] and byes[j][hidx]) or false&lt;br /&gt;
            if bye and roundIsEmpty(j, i) then&lt;br /&gt;
                return false&lt;br /&gt;
            end&lt;br /&gt;
            return true -- header shows (defaults applied) unless hidden or bye+empty&lt;br /&gt;
        elseif ct == &amp;quot;text&amp;quot; then&lt;br /&gt;
            return notempty(e.text)&lt;br /&gt;
        elseif ct == &amp;quot;group&amp;quot; then&lt;br /&gt;
            return notempty(e.group)&lt;br /&gt;
        elseif ct == &amp;quot;line&amp;quot; then&lt;br /&gt;
            -- Count visible borders via path scan, not the placeholder cell itself&lt;br /&gt;
            return notempty(e.text) -- only count if it actually prints text&lt;br /&gt;
        end&lt;br /&gt;
        return false&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Backward scan for last visually-used row (entries or painted paths)&lt;br /&gt;
    local function computeBottomUsedRow(R)&lt;br /&gt;
        for i = R, 1, -1 do&lt;br /&gt;
            -- Any visible entry on this row?&lt;br /&gt;
            for j = MINC, C do&lt;br /&gt;
                if entryIsVisible(j, i) then&lt;br /&gt;
                    local e = entries[j][i]&lt;br /&gt;
                    -- teams occupy a row pair → include the following row if within bounds&lt;br /&gt;
                    if e.ctype == &amp;quot;team&amp;quot; then&lt;br /&gt;
                        return (i + 1 &amp;lt;= R) and (i + 1) or i&lt;br /&gt;
                    else&lt;br /&gt;
                        return i&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
            -- Any path/cross on this row?&lt;br /&gt;
            for j = MINC, C - 1 do&lt;br /&gt;
                local Pj = pathCell[j]&lt;br /&gt;
                local Xj = crossCell[j]&lt;br /&gt;
&lt;br /&gt;
                -- Cross uses a row pair&lt;br /&gt;
                local cc = Xj and Xj[i]&lt;br /&gt;
                if cc and ((cc.left and cc.left[1] == 1) or (cc.right and cc.right[1] == 1)) then&lt;br /&gt;
                    return (i + 1 &amp;lt;= R) and (i + 1) or i&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                -- Any nonzero border on any lane?&lt;br /&gt;
                local row = Pj and Pj[i]&lt;br /&gt;
                if row then&lt;br /&gt;
                    for k = 1, 3 do&lt;br /&gt;
                        local cell = row[k]&lt;br /&gt;
                        local b = cell and cell[1]&lt;br /&gt;
                        if b and ((b[1] or 0) ~= 0 or (b[2] or 0) ~= 0 or (b[3] or 0) ~= 0 or (b[4] or 0) ~= 0) then&lt;br /&gt;
                            return i&lt;br /&gt;
                        end&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return 1 -- nothing visible; keep at least one row&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Effective number of data rows to emit&lt;br /&gt;
    local R_eff = (userRowsArg and userRowsArg ~= &amp;quot;&amp;quot;) and R0 or computeBottomUsedRow(R0)&lt;br /&gt;
&lt;br /&gt;
    -- Precompute entryColspan per round&lt;br /&gt;
    entryColspan = {}&lt;br /&gt;
    for j = MINC, C do&lt;br /&gt;
        local ml = maxlegsArr[j] or 1&lt;br /&gt;
        local col = ml + 2&lt;br /&gt;
        if not config.seeds then&lt;br /&gt;
            col = col - 1&lt;br /&gt;
        end&lt;br /&gt;
        if (config.aggregate and ml &amp;gt; 1) or ml == 0 then&lt;br /&gt;
            col = col + 1&lt;br /&gt;
        end&lt;br /&gt;
        entryColspan[j] = col&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Table skeleton&lt;br /&gt;
    local tbl = mw.html.create(&amp;quot;table&amp;quot;):addClass(&amp;quot;brk&amp;quot;)&lt;br /&gt;
    if config.nowrap then&lt;br /&gt;
        tbl:addClass(&amp;quot;brk-nw&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Fixed internal row height (do NOT use config.height here)&lt;br /&gt;
    local rowHeightPx = &amp;quot;11px&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    -- Column widths (resolve once)&lt;br /&gt;
    local getWidth = Helpers.getWidth&lt;br /&gt;
    local seedW = (getWidth and getWidth(&amp;quot;seed&amp;quot;, &amp;quot;25px&amp;quot;)) or &amp;quot;25px&amp;quot;&lt;br /&gt;
    local teamW = (getWidth and getWidth(&amp;quot;team&amp;quot;, &amp;quot;150px&amp;quot;)) or &amp;quot;150px&amp;quot;&lt;br /&gt;
    local scoreW = (getWidth and getWidth(&amp;quot;score&amp;quot;, &amp;quot;25px&amp;quot;)) or &amp;quot;25px&amp;quot;&lt;br /&gt;
    local aggRaw = (getWidth and getWidth(&amp;quot;agg&amp;quot;, nil)) or nil&lt;br /&gt;
    local aggW = Helpers.isempty(aggRaw) and scoreW or aggRaw&lt;br /&gt;
    local pathW = &amp;quot;2px&amp;quot;&lt;br /&gt;
    local crossW = (getWidth and getWidth(&amp;quot;cross&amp;quot;, &amp;quot;5px&amp;quot;)) or &amp;quot;5px&amp;quot;&lt;br /&gt;
    local crossPad = (getWidth and getWidth(&amp;quot;crosspad&amp;quot;, &amp;quot;5px&amp;quot;)) or &amp;quot;5px&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    -- between-round spacing split (e.g., 6 → 4px left, 2px right)&lt;br /&gt;
    local spacing = tonumber(config.colspacing) or 6&lt;br /&gt;
    local leftFrac = math.floor(spacing * 2 / 3)&lt;br /&gt;
    local leftPad, rightPad = (leftFrac .. &amp;quot;px&amp;quot;), ((spacing - leftFrac) .. &amp;quot;px&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    -- widths row&lt;br /&gt;
    emitWidthsRow(tbl, MINC, C, seedW, teamW, scoreW, aggW, pathW, leftPad, rightPad, crossW, crossPad)&lt;br /&gt;
&lt;br /&gt;
    -- Data rows&lt;br /&gt;
    for i = 1, R_eff do&lt;br /&gt;
        local tr = tbl:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
        emitRowHeight(tr, rowHeightPx) -- left height cell&lt;br /&gt;
&lt;br /&gt;
        for j = MINC, C do&lt;br /&gt;
            insertEntry(tr, j, i, R_eff)&lt;br /&gt;
            if j &amp;lt; C then&lt;br /&gt;
                insertPath(tr, j, i, R_eff)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Wrap with a div that loads TemplateStyles and enables scroll overflow&lt;br /&gt;
    local fr = frame or mw.getCurrentFrame()&lt;br /&gt;
    local container = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    -- Height now applies to container (numbers → px; units respected)&lt;br /&gt;
    local containerHeight = Helpers.toCssLength(config.height, nil)&lt;br /&gt;
    if containerHeight then&lt;br /&gt;
        container:css(&amp;quot;max-height&amp;quot;, containerHeight)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    container:css(&amp;quot;overflow-x&amp;quot;, &amp;quot;auto&amp;quot;):css(&amp;quot;overflow-y&amp;quot;, &amp;quot;auto&amp;quot;)&lt;br /&gt;
    container:wikitext(fr:extensionTag(&amp;quot;templatestyles&amp;quot;, &amp;quot;&amp;quot;, {src = &amp;quot;Module:Build bracket/styles.css&amp;quot;}))&lt;br /&gt;
    container:node(tbl)&lt;br /&gt;
&lt;br /&gt;
    return tostring(container)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ============&lt;br /&gt;
-- 10) EXPORTS&lt;br /&gt;
-- ============&lt;br /&gt;
return Render&lt;/div&gt;</summary>
		<author><name>wikipedia&gt;Pbrks</name></author>
	</entry>
</feed>