1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//! §11 rule 5's arithmetic, in one home: **how much of a container its
//! accessories may take between them.**
//!
//! Rule 5 was written as a per-panel cap — *"no panel may take more than half
//! the window"* — and read that way it is not an invariant at all: the
//! conversation pane docks three accessories (the composer, the settings rows,
//! the in-flight strip) plus a start-goal box, and three halves are 150% of the
//! pane. Measured at the documented 420x320 minimum, the composer and the
//! settings rows took 107 pt of a 138 pt pane, the conversation body was left
//! 26 pt, and every run in it painted on top of every other one — the QUALITY
//! G4 defect bl-9551 was filed for.
//!
//! **The reframe: the cap is a budget over the stack, not a cap on each
//! member.** A container keeps [`KEEP`] of itself for its own content; every
//! accessory it docks draws from the other share, in the order they are
//! created, and each one's ceiling is whatever the budget still holds. Because
//! the ceiling is measured against what is *still unallocated*, the reserve is
//! preserved no matter how many accessories a pane grows — the rule does not
//! have to be re-derived when a fifth one is added, which is exactly what the
//! per-panel spelling could not promise.
//!
//! **Creation order is not priority order** (bl-58e4). egui creates docked
//! panels outermost-first, so the band at the container's bottom edge claims
//! first and the band nearest the container's own content claims last — and a
//! budget spent purely in creation order therefore starves the *innermost* band
//! first. That was harmless while the composer held the bottom edge; the
//! 2026-08-12 ruling moved the settings rows there instead, which would have
//! made the rows the operator demoted outbid the box they were demoted below.
//! So [`share`] takes the count of bands still to be seated inside this one and
//! holds a [`ROW`] back for each. The starved container then sheds from its
//! bottom edge up, and the band nearest its content is the last to go rather
//! than the first.
//!
//! **An accessory the container cannot pay does not paint** ([`share`] answers
//! `None`). egui sizes a panel by its *content*, so a panel handed a ceiling
//! below its content's height does not shrink to it — it lays out at its
//! natural size wherever it was seated, which is the overlap again, one level
//! down. There is therefore no honest "very small accessory": either the budget
//! seats at least [`ROW`] — one line of text, the least a row can be and still
//! say anything — or the accessory is not on screen this frame. This is the
//! in-flight strip's own rule (§11: *"the panel itself is conditional, not its
//! content"*) generalized to every accessory.
//!
//! The same arithmetic bounds the panels that store a size ([`Panel`]'s
//! ceiling, §4.1 `panels`) — one home, so the roster column, the activity trail
//! and the conversation's own accessories cannot disagree about what half means.
//!
//! [`Panel`]: crate::ui_state::Panel
/// The share of itself a container keeps for its own content (§11 rule 5).
///
/// A share rather than a point count because the defect it closes is a ratio:
/// 690 pt of a 1150 pt window is a wide roster, and of an 800 pt one it is an
/// unusable centre. The centre is what the window is *for* — every accessory is
/// a margin around it — so the accessories together may have the other half and
/// no more.
const KEEP: f32 = 0.5;
/// The least an accessory can be and still say anything: one line of text with
/// its frame. Below this there is no small version of a row, only a sliver that
/// paints its content past its own edge, so the answer is to not paint it.
pub const ROW: f32 = 24.0;
/// The ceiling for the **next** accessory in `container`'s stack, given how
/// much of the container is still unallocated (`available`) — or `None` when
/// the budget can no longer seat a [`ROW`], which is the signal not to paint
/// the accessory at all.
///
/// `container` is the extent the stack is a share of, along the accessory's own
/// axis: the window's height for the window-level accessories, the pane's for
/// the conversation's. It is read once, before the first accessory is created,
/// so every member of one stack divides the same number.
///
/// **`held` is what the accessories still to be seated between this one and the
/// container's own content need between them** — each at its own floor, summed
/// by the stack that knows the order. The reserve exists because claim order
/// and seat order are opposed: egui stacks docked panels outermost-first, so
/// the band at the container's bottom edge claims first. Since the 2026-08-12
/// ruling put the conversation's settings rows there (*"the work directory,
/// budget, context, and model selection … should be below the input box, not
/// above it"*), an unreserved budget would let those rows take the pane out
/// from under the box they were just ruled below — an input squeezed under its
/// own content, or gone, in favour of rows the operator had just demoted.
///
/// **A floor is per band, not [`ROW`] for everyone.** A row of figures really is
/// one line, and the strip's own rule says so; a goal box is a target line, a
/// text box and a verb row, and holding one row back for it buys nothing. So
/// the caller sums real floors and this function only subtracts them.
///
/// It stays one rule over every band, not a carve-out for the goal box: each
/// holds back for whatever is inside it, and a container too small to pay even
/// the reserve pays **nobody** — the goal box included, since a pane that
/// cannot seat a row of it has nothing to type into either.
pub
/// The least a value control can be and still show a token of what it holds.
/// In points, not a share, for the same reason [`Panel::min_size`]'s floor is:
/// a legible field is a physical size, and a share of a narrow pane is not one.
///
/// [`Panel::min_size`]: crate::ui_state::Panel::min_size
const FIELD_MIN: f32 = 120.0;
/// The width a row's value control takes: everything the row has left after
/// what is pinned beside it, never below [`FIELD_MIN`] — **the width-axis twin
/// of [`share`]** (§11 rule 1's "trailing metadata pinned right, the greedy
/// element filling what is left", read for a form row rather than a list row).
///
/// egui's own default is a *constant*: `Style::spacing::text_edit_width`, a
/// fixed 280 pt column whatever the pane. Measured at a maximized 2560 pt
/// window, the §9.5 `capabilities` row read `tool_use_native, prompt_caching,
/// streaming, stop_` — cut mid-token, no ellipsis, with ~1700 pt of pane unused
/// immediately to its right: QUALITY G1 and G4 in one row, the space that would
/// un-cut it right there and unspent. A constant cannot be right at two window
/// sizes, so the width is derived at both ends — the same reframe rule 5 makes
/// on the other axis.
pub
/// The largest a *sized* panel may open at, given the extent of the window
/// along its own axis — the same budget with nothing else yet allocated, which
/// is what a panel the operator drags is measured against (§4.1 `panels`,
/// [`crate::ui_state::Panel::max_size`]).
pub