@issuegraph/viewer 0.5.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clusters.d.ts +116 -0
- package/dist/clusters.d.ts.map +1 -1
- package/dist/clusters.js +85 -2
- package/dist/clusters.js.map +1 -1
- package/dist/document.d.ts +76 -5
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +19 -1
- package/dist/document.js.map +1 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +28 -0
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +7 -2
- package/dist/layout.js.map +1 -1
- package/dist/marks.d.ts +105 -0
- package/dist/marks.d.ts.map +1 -0
- package/dist/marks.js +430 -0
- package/dist/marks.js.map +1 -0
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +31 -0
- package/dist/navigation.js.map +1 -1
- package/dist/parts.d.ts +23 -7
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +80 -37
- package/dist/parts.js.map +1 -1
- package/dist/projections/graph.d.ts +15 -0
- package/dist/projections/graph.d.ts.map +1 -1
- package/dist/projections/graph.js +91 -35
- package/dist/projections/graph.js.map +1 -1
- package/dist/projections/linear.d.ts +116 -15
- package/dist/projections/linear.d.ts.map +1 -1
- package/dist/projections/linear.js +171 -69
- package/dist/projections/linear.js.map +1 -1
- package/dist/projections/tree.d.ts.map +1 -1
- package/dist/projections/tree.js +15 -4
- package/dist/projections/tree.js.map +1 -1
- package/dist/skeleton.d.ts +63 -0
- package/dist/skeleton.d.ts.map +1 -0
- package/dist/skeleton.js +108 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/styles.d.ts +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +636 -24
- package/dist/styles.js.map +1 -1
- package/dist/theme.d.ts +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +47 -0
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
package/dist/styles.js
CHANGED
|
@@ -22,6 +22,245 @@
|
|
|
22
22
|
* hairlines — and a host that wants the panel suppressed overrides the four
|
|
23
23
|
* properties on `.ig-viewer`.
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* §17j's rail density, written once and emitted under two keys.
|
|
27
|
+
*
|
|
28
|
+
* ## Why this is a function and not a block
|
|
29
|
+
*
|
|
30
|
+
* The density has to be reachable two ways — by the container's width, which is
|
|
31
|
+
* §17j's own rule, and by a consumer who disagrees with the crossover this
|
|
32
|
+
* package picked. CSS cannot express "this condition OR that selector" across
|
|
33
|
+
* an `@container` boundary: a rule inside the query cannot also be a rule
|
|
34
|
+
* outside it, so the declarations would have to be written twice. The
|
|
35
|
+
* stylesheet is already a template literal, so they are written once here and
|
|
36
|
+
* interpolated twice instead.
|
|
37
|
+
*
|
|
38
|
+
* `scope` is a selector the whole block hangs off, and every rule below is
|
|
39
|
+
* RELATIVE to it. The original block carried its own `.ig-viewer` prefixes on
|
|
40
|
+
* about half its rules; those are gone, because the scope supplies one and two
|
|
41
|
+
* would never match.
|
|
42
|
+
*
|
|
43
|
+
* ## What it does to specificity, which is a gain rather than a risk
|
|
44
|
+
*
|
|
45
|
+
* Every selector here gains the scope's two compound units, so each dense rule
|
|
46
|
+
* beats the base rule it overrides by SPECIFICITY rather than by source order.
|
|
47
|
+
* One of these already had to be hand-scoped for exactly that reason — the
|
|
48
|
+
* together-unit row, where a container query adds no specificity and the base
|
|
49
|
+
* rule further down the file won, leaving the unit row drawn with nothing in
|
|
50
|
+
* it. That hazard is now closed for the whole block rather than at one site.
|
|
51
|
+
*/
|
|
52
|
+
function railDensity(scope) {
|
|
53
|
+
return `
|
|
54
|
+
${scope} .ig-slot {
|
|
55
|
+
align-items: center;
|
|
56
|
+
grid-template-columns: var(--ig-rank-column-dense) 1fr auto;
|
|
57
|
+
min-height: var(--ig-row-height-dense);
|
|
58
|
+
padding-block: var(--ig-row-padding-block-dense);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* TWO LINES, AND NEITHER WRAPS. A wrapping title is what turns a 53px row
|
|
62
|
+
into a 106px one, so the truncation is not cosmetic — it is what makes the
|
|
63
|
+
height a property of the row rather than of its longest title. */
|
|
64
|
+
${scope} .ig-slot .ig-row-head {
|
|
65
|
+
gap: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
${scope} .ig-slot .ig-title {
|
|
69
|
+
line-height: var(--ig-row-title-line);
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
text-overflow: ellipsis;
|
|
72
|
+
white-space: nowrap;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* STEP 5 OF THE DROP ORDER, AND IT IS LAST FOR A REASON '17j' STATES:
|
|
76
|
+
*"A row without a title is not a row."* Everything above leaves first. */
|
|
77
|
+
${scope} .ig-slot .ig-row-body {
|
|
78
|
+
gap: var(--ig-row-line-gap);
|
|
79
|
+
min-width: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* LINE 2, AND IT DOES NOT WRAP. '17j' draws it as one mono run —
|
|
83
|
+
'#512 . P0 . blocked-by #488' — so the chips sit ON the identity's line
|
|
84
|
+
rather than under it. 'nowrap' is what makes the 53px a property of the
|
|
85
|
+
ROW: one long title or one extra badge would otherwise buy a second line
|
|
86
|
+
and double the height, which is exactly how this rail reached 408px. */
|
|
87
|
+
${scope} .ig-slot .ig-row-meta {
|
|
88
|
+
align-items: center;
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-wrap: nowrap;
|
|
91
|
+
gap: var(--ig-space-tight);
|
|
92
|
+
line-height: var(--ig-row-meta-line);
|
|
93
|
+
min-width: 0;
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* The chips keep their own row semantics and stop wrapping, so what does not
|
|
98
|
+
fit is clipped rather than stacked. The drop order above decides WHICH
|
|
99
|
+
chips are there to clip; this only decides they stay on the line. */
|
|
100
|
+
${scope} .ig-slot .ig-row-meta .ig-badges {
|
|
101
|
+
flex-wrap: nowrap;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* The issue number never shrinks away — '17j' lists it among the five things
|
|
106
|
+
never dropped at any width. The title truncates first and the chips clip;
|
|
107
|
+
the number holds its ground. */
|
|
108
|
+
${scope} .ig-slot .ig-row-meta .ig-id {
|
|
109
|
+
flex: none;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* AT RAIL DENSITY LINE 2 IS TEXT, NOT PILLS — and this is read off the frame
|
|
113
|
+
rather than inferred from the height. '17j' draws the meta line as a single
|
|
114
|
+
mono run, '#512 . P0 . blocked-by #488': no outlines, no fills, just the
|
|
115
|
+
glyph and the words. §16a's wider panel is where they are chips.
|
|
116
|
+
|
|
117
|
+
IT IS ALSO WHAT MAKES 53px REACHABLE. A bordered chip is its padding plus
|
|
118
|
+
its stroke plus its line box, so a line of them cannot be 15px however the
|
|
119
|
+
line-height is set — the flex row grows to its tallest item and the row
|
|
120
|
+
followed it to 74px. Removing the chrome removes the reason.
|
|
121
|
+
|
|
122
|
+
THE FOUR REDUNDANT CHANNELS SURVIVE THIS, which is the thing worth
|
|
123
|
+
checking before doing it: dash, terminal and glyph are untouched, and hue
|
|
124
|
+
moves from the border to the text it was outlining. '17j' names the hold
|
|
125
|
+
GLYPH among the five things never dropped, and it is still drawn. */
|
|
126
|
+
${scope} .ig-slot .ig-row-meta .ig-badge {
|
|
127
|
+
background: none;
|
|
128
|
+
border: 0;
|
|
129
|
+
border-radius: 0;
|
|
130
|
+
padding: 0;
|
|
131
|
+
/* AND THE TEXT INSIDE A CHIP DOES NOT WRAP EITHER. Stopping the ROW from
|
|
132
|
+
wrapping is not enough: a chip squeezed by its neighbours wraps its own
|
|
133
|
+
label instead, and 'signals disagree' at 84px became two 15px lines and
|
|
134
|
+
took the row to 67px while every sibling sat at 53. One row in seven,
|
|
135
|
+
which is exactly the kind of thing that survives a review and does not
|
|
136
|
+
survive a measurement. What does not fit is clipped, per the drop
|
|
137
|
+
order. */
|
|
138
|
+
white-space: nowrap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* AND THE SWAP, AT RAIL DENSITY. '17j' draws a together unit here as a
|
|
142
|
+
marker inline with an ordinary title at the ordinary 53px, so the head
|
|
143
|
+
comes back and the enclosure stands down. One row, one rank, in both
|
|
144
|
+
densities - RULINGS.md section 1 - drawn the way each width can afford. */
|
|
145
|
+
/* SCOPED WITH '.ig-viewer' SO ORDER CANNOT DECIDE THIS. A container query
|
|
146
|
+
adds no specificity, so this rule and the wide-density one it overrides
|
|
147
|
+
were an even 0,3,0 and the LATER of the two won — which put the base rule,
|
|
148
|
+
written further down the file, in charge of both densities and left the
|
|
149
|
+
unit row showing nothing but its em dash. Measured, not spotted: every row
|
|
150
|
+
was 53px and one of them was empty. The extra class makes the override win
|
|
151
|
+
on specificity, where it does not depend on where anyone adds a rule
|
|
152
|
+
later. */
|
|
153
|
+
${scope} .ig-slot[data-unit='true'] > .ig-row-body > .ig-row-head {
|
|
154
|
+
display: flex;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
${scope} .ig-slot[data-unit='true'] .ig-unit-mark,
|
|
158
|
+
${scope} .ig-slot[data-unit='true'] .ig-unit {
|
|
159
|
+
display: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* The marker itself: the glyph and the count, on the title's line. It is a
|
|
163
|
+
COUNT and not a pill here because 53px has no room for one, and because
|
|
164
|
+
the pill's words are already the accessible name's. */
|
|
165
|
+
${scope} .ig-unit-count {
|
|
166
|
+
color: var(--ig-edge-together-with);
|
|
167
|
+
display: inline;
|
|
168
|
+
font-family: var(--ig-font-mono);
|
|
169
|
+
margin-right: var(--ig-space-tight);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* THE FOOTER ROW'S TITLE STAYS ON ONE LINE, as a ranked row's does. The row
|
|
173
|
+
is taller than a ranked row now by design — its status and its reason are
|
|
174
|
+
what it exists to show — but a title that wraps still takes the row with it,
|
|
175
|
+
so the name ellipsizes and the reason below it carries the length. */
|
|
176
|
+
${scope} .ig-footer-row .ig-title {
|
|
177
|
+
line-height: var(--ig-row-title-line);
|
|
178
|
+
min-width: 0;
|
|
179
|
+
overflow: hidden;
|
|
180
|
+
text-overflow: ellipsis;
|
|
181
|
+
white-space: nowrap;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* The identity never wraps mid-reference. */
|
|
185
|
+
${scope} .ig-footer-row .ig-id {
|
|
186
|
+
white-space: nowrap;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* THE NOW STRIP AT RAIL DENSITY. '17j' draws it as the first row of the rail
|
|
190
|
+
at all three backlog sizes, in the same rhythm as the rows beneath it -
|
|
191
|
+
RULINGS.md section 4: "a single now strip as the first row of the rail,
|
|
192
|
+
above rank 1, on a raised surface, carrying no rank number".
|
|
193
|
+
|
|
194
|
+
THE RANK SLOT IS ALREADY RIGHT AND IS NOT TOUCHED HERE: the strip carries a
|
|
195
|
+
'now' mark where a rank would be, never a number, which is the half of
|
|
196
|
+
section 4 the build already had. What was wrong was only its height. */
|
|
197
|
+
${scope} .ig-now-row {
|
|
198
|
+
min-height: var(--ig-row-height-dense);
|
|
199
|
+
padding-block: var(--ig-row-padding-block-dense);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
${scope} .ig-now-row .ig-row-head {
|
|
203
|
+
gap: 0;
|
|
204
|
+
min-width: 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
${scope} .ig-now-row .ig-title {
|
|
208
|
+
line-height: var(--ig-row-title-line);
|
|
209
|
+
overflow: hidden;
|
|
210
|
+
text-overflow: ellipsis;
|
|
211
|
+
white-space: nowrap;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
${scope} .ig-now-row .ig-id {
|
|
215
|
+
line-height: var(--ig-row-meta-line);
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
text-overflow: ellipsis;
|
|
218
|
+
white-space: nowrap;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* HIDDEN HERE, AND NOT YET EXPANDABLE — WHICH IS HALF OF WHAT 17j ASKS FOR.
|
|
222
|
+
The tile says: "The provenance line never renders inline here. In the rail
|
|
223
|
+
it is expand-on-demand; in 16a's wider panel it is inline. Same row, two
|
|
224
|
+
densities."
|
|
225
|
+
|
|
226
|
+
THE INLINE HALF IS DONE AND THE ON-DEMAND HALF IS NOT. There is no
|
|
227
|
+
row-level expand affordance at this density — 16f's right-arrow "expand
|
|
228
|
+
provenance" does not exist — so a rail reader reaches the explanation
|
|
229
|
+
through the inspector's WHY RANK block rather than through the row. The
|
|
230
|
+
information is one selection away, not lost, but this comment previously
|
|
231
|
+
claimed "expand-on-demand" and that was an overclaim about a control
|
|
232
|
+
nothing draws.
|
|
233
|
+
|
|
234
|
+
The markup stays whole so the wider container still renders it inline and
|
|
235
|
+
so the accessible name is unchanged; what the rail declines is spending
|
|
236
|
+
53px of every row on it. The missing affordance is filed, not forgotten. */
|
|
237
|
+
${scope} .ig-slot .ig-provenance,
|
|
238
|
+
${scope} .ig-slot .ig-hold,
|
|
239
|
+
${scope} .ig-slot .ig-caveat {
|
|
240
|
+
display: none;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* AND THE ON-DEMAND HALF, WHICH IS WHAT 17j ACTUALLY ASKED FOR. A row the
|
|
244
|
+
reader opened with 16f's right-arrow draws its provenance again.
|
|
245
|
+
|
|
246
|
+
THE 53px IS NOT BROKEN BY THIS, it is spent deliberately: an open row is
|
|
247
|
+
taller because the reader asked it to be, and closing it returns the row to
|
|
248
|
+
the rhythm. That is the difference between a row that grows because nothing
|
|
249
|
+
governs it - the defect this sweep removed - and one that grows because
|
|
250
|
+
somebody pressed a key.
|
|
251
|
+
|
|
252
|
+
ONLY THE PROVENANCE COMES BACK. Holds and caveats stay down: 17j names the
|
|
253
|
+
provenance line and nothing else, and the holds are already in the
|
|
254
|
+
inspector's WHY RANK block as controls rather than prose. */
|
|
255
|
+
${scope} .ig-slot[aria-expanded='true'] {
|
|
256
|
+
min-height: var(--ig-row-height-dense);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
${scope} .ig-slot[aria-expanded='true'] .ig-provenance {
|
|
260
|
+
display: block;
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
25
264
|
export const viewerStylesheet = `
|
|
26
265
|
.ig-viewer {
|
|
27
266
|
background: var(--ig-bg);
|
|
@@ -35,6 +274,51 @@ export const viewerStylesheet = `
|
|
|
35
274
|
position: relative;
|
|
36
275
|
}
|
|
37
276
|
|
|
277
|
+
/* THE FRAME IS THE STANDALONE CASE'S, AND A CONTAINER CAN DECLINE IT.
|
|
278
|
+
Alone in a host's page the viewer is a card and draws its own edge. Composed
|
|
279
|
+
into a surface that already rules its own zones off, that edge lands beside
|
|
280
|
+
the container's and the seam reads as a doubled hairline — so the container
|
|
281
|
+
passes frame: false and takes responsibility for every line on the
|
|
282
|
+
surface. See SceneOptions.frame for why this is an option rather than a
|
|
283
|
+
host stylesheet unsetting the properties above. */
|
|
284
|
+
.ig-viewer[data-frame='none'] {
|
|
285
|
+
border: 0;
|
|
286
|
+
border-radius: 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* THE LEGEND DOCKS AGAINST THE CONTAINER'S SCROLLPORT, NOT THIS ROOT'S.
|
|
290
|
+
See SceneOptions.dockLegend for why only a container can ask for this.
|
|
291
|
+
|
|
292
|
+
THE overflow LINE IS THE WHOLE MECHANISM AND LOOKS LIKE A TIDY-UP. A sticky
|
|
293
|
+
element positions against its nearest SCROLLPORT, and an ancestor with
|
|
294
|
+
overflow: hidden is one — so with the root left as it is above, the legend
|
|
295
|
+
sticks to a box that never scrolls, which is the box it already sat at the
|
|
296
|
+
bottom of. Nothing moves, nothing errors, and the declaration below reads as
|
|
297
|
+
though it works. Lifting the clip hands the legend the container's scroller
|
|
298
|
+
instead, which is the only one that scrolls.
|
|
299
|
+
|
|
300
|
+
WHICH IS ALSO WHY THIS IS SAFE ONLY WITH THE FRAME DECLINED. The clip exists
|
|
301
|
+
so a drawn radius cuts its own corners; a root that has stopped clipping must
|
|
302
|
+
not be drawing one. The rule above and this one are written to be passed
|
|
303
|
+
together, and the workspace passes both.
|
|
304
|
+
|
|
305
|
+
NO z-index, DELIBERATELY. The legend is the root's last child, so it already
|
|
306
|
+
paints over the order it overlaps; a layer number here would be a claim about
|
|
307
|
+
a stacking order this package does not own. */
|
|
308
|
+
.ig-viewer[data-legend='docked'] {
|
|
309
|
+
overflow: visible;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* bottom: 0 IS A DEFAULT THE CONTAINER OVERRIDES, not a fixed position. A
|
|
313
|
+
container with something of its own already pinned to that edge — the
|
|
314
|
+
grooming workspace's rail footer — sets this element's bottom to clear it,
|
|
315
|
+
from a height it measures rather than from a number either package wrote
|
|
316
|
+
down and both would have to keep true. */
|
|
317
|
+
.ig-viewer[data-legend='docked'] > .ig-legend {
|
|
318
|
+
position: sticky;
|
|
319
|
+
bottom: 0;
|
|
320
|
+
}
|
|
321
|
+
|
|
38
322
|
.ig-viewer *,
|
|
39
323
|
.ig-viewer *::before,
|
|
40
324
|
.ig-viewer *::after {
|
|
@@ -46,7 +330,33 @@ export const viewerStylesheet = `
|
|
|
46
330
|
outline-offset: calc(var(--ig-focus-ring) * -1);
|
|
47
331
|
}
|
|
48
332
|
|
|
333
|
+
/* THE ROW'S DENSITY IS READ FROM THIS BOX, AND THAT IS §17j's CLOSING RULE
|
|
334
|
+
RATHER THAN A PREFERENCE. The same row renders at 390px in the workspace
|
|
335
|
+
rail and at 330px in §18's settings rail, so it *"must take its width from
|
|
336
|
+
its container and pick its drop step from that — not from a viewport media
|
|
337
|
+
query, and not from a prop the host sets. A package that reads the window
|
|
338
|
+
cannot be dropped into someone else's settings page, which is the whole BYO
|
|
339
|
+
premise."*
|
|
340
|
+
|
|
341
|
+
A viewport query would have been the obvious reach and it is precisely
|
|
342
|
+
wrong: it answers a question about the WINDOW when the row's question is
|
|
343
|
+
about the COLUMN it was given. Two rails of different widths on one screen
|
|
344
|
+
is not an edge case here — §17a's rail and §18's settings rail are that
|
|
345
|
+
screen.
|
|
346
|
+
|
|
347
|
+
"NOT FROM A PROP THE HOST SETS" IS ABOUT THE DEFAULT, AND data-density DOES
|
|
348
|
+
NOT BREAK IT. What §17j refuses is a package that CANNOT work out its own
|
|
349
|
+
density — one that draws a wrong row until a host wires something up, which
|
|
350
|
+
is how a drop-in stops being a drop-in. This box still answers that question
|
|
351
|
+
on its own and nothing has to be passed for it to be right. What the
|
|
352
|
+
attribute adds is the ability to DISAGREE, which is a different thing: the
|
|
353
|
+
crossover this package picked is a default, the host is the only party that
|
|
354
|
+
knows about print, a user preference or its own breakpoints, and an override
|
|
355
|
+
nobody uses costs the drop-in case nothing. See the crossover comment below
|
|
356
|
+
for why the number needs no ruling once it is a default. */
|
|
49
357
|
.ig-list {
|
|
358
|
+
container-name: ig-rail;
|
|
359
|
+
container-type: inline-size;
|
|
50
360
|
list-style: none;
|
|
51
361
|
margin: 0;
|
|
52
362
|
padding: 0;
|
|
@@ -323,6 +633,13 @@ export const viewerStylesheet = `
|
|
|
323
633
|
/* ── working now ───────────────────────────────────────────────────────── */
|
|
324
634
|
|
|
325
635
|
.ig-now {
|
|
636
|
+
/* THE NOW STRIP IS PART OF THE RAIL'S RHYTHM, so it reads the same container
|
|
637
|
+
the rows do. It is its own list element, so without this the density rules
|
|
638
|
+
scoped to 'ig-rail' simply did not reach it and the strip stood 83px tall
|
|
639
|
+
beside 53px rows - 57% taller than everything under it, in the one slot
|
|
640
|
+
17j gives the top of the rail. */
|
|
641
|
+
container-name: ig-rail;
|
|
642
|
+
container-type: inline-size;
|
|
326
643
|
list-style: none;
|
|
327
644
|
margin: 0;
|
|
328
645
|
padding: 0;
|
|
@@ -391,6 +708,113 @@ export const viewerStylesheet = `
|
|
|
391
708
|
padding: var(--ig-row-padding-block) var(--ig-space-wide);
|
|
392
709
|
}
|
|
393
710
|
|
|
711
|
+
/* ── §17j's RAIL DENSITY ───────────────────────────────────────────────────
|
|
712
|
+
|
|
713
|
+
THE 53px ROW, AND THE ORDER THINGS LEAVE IT. '17j' fixes both, and the
|
|
714
|
+
reason it fixes the second is that the build *"showed everything because
|
|
715
|
+
nothing told it what to give up"*. This is that instruction.
|
|
716
|
+
|
|
717
|
+
9 pad + 17 title + 3 gap + 15 meta + 9 pad = 53px, divider inclusive
|
|
718
|
+
tracks: 30px rank · 1fr issue · auto delta
|
|
719
|
+
|
|
720
|
+
THE FINDING THIS ENCODES, which is the one to keep: at 6, 60 and 312 issues
|
|
721
|
+
the rail is IDENTICAL. What changes is around it — virtualisation appears,
|
|
722
|
+
the runner-hold footer grows, filter chips stop being optional, the canvas
|
|
723
|
+
starts refusing. *"If you are making the rail denser as the backlog grows,
|
|
724
|
+
you are compressing the surface that was never the problem."* So nothing
|
|
725
|
+
here keys off the backlog size, and nothing ever should.
|
|
726
|
+
|
|
727
|
+
430 IS THIS PACKAGE'S DEFAULT, NOT A CLAIM ABOUT THE DESIGN, AND A CONSUMER
|
|
728
|
+
CAN TAKE IT OVER. That is the whole posture of this package — sensible
|
|
729
|
+
defaults, everything overridable — and it is why this number needed no
|
|
730
|
+
ruling in the end. '17j' gives two anchors and no crossover: the workspace
|
|
731
|
+
rail is 390, §18's settings rail is 330 where steps 1-3 apply "by default",
|
|
732
|
+
and §16a's panel, which keeps provenance inline, is wider than either and
|
|
733
|
+
carries no published figure anywhere. 430 sits above the rail and below that
|
|
734
|
+
panel. A host that does nothing gets it and gets correct behaviour; a host
|
|
735
|
+
that disagrees sets data-density on the viewer root and this condition stops
|
|
736
|
+
deciding for them.
|
|
737
|
+
|
|
738
|
+
SO THE OPEN QUESTION IS CLOSED RATHER THAN WAITING. An earlier revision of
|
|
739
|
+
this comment filed the distance between 390 and 430 as needing a width for
|
|
740
|
+
§16a's panel. It does not: a DEFAULT only has to be reasonable, and the
|
|
741
|
+
figure would only have mattered if this were the single crossover every
|
|
742
|
+
consumer had to live with. It is not, so it is not blocking.
|
|
743
|
+
|
|
744
|
+
IT CANNOT BE A TOKEN, AND THE NEXT PERSON WILL TRY. Making the threshold a
|
|
745
|
+
theme property is the obvious reach, and it does not work: a container
|
|
746
|
+
condition takes a length and only a length. Measured in a browser — a
|
|
747
|
+
max-width condition written as a literal applies, and the same condition
|
|
748
|
+
naming a custom property PARSES INTO A RULE THAT MATCHES AT NO WIDTH AT ALL,
|
|
749
|
+
while CSS.supports() reports that same condition as supported. It fails
|
|
750
|
+
silently in both directions: the rule is not dropped, it is simply never
|
|
751
|
+
satisfied, and the one API that could have warned agrees it is fine. That is
|
|
752
|
+
a CSS limitation rather than a decision, and it is why the escape hatch below
|
|
753
|
+
is a selector rather than a property.
|
|
754
|
+
|
|
755
|
+
'17k' MAKES THE LOWER ANCHOR EXACT, which is worth keeping. It fixes the
|
|
756
|
+
three workspace layouts under one rule — "the rail never yields" — so the
|
|
757
|
+
workspace draws its rail at 390 at every width it supports and no amount of
|
|
758
|
+
resizing moves it across this threshold. Before that it fell to 312 below
|
|
759
|
+
1360, so 430 had to clear two numbers and only one was '17j's. The editor's
|
|
760
|
+
sheet pins that relationship rather than restating it: see its test "keeps
|
|
761
|
+
the workspace rail on the dense side of layer 1's crossover". */
|
|
762
|
+
@container ig-rail (max-width: 430px) {
|
|
763
|
+
${railDensity('.ig-viewer:not([data-density])')}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/* THE ESCAPE HATCH ITSELF, AND IT IS THE SAME BLOCK WITH A DIFFERENT KEY.
|
|
767
|
+
Emitted a second time under an attribute that carries no width at all, so
|
|
768
|
+
a consumer who sets it gets the dense row wherever they want it. The
|
|
769
|
+
scopes above and below are mutually exclusive by construction — one is
|
|
770
|
+
:not([data-density]) and the other names a value — so nothing here
|
|
771
|
+
depends on which of them a browser reads first.
|
|
772
|
+
|
|
773
|
+
THE OTHER DIRECTION NEEDS NO RULES. data-density='wide' matches neither
|
|
774
|
+
scope, so the row falls back to the base density this sheet declares
|
|
775
|
+
above, at any container width. */
|
|
776
|
+
${railDensity(".ig-viewer[data-density='dense']")}
|
|
777
|
+
|
|
778
|
+
/* STEPS 1-3 OF THE DROP ORDER, AT §18's 330px SETTINGS RAIL, which '17j'
|
|
779
|
+
names as the width where they apply by default.
|
|
780
|
+
|
|
781
|
+
THE SELECTORS ARE THE MARKUP'S OWN ATTRIBUTES, not class guesses: evidence
|
|
782
|
+
is 'data-evidence', a relationship is 'data-edge', a priority is
|
|
783
|
+
'data-priority' with 'query' / 'tier' / 'promoted'. Three of these were
|
|
784
|
+
written from memory first and two were wrong — the parts publish
|
|
785
|
+
'data-evidence="verified"', never a 'data-ig-badge'. */
|
|
786
|
+
|
|
787
|
+
/* STEP 1 — evidence and verification chips. '17j': *"Reassurance, not an
|
|
788
|
+
answer to any question the rail is asked."* */
|
|
789
|
+
@container ig-rail (max-width: 360px) {
|
|
790
|
+
.ig-slot .ig-badge[data-evidence] {
|
|
791
|
+
display: none;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/* STEP 2 — relationship badges past the FIRST, which is kept because it is
|
|
796
|
+
the one causing the hold. Scoped to 'data-edge' so it counts relationships
|
|
797
|
+
and not the priority, evidence and readiness chips that share '.ig-badge';
|
|
798
|
+
a positional 'nth-of-type' would have hidden whichever chip happened to sit
|
|
799
|
+
second, which is not what the rule says at all. The '+n more' chip carries
|
|
800
|
+
what left, and it already exists — 'data-omitted'. */
|
|
801
|
+
@container ig-rail (max-width: 345px) {
|
|
802
|
+
.ig-slot .ig-badge[data-edge] ~ .ig-badge[data-edge] {
|
|
803
|
+
display: none;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/* STEP 3 — the priority token. A DECLARED TIER goes, because '17j' says it is
|
|
808
|
+
*"recoverable from the rank itself"*. A PROMOTION stays: 'P3 → 0' is the
|
|
809
|
+
one form the rank cannot give back, and it is rank provenance rather than a
|
|
810
|
+
restatement. A matched query stays for the same reason — it names WHICH
|
|
811
|
+
query, which no rank encodes. */
|
|
812
|
+
@container ig-rail (max-width: 335px) {
|
|
813
|
+
.ig-slot .ig-badge[data-priority='tier'] {
|
|
814
|
+
display: none;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
394
818
|
/* THE ONE ROW GROUND THE FRAME DRAWS, and it is not a stripe. A together unit
|
|
395
819
|
is the compound station, and the tint says so; the other ranked rows carry
|
|
396
820
|
no background at all. */
|
|
@@ -464,6 +888,30 @@ export const viewerStylesheet = `
|
|
|
464
888
|
min-width: 0;
|
|
465
889
|
}
|
|
466
890
|
|
|
891
|
+
/* A UNIT AT THE WIDE DENSITY IS ITS ENCLOSURE, which is what §16a draws: the
|
|
892
|
+
pill, the note, and a member list. The ordinary head the row also carries is
|
|
893
|
+
the RAIL's way of drawing the same unit, so it stands down here rather than
|
|
894
|
+
printing the lead's title above a box that already opens with it. */
|
|
895
|
+
.ig-slot[data-unit='true'] > .ig-row-body > .ig-row-head {
|
|
896
|
+
display: none;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.ig-unit-count {
|
|
900
|
+
display: none;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/* LINE 2 AT THE WIDE DENSITY. §16a's panel draws the same sequence — identity
|
|
904
|
+
then chips — and simply has room, so here it WRAPS rather than clipping and
|
|
905
|
+
the provenance turnstile stays inline beneath it. Same markup, two
|
|
906
|
+
densities; the rail's rules are in the container query above. */
|
|
907
|
+
.ig-row-meta {
|
|
908
|
+
align-items: center;
|
|
909
|
+
display: flex;
|
|
910
|
+
flex-wrap: wrap;
|
|
911
|
+
gap: var(--ig-space-tight);
|
|
912
|
+
min-width: 0;
|
|
913
|
+
}
|
|
914
|
+
|
|
467
915
|
/* ── readiness stations ────────────────────────────────────────────────── */
|
|
468
916
|
|
|
469
917
|
.ig-station {
|
|
@@ -745,57 +1193,83 @@ export const viewerStylesheet = `
|
|
|
745
1193
|
|
|
746
1194
|
/* ── the footer group: holds that earn no rank slot ────────────────────── */
|
|
747
1195
|
|
|
748
|
-
.
|
|
749
|
-
|
|
750
|
-
|
|
1196
|
+
/* NO RULE OF ITS OWN ON TOP. The last ranked row above already draws its
|
|
1197
|
+
bottom rule, and a second one here stacked on it as a doubled line. */
|
|
1198
|
+
/* THE PANEL HEADER'S LAYOUT, ONE LEVEL DOWN: a kicker and a count chip on one
|
|
1199
|
+
line, a sentence under them. The kicker and the chip are the header's own
|
|
1200
|
+
classes (see footerHead), so this rule only places them. */
|
|
1201
|
+
.ig-footer-head {
|
|
1202
|
+
display: flex;
|
|
1203
|
+
flex-direction: column;
|
|
1204
|
+
gap: var(--ig-space-tight);
|
|
1205
|
+
padding: var(--ig-row-padding-block-dense) var(--ig-space-wide);
|
|
751
1206
|
}
|
|
752
1207
|
|
|
753
|
-
.ig-footer-
|
|
1208
|
+
.ig-footer-title-row {
|
|
754
1209
|
align-items: center;
|
|
755
1210
|
display: flex;
|
|
756
1211
|
gap: var(--ig-space);
|
|
757
|
-
justify-content: space-between;
|
|
758
1212
|
}
|
|
759
1213
|
|
|
760
1214
|
.ig-footer-title {
|
|
761
|
-
color: var(--ig-text-body);
|
|
762
|
-
font-size: var(--ig-font-size-compact);
|
|
763
1215
|
margin: 0;
|
|
764
1216
|
}
|
|
765
1217
|
|
|
766
|
-
.ig-footer-
|
|
1218
|
+
.ig-footer-note {
|
|
767
1219
|
color: var(--ig-text-muted);
|
|
768
|
-
font-
|
|
769
|
-
|
|
1220
|
+
font-size: var(--ig-font-size-compact);
|
|
1221
|
+
line-height: var(--ig-row-meta-line);
|
|
1222
|
+
margin: 0;
|
|
770
1223
|
}
|
|
771
1224
|
|
|
772
|
-
/* ONE LINE EACH, and the frame is explicit about why: these are not facts
|
|
773
|
-
about the work, so they earn no rank slot and no explanation block. A full
|
|
774
|
-
row here — station, badges, provenance — was claiming the opposite. */
|
|
775
1225
|
.ig-footer .ig-list {
|
|
776
1226
|
display: flex;
|
|
777
1227
|
flex-direction: column;
|
|
778
|
-
gap: var(--ig-space-snug);
|
|
779
|
-
margin-top: var(--ig-space);
|
|
780
1228
|
}
|
|
781
1229
|
|
|
1230
|
+
/* A RANKED ROW'S GRID, PADDING AND RULE, so the group is the rest of the same
|
|
1231
|
+
list rather than a panel of its own: the rank track holds the held station,
|
|
1232
|
+
and it lines up under the stations above because it is the same track.
|
|
1233
|
+
|
|
1234
|
+
ON THE PANEL'S OWN GROUND, NOT A SECOND SURFACE, and at full strength. The
|
|
1235
|
+
group used to sit on --ig-surface-2 with every row at 0.72 opacity, which
|
|
1236
|
+
read as disabled — on the rows whose whole purpose is "open me to see why". */
|
|
782
1237
|
.ig-footer-row {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1238
|
+
border-top: var(--ig-stroke) solid var(--ig-line);
|
|
1239
|
+
column-gap: var(--ig-space);
|
|
1240
|
+
cursor: pointer;
|
|
1241
|
+
display: grid;
|
|
1242
|
+
grid-template-columns: var(--ig-rank-column) 1fr;
|
|
1243
|
+
/* THE DENSE RANKED ROW'S PADDING, at every width: these rows carry three
|
|
1244
|
+
lines where a ranked row carries two, and the wider padding on top of that
|
|
1245
|
+
made each one twice the height of its neighbours above. */
|
|
1246
|
+
padding: var(--ig-row-padding-block-dense) var(--ig-space-wide);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
.ig-footer-row:hover {
|
|
1250
|
+
background: color-mix(in srgb, var(--ig-text) var(--ig-tint-unit), transparent);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/* THE RANKED ROW'S SELECTED BAND, and its fill: one selection, one look,
|
|
1254
|
+
whichever part of the list it was made in. */
|
|
1255
|
+
.ig-footer-row[aria-current='true'] {
|
|
1256
|
+
background: color-mix(in srgb, var(--ig-accent) var(--ig-tint-fill), transparent);
|
|
1257
|
+
box-shadow: inset var(--ig-band-rail) 0 0 var(--ig-accent);
|
|
787
1258
|
}
|
|
788
1259
|
|
|
789
1260
|
.ig-footer-row .ig-title {
|
|
790
|
-
|
|
1261
|
+
color: var(--ig-text-body);
|
|
791
1262
|
}
|
|
792
1263
|
|
|
793
|
-
.ig-footer-row .ig-
|
|
794
|
-
|
|
1264
|
+
.ig-footer-row[aria-current='true'] .ig-title {
|
|
1265
|
+
color: var(--ig-text);
|
|
795
1266
|
}
|
|
796
1267
|
|
|
797
|
-
.ig-footer-
|
|
798
|
-
|
|
1268
|
+
.ig-footer-why {
|
|
1269
|
+
color: var(--ig-text-muted);
|
|
1270
|
+
font-size: var(--ig-font-size-compact);
|
|
1271
|
+
line-height: var(--ig-row-meta-line);
|
|
1272
|
+
margin: 0;
|
|
799
1273
|
}
|
|
800
1274
|
|
|
801
1275
|
/* ── the graph canvas ──────────────────────────────────────────────────── */
|
|
@@ -1033,6 +1507,35 @@ export const viewerStylesheet = `
|
|
|
1033
1507
|
stroke-width: var(--ig-stroke);
|
|
1034
1508
|
}
|
|
1035
1509
|
|
|
1510
|
+
/* A MARK IS HIT-TESTABLE, AND THAT IS THE OPPOSITE OF WHAT IT FIRST SAID.
|
|
1511
|
+
|
|
1512
|
+
It carried a pointer-events none rule, reasoning from the halo: a decoration
|
|
1513
|
+
over a line must not swallow the click aimed at the line. That reasoning does
|
|
1514
|
+
not transfer, because a halo IS the line again and a mark is NOT — every one
|
|
1515
|
+
of these is deliberately offset AWAY from the path, so a click on it does not
|
|
1516
|
+
fall through onto the edge. It falls through onto the canvas, and the viewer's
|
|
1517
|
+
walk climbs to the canvas group and reports a click on nothing, clearing the
|
|
1518
|
+
very selection the reader was making. A conflict's companion is the clearest
|
|
1519
|
+
case: a visibly separate line that could not be pointed at.
|
|
1520
|
+
|
|
1521
|
+
That is a defect this package has already paid for once. The overlay module
|
|
1522
|
+
keeps its pointer identity on the dash clone for exactly this reason, and says
|
|
1523
|
+
so: dropping the identity makes a clone a dead zone over its own edge. Every
|
|
1524
|
+
mark here publishes the same identity, so making it unhittable spent the
|
|
1525
|
+
identity it had just been given.
|
|
1526
|
+
|
|
1527
|
+
Colour is set per element, from the token name the caller supplied, for the
|
|
1528
|
+
reason the edge hues are set per element: one source for a channel. Nothing
|
|
1529
|
+
here paints a state, because nothing here knows what a state is. */
|
|
1530
|
+
.ig-edge-mark {
|
|
1531
|
+
font-family: var(--ig-font-ui);
|
|
1532
|
+
font-size: var(--ig-font-size-small);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
.ig-edge-companion {
|
|
1536
|
+
stroke-width: var(--ig-stroke);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1036
1539
|
.ig-terminal[data-edge='blocked-by'] { color: var(--ig-edge-blocked-by); }
|
|
1037
1540
|
.ig-terminal[data-edge='serialize-with'] { color: var(--ig-edge-serialize-with); }
|
|
1038
1541
|
.ig-terminal[data-edge='together-with'] { color: var(--ig-edge-together-with); }
|
|
@@ -1101,6 +1604,94 @@ export const viewerStylesheet = `
|
|
|
1101
1604
|
padding: var(--ig-space-tight) 0;
|
|
1102
1605
|
}
|
|
1103
1606
|
|
|
1607
|
+
/* ── loading placeholder ───────────────────────────────────────────────── */
|
|
1608
|
+
|
|
1609
|
+
/* THE HOST'S HOOK, AND THE ONLY ONE. Every placeholder shape is one of these,
|
|
1610
|
+
filled with the second surface and holding still: this package ships no
|
|
1611
|
+
motion, and the fill already follows the host's theme. A host that wants a
|
|
1612
|
+
pulse animates this class under its own reduced-motion rule. */
|
|
1613
|
+
.ig-skeleton-block {
|
|
1614
|
+
background: var(--ig-surface-2);
|
|
1615
|
+
border-radius: var(--ig-radius);
|
|
1616
|
+
display: block;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/* ON THE HEADER'S OWN GROUND the second surface is the ground, so the shapes
|
|
1620
|
+
there take the hairline colour instead, or they vanish into it. */
|
|
1621
|
+
.ig-header .ig-skeleton-block {
|
|
1622
|
+
background: var(--ig-line);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
.ig-skeleton-block[data-shape='label'] {
|
|
1626
|
+
block-size: var(--ig-space);
|
|
1627
|
+
inline-size: calc(var(--ig-char-width) * 14);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.ig-skeleton-chips {
|
|
1631
|
+
display: flex;
|
|
1632
|
+
gap: var(--ig-space-snug);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
.ig-skeleton-block[data-shape='chip'] {
|
|
1636
|
+
block-size: calc(var(--ig-space) * 2);
|
|
1637
|
+
border-radius: var(--ig-radius);
|
|
1638
|
+
inline-size: calc(var(--ig-char-width) * 9);
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
.ig-skeleton-block[data-shape='station'] {
|
|
1642
|
+
block-size: var(--ig-space);
|
|
1643
|
+
border-radius: 50%;
|
|
1644
|
+
inline-size: var(--ig-space);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/* THE ROW'S OWN LINE HEIGHTS, so a placeholder row and a real row are the same
|
|
1648
|
+
height at every density the container picks. */
|
|
1649
|
+
.ig-skeleton-block[data-shape='title'] {
|
|
1650
|
+
block-size: var(--ig-row-title-line);
|
|
1651
|
+
inline-size: 68%;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.ig-skeleton-block[data-shape='title'][data-width='1'] {
|
|
1655
|
+
inline-size: 54%;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
.ig-skeleton-block[data-shape='title'][data-width='2'] {
|
|
1659
|
+
inline-size: 82%;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
.ig-skeleton-block[data-shape='meta'] {
|
|
1663
|
+
block-size: var(--ig-row-meta-line);
|
|
1664
|
+
inline-size: 36%;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
/* THE TWO LINES OF A ROW, stacked with no gap of their own: each block is its
|
|
1668
|
+
line's full height, which already carries the leading a real line has. */
|
|
1669
|
+
.ig-skeleton-lines {
|
|
1670
|
+
display: flex;
|
|
1671
|
+
flex-direction: column;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
/* A placeholder row points at nothing, so it takes no pointer and no hover. */
|
|
1675
|
+
.ig-skeleton-row {
|
|
1676
|
+
pointer-events: none;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
.ig-skeleton-stage {
|
|
1680
|
+
align-items: center;
|
|
1681
|
+
display: flex;
|
|
1682
|
+
flex-direction: column;
|
|
1683
|
+
gap: var(--ig-space-wide);
|
|
1684
|
+
padding: var(--ig-space-wide);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/* THE SPINE CARD'S OWN WIDTH, so the graph's placeholder sits where its cards
|
|
1688
|
+
will, as one solid block with the large radius the panel's cards use. */
|
|
1689
|
+
.ig-skeleton-block[data-shape='card'] {
|
|
1690
|
+
block-size: calc(var(--ig-station-box) * 4);
|
|
1691
|
+
border-radius: var(--ig-radius-large);
|
|
1692
|
+
inline-size: min(100%, var(--ig-spine-width));
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1104
1695
|
/* ── legend ────────────────────────────────────────────────────────────── */
|
|
1105
1696
|
|
|
1106
1697
|
/* A FOOTER BAR, WHERE §16b PUTS IT, and worded rather than glyph-only. It sits
|
|
@@ -1119,8 +1710,29 @@ export const viewerStylesheet = `
|
|
|
1119
1710
|
padding: var(--ig-space) var(--ig-space-wide);
|
|
1120
1711
|
}
|
|
1121
1712
|
|
|
1713
|
+
/* FLOATED SO THE BROWSER STOPS TREATING IT AS A RENDERED LEGEND, which is the
|
|
1714
|
+
only reason this declaration exists. HTML gives the first in-flow legend of a
|
|
1715
|
+
fieldset a layout nothing else in CSS has: it is lifted OUT of the fieldset's
|
|
1716
|
+
content box, painted across the top border with a notch cut through the rule
|
|
1717
|
+
either side of it, and the content box then starts below it. On this bar that
|
|
1718
|
+
drew the caption sitting on the rule, a gap of bare ground under the caption
|
|
1719
|
+
where the fieldset's own surface should have been, and a top rule broken in
|
|
1720
|
+
the middle — all three of which looked like a styling bug and none of which
|
|
1721
|
+
any rule here asked for.
|
|
1722
|
+
|
|
1723
|
+
The spec's own escape hatch is the float: a legend whose computed float is
|
|
1724
|
+
not none is not the rendered legend, and becomes an ordinary child. This bar
|
|
1725
|
+
is a flex container, where float does not apply to an item at all, so the
|
|
1726
|
+
caption simply lays out as the first item on the row — which is what the
|
|
1727
|
+
flex rule above, its muted uppercase micro type and its centred alignment
|
|
1728
|
+
were always written for.
|
|
1729
|
+
|
|
1730
|
+
IT IS LOAD-BEARING AND LOOKS DECORATIVE, which is why it is recorded here at
|
|
1731
|
+
this length: delete it and the notch, the gap and the broken rule all come
|
|
1732
|
+
back, with nothing else in this file changed. */
|
|
1122
1733
|
.ig-legend-caption {
|
|
1123
1734
|
color: var(--ig-text-muted);
|
|
1735
|
+
float: left;
|
|
1124
1736
|
font-family: var(--ig-font-mono);
|
|
1125
1737
|
font-size: var(--ig-font-size-pill);
|
|
1126
1738
|
letter-spacing: var(--ig-tracking-group);
|