Help with `ui_template` layout code (DB 1.0)

Folks, ChatGPT is just going around in circles with this.

Here's the problem.

(See picture)
Normally the Zoom is 133%.
So this is really stepping back from things.

It is supposed to be a calendar that shows me upcoming bills. (red) and 4 days leading up to them.
Today is circled in blue.

But I'm working on how to add new bills - in case I missed them and want to add them.
So at the bottom is/are buttons to add bills.
(and there are two for reasons unknown.)

This is what it should look like - WRT zom

Here's the code:

<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:5px">
  <button id="prevBtn">◀ Prev</button>
  <span id="monthLabel" style="font-weight:bold"></span>
  <button id="nextBtn">Next ▶</button>
</div>

<div id="calendar"></div>

<div style="margin-top:10px;border-top:1px solid #666;padding-top:10px">
  <h4>Add Bill</h4>
  <label>Day <input type="number" id="billDay" min="1" max="31"></label>
  <label>Month <input type="number" id="billMonth" min="1" max="12"></label>
  <label>Label <input type="text" id="billLabel"></label>
  <label>Color <input type="color" id="billColor" value="#e53935"></label>
  <label>Lead Days <input type="number" id="billLead" min="0" max="10" value="4"></label>
  <button id="addBillBtn">Add Bill</button>
</div>

<script>
  (function(scope){
  const leadDayColor = "#CE93D8"
  let billsData = []
  let viewMonth = (new Date()).getMonth()
  let viewYear = (new Date()).getFullYear()

  function renderCalendar(bills, month, year){
    const calendarEl = document.getElementById("calendar")
    const monthLabel = document.getElementById("monthLabel")
    if(!calendarEl || !monthLabel) return

    const today = new Date()
    const todayDate = today.getDate()
    const currentMonth = today.getMonth()
    const currentYear = today.getFullYear()

    const firstDay = new Date(year, month, 1).getDay()
    const daysInMonth = new Date(year, month+1, 0).getDate()
    const monthNames = ["January","February","March","April","May","June","July","August","September","October","November","December"]

    monthLabel.textContent = monthNames[month] + " " + year

    const billsThisMonth = bills.filter(b => b.month === month+1)
    const billMap = {}, leadMap = {}
    billsThisMonth.forEach(bill => {
      if(!billMap[bill.day]) billMap[bill.day] = { color: bill.color, labels: [] }
      billMap[bill.day].labels.push(bill.label)
      for(let i=1;i<=bill.leadDays;i++){
        const leadDay = bill.day-i
        if(leadDay>0 && !billMap[leadDay]){
          if(!leadMap[leadDay]) leadMap[leadDay] = { color: leadDayColor, labels: [] }
          leadMap[leadDay].labels.push(bill.label)
        }
      }
    })

    let html = "<table><thead><tr><th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th></tr></thead><tbody><tr>"
    for(let i=0;i<firstDay;i++) html += "<td></td>"
    for(let day=1;day<=daysInMonth;day++){
      const isBillDay = billMap[day], isLeadDay = leadMap[day]
      let bgColor='', textColor='', tooltip=''
      if(isBillDay){ bgColor=isBillDay.color; textColor='black'; tooltip=isBillDay.labels.join("\n") }
      else if(isLeadDay){ bgColor=isLeadDay.color; textColor='black'; tooltip=isLeadDay.labels.join("\n") }
      else { bgColor='#2a2a2a'; textColor='#eee' }
      const isToday = day===todayDate && month===currentMonth && year===currentYear
      html += `<td style="background-color:${bgColor};color:${textColor}" title="${tooltip}" ${isToday ? 'class="today"' : ''}>${day}</td>`
      if((firstDay+day)%7===0 && day!==daysInMonth) html += "</tr><tr>"
    }
    const totalCells = firstDay+daysInMonth
    const emptyCells = totalCells%7===0 ? 0 : 7-(totalCells%7)
    for(let i=0;i<emptyCells;i++) html += "<td></td>"
    html += "</tr></tbody></table>"
    calendarEl.innerHTML = html
  }

  document.getElementById("prevBtn").onclick = () => {
    viewMonth--
    if(viewMonth<0){ viewMonth=11; viewYear-- }
    renderCalendar(billsData, viewMonth, viewYear)
  }

  document.getElementById("nextBtn").onclick = () => {
    viewMonth++
    if(viewMonth>11){ viewMonth=0; viewYear++ }
    renderCalendar(billsData, viewMonth, viewYear)
  }

  scope.$watch('msg.payload', function(payload){
    if(payload && payload.bills){
      billsData = payload.bills
      const now = new Date()
      viewMonth = now.getMonth()
      viewYear = now.getFullYear()
      renderCalendar(billsData, viewMonth, viewYear)
    }
  })

  document.getElementById('addBillBtn').onclick = function(){
    const day=parseInt(document.getElementById('billDay').value)
    const month=parseInt(document.getElementById('billMonth').value)
    const label=document.getElementById('billLabel').value
    const color=document.getElementById('billColor').value
    const leadDays=parseInt(document.getElementById('billLead').value)
    if(!day || !month || !label){ alert('Day, Month, and Label are required'); return }
    const newBill={ day, month, label, color, leadDays }
    if(!scope.msg.payload.bills) scope.msg.payload.bills=[]
    scope.msg.payload.bills.push(newBill)
    billsData.push(newBill)
    renderCalendar(billsData, viewMonth, viewYear)
    scope.send({ payload: scope.msg.payload.bills })
  }
})(scope)
</script>

Could someone have a look and help me please?
DB 1.0
Grid size 48 x 48
Widget spacing 5 x 5
Group padding 0 x 0
Group spacing 5 x 5

Not sure if there are any other Monkeys under the hood.
But I believe my CSS codes are mostly local.
Yes, there are some global ones, but they are for buttons.

Yes, I should study this a bit more, but just now is not a good time for me - yeah, maybe an excuse.
But as I see it, it is more a reason than excuse.
Anyway...... Please?


This is how it looks for me with a 10x6 widget size. I assume you do have some other CSS not in the template, which may be having an effect on things.

Ok, thanks.

I have my "width" set to auto as the group width was 12.
I changed it to 12 x 6. No luck. Still this huge gap below.

Then tried 10 x 6.

Same.

How do I include any external CSS stuff to share it so any problems can be seen/found and (I hope) resolved?

Dug around the other flows.
Here are some chunks of code which may be of importance.

<style id="program-names">
    :root {
      --dashboard-unit-width: 48px;
      --dashboard-unit-height: 48px;
    }
    .nr-dashboard-template {
        padding: 0px;
    }

/*    
    .program-names.disabled{
        cursor: not-allowed;
        pointer-events: none;
        color: #aaaaaa !important;
    }
    
    .program-names:not([disabled]):hover{
         background-color: #232323 !important;
    }
*/
    /*   This is the normal button definition  */
    .program-names{
        background-color: var(--program-names-background);
        color: var(--program-names-foreground);
        height: var(--dashboard-unit-height);
        width: 100%;
        border-radius: 10px;
        font-size:1.0em;
        font-weight:normal;
        margin: 0;
        min-height: 36px;
        min-width: unset;
        line-height: unset;
        }
    /*  This is a sub-set which is invoked by */
    /*  <md-button class="md-button program-names bigger"> */
    /*  note the (space) "bigger" at the end.  */
    .program-names.bigger{
        font-weight:bold;
        font-size:1.5em;
    }
    /*  This is for buttons with a lot of text.  `font-size:0.7em` */
    /*  makes the font 70% normal size  */
    .program-names.small{
        font-size:0.7em;
    }
    .program-names.bold{
        font-weight:bold;
    }
    /*  This is for buttons with just icons, to upsize the size */
    /*  of the icon with the line: */
    /*  <i class="fa fa-fw fa-plus remote-icon"> in the other node  */
    .remote-icon{
        font-size:2.0em;
    }
    /*  This is the same as the other one, but it makes the icon smaller  */
    .remote-iconS{
        font-size:0.5em;
    }

    .program-names.black{
        background-color: var(--program-names-background) !important;
        color: var(--program-names-foreground) !important;
    }

    .program-names.teal{
        background-color: teal;
        color: var(--program-names-foreground) !important;
    }

    .program-names.red{
        background-color: red !important;
        color: var(--program-names-foreground) !important;
    }
    .program-names.red:not([disabled]):hover{
         background-color: orange !important;
    }
    
    .program-names.darkred{
        background-color: darkred !important;
        color: black !important;
    }
    .font-black{
        color: black;
    }

</style>

--

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<i class="wi wi-wu-nt_flurries"></i>
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.10/css/weather-icons.min.css" rel="stylesheet">

--

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<i class="wi wi-wu-nt_flurries"></i>
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.10/css/weather-icons.min.css" rel="stylesheet">

(Ok, these two are the same, so I may get rid of one and see what happens)
(Ah! One is in a subflow. Just mentioning. So is that a good thing or bad?)

--

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<i class="wi wi-wu-nt_flurries"></i>
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.10/css/weather-icons.min.css" rel="stylesheet">

(and a third)

--

Last one.

<style id="program-names">
    :root {
      --dashboard-unit-width: 48px;
      --dashboard-unit-height: 48px;
    }
    .nr-dashboard-template {
        padding: 0px;
    }

/*    
    .program-names.disabled{
        cursor: not-allowed;
        pointer-events: none;
        color: #aaaaaa !important;
    }
    
    .program-names:not([disabled]):hover{
         background-color: #232323 !important;
    }
*/
    /*   This is the normal button definition  */
    .program-names{
        background-color: var(--program-names-background);
        color: var(--program-names-foreground);
        height: var(--dashboard-unit-height);
        width: 100%;
        border-radius: 10px;
        font-size:1.0em;
        font-weight:normal;
        margin: 0;
        min-height: 36px;
        min-width: unset;
        line-height: unset;
        }
    /*  This is a sub-set which is invoked by */
    /*  <md-button class="md-button program-names bigger"> */
    /*  note the (space) "bigger" at the end.  */
    .program-names.bigger{
        font-weight:bold;
        font-size:1.5em;
    }
    /*  This is for buttons with a lot of text.  `font-size:0.7em` */
    /*  makes the font 70% normal size  */
    .program-names.small{
        font-size:0.7em;
    }
    .program-names.bold{
        font-weight:bold;
    }
    /*  This is for buttons with just icons, to upsize the size */
    /*  of the icon with the line: */
    /*  <i class="fa fa-fw fa-plus remote-icon"> in the other node  */
    .remote-icon{
        font-size:2.0em;
    }
    /*  This is the same as the other one, but it makes the icon smaller  */
    .remote-iconS{
        font-size:0.5em;
    }

    .program-names.black{
        background-color: var(--program-names-background) !important;
        color: var(--program-names-foreground) !important;
    }

    .program-names.red{
        background-color: red !important;
        color: var(--program-names-foreground) !important;
    }
    .program-names.red:not([disabled]):hover{
         background-color: orange !important;
    }
    
    .program-names.darkred{
        background-color: darkred !important;
        color: black !important;
    }
    .font-black{
        color: black;
    }

</style>

Which I think is the same as the first one/block.
(Seems it is, but if I disable it, buttons on that tab are corrupt.)

And that tab is not the one where the bills stuff is.
Again, just mentioning.

To declare:
I have an appreciation of the 3 levels of CSS.
Something like:
1 - this node.
2 - this flow
3 - global
But I know they aren't the actual terms used.