@bongos/core 1.19.457 → 1.19.458

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.
@@ -0,0 +1,296 @@
1
+ /* oversight.css — the oversight family's archetype (task 1003469, goal
2
+ 1000081): what a oversight ROW is in the chrome world, and the pieces the
3
+ four pages (government, watch, harbor, gate) share around it — the figure
4
+ band inside a panel, the group head, the inline form, the grant toggle, the
5
+ confirm modal. The third family sheet after record.css and room.css: a page
6
+ sheet holds only what one page has and the others do not.
7
+
8
+ Every panel is the shell's .scroll; every heading its .scroll__h; every state
9
+ pill its .fact-pill; every table its .ledger. This sheet adds nothing the
10
+ shell already says, and spends no colour the fifteen do not resolve. */
11
+
12
+ /* ---- the figure band, inside a panel ---------------------------------------
13
+ The record family's band (.rec-figs), restated for this family: hairline
14
+ columns, the figure in the display face at 300, the label above it. A glass
15
+ .stat-row is the TOP-of-page strip (Watch's attention row, Harbor and Gate's
16
+ summaries); this is the figure row a panel carries under its own heading. */
17
+ .ov-figs {
18
+ display: grid;
19
+ grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
20
+ gap: 0;
21
+ margin: 0 0 var(--sp-sm);
22
+ padding: 0 0 var(--sp-sm);
23
+ border-bottom: var(--line) solid var(--rule-soft);
24
+ }
25
+ .ov-fig { padding: 4px 18px 0; border-left: var(--line) solid var(--rule-soft); min-width: 0; }
26
+ .ov-fig:first-child { border-left: 0; padding-left: 0; }
27
+ .ov-fig__l {
28
+ display: block;
29
+ font-family: var(--label-face);
30
+ font-size: var(--label-size);
31
+ letter-spacing: var(--label-space);
32
+ text-transform: var(--label-case);
33
+ color: var(--ink-faint);
34
+ margin-bottom: 8px;
35
+ white-space: nowrap;
36
+ overflow: hidden;
37
+ text-overflow: ellipsis;
38
+ }
39
+ .ov-fig__v {
40
+ display: block;
41
+ font-family: var(--font-display);
42
+ font-weight: 300;
43
+ font-size: clamp(22px, 2.2vw, 30px);
44
+ line-height: 1;
45
+ letter-spacing: -0.03em;
46
+ color: var(--ink);
47
+ font-variant-numeric: tabular-nums;
48
+ }
49
+ .ov-fig__s { display: block; margin-top: 6px; font-size: 12px; color: var(--ink-faint); }
50
+ @media (max-width: 480px) {
51
+ .ov-figs { grid-template-columns: 1fr 1fr; row-gap: 16px; }
52
+ .ov-fig:nth-child(odd) { border-left: 0; padding-left: 0; }
53
+ }
54
+
55
+ /* ---- the group head ---------------------------------------------------------
56
+ A named run of rows inside a panel (the mock's .group__head): the name in the
57
+ label voice, the count in mono, one full rule under. The first row after a
58
+ head drops its own hairline, since the head already drew one. */
59
+ .ov-group { margin: var(--sp-md) 0 0; }
60
+ .ov-group:first-child, .scroll__lede + .ov-group, .ov-figs + .ov-group { margin-top: 0; }
61
+ .ov-group__head {
62
+ display: flex;
63
+ align-items: baseline;
64
+ gap: 12px;
65
+ padding: 0 0 10px;
66
+ border-bottom: var(--line) solid var(--rule);
67
+ }
68
+ .ov-group__name {
69
+ font-family: var(--label-face);
70
+ font-size: var(--label-size);
71
+ letter-spacing: var(--label-space);
72
+ text-transform: var(--label-case);
73
+ color: var(--ink);
74
+ }
75
+ .ov-group__n { font-family: var(--font-mono); font-size: 12px; font-variant-numeric: tabular-nums; color: var(--ink-faint); }
76
+ .ov-group__note { margin-left: auto; font-size: 12.5px; color: var(--ink-faint); text-align: right; }
77
+
78
+ /* ---- the oversight row -----------------------------------------------------
79
+ The goals row (.gr-row) at this family's density: one hairline on top, the
80
+ title at 15px/500, an optional one-line sub, a facts line of pills, chips and
81
+ plain facts, and the actions on the right. The rule sits on top so the first
82
+ row starts flush against the panel, or against the group head that already
83
+ drew its rule. Two columns; under 640px the right column drops beneath. */
84
+ .ov-rows { margin: 0; padding: 0; list-style: none; }
85
+ .ov-row {
86
+ display: grid;
87
+ grid-template-columns: minmax(0, 1fr) auto;
88
+ gap: 10px 24px;
89
+ align-items: start;
90
+ padding: 14px 0;
91
+ border-top: var(--line) solid var(--rule-soft);
92
+ }
93
+ .ov-rows > .ov-row:first-child, .ov-group__head + .ov-rows > .ov-row:first-child, .ov-group__head + .ov-row { border-top: 0; }
94
+ .ov-row--lead { grid-template-columns: auto minmax(0, 1fr) auto; }
95
+ /* A dense row: a permission, a voter, a machine principal — sixty of them in
96
+ one panel is the ordinary case, so the air tightens. */
97
+ .ov-row--dense { padding: 10px 0; }
98
+ /* The parts are divs in a list row and spans in a button row (a button holds
99
+ phrasing content only), so each part states its own display. */
100
+ .ov-row__main { display: block; min-width: 0; }
101
+ .ov-row__title {
102
+ display: inline-block;
103
+ font-size: 15px;
104
+ font-weight: 500;
105
+ letter-spacing: -0.01em;
106
+ line-height: 1.35;
107
+ color: var(--ink);
108
+ text-decoration: none;
109
+ overflow-wrap: anywhere;
110
+ }
111
+ /* A title that is a link is a control and owes the 24px floor on both axes:
112
+ the padding buys the box, the equal negative margin hands the space back. */
113
+ a.ov-row__title { min-height: 24px; min-width: 24px; padding: 2px 4px; margin: -2px -4px; }
114
+ a.ov-row__title:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
115
+ .ov-row__title .ov-mono { margin-left: 8px; }
116
+ .ov-row__sub { display: block; margin: 4px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); max-width: var(--measure); overflow-wrap: anywhere; }
117
+ .ov-row__facts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin: 10px 0 0; }
118
+ .ov-row__sub + .ov-row__facts { margin-top: 8px; }
119
+ .ov-row__right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; text-align: right; }
120
+ .ov-row__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
121
+ .ov-row__when { font-size: 12.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; white-space: nowrap; }
122
+ @media (max-width: 640px) {
123
+ .ov-row { grid-template-columns: minmax(0, 1fr); }
124
+ .ov-row--lead { grid-template-columns: auto minmax(0, 1fr); }
125
+ .ov-row--lead > .ov-row__right { grid-column: 2; }
126
+ .ov-row__right { align-items: flex-start; text-align: left; }
127
+ .ov-row__actions { justify-content: flex-start; }
128
+ }
129
+
130
+ /* A row that is itself the control — the rank list, where picking a row is the
131
+ page's one selection. The world marks a current thing with its tint (the
132
+ ranks ladder's --current card), never with a coloured bar. */
133
+ button.ov-row {
134
+ width: 100%;
135
+ text-align: left;
136
+ font: inherit;
137
+ color: inherit;
138
+ background: none;
139
+ border-left: 0; border-right: 0; border-bottom: 0;
140
+ border-radius: 0;
141
+ cursor: pointer;
142
+ }
143
+ button.ov-row:hover { background: var(--glass); }
144
+ button.ov-row[aria-pressed="true"] { background: var(--accent-tint); border-top-color: transparent; border-radius: var(--radius-sm); }
145
+ button.ov-row[aria-pressed="true"] + button.ov-row { border-top-color: transparent; }
146
+ button.ov-row[aria-pressed="true"] .ov-row__title { color: var(--accent-ink); }
147
+ .ov-rows--select button.ov-row { padding-left: 12px; padding-right: 12px; margin: 0 -12px; width: calc(100% + 24px); }
148
+
149
+ /* ---- the top-of-page summary strip ----------------------------------------------
150
+ The shell's glass .stat-row, given the air a panel would have under it. */
151
+ .ov-summary { margin: 0 0 var(--sp-md); }
152
+
153
+ /* ---- plain facts and the machine's words ------------------------------------ */
154
+ .ov-fact { font-size: 12.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
155
+ .ov-fact b { color: var(--ink-soft); font-weight: 500; }
156
+ /* A link inside a fact line is a control at a 12.5px line box: the padding buys
157
+ the 24px floor on both axes and the equal negative margin hands it back. */
158
+ .ov-fact a { display: inline-block; color: var(--accent-ink); min-height: 24px; min-width: 24px; padding: 3px 4px; margin: -3px -4px; line-height: 18px; }
159
+ .ov-mono { font-family: var(--font-mono); font-size: 12px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
160
+ .ov-key { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink); overflow-wrap: anywhere; }
161
+ .ov-key--faint { color: var(--ink-faint); }
162
+ .ov-danger { color: var(--danger); }
163
+ .ov-ok { color: var(--ok); }
164
+
165
+ /* Detail lines under a row: a reason per line (the gate's holds), or a key and
166
+ a value (the harbor's make and cost). Hairlines between, none on the first. */
167
+ .ov-lines { list-style: none; margin: 10px 0 0; padding: 0; max-width: 72ch; }
168
+ .ov-lines li { display: flex; gap: 12px; align-items: baseline; padding: 6px 0; border-top: var(--line) solid var(--rule-soft); font-size: 13px; line-height: 1.45; color: var(--ink-soft); }
169
+ .ov-lines li:first-child { border-top: 0; padding-top: 0; }
170
+ .ov-lines .ov-key { flex: none; max-width: 46%; }
171
+ .ov-lines .ov-lines__v { margin-left: auto; text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }
172
+ /* On a phone the key takes the line and the value or reason drops under it:
173
+ three narrow columns at 390px read as a table nobody laid out. */
174
+ @media (max-width: 640px) {
175
+ .ov-lines li { flex-wrap: wrap; gap: 2px 10px; }
176
+ .ov-lines .ov-key { max-width: 100%; }
177
+ }
178
+
179
+ /* Prose inside a row or a panel — the idea a board votes on, set as prose and
180
+ never as config rows. Each part is a label over a paragraph. */
181
+ .ov-prose { margin: 14px 0 0; max-width: var(--measure); }
182
+ .ov-prose__l {
183
+ margin: 14px 0 4px;
184
+ font-family: var(--label-face);
185
+ font-size: var(--label-size);
186
+ letter-spacing: var(--label-space);
187
+ text-transform: var(--label-case);
188
+ color: var(--ink-faint);
189
+ }
190
+ .ov-prose__l:first-child { margin-top: 0; }
191
+ .ov-prose__p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }
192
+
193
+ /* ---- the inline form ---------------------------------------------------------
194
+ Label over field, fields in one wrapping row, the button on the baseline. The
195
+ controls themselves are the shell's (hairline pill inputs); this only lays
196
+ them out. A form that explains itself does so in one line under the row. */
197
+ .ov-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px; margin: 0 0 var(--sp-sm); }
198
+ .ov-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 180px; min-width: 0; }
199
+ .ov-field--sm { flex: 0 1 140px; }
200
+ .ov-field--wide { flex: 1 1 100%; }
201
+ .ov-field__l {
202
+ font-family: var(--label-face);
203
+ font-size: 10.5px;
204
+ letter-spacing: var(--label-space);
205
+ text-transform: var(--label-case);
206
+ color: var(--ink-faint);
207
+ }
208
+ /* The shell styles text and search inputs; a number input (the builder id) would
209
+ otherwise render at the browser's 21px and fail the 24px floor, so the field
210
+ restates the shell's hairline pill for every control it holds. */
211
+ .ov-field input, .ov-field select, .ov-field textarea {
212
+ width: 100%;
213
+ box-sizing: border-box;
214
+ min-height: 30px;
215
+ padding: 5px 12px;
216
+ font-family: var(--font-body);
217
+ font-size: 14px;
218
+ color: var(--ink);
219
+ background: none;
220
+ border: var(--line) solid var(--rule);
221
+ border-radius: var(--radius-pill);
222
+ }
223
+ .ov-field textarea { border-radius: var(--radius-sm); }
224
+ .ov-field input:hover, .ov-field select:hover, .ov-field textarea:hover { border-color: var(--ink-faint); }
225
+ .ov-field input::placeholder, .ov-field textarea::placeholder { color: var(--ink-faint); }
226
+ /* The one line under the row. A max-width here would cap the flex basis and let
227
+ the line ride beside the button, so the line takes the full row instead. */
228
+ .ov-form__why { flex: 1 1 100%; min-width: 100%; margin: 0; font-size: 12.5px; color: var(--ink-faint); }
229
+
230
+ /* ---- the grant toggle ---------------------------------------------------------
231
+ Held is a hairline pill in ink; not held is the same pill in the faint ink.
232
+ The accent arrives only on hover, because forty granted permissions painted
233
+ salmon were the loudest thing on the page and none of them was live. */
234
+ .ov-toggle {
235
+ display: inline-flex;
236
+ align-items: center;
237
+ justify-content: center;
238
+ min-height: 28px;
239
+ min-width: 64px;
240
+ padding: 0 12px;
241
+ font: inherit;
242
+ font-size: 12.5px;
243
+ color: var(--ink-faint);
244
+ background: none;
245
+ border: var(--line) solid var(--rule);
246
+ border-radius: var(--radius-pill);
247
+ cursor: pointer;
248
+ white-space: nowrap;
249
+ }
250
+ .ov-toggle[aria-pressed="true"] { color: var(--ink); border-color: var(--ink-soft); }
251
+ .ov-toggle:hover:not(:disabled) { color: var(--accent-ink); border-color: var(--accent); }
252
+ .ov-toggle:disabled { opacity: 0.55; cursor: default; }
253
+
254
+ /* A ghost pill whose action is destructive: the danger ink on the same hairline
255
+ shape, so Close, Dismiss, Deny and Offboard read as the same kind of control
256
+ as their neighbours and still warn. */
257
+ .btn-ghost--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, var(--rule)); }
258
+ .btn-ghost--danger:hover:not(:disabled) { color: var(--danger); border-color: var(--danger); }
259
+
260
+ /* ---- the foot line ----------------------------------------------------------- */
261
+ .ov-foot { margin: 14px 0 0; font-size: 12.5px; color: var(--ink-faint); max-width: var(--measure); }
262
+ /* A link in the foot line is a control at a 12.5px line box: the padding buys
263
+ the 24px floor and the equal negative margin hands the space back. */
264
+ .ov-foot a { display: inline-block; color: var(--accent-ink); min-height: 24px; min-width: 24px; padding: 3px 4px; margin: -3px -4px; line-height: 18px; }
265
+
266
+ /* ---- the confirm modal ----------------------------------------------------------
267
+ Harbor and Gate share one confirm dialog. A --bg-card panel closed by one rule
268
+ hairline and no shadow (the hub's project card is the reference), on the
269
+ shell's --z-modal layer, over a scrim mixed from the ink. */
270
+ .ov-modal-bg {
271
+ position: fixed;
272
+ inset: 0;
273
+ z-index: var(--z-modal);
274
+ display: flex;
275
+ align-items: center;
276
+ justify-content: center;
277
+ padding: 20px;
278
+ background: color-mix(in srgb, var(--ink) 40%, transparent);
279
+ }
280
+ .ov-modal {
281
+ width: 100%;
282
+ max-width: 480px;
283
+ padding: 22px 24px 24px;
284
+ background: var(--bg-card);
285
+ border: var(--line) solid var(--rule);
286
+ border-radius: var(--radius);
287
+ }
288
+ .ov-modal .scroll__h { margin-bottom: 10px; }
289
+ .ov-modal p { margin: 0 0 12px; font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); }
290
+ .ov-modal p strong, .ov-modal p b { color: var(--ink); font-weight: 500; }
291
+ .ov-modal p:last-of-type { margin-bottom: 0; }
292
+ .ov-modal label:not(.ov-modal__check) { display: block; margin: 14px 0 6px; font-family: var(--label-face); font-size: 10.5px; letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
293
+ .ov-modal input[type="text"], .ov-modal textarea { width: 100%; box-sizing: border-box; }
294
+ .ov-modal__check { display: flex; align-items: flex-start; gap: 8px; margin: 14px 0 0; font-size: 13px; color: var(--ink); }
295
+ .ov-modal__check input { margin-top: 3px; width: 16px; height: 16px; }
296
+ .ov-modal__actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }
@@ -1,189 +1,75 @@
1
- /* watch.css — page-local styles for Watch (task 2173; extracted from
2
- watch.html's old inline <style> per the hall placement rules). Built on the
3
- shared design system's derived tokens; class names are load-bearing
4
- (watch.js writes them). The attention row is the shared .stat-row/.stat-tile;
5
- tabs/pager/empty states come from style.css's hall-kit section. */
1
+ /* watch.css — page-local styles for Watch (task 1003469 rebuild; first
2
+ extracted from the page's inline <style> by task 2173). Every list on the page
3
+ is the kit's .ledger, every figure row the oversight family's .ov-figs, every
4
+ sub-section an .ov-group head (oversight.css). What stays here is what only
5
+ Watch has: the severity vocabulary, the engagement-report reader, and the
6
+ grade trend. Class names are load-bearing (watch.js writes them). */
6
7
 
7
- /* task 2173 — the attention row sits above the tabs; a touch tighter than the
8
- Home tiles (this is a dashboard header, not a landing zone). */
9
- .watch-attention { margin: 0 0 14px; }
10
- .watch-attention .stat-tile { min-height: 76px; padding: 12px 16px; }
11
- .watch-attention .stat-tile__num { font-size: 23px; }
8
+ /* Severity / status pills. Base: the shell's .fact-pill (task 1003307). A
9
+ severity is a state, so it is a hairline in its own colour rather than a
10
+ filled chip — four filled severities in one row was the loudest thing here. */
11
+ .badge--sev-critical { color: var(--danger); }
12
+ .badge--sev-high { color: var(--warn); }
13
+ .badge--sev-medium { color: var(--info); }
14
+ .badge--sev-low { color: var(--ink-faint); }
15
+ .badge--status { color: var(--ink-faint); }
12
16
 
13
- /* task 2173 density pass — panels stack inside tab panes. */
14
- [id^="pane-"] .scroll { padding: 16px 18px; margin: 0 0 14px; }
17
+ /* Numeric cells in a kit ledger read right-aligned and tabular; a cell that
18
+ warns takes the danger ink. */
19
+ .ledger th.num, .ledger td.num { text-align: right; font-variant-numeric: tabular-nums; }
20
+ .ledger td.num.warn { color: var(--danger); font-weight: 500; }
21
+ /* Row actions inside a ledger cell: ghost pills in a row. */
22
+ .watch-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
15
23
 
16
- .watch-stats {
17
- display: grid;
18
- grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
19
- gap: 12px;
20
- margin-top: 6px;
21
- }
22
- .watch-stat {
23
- background: var(--bg-card);
24
- border: var(--line) solid var(--rule-soft);
25
- border-radius: var(--radius-sm);
26
- padding: 12px 14px;
27
- text-align: center;
28
- }
29
- .watch-stat__num {
30
- font-family: var(--font-display);
31
- font-size: 1.5rem;
32
- font-weight: 650;
33
- color: var(--ink);
34
- line-height: 1.2;
35
- font-variant-numeric: tabular-nums;
36
- }
37
- .watch-stat__label {
38
- font-size: 11px;
39
- font-weight: 600;
40
- color: var(--ink-faint);
41
- text-transform: uppercase;
42
- letter-spacing: 0.06em;
43
- margin-top: 4px;
44
- }
24
+ /* A sealed or failed section says so in place. Three states, three sentences:
25
+ "nothing here" is the kit's empty state, this is "you may not see this" and
26
+ "could not load". */
27
+ .watch-unavailable { margin: 0; padding: 8px 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); max-width: var(--measure); }
45
28
 
46
- .watch-table-wrap { overflow-x: auto; margin-top: 6px; }
47
- table.watch {
48
- width: 100%;
49
- border-collapse: collapse;
50
- font-size: 13px;
29
+ /* The engagement-report reader: exploit text, escaped into a pre and scrolled
30
+ in its own frame, never injected as HTML (threat-model §6.3). */
31
+ .watch-doc__h {
32
+ margin: var(--sp-sm) 0 6px;
33
+ font-family: var(--label-face);
34
+ font-size: var(--label-size);
35
+ font-weight: 400;
36
+ letter-spacing: var(--label-space);
37
+ text-transform: var(--label-case);
51
38
  color: var(--ink);
52
39
  }
53
- table.watch th, table.watch td {
54
- padding: 6px 10px;
55
- text-align: left;
56
- border-bottom: var(--line) solid var(--rule-soft);
57
- vertical-align: top;
58
- }
59
- table.watch th {
60
- font-size: 11px;
61
- font-weight: 600;
62
- text-transform: uppercase;
63
- letter-spacing: 0.06em;
64
- color: var(--ink-faint);
65
- border-bottom: var(--line) solid var(--rule);
66
- white-space: nowrap;
67
- }
68
- table.watch td.num { text-align: right; font-variant-numeric: tabular-nums; }
69
- table.watch td.warn { color: var(--danger); font-weight: 600; }
70
- table.watch tr:hover td { background: var(--glass); }
71
- /* the kit ledger (audit log) shares the same numeric-cell affordances */
72
- .ledger td.num { text-align: right; font-variant-numeric: tabular-nums; }
73
- .ledger td.num.warn { color: var(--danger); font-weight: 600; }
74
- .watch-mono { font-family: var(--font-mono); font-size: 0.84rem; color: var(--info); }
75
- .watch-empty { color: var(--ink-faint); font-size: 13px; padding: 10px 0; }
76
- /* .watch-subh is .watch-sub-h without the second hyphen, and watch.js emits
77
- both (:400/832/857 vs :638/640). The base rule below already groups them, so
78
- the two spellings LOOK the same — the only real divergence was :first-of-type
79
- below, which matched one spelling and not the other, so a section whose first
80
- sub-heading happened to be spelled the other way carried 16px of top margin
81
- instead of 8. Grouped there too (task 1003307). */
82
- .watch-note { color: var(--ink-faint); font-size: 12.5px; margin-top: 10px; }
83
- .watch-rank { font-size: 12px; color: var(--ink-faint); }
84
40
  .watch-doc {
41
+ margin: 0;
42
+ padding: 12px 14px;
43
+ max-height: 60vh;
44
+ overflow-y: auto;
85
45
  white-space: pre-wrap;
86
46
  word-break: break-word;
87
47
  font-family: var(--font-mono);
88
- font-size: 0.8rem;
89
- line-height: 1.5;
90
- max-height: 60vh;
91
- overflow-y: auto;
92
- padding: 12px;
93
- margin-top: 8px;
94
- background: var(--glass);
95
- border: var(--line) solid var(--rule-soft);
96
- border-radius: var(--radius-sm);
97
- }
98
- .watch-sub-h, .watch-subh {
99
- font-family: var(--font-display);
100
- font-size: 14px;
101
- font-weight: 600;
102
- color: var(--ink);
103
- margin: 16px 0 4px;
104
- }
105
- .watch-sub-h:first-of-type, .watch-subh:first-of-type { margin-top: 8px; }
106
-
107
- /* Severity / status badges. */
108
- /* Base: the shell's .fact-pill (task 1003307). A severity is a state, so it is a
109
- hairline in its own colour rather than a filled chip — four filled severities
110
- stacked in one table row was the loudest thing on the Watch board. */
111
- .badge--sev-critical { color: var(--danger); }
112
- .badge--sev-high { color: var(--warn); }
113
- .badge--sev-medium { color: var(--info); }
114
- .badge--sev-low { color: var(--ink-faint); }
115
- .badge--status { color: var(--ink-faint); }
116
-
117
- /* Row action buttons + selects. */
118
- .watch-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
119
- .watch-btn {
120
- font-family: var(--font-body);
121
48
  font-size: 12.5px;
122
- font-weight: 500;
123
- padding: 4px 12px;
124
- border: var(--line) solid var(--rule);
125
- background: var(--bg-card);
126
- color: var(--ink-soft);
127
- border-radius: var(--radius-sm);
128
- cursor: pointer;
129
- }
130
- .watch-btn:hover:not(:disabled) { background: var(--glass); color: var(--ink); }
131
- .watch-btn:disabled { opacity: 0.45; cursor: default; }
132
- .watch-btn--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--rule)); }
133
- .watch-select {
134
- font-family: var(--font-body);
135
- font-size: 13px;
136
- padding: 4px 6px;
137
- border: var(--line) solid var(--rule);
138
- background: var(--bg-card);
49
+ line-height: 1.5;
139
50
  color: var(--ink);
51
+ background: var(--glass);
140
52
  border-radius: var(--radius-sm);
141
53
  }
142
54
 
143
- .watch-req {
144
- border-bottom: var(--line) solid var(--rule-soft);
145
- padding: 10px 0;
146
- display: flex; gap: 14px; flex-wrap: wrap;
147
- align-items: flex-start; justify-content: space-between;
148
- }
149
- .watch-req__who { font-weight: 600; color: var(--ink); }
150
- .watch-req__meta { color: var(--ink-faint); font-size: 12.5px; margin-top: 2px; }
151
- .watch-req__note { color: var(--ink); font-size: 13.5px; margin-top: 6px; max-width: 56ch; }
152
-
153
- .watch-unavailable { color: var(--ink-faint); font-size: 13px; padding: 8px 0; }
154
-
155
- .watch-trend { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
55
+ /* The 14-day grade trend: a day, a bar, then the count and score. The bar is a
56
+ measurement, not a control, so it is ink on a hairline track and never the
57
+ accent. */
58
+ .watch-trend { display: flex; flex-direction: column; margin-top: 4px; }
156
59
  .watch-trend__row {
157
- display: grid; grid-template-columns: 84px 1fr 64px;
158
- gap: 10px; align-items: center;
159
- font-size: 13px; color: var(--ink);
160
- }
161
- .watch-trend__bar-track {
162
- background: var(--glass); border-radius: 3px; height: 12px; overflow: hidden;
163
- border: var(--line) solid var(--rule-soft);
164
- }
165
- .watch-trend__bar-fill { background: var(--accent); height: 100%; display: block; }
166
- .watch-trend__val { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
167
-
168
- .watch-list { list-style: none; padding: 0; margin: 8px 0 0; }
169
- .watch-list li {
170
- display: flex; justify-content: space-between; gap: 12px;
171
- padding: 5px 0; border-bottom: var(--line) solid var(--rule-soft);
60
+ display: grid;
61
+ grid-template-columns: 64px minmax(0, 1fr) 96px;
62
+ gap: 12px;
63
+ align-items: center;
64
+ min-height: 28px;
172
65
  font-size: 13px;
66
+ color: var(--ink-soft);
67
+ font-variant-numeric: tabular-nums;
173
68
  }
174
- .watch-list li .k { color: var(--ink); }
175
- .watch-list li .v { color: var(--ink-soft); font-variant-numeric: tabular-nums; }
176
-
177
- .watch-foot-link {
178
- display: inline-block; margin-top: 12px;
179
- font-size: 13px; font-weight: 500;
180
- color: var(--accent-ink);
181
- }
69
+ .watch-trend__bar-track { height: 6px; overflow: hidden; border-radius: var(--radius-pill); background: var(--rule-soft); }
70
+ .watch-trend__bar-fill { display: block; height: 100%; background: var(--ink-soft); }
71
+ .watch-trend__val { text-align: right; color: var(--ink); }
182
72
 
183
- /* Invite by GitHub username (task 1003044) — the Access requests section's own
184
- form: the way in on an invite-only project, a shortcut on an apply one. */
185
- .watch-invite { margin: 0 0 14px; padding: 12px 14px; border: var(--line) solid var(--rule-soft); border-radius: 10px; }
186
- .watch-invite__label { display: block; font-weight: 600; margin-bottom: 6px; }
187
- .watch-invite__row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
188
- .watch-invite__row input[type="text"] { flex: 1 1 200px; min-width: 0; }
189
- .watch-invite__why { margin: 8px 0 0; font-size: 13px; opacity: .8; }
73
+ /* A link inside a ledger cell (a session's tasks) is a control at a 13.5px line
74
+ box: the padding buys the 24px floor and the negative margin hands it back. */
75
+ .ledger td a:not(.lb-name) { display: inline-block; min-height: 24px; padding: 3px 0; margin: -3px 0; line-height: 18px; }