Repository: spectreconsole/spectre.console (csharp)

Issue:
Panel in layout adds newline in more complex layout split
**Information**
 - OS: MacOS
 - Version: 0.48.0, 0.47.0
 - Terminal: Kitty

**Describe the bug**
There's some issue with adding newline or setting the wrong height on panel. It occurs mostly when there are 3 rows in layout and height of AnsiConsole is a specific number e.g. 17, 20, 23, 28, 31. Changing console height to other "correct" number seems to resolve the problem, so I would assume it's correlated to some measurement calculation?

**To Reproduce**
Run this code and set height of terminal to specific number e.g. provided above or try to change height by one unit at a time, until issue occurs.

```csharp
using Spectre.Console;

var layout = new Layout();
var col1 = new Layout();
var col1Row1 = new Layout();
var col1Row2 = new Layout();
var col1Row3 = new Layout();

col1.SplitRows(col1Row1, col1Row2, col1Row3);

var col2 = new Layout();

layout.SplitColumns(col1, col2);

var panel = new Panel("Hello, World!") { Expand = true };

List<Layout> layouts = [col1Row1, col1Row2, col1Row3, col2];
foreach (var l in layouts)
{
    l.Update(panel);
}

AnsiConsole.Clear();
AnsiConsole.Write(layout);
Console.ReadKey();
```

**Expected behavior**
Display correct panels, without newline.

**Screenshots**
Should be:
<img width="774" alt="image" src="https://github.com/spectreconsole/spectre.console/assets/40443396/6b9f7f36-d8f5-4853-87be-ae03f4c57225">
but is:
<img width="789" alt="image" src="https://github.com/spectreconsole/spectre.console/assets/40443396/d8c4b6e7-13c3-4159-92d0-2dac154f5a4f">

---
Please upvote :+1: this issue if you are interested in it.

Pull request:
<!--
Do NOT open a PR without discussing the changes on an open issue, first.

Add the issue number here. e.g. #123
-->
fixes #1390 

<!-- formalities. These are not optional. -->

- [x] I have read the [Contribution Guidelines](https://github.com/spectreconsole/spectre.console/blob/main/CONTRIBUTING.md)
- [x] I have commented on the issue above and discussed the intended changes
- [ ] A maintainer has signed off on the changes and the issue was assigned to me
- [x] All newly added code is adequately covered by tests
- [x] All existing tests are still running without errors
- [x] The documentation was modified to reflect the changes _OR_ no documentation changes are required.

## Changes

Updated the ratio calculation to round up if the remainder is within 0.9999 I have tested this with a good amount of examples and it still works, but I have not written any proof that this will remain correct at any value. We could use a much smaller target to round say .99 as well.
<!-- describe the changes you made. -->

---
Please upvote :+1: this pull request if you are interested in it.

Patch:
diff --git a/src/Spectre.Console/Internal/Ratio.cs b/src/Spectre.Console/Internal/Ratio.cs
index fb38bdd3b..4ef550444 100644
--- a/src/Spectre.Console/Internal/Ratio.cs
+++ b/src/Spectre.Console/Internal/Ratio.cs
@@ -9,7 +9,17 @@ public static List<int> Resolve(int total, IEnumerable<IRatioResolvable> edges)
     {
         static (int Div, float Mod) DivMod(float x, float y)
         {
-            return ((int)(x / y), x % y);
+            var (div, mod) = ((int)(x / y), x % y);
+
+            // If remainder is within .0001 of 1 then we round up
+            if (!(mod > 0.9999))
+            {
+                return (div, mod);
+            }
+
+            div++;
+            mod = 0;
+            return (div, mod);
         }
 
         static int? GetEdgeWidth(IRatioResolvable edge)
@@ -22,7 +32,7 @@ public static List<int> Resolve(int total, IEnumerable<IRatioResolvable> edges)
             return edge.Size;
         }
 
-        var sizes = edges.Select(x => GetEdgeWidth(x)).ToArray();
+        var sizes = edges.Select(GetEdgeWidth).ToArray();
 
         while (sizes.Any(s => s == null))
         {


Test patch:
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_17.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_17.verified.txt
new file mode 100644
index 000000000..1a64de78d
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_17.verified.txt
@@ -0,0 +1,17 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_20.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_20.verified.txt
new file mode 100644
index 000000000..4c6a7c9d2
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_20.verified.txt
@@ -0,0 +1,20 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_23.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_23.verified.txt
new file mode 100644
index 000000000..d6e747113
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_23.verified.txt
@@ -0,0 +1,23 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_28.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_28.verified.txt
new file mode 100644
index 000000000..f34e9d753
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_28.verified.txt
@@ -0,0 +1,28 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_30.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_30.verified.txt
new file mode 100644
index 000000000..be6f4b5e0
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_30.verified.txt
@@ -0,0 +1,31 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_31.verified.txt b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_31.verified.txt
new file mode 100644
index 000000000..be6f4b5e0
--- /dev/null
+++ b/src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Nested_Three_Rows_In_One_Column.Output_31.verified.txt
@@ -0,0 +1,31 @@
+﻿┌──────────────────┐┌──────────────────┐
+│ Hello, World!    ││ Hello, World!    │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘│                  │
+┌──────────────────┐│                  │
+│ Hello, World!    ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+│                  ││                  │
+└──────────────────┘└──────────────────┘
\ No newline at end of file
diff --git a/src/Tests/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs b/src/Tests/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs
index 550922a97..54182e12c 100644
--- a/src/Tests/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs
+++ b/src/Tests/Spectre.Console.Tests/Unit/Widgets/LayoutTests.cs
@@ -153,6 +153,35 @@ public Task Should_Render_Layout_With_Nested_Rows_And_Columns()
         return Verifier.Verify(console.Output);
     }
 
+    [Theory]
+    [InlineData(17, "17")]
+    [InlineData(20, "20")]
+    [InlineData(23, "23")]
+    [InlineData(28, "28")]
+    [InlineData(31, "31")]
+    [Expectation("Render_Layout_With_Nested_Three_Rows_In_One_Column")]
+    public Task Should_Render_Layout_With_Three_And_One_Columns(int height, string expectationPrefix)
+    {
+        // Given
+        var console = new TestConsole().Size(new Size(40, height));
+
+        // Layout with 2 columns, left column has 3 rows and right column has 1 row
+        var layout = new Layout(new Panel("Hello, World!") { Expand = true })
+            .SplitColumns(
+                new Layout(new Panel("Hello, World!") { Expand = true })
+                    .SplitRows(
+                        new Layout(new Panel("Hello, World!") { Expand = true }),
+                        new Layout(new Panel("Hello, World!") { Expand = true }),
+                        new Layout(new Panel("Hello, World!") { Expand = true })),
+                new Layout(new Panel("Hello, World!") { Expand = true }));
+
+        // When
+        console.Write(layout);
+
+        // Then
+        return Verifier.Verify(console.Output).UseTextForParameters(expectationPrefix);
+    }
+
     [Fact]
     [Expectation("Render_Layout_Without_Invisible_Children")]
     public Task Should_Render_Layout_Without_Invisible_Children()