@seanmars/tospec 0.23.0 → 0.24.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +17 -3
  3. package/assets/claude-mod/tospec-dashboard/.claude-plugin/plugin.json +7 -0
  4. package/assets/claude-mod/tospec-dashboard/hooks/hooks.json +1 -0
  5. package/assets/claude-mod/tospec-dashboard/hooks/register.ts +695 -0
  6. package/assets/claude-mod/tospec-dashboard/tests/register.test.ts +448 -0
  7. package/assets/claude-mod/tospec-dashboard/types/index.d.ts +8 -0
  8. package/assets/dashboard/app.js +218 -1180
  9. package/assets/dashboard/index.html +31 -22
  10. package/assets/dashboard/lib/charts.js +355 -0
  11. package/assets/dashboard/lib/derive.js +369 -0
  12. package/assets/dashboard/lib/dom.js +121 -0
  13. package/assets/dashboard/lib/routes.js +52 -0
  14. package/assets/dashboard/lib/store.js +324 -0
  15. package/assets/dashboard/style.css +3103 -664
  16. package/assets/dashboard/views/alerts.js +170 -0
  17. package/assets/dashboard/views/change.js +232 -0
  18. package/assets/dashboard/views/docs.js +214 -0
  19. package/assets/dashboard/views/home.js +357 -0
  20. package/assets/dashboard/views/project.js +168 -0
  21. package/assets/dashboard/views/session.js +270 -0
  22. package/assets/dashboard/views/sidebar.js +131 -0
  23. package/dist/cli/index.d.ts.map +1 -1
  24. package/dist/cli/index.js +74 -95
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/commands/dashboard-relay.d.ts +11 -0
  27. package/dist/commands/dashboard-relay.d.ts.map +1 -0
  28. package/dist/commands/dashboard-relay.js +88 -0
  29. package/dist/commands/dashboard-relay.js.map +1 -0
  30. package/dist/commands/dashboard.d.ts +62 -102
  31. package/dist/commands/dashboard.d.ts.map +1 -1
  32. package/dist/commands/dashboard.js +375 -609
  33. package/dist/commands/dashboard.js.map +1 -1
  34. package/dist/core/dashboard-hub.d.ts +258 -0
  35. package/dist/core/dashboard-hub.d.ts.map +1 -0
  36. package/dist/core/dashboard-hub.js +643 -0
  37. package/dist/core/dashboard-hub.js.map +1 -0
  38. package/dist/core/dashboard-routes.d.ts +56 -0
  39. package/dist/core/dashboard-routes.d.ts.map +1 -0
  40. package/dist/core/dashboard-routes.js +329 -0
  41. package/dist/core/dashboard-routes.js.map +1 -0
  42. package/dist/core/init.d.ts.map +1 -1
  43. package/dist/core/init.js +4 -1
  44. package/dist/core/init.js.map +1 -1
  45. package/dist/core/local-server.d.ts +1 -1
  46. package/dist/core/local-server.js +1 -1
  47. package/dist/core/shared/dashboard-mod.d.ts +24 -0
  48. package/dist/core/shared/dashboard-mod.d.ts.map +1 -0
  49. package/dist/core/shared/dashboard-mod.js +44 -0
  50. package/dist/core/shared/dashboard-mod.js.map +1 -0
  51. package/dist/core/shared/index.d.ts +1 -0
  52. package/dist/core/shared/index.d.ts.map +1 -1
  53. package/dist/core/shared/index.js +1 -0
  54. package/dist/core/shared/index.js.map +1 -1
  55. package/dist/core/update.d.ts.map +1 -1
  56. package/dist/core/update.js +4 -1
  57. package/dist/core/update.js.map +1 -1
  58. package/package.json +3 -2
  59. package/assets/dashboard/chart.umd.js +0 -14
@@ -1,956 +1,3395 @@
1
- /* tospec dashboard — light/dark via [data-theme] (JS-resolved), no webfonts. */
2
-
3
- :root {
4
- --bg: #f6f7f9;
1
+ /* tospec dashboard: every project as a transit line on a shared station grid.
2
+ The world (Taipei Metro wayfinding) lends type, palette, density and one
3
+ move; navigation and controls stay ordinary web controls. Themes are
4
+ resolved by app.js into [data-theme]; no webfonts, no external resources. */
5
+
6
+ /* -- tokens ------------------------------------------------------------------ */
7
+
8
+ /* Line colours are categorical identity, validated per theme with the dataviz
9
+ palette checks (OKLCH lightness band, chroma floor, adjacent-pair CVD
10
+ separation under protan/deutan, normal-vision floor, 3:1 against the
11
+ surface). The order is part of the validation: slot N stays slot N.
12
+ Red is not a line colour in any theme: it is reserved for a stopped train. */
13
+ :root,
14
+ :root[data-theme='light'] {
15
+ color-scheme: light;
16
+ --ground: #f1f3f1;
5
17
  --surface: #ffffff;
6
- --border: #e2e5ea;
7
- --text: #1c2024;
8
- --muted: #6b7280;
9
- --accent: #2563eb;
10
- --done: #16a34a;
11
- --ready: #d97706;
12
- --blocked: #9ca3af;
13
- --error: #dc2626;
14
- --error-bg: #fef2f2;
15
- --badge-req-bg: #e0edff;
16
- --badge-req-fg: #1d4ed8;
17
- --badge-issue-bg: #ffedd5;
18
- --badge-issue-fg: #c2410c;
19
- --badge-applying-bg: #cffafe;
20
- --badge-applying-fg: #0e7490;
21
- --badge-archiving-bg: #ede9fe;
22
- --badge-archiving-fg: #6d28d9;
23
- --badge-ready-bg: #dcfce7;
24
- --badge-ready-fg: #15803d;
25
- /* chart series (CVD-validated pair per theme, see ADR 001) */
26
- --chart-1: #2563eb;
27
- --chart-2: #0d9488;
28
- --ok: #16a34a;
29
- --ok-bg: #f0fdf4;
30
- --warn-bg: #fffbeb;
31
- --flash-bg: #dbeafe;
32
- --radius: 8px;
18
+ --surface-2: #f5f6f5;
19
+ --ink: #15181b;
20
+ --ink-2: #3a4147;
21
+ --muted: #5a6269;
22
+ --rule: #dcdfdc;
23
+ --rule-strong: #b3b9b5;
24
+ --sign: #262b30;
25
+ --sign-2: #343a40;
26
+ --sign-ink: #ffffff;
27
+ --sign-muted: #b9c1c8;
28
+ --focus: #0b63ce;
29
+ --stop: #e3002c;
30
+ /* Text on a --stop fill. The dark themes' brighter reds give white only
31
+ ~3:1, so they take the ground's near-black instead (>= 5:1). */
32
+ --stop-ink: #ffffff;
33
+ --error: #c4001f;
34
+ --error-bg: #fdecee;
35
+ /* Session state, never a line colour's job: working, and waiting on you. */
36
+ --live: #0a8a4a;
37
+ --wait: #b46a00;
38
+ --line-1: #0070bd;
39
+ --line-2: #b07a22;
40
+ --line-3: #008fa3;
41
+ --line-4: #d97706;
42
+ --line-5: #8246af;
43
+ --line-6: #008659;
44
+ --shadow-tip: 0 6px 18px rgb(0 0 0 / 0.18);
33
45
  }
34
46
 
35
47
  :root[data-theme='dark'] {
36
- --bg: #0f1115;
37
- --surface: #171a20;
38
- --border: #2a2f38;
39
- --text: #e6e8eb;
40
- --muted: #9199a3;
41
- --accent: #60a5fa;
42
- --done: #4ade80;
43
- --ready: #fbbf24;
44
- --blocked: #6b7280;
45
- --error: #f87171;
46
- --error-bg: #2a1414;
47
- --badge-req-bg: #16263f;
48
- --badge-req-fg: #93c5fd;
49
- --badge-issue-bg: #3a2411;
50
- --badge-issue-fg: #fdba74;
51
- --badge-applying-bg: #0b2e33;
52
- --badge-applying-fg: #67e8f9;
53
- --badge-archiving-bg: #241a3a;
54
- --badge-archiving-fg: #c4b5fd;
55
- --badge-ready-bg: #0d2b1a;
56
- --badge-ready-fg: #86efac;
57
- --chart-1: #3b82f6;
58
- --chart-2: #0d9488;
59
- --ok: #4ade80;
60
- --ok-bg: #10241a;
61
- --warn-bg: #2a2210;
62
- --flash-bg: #1e3a5f;
63
- }
64
-
48
+ color-scheme: dark;
49
+ --ground: #0e1012;
50
+ --surface: #1a1d21;
51
+ --surface-2: #22262b;
52
+ --ink: #e8ebed;
53
+ --ink-2: #c4cacf;
54
+ --muted: #9aa3ab;
55
+ --rule: #2b3036;
56
+ --rule-strong: #434a51;
57
+ --sign: #24292e;
58
+ --sign-2: #30363c;
59
+ --sign-ink: #f4f6f7;
60
+ --sign-muted: #aab3bb;
61
+ --focus: #6cb2ff;
62
+ --stop: #ff5a6a;
63
+ --stop-ink: #0e1012;
64
+ --error: #ff7a86;
65
+ --error-bg: #3b1b21;
66
+ --live: #3ec27e;
67
+ --wait: #f0a43a;
68
+ --line-1: #328edd;
69
+ --line-2: #b47d25;
70
+ --line-3: #0c9aaf;
71
+ --line-4: #ca6e01;
72
+ --line-5: #a26dce;
73
+ --line-6: #319f71;
74
+ --shadow-tip: 0 6px 18px rgb(0 0 0 / 0.5);
75
+ }
76
+
77
+ /* Dracula's own accents sit above the dark lightness band and fail the chroma
78
+ floor (cyan), so its lines keep Dracula's hues at validated lightness. */
65
79
  :root[data-theme='dracula'] {
66
- --bg: #282a36;
80
+ color-scheme: dark;
81
+ --ground: #282a36;
67
82
  --surface: #343746;
68
- --border: #44475a;
69
- --text: #f8f8f2;
70
- --muted: #6272a4;
71
- --accent: #bd93f9;
72
- --done: #50fa7b;
73
- --ready: #ffb86c;
74
- --blocked: #6272a4;
75
- --error: #ff5555;
76
- --error-bg: #402a33;
77
- --badge-req-bg: #313552;
78
- --badge-req-fg: #bd93f9;
79
- --badge-issue-bg: #3d3348;
80
- --badge-issue-fg: #ffb86c;
81
- --badge-applying-bg: #1e3a3f;
82
- --badge-applying-fg: #8be9fd;
83
- --badge-archiving-bg: #3d2b38;
84
- --badge-archiving-fg: #ff79c6;
85
- --badge-ready-bg: #1f3d2b;
86
- --badge-ready-fg: #50fa7b;
87
- --chart-1: #a76ef5;
88
- --chart-2: #0d9488;
89
- --ok: #50fa7b;
90
- --ok-bg: #1e3327;
91
- --warn-bg: #3a3120;
92
- --flash-bg: #2d3455;
93
- }
94
-
95
- * {
83
+ --surface-2: #3c3f51;
84
+ --ink: #f8f8f2;
85
+ --ink-2: #e2e2dc;
86
+ --muted: #bac0db;
87
+ --rule: #44475a;
88
+ --rule-strong: #5c6079;
89
+ --sign: #21222c;
90
+ --sign-2: #2d2f3c;
91
+ --sign-ink: #f8f8f2;
92
+ --sign-muted: #bac0db;
93
+ --focus: #bd93f9;
94
+ --stop: #ff5555;
95
+ --stop-ink: #21222c;
96
+ --error: #ff8080;
97
+ --error-bg: #4a2a33;
98
+ --live: #50fa7b;
99
+ --wait: #ffb86c;
100
+ --line-1: #a076da;
101
+ --line-2: #37a953;
102
+ --line-3: #d261a2;
103
+ --line-4: #919720;
104
+ --line-5: #738ad8;
105
+ --line-6: #c17e2f;
106
+ --shadow-tip: 0 6px 18px rgb(0 0 0 / 0.45);
107
+ }
108
+
109
+ :root {
110
+ --font-sans: system-ui, -apple-system, 'Segoe UI', 'PingFang TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', 'Noto Sans TC', 'Noto Sans CJK TC', sans-serif;
111
+ --font-mono: ui-monospace, 'Cascadia Mono', 'SF Mono', Menlo, Consolas, monospace;
112
+ --signbar-h: 52px;
113
+ --sidebar-w: 224px;
114
+ --line: var(--ink-2);
115
+ --line-soft: color-mix(in oklab, var(--line) 14%, var(--surface));
116
+ }
117
+
118
+ /* -- base -------------------------------------------------------------------- */
119
+
120
+ *,
121
+ *::before,
122
+ *::after {
96
123
  box-sizing: border-box;
97
124
  }
98
125
 
126
+ html {
127
+ scrollbar-color: var(--rule-strong) var(--ground);
128
+ -webkit-text-size-adjust: 100%;
129
+ }
130
+
99
131
  body {
100
132
  margin: 0;
101
- background: var(--bg);
102
- color: var(--text);
103
- font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
133
+ background: var(--ground);
134
+ color: var(--ink);
135
+ font-family: var(--font-sans);
104
136
  font-size: 14px;
105
- line-height: 1.5;
137
+ line-height: 1.55;
106
138
  }
107
139
 
108
- .mono {
109
- font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
110
- font-size: 0.9em;
140
+ ::selection {
141
+ background: color-mix(in oklab, var(--focus) 30%, var(--surface));
142
+ color: var(--ink);
111
143
  }
112
144
 
113
- .muted {
114
- color: var(--muted);
145
+ a {
146
+ color: inherit;
147
+ text-decoration-thickness: 1px;
148
+ text-underline-offset: 3px;
149
+ text-decoration-color: var(--rule-strong);
115
150
  }
116
151
 
117
- /* -- top bar -- */
118
- .topbar {
119
- display: flex;
120
- align-items: center;
121
- justify-content: space-between;
122
- gap: 16px;
123
- padding: 12px 20px;
124
- background: var(--surface);
125
- border-bottom: 1px solid var(--border);
126
- position: sticky;
127
- top: 0;
128
- z-index: 10;
152
+ a:hover {
153
+ text-decoration-color: currentColor;
129
154
  }
130
155
 
131
- .topbar-left {
132
- display: flex;
133
- align-items: baseline;
134
- gap: 12px;
135
- min-width: 0;
156
+ :focus-visible {
157
+ outline: 2px solid var(--focus);
158
+ outline-offset: 2px;
159
+ border-radius: 3px;
136
160
  }
137
161
 
138
- .brand {
139
- font-size: 18px;
140
- margin: 0;
141
- font-weight: 650;
162
+ button,
163
+ input,
164
+ select,
165
+ textarea {
166
+ font: inherit;
167
+ color: inherit;
142
168
  }
143
169
 
144
- .tabs {
145
- display: flex;
146
- gap: 4px;
170
+ .mono {
171
+ font-family: var(--font-mono);
172
+ font-size: 0.92em;
147
173
  }
148
174
 
149
- .tab {
150
- color: var(--muted);
151
- text-decoration: none;
152
- font-size: 13px;
153
- font-weight: 600;
154
- padding: 4px 10px;
155
- border-radius: var(--radius);
175
+ .num {
176
+ font-variant-numeric: tabular-nums;
156
177
  }
157
178
 
158
- .tab:hover {
159
- color: var(--text);
179
+ .muted {
180
+ color: var(--muted);
160
181
  }
161
182
 
162
- .tab-active {
163
- color: var(--accent);
164
- background: var(--bg);
183
+ .note {
184
+ color: var(--muted);
185
+ font-size: 13px;
186
+ margin: 8px 0;
165
187
  }
166
188
 
167
- .root-path {
168
- color: var(--muted);
169
- white-space: nowrap;
189
+ .sr-only {
190
+ position: absolute;
191
+ width: 1px;
192
+ height: 1px;
193
+ margin: -1px;
194
+ padding: 0;
170
195
  overflow: hidden;
171
- text-overflow: ellipsis;
172
- max-width: 40vw;
196
+ clip: rect(0 0 0 0);
197
+ white-space: nowrap;
198
+ border: 0;
173
199
  }
174
200
 
175
- .topbar-right {
201
+ .icon {
202
+ flex: none;
203
+ fill: none;
204
+ stroke: currentColor;
205
+ stroke-width: 1.6;
206
+ stroke-linecap: round;
207
+ stroke-linejoin: round;
208
+ }
209
+
210
+ /* -- sign bar: the station-name panel ---------------------------------------- */
211
+
212
+ .signbar {
213
+ position: sticky;
214
+ top: 0;
215
+ z-index: 20;
176
216
  display: flex;
177
217
  align-items: center;
178
- gap: 12px;
218
+ gap: 18px;
219
+ height: var(--signbar-h);
220
+ padding: 0 20px;
221
+ background: var(--sign);
222
+ color: var(--sign-ink);
179
223
  }
180
224
 
181
- .conn {
182
- color: var(--error);
183
- font-size: 12px;
225
+ /* On a project's pages the panel carries that line's colour along its foot,
226
+ the way a platform sign names the line it serves. */
227
+ .signbar.has-line {
228
+ box-shadow: inset 0 -4px 0 var(--line);
184
229
  }
185
230
 
186
- .conn.disconnected::before {
187
- content: "\25cf ";
231
+ .wordmark {
232
+ display: inline-flex;
233
+ align-items: center;
234
+ gap: 9px;
235
+ font-size: 18px;
236
+ font-weight: 800;
237
+ letter-spacing: -0.01em;
238
+ color: var(--sign-ink);
239
+ text-decoration: none;
240
+ flex: none;
188
241
  }
189
242
 
190
- button,
191
- #theme-select,
192
- .range-select {
193
- font: inherit;
194
- color: var(--text);
195
- background: var(--surface);
196
- border: 1px solid var(--border);
197
- border-radius: var(--radius);
198
- padding: 5px 12px;
199
- cursor: pointer;
243
+ .wordmark::before {
244
+ content: '';
245
+ width: 14px;
246
+ height: 14px;
247
+ border-radius: 50%;
248
+ border: 3.5px solid var(--sign-ink);
249
+ background: var(--sign);
200
250
  }
201
251
 
202
- button:hover,
203
- #theme-select:hover,
204
- .range-select:hover {
205
- border-color: var(--accent);
252
+ .crumbs-nav {
253
+ min-width: 0;
254
+ flex: 1;
206
255
  }
207
256
 
208
- .range-select {
209
- float: right;
210
- font-size: 11px;
211
- text-transform: none;
212
- letter-spacing: normal;
213
- padding: 1px 6px;
257
+ .crumbs {
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 8px;
261
+ margin: 0;
262
+ padding: 0;
263
+ list-style: none;
264
+ font-size: 13px;
265
+ color: var(--sign-muted);
266
+ min-width: 0;
214
267
  }
215
268
 
216
- /* -- layout -- */
217
- .view {
218
- max-width: 900px;
219
- margin: 0 auto;
220
- padding: 20px;
269
+ .crumbs li {
270
+ display: flex;
271
+ align-items: center;
272
+ gap: 8px;
273
+ min-width: 0;
274
+ white-space: nowrap;
221
275
  }
222
276
 
223
- .cards {
224
- display: flex;
225
- flex-wrap: wrap;
226
- gap: 12px;
227
- margin-bottom: 24px;
277
+ .crumbs li + li::before {
278
+ content: '/';
279
+ color: var(--sign-muted);
280
+ opacity: 0.6;
228
281
  }
229
282
 
230
- .card {
231
- flex: 1 1 140px;
232
- background: var(--surface);
233
- border: 1px solid var(--border);
234
- border-radius: var(--radius);
235
- padding: 14px 16px;
236
- display: flex;
237
- flex-direction: column;
238
- gap: 2px;
283
+ /* Every crumb may shrink; the text inside it ellipsizes rather than running
284
+ into the next crumb on a narrow bar. */
285
+ .crumbs li > * {
286
+ min-width: 0;
239
287
  }
240
288
 
241
- .card-count {
242
- font-size: 26px;
243
- font-weight: 700;
289
+ .crumb-text {
290
+ overflow: hidden;
291
+ text-overflow: ellipsis;
292
+ white-space: nowrap;
244
293
  }
245
294
 
246
- .card-label {
247
- color: var(--muted);
248
- font-size: 12px;
249
- text-transform: uppercase;
250
- letter-spacing: 0.04em;
295
+ .crumbs a {
296
+ color: var(--sign-muted);
297
+ text-decoration: none;
251
298
  }
252
299
 
253
- /* -- health strip -- */
254
- .health {
255
- display: flex;
256
- flex-wrap: wrap;
257
- align-items: center;
258
- gap: 8px 20px;
259
- padding: 10px 14px;
260
- border-radius: var(--radius);
261
- border: 1px solid var(--border);
262
- margin-bottom: 16px;
263
- font-size: 13px;
300
+ .crumbs a:hover {
301
+ color: var(--sign-ink);
264
302
  }
265
303
 
266
- .health-ok {
267
- background: var(--ok-bg);
268
- border-color: var(--ok);
269
- color: var(--ok);
304
+ .crumbs [aria-current] {
305
+ color: var(--sign-ink);
306
+ font-weight: 600;
270
307
  }
271
308
 
272
- .health-warn {
273
- background: var(--warn-bg);
274
- border-color: var(--ready);
309
+ .crumb-project a,
310
+ .crumb-project > span {
311
+ display: inline-flex;
312
+ align-items: center;
313
+ gap: 7px;
275
314
  }
276
315
 
277
- .health-warn .health-item::before {
278
- content: "\26a0 ";
279
- color: var(--ready);
316
+ .crumbs .line-swatch,
317
+ .crumb-back .line-swatch {
318
+ width: 16px;
319
+ height: 5px;
280
320
  }
281
321
 
282
- a.health-item {
283
- color: inherit;
322
+ /* Narrow bars only: one step up, in place of the trail. */
323
+ .crumb-back {
324
+ display: none;
325
+ align-items: center;
326
+ gap: 6px;
327
+ min-width: 0;
328
+ max-width: 100%;
329
+ font-size: 13px;
330
+ font-weight: 600;
331
+ color: var(--sign-ink);
284
332
  text-decoration: none;
285
333
  }
286
334
 
287
- a.health-item:hover {
288
- text-decoration: underline;
335
+ .crumb-back .icon {
336
+ color: var(--sign-muted);
289
337
  }
290
338
 
291
- /* -- charts -- */
292
- .charts-grid {
293
- display: grid;
294
- grid-template-columns: 2fr 1fr;
295
- gap: 12px;
296
- margin-bottom: 24px;
339
+ .signbar-tools {
340
+ display: flex;
341
+ align-items: center;
342
+ gap: 10px;
343
+ flex: none;
297
344
  }
298
345
 
299
- .charts-grid-3 {
300
- grid-template-columns: 1fr 1fr 1fr;
346
+ .hub-status {
347
+ display: inline-flex;
348
+ align-items: center;
349
+ gap: 7px;
350
+ font-size: 12px;
351
+ color: var(--sign-muted);
301
352
  }
302
353
 
303
- @media (max-width: 720px) {
304
- .charts-grid,
305
- .charts-grid-3 {
306
- grid-template-columns: 1fr;
307
- }
354
+ .hub-dot {
355
+ width: 9px;
356
+ height: 9px;
357
+ border-radius: 50%;
358
+ border: 2px solid var(--sign-ink);
359
+ background: var(--sign-ink);
308
360
  }
309
361
 
310
- .chart-panel {
311
- background: var(--surface);
312
- border: 1px solid var(--border);
313
- border-radius: var(--radius);
314
- padding: 12px 14px;
315
- min-width: 0;
316
- margin-bottom: 0;
362
+ .hub-status.is-down {
363
+ color: var(--sign-ink);
317
364
  }
318
365
 
319
- /* -- task progress -- */
320
- details.task-change,
321
- .row.task-none {
322
- background: var(--surface);
323
- border: 1px solid var(--border);
324
- border-radius: var(--radius);
325
- margin-bottom: 6px;
366
+ .hub-status.is-down .hub-dot {
367
+ border-radius: 1.5px;
368
+ border-color: var(--stop);
369
+ background: var(--stop);
326
370
  }
327
371
 
328
- details.task-change summary {
372
+ .sign-control {
373
+ height: 32px;
374
+ padding: 0 10px;
375
+ border: 1px solid color-mix(in oklab, var(--sign-ink) 22%, transparent);
376
+ border-radius: 6px;
377
+ background: var(--sign-2);
378
+ color: var(--sign-ink);
329
379
  cursor: pointer;
330
- display: flex;
331
- align-items: center;
332
- gap: 12px;
333
- padding: 10px 12px;
334
- list-style: none;
335
380
  }
336
381
 
337
- /* display:flex drops the native marker, so draw our own caret. */
338
- details.task-change summary::-webkit-details-marker {
339
- display: none;
382
+ .sign-control:hover {
383
+ border-color: color-mix(in oklab, var(--sign-ink) 55%, transparent);
340
384
  }
341
385
 
342
- details.task-change summary::before {
343
- content: '';
344
- flex: none;
345
- width: 0;
346
- height: 0;
347
- border-left: 5px solid var(--muted);
348
- border-top: 4px solid transparent;
349
- border-bottom: 4px solid transparent;
350
- transition: transform 0.15s ease;
386
+ .sign-button {
387
+ display: inline-flex;
388
+ align-items: center;
389
+ gap: 6px;
351
390
  }
352
391
 
353
- details.task-change[open] summary::before {
354
- transform: rotate(90deg);
392
+ .sign-button:disabled {
393
+ cursor: progress;
394
+ opacity: 0.65;
355
395
  }
356
396
 
357
- details.task-change summary:hover {
358
- color: var(--accent);
397
+ .sign-button:disabled .icon {
398
+ animation: spin 0.9s linear infinite;
359
399
  }
360
400
 
361
- .task-bar {
362
- margin-left: auto;
363
- width: 140px;
364
- height: 8px;
365
- flex: none;
366
- border: none;
367
- border-radius: 4px;
368
- background: var(--border);
369
- /* Firefox styles the bar through the element itself. */
370
- appearance: none;
401
+ @keyframes spin {
402
+ to {
403
+ transform: rotate(360deg);
404
+ }
371
405
  }
372
406
 
373
- .task-bar::-webkit-progress-bar {
374
- background: var(--border);
375
- border-radius: 4px;
376
- }
407
+ /* -- page frame: the sidebar beside the page --------------------------------- */
377
408
 
378
- .task-bar::-webkit-progress-value {
379
- background: var(--done);
380
- border-radius: 4px;
409
+ .shell {
410
+ display: grid;
411
+ grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
412
+ align-items: start;
381
413
  }
382
414
 
383
- .task-bar::-moz-progress-bar {
384
- background: var(--done);
385
- border-radius: 4px;
415
+ /* The page reflows on its own width, not the window's: the sidebar takes a
416
+ share of the window, and the map needs what is left for its four columns. */
417
+ .view {
418
+ container: view / inline-size;
419
+ width: 100%;
420
+ max-width: 1480px;
421
+ margin: 0 auto;
422
+ padding: 28px 24px 72px;
386
423
  }
387
424
 
388
- .task-count {
389
- font-variant-numeric: tabular-nums;
390
- font-size: 12px;
391
- color: var(--muted);
392
- min-width: 44px;
393
- text-align: right;
425
+ .view:focus {
426
+ outline: none;
394
427
  }
395
428
 
396
- .task-body {
397
- padding: 2px 12px 10px 29px;
429
+ /* Only below 960px, where the sidebar is a drawer. */
430
+ .nav-toggle {
431
+ display: none;
398
432
  }
399
433
 
400
- .task-file {
401
- font-size: 11px;
402
- color: var(--muted);
403
- margin: 8px 0 4px;
434
+ .sidebar {
435
+ position: sticky;
436
+ top: var(--signbar-h);
437
+ height: calc(100vh - var(--signbar-h));
438
+ overflow-y: auto;
439
+ overscroll-behavior: contain;
440
+ padding: 14px 10px 24px;
441
+ background: var(--surface);
442
+ border-right: 1px solid var(--rule);
404
443
  }
405
444
 
406
- .task-item {
445
+ .side-home {
407
446
  display: flex;
408
- align-items: baseline;
409
- gap: 8px;
410
- padding: 4px 0;
411
- cursor: pointer;
412
- }
413
-
414
- .task-item:hover .task-text {
415
- color: var(--accent);
447
+ align-items: center;
448
+ gap: 9px;
449
+ padding: 7px 10px;
450
+ border-radius: 7px;
451
+ font-weight: 650;
452
+ text-decoration: none;
453
+ color: var(--ink-2);
416
454
  }
417
455
 
418
- .task-box {
419
- accent-color: var(--done);
420
- cursor: pointer;
456
+ .side-home:hover {
457
+ background: var(--surface-2);
458
+ color: var(--ink);
421
459
  }
422
460
 
423
- .task-box:disabled {
424
- cursor: progress;
461
+ .side-home[aria-current='page'] {
462
+ background: var(--surface-2);
463
+ color: var(--ink);
464
+ box-shadow: inset 3px 0 0 var(--ink);
425
465
  }
426
466
 
427
- .task-item-done .task-text {
467
+ .side-title {
468
+ display: flex;
469
+ align-items: center;
470
+ gap: 8px;
471
+ margin: 18px 10px 6px;
472
+ font-size: 12px;
473
+ font-weight: 700;
474
+ letter-spacing: 0.04em;
475
+ text-transform: uppercase;
428
476
  color: var(--muted);
429
- text-decoration: line-through;
430
477
  }
431
478
 
432
- .task-item-locked {
433
- opacity: 0.55;
434
- cursor: not-allowed;
479
+ .side-projects,
480
+ .side-changes {
481
+ margin: 0;
482
+ padding: 0;
483
+ list-style: none;
435
484
  }
436
485
 
437
- .task-locked-note {
438
- font-size: 11px;
439
- color: var(--muted);
440
- margin: 8px 0;
486
+ .side-project + .side-project {
487
+ margin-top: 2px;
441
488
  }
442
489
 
443
- .task-error {
444
- color: var(--error);
445
- font-size: 12px;
490
+ .side-row {
491
+ display: grid;
492
+ grid-template-columns: 24px minmax(0, 1fr) auto;
493
+ align-items: center;
494
+ gap: 2px;
495
+ border-radius: 7px;
446
496
  }
447
497
 
448
- .chart-wrap {
449
- position: relative;
498
+ .side-project.is-current > .side-row {
499
+ background: var(--line-soft);
450
500
  }
451
501
 
452
- .chart-note {
453
- margin: 0;
502
+ .side-toggle {
503
+ display: grid;
504
+ place-items: center;
505
+ width: 24px;
506
+ height: 28px;
507
+ padding: 0;
508
+ border: 0;
509
+ border-radius: 5px;
510
+ background: transparent;
511
+ color: var(--muted);
512
+ cursor: pointer;
454
513
  }
455
514
 
456
- /* -- dynamics -- */
457
- @keyframes row-flash {
458
- 0% {
459
- background: var(--flash-bg);
460
- }
461
- 100% {
462
- background: var(--surface);
463
- }
515
+ .side-toggle:hover {
516
+ color: var(--ink);
464
517
  }
465
518
 
466
- .row.flash {
467
- animation: row-flash 1.6s ease-out;
519
+ .side-toggle .icon {
520
+ transform: rotate(-90deg);
521
+ transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
468
522
  }
469
523
 
470
- /* Live phase: a persistent breathing glow, distinct from the one-shot flash.
471
- The inset bar reads even at rest; the outer glow pulses. Hue and cadence
472
- separate applying (cyan, ~2s) from archiving (violet, ~3.2s) from ready
473
- (green, ~4.4s). Cadence tracks how much the row wants your attention, not
474
- lifecycle order: archiving is transient and worth a look, ready is a standing
475
- reminder that should not nag, so it breathes slowest of the three. */
476
- @keyframes pulse-applying {
477
- 0%,
478
- 100% {
479
- box-shadow: inset 3px 0 0 var(--badge-applying-fg), 0 0 0 0 transparent;
480
- }
481
- 50% {
482
- box-shadow: inset 3px 0 0 var(--badge-applying-fg), 0 0 7px 0 var(--badge-applying-fg);
483
- }
524
+ .side-toggle[aria-expanded='true'] .icon {
525
+ transform: none;
484
526
  }
485
527
 
486
- .row-applying {
487
- animation: pulse-applying 2s ease-in-out infinite;
528
+ .side-link {
529
+ display: flex;
530
+ align-items: center;
531
+ gap: 8px;
532
+ min-width: 0;
533
+ padding: 5px 4px;
534
+ font-weight: 650;
535
+ text-decoration: none;
488
536
  }
489
537
 
490
- @keyframes pulse-archiving {
491
- 0%,
492
- 100% {
493
- box-shadow: inset 3px 0 0 var(--badge-archiving-fg), 0 0 0 0 transparent;
494
- }
495
- 50% {
496
- box-shadow: inset 3px 0 0 var(--badge-archiving-fg), 0 0 9px 0 var(--badge-archiving-fg);
497
- }
538
+ .side-link:hover .side-name {
539
+ text-decoration: underline;
498
540
  }
499
541
 
500
- .row-archiving {
501
- animation: pulse-archiving 3.2s ease-in-out infinite;
542
+ .side-link[aria-current='page'] .side-name {
543
+ font-weight: 800;
502
544
  }
503
545
 
504
- @keyframes pulse-ready {
505
- 0%,
506
- 100% {
507
- box-shadow: inset 3px 0 0 var(--badge-ready-fg), 0 0 0 0 transparent;
508
- }
509
- 50% {
510
- box-shadow: inset 3px 0 0 var(--badge-ready-fg), 0 0 9px 0 var(--badge-ready-fg);
511
- }
546
+ .side-link .line-swatch {
547
+ width: 16px;
548
+ height: 6px;
512
549
  }
513
550
 
514
- .row-ready {
515
- animation: pulse-ready 4.4s ease-in-out infinite;
551
+ .side-name,
552
+ .side-change-name {
553
+ overflow: hidden;
554
+ text-overflow: ellipsis;
555
+ white-space: nowrap;
516
556
  }
517
557
 
518
- /* No prior reduced-motion handling existed; a persistent animation needs this
519
- accessibility floor. Degrade the breathing glow to a static left colour bar. */
520
- @media (prefers-reduced-motion: reduce) {
521
- .row-applying,
522
- .row-archiving,
523
- .row-ready {
524
- animation: none;
525
- }
526
- .row-applying {
527
- box-shadow: inset 3px 0 0 var(--badge-applying-fg);
528
- }
529
- .row-archiving {
530
- box-shadow: inset 3px 0 0 var(--badge-archiving-fg);
531
- }
532
- .row-ready {
533
- box-shadow: inset 3px 0 0 var(--badge-ready-fg);
534
- }
558
+ .is-offline .side-name {
559
+ color: var(--muted);
535
560
  }
536
561
 
537
- /* -- panels & rows -- */
538
- .panel {
539
- margin-bottom: 24px;
562
+ .side-sessions {
563
+ display: inline-flex;
564
+ align-items: center;
565
+ gap: 6px;
566
+ padding: 0 9px 0 6px;
567
+ font-size: 12px;
568
+ font-weight: 650;
569
+ color: var(--ink-2);
540
570
  }
541
571
 
542
- .section-title,
543
- .panel h3 {
544
- font-size: 13px;
545
- text-transform: uppercase;
546
- letter-spacing: 0.05em;
547
- color: var(--muted);
548
- margin: 0 0 8px;
572
+ .side-changes {
573
+ margin: 2px 0 6px 24px;
574
+ border-left: 2px solid color-mix(in oklab, var(--line) 40%, var(--surface));
549
575
  }
550
576
 
551
- .row {
577
+ .side-change {
552
578
  display: flex;
553
579
  align-items: center;
554
- gap: 12px;
555
- padding: 10px 12px;
556
- background: var(--surface);
557
- border: 1px solid var(--border);
558
- border-radius: var(--radius);
559
- margin-bottom: 6px;
580
+ gap: 7px;
581
+ min-width: 0;
582
+ padding: 4px 8px 4px 10px;
583
+ border-radius: 0 6px 6px 0;
584
+ font-size: 13px;
585
+ color: var(--ink-2);
560
586
  text-decoration: none;
561
- color: inherit;
562
587
  }
563
588
 
564
- a.row:hover {
565
- border-color: var(--accent);
589
+ .side-change:hover {
590
+ background: var(--surface-2);
591
+ color: var(--ink);
566
592
  }
567
593
 
568
- .row-name {
569
- font-weight: 600;
594
+ .side-change[aria-current='page'] {
595
+ margin-left: -2px;
596
+ border-left: 2px solid var(--line);
597
+ background: var(--line-soft);
598
+ color: var(--ink);
599
+ font-weight: 650;
570
600
  }
571
601
 
572
- .row-meta {
573
- color: var(--muted);
602
+ .side-empty {
603
+ margin: 4px 10px;
604
+ padding: 2px 0;
574
605
  font-size: 12px;
575
- }
576
-
577
- .row-time {
578
- margin-left: auto;
579
606
  color: var(--muted);
580
- font-size: 12px;
581
- white-space: nowrap;
582
607
  }
583
608
 
584
- .row-error {
585
- border-color: var(--error);
586
- background: var(--error-bg);
609
+ .side-changes .side-empty {
610
+ margin-left: 12px;
587
611
  }
588
612
 
589
- .parse-error {
590
- color: var(--error);
613
+ .side-foot {
614
+ margin: 18px 10px 0;
615
+ padding-top: 10px;
616
+ border-top: 1px solid var(--rule);
591
617
  font-size: 12px;
618
+ color: var(--muted);
592
619
  }
593
620
 
594
- /* Ticket text wraps instead of being clipped. overflow-wrap: anywhere, not
595
- break-word: only anywhere shrinks a flex item's min-content size, so a long
596
- token breaks instead of widening the row. Inherits to title, link, summary. */
597
- .ticket-row {
598
- flex-wrap: wrap;
599
- overflow-wrap: anywhere;
621
+ .nav-scrim {
622
+ position: fixed;
623
+ inset: var(--signbar-h) 0 0;
624
+ z-index: 25;
625
+ background: rgb(0 0 0 / 0.32);
600
626
  }
601
627
 
602
- /* The leading date reuses .row-time (margin-left:auto); cancel it so ticket
603
- content stays packed to the left instead of being pushed to the right. */
604
- .ticket-row .row-time {
605
- margin-left: 0;
628
+ .nav-scrim[hidden] {
629
+ display: none;
606
630
  }
607
631
 
608
- .ticket-summary {
609
- color: var(--muted);
610
- }
632
+ @media (max-width: 959px) {
633
+ .shell {
634
+ grid-template-columns: minmax(0, 1fr);
635
+ }
611
636
 
612
- .ticket-change {
613
- color: var(--accent);
614
- text-decoration: none;
615
- font-size: 12px;
616
- }
637
+ .nav-toggle {
638
+ display: inline-flex;
639
+ width: 34px;
640
+ padding: 0;
641
+ justify-content: center;
642
+ flex: none;
643
+ }
617
644
 
618
- .ticket-change:hover {
619
- text-decoration: underline;
645
+ .sidebar {
646
+ position: fixed;
647
+ top: var(--signbar-h);
648
+ bottom: 0;
649
+ left: 0;
650
+ z-index: 30;
651
+ width: min(300px, 86vw);
652
+ height: auto;
653
+ box-shadow: var(--shadow-tip);
654
+ transform: translateX(-102%);
655
+ visibility: hidden;
656
+ transition: transform 0.24s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 0.24s;
657
+ }
658
+
659
+ .sidebar.is-open {
660
+ transform: none;
661
+ visibility: visible;
662
+ transition: transform 0.24s cubic-bezier(0.16, 1, 0.3, 1);
663
+ }
620
664
  }
621
665
 
622
- /* -- badges -- */
623
- .badge {
624
- font-size: 11px;
625
- font-weight: 600;
626
- padding: 1px 7px;
627
- border-radius: 999px;
628
- text-transform: lowercase;
666
+ /* -- session activity: shape and motion, colour reinforcing ----------------------- */
667
+
668
+ .activity-dot {
669
+ position: relative;
670
+ flex: none;
671
+ display: inline-block;
672
+ width: 10px;
673
+ height: 10px;
674
+ border-radius: 50%;
629
675
  }
630
676
 
631
- .badge-requirement,
632
- .badge-sdd {
633
- background: var(--badge-req-bg);
634
- color: var(--badge-req-fg);
677
+ .activity-working {
678
+ background: var(--live);
635
679
  }
636
680
 
637
- .badge-issue {
638
- background: var(--badge-issue-bg);
639
- color: var(--badge-issue-fg);
681
+ /* A ring spreading from the disc: work is happening now. */
682
+ .activity-working::after {
683
+ content: '';
684
+ position: absolute;
685
+ inset: 0;
686
+ border-radius: 50%;
687
+ background: var(--live);
688
+ animation: activity-pulse 1.6s cubic-bezier(0.16, 1, 0.3, 1) infinite;
640
689
  }
641
690
 
642
- .badge-applying {
643
- background: var(--badge-applying-bg);
644
- color: var(--badge-applying-fg);
691
+ @keyframes activity-pulse {
692
+ from {
693
+ opacity: 0.55;
694
+ transform: scale(1);
695
+ }
696
+ to {
697
+ opacity: 0;
698
+ transform: scale(2.6);
699
+ }
645
700
  }
646
701
 
647
- .badge-archiving {
648
- background: var(--badge-archiving-bg);
649
- color: var(--badge-archiving-fg);
702
+ /* Half filled, blinking: the session is blocked on the person. */
703
+ .activity-waiting {
704
+ border: 2px solid var(--wait);
705
+ background: linear-gradient(90deg, var(--wait) 50%, transparent 50%);
706
+ animation: activity-blink 1.2s steps(2, jump-none) infinite;
650
707
  }
651
708
 
652
- .badge-ready {
653
- background: var(--badge-ready-bg);
654
- color: var(--badge-ready-fg);
709
+ @keyframes activity-blink {
710
+ 50% {
711
+ opacity: 0.35;
712
+ }
655
713
  }
656
714
 
657
- .badge-unknown,
658
- .badge-artifact {
659
- background: var(--border);
660
- color: var(--muted);
715
+ .activity-idle {
716
+ border: 2px solid var(--muted);
661
717
  }
662
718
 
663
- /* health-signal badges on rows */
664
- .badge-stale {
665
- background: var(--warn-bg);
666
- color: var(--ready);
719
+ .activity-offline {
720
+ height: 3px;
721
+ border-radius: 2px;
722
+ background: var(--rule-strong);
667
723
  }
668
724
 
669
- .badge-blocked-warn {
670
- background: var(--error-bg);
671
- color: var(--error);
725
+ .icon-button {
726
+ display: inline-grid;
727
+ place-items: center;
728
+ width: 28px;
729
+ height: 28px;
730
+ padding: 0;
731
+ border: 1px solid var(--rule);
732
+ border-radius: 6px;
733
+ background: var(--surface);
734
+ color: var(--ink-2);
735
+ cursor: pointer;
672
736
  }
673
737
 
674
- /* A change whose .tospec.yaml would not parse: every count beside it is a zero
675
- rather than a measurement, so it is marked as an error, not a progress state. */
676
- .badge-unreadable {
677
- background: var(--error-bg);
678
- color: var(--error);
738
+ .icon-button:hover {
739
+ border-color: var(--rule-strong);
740
+ color: var(--ink);
679
741
  }
680
742
 
681
- /* -- artifact blocks & status -- */
682
- .blocks {
683
- display: inline-flex;
684
- gap: 3px;
743
+ .page-head {
744
+ display: flex;
745
+ align-items: flex-end;
746
+ justify-content: space-between;
747
+ gap: 16px 24px;
748
+ flex-wrap: wrap;
749
+ margin-bottom: 16px;
685
750
  }
686
751
 
687
- .block {
688
- width: 12px;
689
- height: 12px;
690
- border-radius: 2px;
691
- border: 1px solid var(--blocked);
752
+ .page-title {
753
+ margin: 0;
754
+ font-size: 26px;
755
+ line-height: 1.25;
756
+ font-weight: 750;
757
+ letter-spacing: -0.01em;
758
+ overflow-wrap: anywhere;
759
+ text-wrap: balance;
692
760
  }
693
761
 
694
- .block-done {
695
- background: var(--done);
696
- border-color: var(--done);
762
+ .page-sub {
763
+ margin: 4px 0 0;
764
+ color: var(--muted);
765
+ font-size: 13px;
697
766
  }
698
767
 
699
- .dot {
700
- width: 10px;
701
- height: 10px;
702
- border-radius: 50%;
768
+ .count {
703
769
  display: inline-block;
704
- flex: none;
770
+ min-width: 20px;
771
+ padding: 0 7px;
772
+ border-radius: 999px;
773
+ background: var(--surface-2);
774
+ border: 1px solid var(--rule);
775
+ color: var(--ink-2);
776
+ font-size: 12px;
777
+ font-weight: 650;
778
+ line-height: 18px;
779
+ text-align: center;
780
+ font-variant-numeric: tabular-nums;
705
781
  }
706
782
 
707
- .dot-done {
708
- background: var(--done);
709
- }
710
- .dot-ready {
711
- background: var(--ready);
712
- }
713
- .dot-blocked {
714
- background: var(--blocked);
783
+ /* -- markers: shape carries the signal, colour only reinforces it ------------- */
784
+
785
+ .marker {
786
+ flex: none;
787
+ overflow: visible;
715
788
  }
716
789
 
717
- .artifact-row {
718
- display: flex;
719
- align-items: center;
720
- gap: 10px;
721
- padding: 6px 0;
790
+ .marker-moving circle,
791
+ .marker-running circle {
792
+ fill: var(--line);
722
793
  }
723
794
 
724
- .artifact-status {
725
- color: var(--muted);
726
- font-size: 12px;
795
+ .marker-call circle {
796
+ fill: var(--surface);
797
+ stroke: var(--line);
798
+ stroke-width: 2.6;
727
799
  }
728
800
 
729
- .blocked-by {
730
- color: var(--blocked);
731
- font-size: 12px;
801
+ .marker-idle circle {
802
+ fill: none;
803
+ stroke: var(--muted);
804
+ stroke-width: 2;
805
+ stroke-dasharray: 2.6 2.2;
732
806
  }
733
807
 
734
- /* -- detail views -- */
735
- .back {
736
- display: inline-block;
737
- margin-bottom: 12px;
738
- color: var(--accent);
739
- text-decoration: none;
808
+ .marker-stop rect {
809
+ fill: var(--stop);
740
810
  }
741
811
 
742
- .back:hover {
743
- text-decoration: underline;
812
+ .marker-parked rect {
813
+ fill: var(--muted);
744
814
  }
745
815
 
746
- .meta {
816
+ .legend {
747
817
  display: flex;
748
818
  flex-wrap: wrap;
749
- gap: 8px 16px;
750
- margin-bottom: 12px;
819
+ gap: 6px 16px;
820
+ margin: 0;
821
+ padding: 0;
822
+ list-style: none;
823
+ font-size: 12px;
824
+ color: var(--ink-2);
751
825
  }
752
826
 
753
- .meta-item {
827
+ .legend-item {
754
828
  display: inline-flex;
829
+ align-items: center;
755
830
  gap: 6px;
756
- align-items: baseline;
757
831
  }
758
832
 
759
- .meta-label {
760
- color: var(--muted);
761
- font-size: 12px;
762
- text-transform: uppercase;
763
- letter-spacing: 0.04em;
833
+ .line-badge {
834
+ display: inline-flex;
835
+ align-items: center;
836
+ gap: 7px;
837
+ min-width: 0;
764
838
  }
765
839
 
766
- .task-progress {
767
- font-weight: 600;
840
+ .line-swatch {
841
+ flex: none;
842
+ display: inline-block;
843
+ width: 22px;
844
+ height: 7px;
845
+ border-radius: 4px;
846
+ background: var(--line);
847
+ }
848
+
849
+ .line-name {
850
+ font-size: 12px;
851
+ font-weight: 650;
852
+ color: var(--ink-2);
768
853
  }
769
854
 
770
- details.file,
771
- details.archive {
772
- border: 1px solid var(--border);
773
- border-radius: var(--radius);
855
+ /* -- notices: what needs the user, across every project ---------------------- */
856
+
857
+ .notices {
858
+ margin-bottom: 20px;
859
+ padding: 14px 18px 6px;
774
860
  background: var(--surface);
775
- margin-bottom: 6px;
776
- padding: 4px 12px;
861
+ border: 1px solid var(--rule);
862
+ border-radius: 10px;
777
863
  }
778
864
 
779
- details.file summary,
780
- details.archive summary {
781
- cursor: pointer;
865
+ .notices-title {
782
866
  display: flex;
783
867
  align-items: center;
784
- gap: 10px;
785
- padding: 6px 0;
868
+ gap: 8px;
869
+ margin: 0 0 6px;
870
+ font-size: 15px;
871
+ font-weight: 700;
786
872
  }
787
873
 
788
- .rendered {
789
- padding: 4px 2px 12px;
790
- overflow-x: auto;
874
+ .notices-clear {
875
+ padding: 10px 18px;
876
+ background: transparent;
877
+ border-style: dashed;
791
878
  }
792
879
 
793
- .rendered pre {
794
- background: var(--bg);
795
- padding: 12px;
796
- border-radius: var(--radius);
797
- overflow-x: auto;
880
+ .notices-clear .notices-title {
881
+ margin: 0;
882
+ font-size: 13px;
883
+ font-weight: 600;
884
+ color: var(--muted);
798
885
  }
799
886
 
800
- .rendered code {
801
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
887
+ .notice-list {
888
+ margin: 0;
889
+ padding: 0;
890
+ list-style: none;
802
891
  }
803
892
 
804
- .rendered h1,
805
- .rendered h2,
806
- .rendered h3 {
807
- line-height: 1.3;
893
+ .notice {
894
+ display: grid;
895
+ grid-template-columns: 16px minmax(120px, max-content) minmax(0, max-content) minmax(0, 1fr);
896
+ align-items: center;
897
+ gap: 4px 12px;
898
+ padding: 9px 0;
899
+ border-top: 1px solid var(--rule);
900
+ }
901
+
902
+ .notice:first-child {
903
+ border-top: 0;
904
+ }
905
+
906
+ .notice-subject {
907
+ font-weight: 650;
908
+ overflow-wrap: anywhere;
808
909
  }
809
910
 
810
- .empty {
911
+ .notice-text {
811
912
  color: var(--muted);
812
- padding: 8px 2px;
913
+ font-size: 13px;
914
+ text-wrap: pretty;
813
915
  }
814
916
 
815
- .error {
917
+ .notice-stop .notice-text {
816
918
  color: var(--error);
817
- padding: 8px 12px;
818
- border: 1px solid var(--error);
819
- background: var(--error-bg);
820
- border-radius: var(--radius);
919
+ font-weight: 600;
821
920
  }
822
921
 
823
- /* -- decisions tab -- */
922
+ /* -- the route map ------------------------------------------------------------- */
923
+
924
+ /* --terminal-room: past the last station the line ends, but the trains
925
+ waiting there still need a full column's width to read. */
926
+ .map {
927
+ --label-w: 260px;
928
+ --terminal-room: 120px;
929
+ background: var(--surface);
930
+ border: 1px solid var(--rule);
931
+ border-radius: 12px;
932
+ }
824
933
 
825
- /* The index floats over the page instead of scrolling with it: always
826
- reachable while reading a long decision on the right. */
827
- .view-decisions {
828
- max-width: none;
829
- padding-left: 300px;
934
+ .map-head {
935
+ position: sticky;
936
+ top: var(--signbar-h);
937
+ z-index: 4;
938
+ display: grid;
939
+ grid-template-columns: var(--label-w) repeat(4, minmax(0, 1fr)) var(--terminal-room);
940
+ align-items: end;
941
+ padding: 14px 0 10px;
942
+ background: var(--surface);
943
+ border-bottom: 1px solid var(--rule);
944
+ border-radius: 12px 12px 0 0;
830
945
  }
831
946
 
832
- .decisions-index {
833
- position: fixed;
834
- left: 20px;
835
- top: 12%;
836
- height: 70vh;
837
- width: 260px;
947
+ .map-head-label {
948
+ padding-left: 22px;
949
+ font-size: 12px;
950
+ color: var(--muted);
951
+ }
952
+
953
+ .map-head-station {
838
954
  display: flex;
839
955
  flex-direction: column;
840
- padding: 12px;
841
- background: var(--surface);
842
- border: 1px solid var(--border);
843
- border-radius: var(--radius);
844
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
845
- z-index: 5;
956
+ align-items: center;
957
+ gap: 1px;
958
+ text-align: center;
846
959
  }
847
960
 
848
- .decisions-search {
849
- font: inherit;
850
- color: var(--text);
851
- background: var(--bg);
852
- border: 1px solid var(--border);
853
- border-radius: var(--radius);
854
- padding: 6px 10px;
855
- margin-bottom: 8px;
856
- flex: none;
961
+ .map-head-station strong {
962
+ font-size: 15px;
963
+ font-weight: 750;
964
+ letter-spacing: 0.01em;
857
965
  }
858
966
 
859
- .decisions-list {
860
- overflow-y: auto;
861
- flex: 1;
862
- min-height: 0;
967
+ .map-head-hint {
968
+ font-size: 12px;
969
+ color: var(--muted);
863
970
  }
864
971
 
865
- .decision-row {
866
- display: block;
867
- padding: 8px 10px;
868
- margin-bottom: 4px;
869
- border: 1px solid transparent;
870
- border-radius: var(--radius);
871
- text-decoration: none;
872
- color: inherit;
972
+ .map-head-count {
973
+ margin-top: 3px;
974
+ min-width: 22px;
975
+ padding: 0 7px;
976
+ border-radius: 999px;
977
+ background: var(--ink);
978
+ color: var(--surface);
979
+ font-size: 11px;
980
+ font-weight: 700;
981
+ line-height: 18px;
982
+ font-variant-numeric: tabular-nums;
873
983
  }
874
984
 
875
- .decision-row:hover {
876
- border-color: var(--accent);
985
+ .map-head-count.is-zero {
986
+ background: transparent;
987
+ color: var(--muted);
988
+ box-shadow: inset 0 0 0 1px var(--rule);
877
989
  }
878
990
 
879
- .decision-row-active {
880
- border-color: var(--accent);
881
- background: var(--bg);
991
+ .line-row {
992
+ display: grid;
993
+ grid-template-columns: var(--label-w) minmax(0, 1fr) var(--terminal-room);
994
+ align-items: start;
995
+ padding: 20px 0 22px;
996
+ border-top: 1px solid var(--rule);
882
997
  }
883
998
 
884
- .decision-title {
885
- font-weight: 600;
886
- display: block;
999
+ .map-head + .line-row {
1000
+ border-top: 0;
887
1001
  }
888
1002
 
889
- .decision-meta {
890
- display: flex;
1003
+ .line-label {
1004
+ padding: 0 18px 0 22px;
1005
+ min-width: 0;
1006
+ }
1007
+
1008
+ .line-title {
1009
+ margin: 0;
1010
+ font-size: 17px;
1011
+ font-weight: 700;
1012
+ line-height: 1.3;
1013
+ }
1014
+
1015
+ .line-title a {
1016
+ display: inline-flex;
891
1017
  align-items: center;
892
- gap: 8px;
1018
+ gap: 9px;
1019
+ text-decoration: none;
1020
+ overflow-wrap: anywhere;
1021
+ }
1022
+
1023
+ .line-title a:hover span:last-child {
1024
+ text-decoration: underline;
1025
+ text-underline-offset: 3px;
1026
+ }
1027
+
1028
+ .line-title .line-swatch {
1029
+ width: 28px;
1030
+ height: 9px;
1031
+ border-radius: 5px;
1032
+ }
1033
+
1034
+ .line-status,
1035
+ .line-terminal {
1036
+ margin: 4px 0 0;
1037
+ font-size: 12px;
893
1038
  color: var(--muted);
894
- font-size: 11px;
895
- margin-top: 2px;
1039
+ display: flex;
1040
+ align-items: center;
1041
+ flex-wrap: wrap;
1042
+ gap: 0 6px;
1043
+ }
1044
+
1045
+ .status-dot {
1046
+ width: 8px;
1047
+ height: 8px;
1048
+ border-radius: 50%;
1049
+ background: var(--line);
896
1050
  }
897
1051
 
898
- .decisions-content {
899
- min-height: 200px;
1052
+ .status-word {
1053
+ font-weight: 700;
1054
+ color: var(--ink-2);
900
1055
  }
901
1056
 
902
- .badge-proposed {
903
- background: var(--warn-bg);
904
- color: var(--ready);
1057
+ .stations {
1058
+ position: relative;
1059
+ display: grid;
1060
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1061
+ margin: 0;
1062
+ padding: 0;
1063
+ list-style: none;
905
1064
  }
906
1065
 
907
- .badge-accepted {
908
- background: var(--ok-bg);
909
- color: var(--done);
1066
+ /* The line runs from the first station's centre to the last one's. */
1067
+ .track,
1068
+ .run-segment {
1069
+ position: absolute;
1070
+ top: 9px;
1071
+ height: 8px;
1072
+ border-radius: 4px;
910
1073
  }
911
1074
 
912
- .badge-superseded {
913
- background: var(--border);
914
- color: var(--muted);
1075
+ .track {
1076
+ left: 12.5%;
1077
+ right: 12.5%;
1078
+ background: var(--line);
915
1079
  }
916
1080
 
917
- /* 決策過程 Q&A cards (client-side enhancement of the last section). */
918
- .qa-cards {
1081
+ /* A change being worked on right now: the segment it is about to travel
1082
+ flows toward sync. */
1083
+ .run-segment {
1084
+ display: none;
1085
+ left: 37.5%;
1086
+ width: 25%;
1087
+ background: repeating-linear-gradient(90deg, color-mix(in oklab, var(--surface) 85%, transparent) 0 5px, transparent 5px 15px);
1088
+ animation: run-flow 1.1s linear infinite;
1089
+ }
1090
+
1091
+ .has-running .run-segment {
1092
+ display: block;
1093
+ }
1094
+
1095
+ @keyframes run-flow {
1096
+ from {
1097
+ background-position: 0 0;
1098
+ }
1099
+ to {
1100
+ background-position: 15px 0;
1101
+ }
1102
+ }
1103
+
1104
+ /* No session runs the line: a thin, faded rail. Dashes are left to the one
1105
+ segment that means "being worked on now". */
1106
+ .is-offline .track {
1107
+ top: 11px;
1108
+ height: 4px;
1109
+ border-radius: 2px;
1110
+ background: color-mix(in oklab, var(--line) 38%, var(--surface));
1111
+ }
1112
+
1113
+ .station {
1114
+ position: relative;
919
1115
  display: flex;
920
1116
  flex-direction: column;
921
- gap: 12px;
922
- margin-top: 12px;
1117
+ align-items: center;
1118
+ min-width: 0;
1119
+ padding: 0 10px;
923
1120
  }
924
1121
 
925
- .qa-card {
1122
+ .station-dot {
1123
+ position: relative;
1124
+ z-index: 1;
1125
+ width: 26px;
1126
+ height: 26px;
1127
+ border-radius: 50%;
1128
+ border: 4px solid var(--line);
926
1129
  background: var(--surface);
927
- border: 1px solid var(--border);
928
- border-radius: var(--radius);
929
- padding: 12px 14px;
930
1130
  }
931
1131
 
932
- .qa-q {
933
- font-weight: 600;
934
- color: var(--accent);
935
- margin-bottom: 6px;
1132
+ /* A terminal is drawn as the route map draws one: a longer stop at the line's end. */
1133
+ .station:last-child .station-dot {
1134
+ width: 42px;
1135
+ border-radius: 13px;
936
1136
  }
937
1137
 
938
- .qa-a {
939
- color: var(--text);
940
- white-space: pre-line; /* keep intentional line breaks in multi-line answers */
1138
+ .station.is-occupied .station-dot {
1139
+ background: var(--line);
1140
+ box-shadow: 0 0 0 3px var(--surface);
941
1141
  }
942
1142
 
943
- /* Narrow viewports: the fixed 70vh side panel would eat the whole screen —
944
- drop it back into the normal document flow above the content. */
945
- @media (max-width: 900px) {
946
- .view-decisions {
947
- padding-left: 20px;
948
- }
949
- .decisions-index {
950
- position: static;
951
- width: auto;
952
- height: auto;
953
- max-height: 40vh;
954
- margin-bottom: 16px;
1143
+ /* From an occupied station down to its first train. */
1144
+ .station.is-occupied::after {
1145
+ content: '';
1146
+ position: absolute;
1147
+ top: 26px;
1148
+ left: calc(50% - 1px);
1149
+ width: 2px;
1150
+ height: 18px;
1151
+ background: var(--line);
1152
+ }
1153
+
1154
+ .is-offline .station-dot {
1155
+ border-color: color-mix(in oklab, var(--line) 45%, var(--surface));
1156
+ }
1157
+
1158
+ .is-offline .station.is-occupied .station-dot {
1159
+ background: color-mix(in oklab, var(--line) 45%, var(--surface));
1160
+ }
1161
+
1162
+ .is-offline .station.is-occupied::after {
1163
+ background: color-mix(in oklab, var(--line) 45%, var(--surface));
1164
+ }
1165
+
1166
+ /* Trains hang from their station: each marker's centre sits on the station's
1167
+ x (8px padding + half a 14px marker), and the block runs right as far as
1168
+ the next station's x, where that station's own trains begin. */
1169
+ .trains {
1170
+ position: relative;
1171
+ display: flex;
1172
+ flex-direction: column;
1173
+ gap: 4px;
1174
+ align-self: flex-start;
1175
+ width: 100%;
1176
+ margin: 14px 0 0 calc(50% - 15px);
1177
+ padding: 0;
1178
+ list-style: none;
1179
+ }
1180
+
1181
+ /* Reaches into the label column's padding: a stopped train's name is the
1182
+ row's most important text and should not break inside it. */
1183
+ .depot {
1184
+ margin: 14px -14px 0;
1185
+ padding-top: 10px;
1186
+ border-top: 1px dashed var(--rule-strong);
1187
+ }
1188
+
1189
+ .depot-title {
1190
+ padding: 0 14px;
1191
+ }
1192
+
1193
+ .depot-title {
1194
+ margin: 0 0 4px;
1195
+ font-size: 12px;
1196
+ font-weight: 700;
1197
+ color: var(--ink-2);
1198
+ }
1199
+
1200
+ .depot .trains {
1201
+ width: auto;
1202
+ margin: 0;
1203
+ }
1204
+
1205
+ .station:last-child .trains {
1206
+ width: calc(50% + var(--terminal-room) - 6px);
1207
+ }
1208
+
1209
+ .train {
1210
+ padding: 7px 8px 8px;
1211
+ border-radius: 8px;
1212
+ transition: background-color 0.2s ease-out;
1213
+ }
1214
+
1215
+ .train:hover {
1216
+ background: var(--surface-2);
1217
+ }
1218
+
1219
+ .train.signal-stop {
1220
+ background: var(--error-bg);
1221
+ }
1222
+
1223
+ .train.just-arrived {
1224
+ animation: arrived 2.6s cubic-bezier(0.16, 1, 0.3, 1);
1225
+ }
1226
+
1227
+ @keyframes arrived {
1228
+ from {
1229
+ background-color: var(--line-soft);
1230
+ }
1231
+ }
1232
+
1233
+ .train-head {
1234
+ display: grid;
1235
+ grid-template-columns: 14px minmax(0, max-content) 24px;
1236
+ justify-content: start;
1237
+ align-items: center;
1238
+ gap: 8px;
1239
+ }
1240
+
1241
+ .train-name {
1242
+ font-weight: 650;
1243
+ line-height: 1.3;
1244
+ text-decoration: none;
1245
+ overflow-wrap: anywhere;
1246
+ }
1247
+
1248
+ .train-name:hover {
1249
+ text-decoration: underline;
1250
+ }
1251
+
1252
+ .train-toggle {
1253
+ display: grid;
1254
+ place-items: center;
1255
+ width: 24px;
1256
+ height: 24px;
1257
+ padding: 0;
1258
+ border: 0;
1259
+ border-radius: 5px;
1260
+ background: transparent;
1261
+ color: var(--muted);
1262
+ cursor: pointer;
1263
+ }
1264
+
1265
+ .train-toggle:hover {
1266
+ background: var(--rule);
1267
+ color: var(--ink);
1268
+ }
1269
+
1270
+ .train-toggle .icon {
1271
+ transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
1272
+ }
1273
+
1274
+ .train-toggle[aria-expanded='true'] .icon {
1275
+ transform: rotate(180deg);
1276
+ }
1277
+
1278
+ .train-gap {
1279
+ margin: 2px 0 0 22px;
1280
+ font-size: 12px;
1281
+ line-height: 1.45;
1282
+ color: var(--muted);
1283
+ text-wrap: pretty;
1284
+ }
1285
+
1286
+ /* A phrase that must not split: CJK text breaks between any two characters,
1287
+ which left a lone 析 on its own line. */
1288
+ .keep {
1289
+ white-space: nowrap;
1290
+ }
1291
+
1292
+ .signal-call .train-gap {
1293
+ color: var(--ink-2);
1294
+ font-weight: 600;
1295
+ }
1296
+
1297
+ .train-reason {
1298
+ display: block;
1299
+ margin-top: 2px;
1300
+ color: var(--ink-2);
1301
+ overflow-wrap: anywhere;
1302
+ }
1303
+
1304
+ .notice-hint {
1305
+ display: block;
1306
+ font-size: 12px;
1307
+ font-weight: 400;
1308
+ color: var(--muted);
1309
+ }
1310
+
1311
+ .drawer-goal code,
1312
+ .change-unreadable code {
1313
+ font-family: var(--font-mono);
1314
+ font-size: 0.92em;
1315
+ overflow-wrap: anywhere;
1316
+ }
1317
+
1318
+ .train-drawer {
1319
+ margin: 8px 0 2px 22px;
1320
+ padding-top: 8px;
1321
+ border-top: 1px dashed var(--rule-strong);
1322
+ font-size: 12px;
1323
+ color: var(--ink-2);
1324
+ }
1325
+
1326
+ .drawer-line {
1327
+ display: flex;
1328
+ align-items: center;
1329
+ gap: 8px;
1330
+ margin: 4px 0;
1331
+ }
1332
+
1333
+ .drawer-key {
1334
+ width: 32px;
1335
+ color: var(--muted);
1336
+ }
1337
+
1338
+ .drawer-goal {
1339
+ margin: 6px 0 0;
1340
+ color: var(--muted);
1341
+ }
1342
+
1343
+ .artifact-chips {
1344
+ display: flex;
1345
+ flex-wrap: wrap;
1346
+ gap: 4px 10px;
1347
+ margin: 0 0 6px;
1348
+ padding: 0;
1349
+ list-style: none;
1350
+ }
1351
+
1352
+ .artifact-chip {
1353
+ display: inline-flex;
1354
+ align-items: center;
1355
+ gap: 5px;
1356
+ font-size: 12px;
1357
+ }
1358
+
1359
+ .chip-dot {
1360
+ width: 9px;
1361
+ height: 9px;
1362
+ border-radius: 50%;
1363
+ border: 2px solid var(--line);
1364
+ }
1365
+
1366
+ .status-done .chip-dot {
1367
+ background: var(--line);
1368
+ }
1369
+
1370
+ .status-blocked .chip-dot {
1371
+ border-color: var(--rule-strong);
1372
+ border-style: dashed;
1373
+ }
1374
+
1375
+ .status-stub .chip-dot {
1376
+ background: linear-gradient(90deg, var(--line) 50%, transparent 50%);
1377
+ }
1378
+
1379
+ .meter {
1380
+ display: inline-block;
1381
+ width: 72px;
1382
+ height: 6px;
1383
+ overflow: hidden;
1384
+ border-radius: 3px;
1385
+ background: color-mix(in oklab, var(--line) 20%, var(--surface));
1386
+ vertical-align: middle;
1387
+ }
1388
+
1389
+ .meter-fill {
1390
+ display: block;
1391
+ height: 100%;
1392
+ border-radius: 3px;
1393
+ background: var(--line);
1394
+ }
1395
+
1396
+ .mini-route {
1397
+ display: none;
1398
+ }
1399
+
1400
+ .line-note {
1401
+ grid-column: 2;
1402
+ margin: 12px 0 0;
1403
+ text-align: center;
1404
+ font-size: 13px;
1405
+ color: var(--muted);
1406
+ }
1407
+
1408
+ .line-error {
1409
+ display: flex;
1410
+ align-items: center;
1411
+ justify-content: center;
1412
+ gap: 8px;
1413
+ color: var(--error);
1414
+ }
1415
+
1416
+ .badge-unreadable {
1417
+ display: inline-block;
1418
+ padding: 0 6px;
1419
+ border-radius: 3px;
1420
+ background: var(--error-bg);
1421
+ color: var(--error);
1422
+ font-size: 11px;
1423
+ font-weight: 750;
1424
+ line-height: 18px;
1425
+ }
1426
+
1427
+ .signal-stop .badge-unreadable {
1428
+ background: var(--stop);
1429
+ color: var(--stop-ink);
1430
+ }
1431
+
1432
+ /* A page narrower than the map was drawn for (a 1280px window beside the
1433
+ sidebar): the label column and the terminal give up width before the
1434
+ station columns do, so change names keep whole words. */
1435
+ @container view (max-width: 1099px) {
1436
+ .map {
1437
+ --label-w: 210px;
1438
+ --terminal-room: 100px;
1439
+ }
1440
+ }
1441
+
1442
+ /* Below the width four station columns can hold, each train carries its own
1443
+ four-stop strip and the shared grid steps aside. Measured on the page, not
1444
+ the window: beside the sidebar a 1280px window leaves the page ~1000px. */
1445
+ @container view (max-width: 959px) {
1446
+ .map-head,
1447
+ .track,
1448
+ .run-segment,
1449
+ .station-dot,
1450
+ .station:not(.is-occupied) {
1451
+ display: none;
1452
+ }
1453
+
1454
+ .line-row {
1455
+ grid-template-columns: minmax(0, 1fr);
1456
+ padding: 16px 16px 12px;
1457
+ }
1458
+
1459
+ .line-label {
1460
+ padding: 0 0 8px;
1461
+ }
1462
+
1463
+ .stations {
1464
+ display: block;
1465
+ }
1466
+
1467
+ .station {
1468
+ display: block;
1469
+ padding: 0;
1470
+ }
1471
+
1472
+ .station.is-occupied::after {
1473
+ display: none;
1474
+ }
1475
+
1476
+ .trains,
1477
+ .station:last-child .trains {
1478
+ width: auto;
1479
+ margin: 0;
1480
+ gap: 0;
1481
+ }
1482
+
1483
+ .train {
1484
+ display: grid;
1485
+ grid-template-columns: 108px minmax(0, 1fr);
1486
+ grid-template-areas: 'route head' 'route gap' 'drawer drawer';
1487
+ column-gap: 14px;
1488
+ padding: 10px 6px;
1489
+ border-top: 1px solid var(--rule);
1490
+ border-radius: 0;
1491
+ }
1492
+
1493
+ .train-head {
1494
+ grid-area: head;
1495
+ }
1496
+
1497
+ .train-gap {
1498
+ grid-area: gap;
1499
+ }
1500
+
1501
+ .train-drawer {
1502
+ grid-area: drawer;
1503
+ margin-left: 122px;
1504
+ }
1505
+
1506
+ .mini-route {
1507
+ grid-area: route;
1508
+ position: relative;
1509
+ display: grid;
1510
+ grid-template-columns: repeat(4, 12px);
1511
+ column-gap: 13px;
1512
+ align-content: start;
1513
+ padding-top: 3px;
1514
+ }
1515
+
1516
+ .mini-route::before {
1517
+ content: '';
1518
+ position: absolute;
1519
+ top: 7px;
1520
+ left: 6px;
1521
+ width: 75px;
1522
+ height: 4px;
1523
+ border-radius: 2px;
1524
+ background: var(--line);
1525
+ }
1526
+
1527
+ .mini-stop {
1528
+ position: relative;
1529
+ width: 12px;
1530
+ height: 12px;
1531
+ border-radius: 50%;
1532
+ border: 2.5px solid var(--line);
1533
+ background: var(--surface);
1534
+ }
1535
+
1536
+ .mini-stop.is-passed {
1537
+ background: color-mix(in oklab, var(--line) 45%, var(--surface));
1538
+ }
1539
+
1540
+ .mini-stop.is-here {
1541
+ background: var(--line);
1542
+ box-shadow: 0 0 0 3px var(--line-soft);
1543
+ }
1544
+
1545
+ .mini-route.is-unknown::before {
1546
+ background: var(--rule-strong);
1547
+ }
1548
+
1549
+ .mini-route.is-unknown .mini-stop {
1550
+ border-color: var(--rule-strong);
1551
+ border-style: dashed;
1552
+ }
1553
+
1554
+ .mini-label {
1555
+ grid-column: 1 / -1;
1556
+ margin-top: 5px;
1557
+ font-size: 11px;
1558
+ font-weight: 650;
1559
+ color: var(--ink-2);
1560
+ }
1561
+
1562
+ .line-note {
1563
+ grid-column: 1;
1564
+ text-align: left;
1565
+ }
1566
+
1567
+ .line-error {
1568
+ justify-content: flex-start;
1569
+ }
1570
+ }
1571
+
1572
+ /* Beside a terminal (a 620-959px page) the strip has room to read as a route. */
1573
+ @container view (min-width: 620px) and (max-width: 959px) {
1574
+ .train {
1575
+ grid-template-columns: 176px minmax(0, 1fr);
1576
+ }
1577
+
1578
+ .mini-route {
1579
+ column-gap: 30px;
1580
+ }
1581
+
1582
+ .mini-route::before {
1583
+ width: 126px;
1584
+ }
1585
+
1586
+ .train-drawer {
1587
+ margin-left: 190px;
1588
+ }
1589
+ }
1590
+
1591
+ /* -- onboarding ------------------------------------------------------------------ */
1592
+
1593
+ .onboard {
1594
+ max-width: 680px;
1595
+ margin: 48px auto;
1596
+ }
1597
+
1598
+ .onboard-lead {
1599
+ font-size: 15px;
1600
+ color: var(--ink-2);
1601
+ max-width: 62ch;
1602
+ }
1603
+
1604
+ .onboard-stations {
1605
+ --line: var(--ink-2);
1606
+ position: relative;
1607
+ display: grid;
1608
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1609
+ margin: 28px 0;
1610
+ padding: 0;
1611
+ list-style: none;
1612
+ }
1613
+
1614
+ .onboard-stations::before {
1615
+ content: '';
1616
+ position: absolute;
1617
+ top: 9px;
1618
+ left: 12.5%;
1619
+ right: 12.5%;
1620
+ height: 6px;
1621
+ border-radius: 3px;
1622
+ background: repeating-linear-gradient(90deg, var(--rule-strong) 0 12px, transparent 12px 20px);
1623
+ }
1624
+
1625
+ .onboard-stations li {
1626
+ display: flex;
1627
+ flex-direction: column;
1628
+ align-items: center;
1629
+ gap: 2px;
1630
+ text-align: center;
1631
+ }
1632
+
1633
+ .onboard-stations .station-dot {
1634
+ display: block;
1635
+ margin-bottom: 8px;
1636
+ border-color: var(--rule-strong);
1637
+ }
1638
+
1639
+ /* -- project page ------------------------------------------------------------------ */
1640
+
1641
+ .project-head {
1642
+ margin-bottom: 18px;
1643
+ }
1644
+
1645
+ .project-title {
1646
+ display: flex;
1647
+ align-items: center;
1648
+ gap: 12px;
1649
+ }
1650
+
1651
+ .project-title .line-swatch {
1652
+ width: 34px;
1653
+ height: 11px;
1654
+ border-radius: 6px;
1655
+ }
1656
+
1657
+ .project-root {
1658
+ margin: 6px 0 0;
1659
+ color: var(--muted);
1660
+ overflow: hidden;
1661
+ text-overflow: ellipsis;
1662
+ white-space: nowrap;
1663
+ }
1664
+
1665
+ .project-status {
1666
+ display: flex;
1667
+ align-items: center;
1668
+ flex-wrap: wrap;
1669
+ gap: 4px 8px;
1670
+ margin: 6px 0 0;
1671
+ font-size: 13px;
1672
+ color: var(--ink-2);
1673
+ }
1674
+
1675
+ .subnav {
1676
+ display: flex;
1677
+ gap: 4px;
1678
+ margin-top: 16px;
1679
+ border-bottom: 1px solid var(--rule);
1680
+ }
1681
+
1682
+ .subnav-link {
1683
+ display: inline-flex;
1684
+ align-items: center;
1685
+ gap: 8px;
1686
+ padding: 8px 12px 10px;
1687
+ margin-bottom: -1px;
1688
+ font-weight: 650;
1689
+ color: var(--muted);
1690
+ text-decoration: none;
1691
+ border-bottom: 3px solid transparent;
1692
+ }
1693
+
1694
+ .subnav-link:hover {
1695
+ color: var(--ink);
1696
+ }
1697
+
1698
+ .subnav-link[aria-current='page'] {
1699
+ color: var(--ink);
1700
+ border-bottom-color: var(--line);
1701
+ }
1702
+
1703
+ .map-single .line-row {
1704
+ padding-top: 18px;
1705
+ }
1706
+
1707
+ .drift-note {
1708
+ margin: 16px 0 0;
1709
+ padding: 10px 14px;
1710
+ border-radius: 8px;
1711
+ background: var(--surface);
1712
+ border: 1px dashed var(--rule-strong);
1713
+ color: var(--ink-2);
1714
+ font-size: 13px;
1715
+ }
1716
+
1717
+ /* -- charts ---------------------------------------------------------------------- */
1718
+
1719
+ .charts {
1720
+ display: grid;
1721
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1722
+ gap: 16px;
1723
+ margin: 28px 0 36px;
1724
+ }
1725
+
1726
+ .chart {
1727
+ position: relative;
1728
+ min-width: 0;
1729
+ margin: 0;
1730
+ padding: 16px 18px 12px;
1731
+ background: var(--surface);
1732
+ border: 1px solid var(--rule);
1733
+ border-radius: 12px;
1734
+ }
1735
+
1736
+ .chart-title {
1737
+ margin: 0;
1738
+ font-size: 15px;
1739
+ font-weight: 750;
1740
+ }
1741
+
1742
+ .chart-summary {
1743
+ margin: 2px 0 0;
1744
+ color: var(--muted);
1745
+ font-size: 13px;
1746
+ }
1747
+
1748
+ .chart-plot {
1749
+ margin-top: 14px;
1750
+ min-height: 24px;
1751
+ }
1752
+
1753
+ .chart-svg {
1754
+ display: block;
1755
+ overflow: visible;
1756
+ }
1757
+
1758
+ .chart-svg text {
1759
+ font-family: var(--font-sans);
1760
+ font-size: 12px;
1761
+ fill: var(--muted);
1762
+ }
1763
+
1764
+ .chart-svg .tick {
1765
+ font-variant-numeric: tabular-nums;
1766
+ }
1767
+
1768
+ .chart-svg .row-label {
1769
+ fill: var(--ink-2);
1770
+ }
1771
+
1772
+ .chart-svg .value {
1773
+ fill: var(--ink);
1774
+ font-weight: 650;
1775
+ font-variant-numeric: tabular-nums;
1776
+ }
1777
+
1778
+ .chart-svg .grid {
1779
+ stroke: var(--rule);
1780
+ stroke-width: 1;
1781
+ }
1782
+
1783
+ .chart-svg .axis {
1784
+ stroke: var(--rule-strong);
1785
+ stroke-width: 1;
1786
+ }
1787
+
1788
+ .chart-svg .hit {
1789
+ fill: transparent;
1790
+ }
1791
+
1792
+ .chart-svg [data-tip]:hover .hit {
1793
+ fill: var(--surface-2);
1794
+ }
1795
+
1796
+ .chart-svg .threshold {
1797
+ stroke: var(--ink-2);
1798
+ stroke-width: 1;
1799
+ stroke-dasharray: 4 3;
1800
+ }
1801
+
1802
+ .chart-svg .threshold-label {
1803
+ fill: var(--ink-2);
1804
+ font-size: 11px;
1805
+ }
1806
+
1807
+ .chart-svg .run {
1808
+ stroke: var(--line);
1809
+ stroke-width: 6;
1810
+ stroke-linecap: round;
1811
+ }
1812
+
1813
+ .chart-svg .idle {
1814
+ stroke: var(--muted);
1815
+ stroke-width: 2;
1816
+ stroke-dasharray: 2 4;
1817
+ stroke-linecap: round;
1818
+ }
1819
+
1820
+ .chart-svg .seen {
1821
+ fill: var(--line);
1822
+ stroke: var(--surface);
1823
+ stroke-width: 2;
1824
+ }
1825
+
1826
+ /* A stale change's last-seen dot takes the idle marker's dashed ring. */
1827
+ .chart-svg .is-stale .seen {
1828
+ fill: var(--surface);
1829
+ stroke: var(--muted);
1830
+ stroke-dasharray: 2.4 2;
1831
+ }
1832
+
1833
+ .chart-svg .is-stale .row-label {
1834
+ fill: var(--ink);
1835
+ font-weight: 700;
1836
+ }
1837
+
1838
+ .chart-svg .bar {
1839
+ fill: var(--line);
1840
+ }
1841
+
1842
+ .chart-svg .bar.is-other {
1843
+ fill: color-mix(in oklab, var(--line) 45%, var(--surface));
1844
+ }
1845
+
1846
+ .adr-accepted {
1847
+ fill: var(--line);
1848
+ stroke: var(--surface);
1849
+ stroke-width: 2;
1850
+ }
1851
+
1852
+ .adr-proposed {
1853
+ fill: var(--surface);
1854
+ stroke: var(--line);
1855
+ stroke-width: 2.2;
1856
+ }
1857
+
1858
+ .adr-superseded {
1859
+ fill: none;
1860
+ stroke: var(--muted);
1861
+ stroke-width: 1.8;
1862
+ stroke-linecap: round;
1863
+ }
1864
+
1865
+ .adr-other {
1866
+ fill: var(--muted);
1867
+ }
1868
+
1869
+ .chart-legend {
1870
+ display: flex;
1871
+ flex-wrap: wrap;
1872
+ gap: 4px 16px;
1873
+ margin: 8px 0 0;
1874
+ padding: 0;
1875
+ list-style: none;
1876
+ font-size: 12px;
1877
+ color: var(--ink-2);
1878
+ }
1879
+
1880
+ .chart-legend li {
1881
+ display: inline-flex;
1882
+ align-items: center;
1883
+ gap: 6px;
1884
+ }
1885
+
1886
+ .legend-swatch {
1887
+ overflow: visible;
1888
+ }
1889
+
1890
+ .chart-tip {
1891
+ position: absolute;
1892
+ z-index: 6;
1893
+ max-width: 260px;
1894
+ padding: 6px 9px;
1895
+ border-radius: 6px;
1896
+ background: var(--sign);
1897
+ color: var(--sign-ink);
1898
+ font-size: 12px;
1899
+ line-height: 1.45;
1900
+ pointer-events: none;
1901
+ box-shadow: var(--shadow-tip);
1902
+ }
1903
+
1904
+ .chart-tip.is-flipped {
1905
+ transform: translateX(-100%);
1906
+ }
1907
+
1908
+ .chart-table {
1909
+ margin-top: 8px;
1910
+ font-size: 12px;
1911
+ }
1912
+
1913
+ .chart-table summary {
1914
+ display: inline-flex;
1915
+ align-items: center;
1916
+ gap: 4px;
1917
+ cursor: pointer;
1918
+ color: var(--muted);
1919
+ list-style: none;
1920
+ }
1921
+
1922
+ .chart-table summary::-webkit-details-marker {
1923
+ display: none;
1924
+ }
1925
+
1926
+ .chart-table summary .icon {
1927
+ transform: rotate(-90deg);
1928
+ transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
1929
+ }
1930
+
1931
+ .chart-table[open] summary .icon {
1932
+ transform: none;
1933
+ }
1934
+
1935
+ .chart-table summary:hover {
1936
+ color: var(--ink);
1937
+ }
1938
+
1939
+ .data-table {
1940
+ width: 100%;
1941
+ margin-top: 8px;
1942
+ border-collapse: collapse;
1943
+ font-variant-numeric: tabular-nums;
1944
+ }
1945
+
1946
+ .data-table th {
1947
+ text-align: left;
1948
+ font-weight: 650;
1949
+ color: var(--ink-2);
1950
+ border-bottom: 1px solid var(--rule-strong);
1951
+ padding: 4px 8px 4px 0;
1952
+ }
1953
+
1954
+ .data-table td {
1955
+ padding: 4px 8px 4px 0;
1956
+ border-bottom: 1px solid var(--rule);
1957
+ overflow-wrap: anywhere;
1958
+ }
1959
+
1960
+ /* -- lists ------------------------------------------------------------------------- */
1961
+
1962
+ .project-lists {
1963
+ display: grid;
1964
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1965
+ gap: 28px 40px;
1966
+ }
1967
+
1968
+ .section-title {
1969
+ display: flex;
1970
+ align-items: center;
1971
+ gap: 8px;
1972
+ margin: 0 0 8px;
1973
+ font-size: 15px;
1974
+ font-weight: 750;
1975
+ }
1976
+
1977
+ .plain-list {
1978
+ margin: 0;
1979
+ padding: 0;
1980
+ list-style: none;
1981
+ }
1982
+
1983
+ .row {
1984
+ display: flex;
1985
+ align-items: baseline;
1986
+ gap: 10px;
1987
+ padding: 8px 0;
1988
+ border-bottom: 1px solid var(--rule);
1989
+ }
1990
+
1991
+ .row-name {
1992
+ font-weight: 650;
1993
+ }
1994
+
1995
+ a.row-name {
1996
+ text-decoration: none;
1997
+ }
1998
+
1999
+ a.row-name:hover {
2000
+ text-decoration: underline;
2001
+ }
2002
+
2003
+ .row-meta,
2004
+ .row-time {
2005
+ margin-left: auto;
2006
+ font-size: 12px;
2007
+ color: var(--muted);
2008
+ }
2009
+
2010
+ .row-time {
2011
+ white-space: nowrap;
2012
+ }
2013
+
2014
+ /* Ticket text wraps instead of being clipped. overflow-wrap: anywhere, not
2015
+ break-word: only anywhere shrinks a flex item's min-content size, so a long
2016
+ token breaks instead of widening the row. Inherits to title, link, summary. */
2017
+ .ticket-row {
2018
+ flex-wrap: wrap;
2019
+ overflow-wrap: anywhere;
2020
+ }
2021
+
2022
+ /* The leading date reuses .row-time (margin-left:auto); cancel it so ticket
2023
+ content stays packed to the left instead of being pushed to the right. */
2024
+ .ticket-row .row-time {
2025
+ margin-left: 0;
2026
+ }
2027
+
2028
+ .ticket-summary {
2029
+ flex-basis: 100%;
2030
+ color: var(--muted);
2031
+ font-size: 13px;
2032
+ }
2033
+
2034
+ .ticket-change {
2035
+ font-size: 12px;
2036
+ }
2037
+
2038
+ .row-error {
2039
+ background: var(--error-bg);
2040
+ padding-left: 8px;
2041
+ padding-right: 8px;
2042
+ border-radius: 6px;
2043
+ }
2044
+
2045
+ /* -- the project's sessions -------------------------------------------------------- */
2046
+
2047
+ .sessions-board {
2048
+ margin: 20px 0 0;
2049
+ padding: 14px 18px 8px;
2050
+ background: var(--surface);
2051
+ border: 1px solid var(--rule);
2052
+ border-radius: 10px;
2053
+ }
2054
+
2055
+ /* Session ids are full UUIDs: the id column takes the slack and wraps rather
2056
+ than push the time and the buttons off a narrow screen. */
2057
+ .session-row {
2058
+ display: grid;
2059
+ grid-template-columns: 96px minmax(0, 1fr) auto auto auto;
2060
+ align-items: center;
2061
+ gap: 4px 12px;
2062
+ padding: 8px 0;
2063
+ border-top: 1px solid var(--rule);
2064
+ }
2065
+
2066
+ .session-row:first-child {
2067
+ border-top: 0;
2068
+ }
2069
+
2070
+ .session-state {
2071
+ display: inline-flex;
2072
+ align-items: center;
2073
+ gap: 8px;
2074
+ font-size: 12px;
2075
+ font-weight: 650;
2076
+ color: var(--ink-2);
2077
+ }
2078
+
2079
+ .session-main {
2080
+ display: flex;
2081
+ flex-direction: column;
2082
+ min-width: 0;
2083
+ }
2084
+
2085
+ .session-id {
2086
+ overflow-wrap: anywhere;
2087
+ }
2088
+
2089
+ .session-detail {
2090
+ overflow: hidden;
2091
+ text-overflow: ellipsis;
2092
+ white-space: nowrap;
2093
+ font-size: 12px;
2094
+ color: var(--muted);
2095
+ }
2096
+
2097
+ .session-row.is-waiting .session-detail {
2098
+ font-weight: 600;
2099
+ color: var(--ink-2);
2100
+ }
2101
+
2102
+ .session-actions {
2103
+ display: inline-flex;
2104
+ gap: 6px;
2105
+ }
2106
+
2107
+ .tag {
2108
+ display: inline-block;
2109
+ padding: 0 7px;
2110
+ border-radius: 4px;
2111
+ border: 1px solid var(--rule);
2112
+ background: var(--surface-2);
2113
+ color: var(--ink-2);
2114
+ font-size: 11px;
2115
+ font-weight: 650;
2116
+ line-height: 18px;
2117
+ white-space: nowrap;
2118
+ }
2119
+
2120
+ .tag-strong {
2121
+ background: var(--ink);
2122
+ border-color: var(--ink);
2123
+ color: var(--surface);
2124
+ }
2125
+
2126
+ .tag.status-proposed {
2127
+ border-color: var(--ink-2);
2128
+ color: var(--ink);
2129
+ }
2130
+
2131
+ .tag.status-superseded {
2132
+ text-decoration: line-through;
2133
+ color: var(--muted);
2134
+ }
2135
+
2136
+ /* -- change page ------------------------------------------------------------------- */
2137
+
2138
+ .page-change,
2139
+ .page-doc {
2140
+ max-width: 1080px;
2141
+ }
2142
+
2143
+ .change-head .page-title {
2144
+ font-size: 28px;
2145
+ }
2146
+
2147
+ .change-signal {
2148
+ display: flex;
2149
+ align-items: center;
2150
+ flex-wrap: wrap;
2151
+ gap: 6px 8px;
2152
+ margin: 10px 0 0;
2153
+ font-size: 14px;
2154
+ color: var(--ink-2);
2155
+ }
2156
+
2157
+ .change-signal strong {
2158
+ color: var(--ink);
2159
+ }
2160
+
2161
+ .meta {
2162
+ display: grid;
2163
+ grid-template-columns: max-content minmax(0, 1fr);
2164
+ gap: 3px 16px;
2165
+ margin: 16px 0 0;
2166
+ font-size: 13px;
2167
+ }
2168
+
2169
+ .meta dt {
2170
+ color: var(--muted);
2171
+ }
2172
+
2173
+ .meta dd {
2174
+ margin: 0;
2175
+ overflow-wrap: anywhere;
2176
+ }
2177
+
2178
+ .change-goal,
2179
+ .change-unreadable {
2180
+ margin: 12px 0 0;
2181
+ max-width: 75ch;
2182
+ color: var(--ink-2);
2183
+ }
2184
+
2185
+ .change-unreadable p {
2186
+ margin: 0;
2187
+ }
2188
+
2189
+ .change-unreadable .stop-reason {
2190
+ margin-top: 6px;
2191
+ overflow-wrap: anywhere;
2192
+ }
2193
+
2194
+ .change-unreadable .stop-fix {
2195
+ margin-top: 4px;
2196
+ color: var(--muted);
2197
+ }
2198
+
2199
+ .station-strip {
2200
+ position: relative;
2201
+ display: grid;
2202
+ grid-template-columns: repeat(4, minmax(0, 1fr));
2203
+ max-width: 640px;
2204
+ margin: 24px 0 0;
2205
+ padding: 0;
2206
+ list-style: none;
2207
+ }
2208
+
2209
+ .station-strip::before {
2210
+ content: '';
2211
+ position: absolute;
2212
+ top: 7px;
2213
+ left: 12.5%;
2214
+ right: 12.5%;
2215
+ height: 5px;
2216
+ border-radius: 3px;
2217
+ background: var(--line);
2218
+ }
2219
+
2220
+ .strip-stop {
2221
+ position: relative;
2222
+ display: flex;
2223
+ flex-direction: column;
2224
+ align-items: center;
2225
+ gap: 6px;
2226
+ font-size: 13px;
2227
+ color: var(--muted);
2228
+ }
2229
+
2230
+ .strip-dot {
2231
+ width: 19px;
2232
+ height: 19px;
2233
+ border-radius: 50%;
2234
+ border: 3.5px solid var(--line);
2235
+ background: var(--surface);
2236
+ }
2237
+
2238
+ .strip-stop.is-passed .strip-dot {
2239
+ background: color-mix(in oklab, var(--line) 45%, var(--surface));
2240
+ }
2241
+
2242
+ .strip-stop.is-here .strip-dot {
2243
+ background: var(--line);
2244
+ box-shadow: 0 0 0 4px var(--line-soft);
2245
+ }
2246
+
2247
+ .strip-stop.is-here {
2248
+ color: var(--ink);
2249
+ font-weight: 750;
2250
+ }
2251
+
2252
+ .detail-section {
2253
+ margin-top: 36px;
2254
+ }
2255
+
2256
+ .section-head {
2257
+ display: flex;
2258
+ align-items: center;
2259
+ gap: 16px;
2260
+ flex-wrap: wrap;
2261
+ }
2262
+
2263
+ .section-head .section-title {
2264
+ margin: 0;
2265
+ }
2266
+
2267
+ .meter-wide {
2268
+ width: 220px;
2269
+ height: 8px;
2270
+ border-radius: 4px;
2271
+ }
2272
+
2273
+ .artifact-route {
2274
+ display: flex;
2275
+ flex-wrap: wrap;
2276
+ row-gap: 16px;
2277
+ margin: 12px 0 0;
2278
+ padding: 0;
2279
+ list-style: none;
2280
+ }
2281
+
2282
+ .artifact-stop {
2283
+ position: relative;
2284
+ display: flex;
2285
+ flex-direction: column;
2286
+ gap: 2px;
2287
+ min-width: 140px;
2288
+ padding: 26px 16px 0 0;
2289
+ }
2290
+
2291
+ .artifact-stop:not(:last-child)::before {
2292
+ content: '';
2293
+ position: absolute;
2294
+ top: 7px;
2295
+ left: 8px;
2296
+ right: 0;
2297
+ height: 4px;
2298
+ background: var(--line);
2299
+ }
2300
+
2301
+ .artifact-dot {
2302
+ position: absolute;
2303
+ top: 0;
2304
+ left: 0;
2305
+ width: 18px;
2306
+ height: 18px;
2307
+ border-radius: 50%;
2308
+ border: 3.5px solid var(--line);
2309
+ background: var(--surface);
2310
+ }
2311
+
2312
+ .artifact-stop.status-done .artifact-dot {
2313
+ background: var(--line);
2314
+ }
2315
+
2316
+ .artifact-stop.status-stub .artifact-dot {
2317
+ background: linear-gradient(90deg, var(--line) 50%, var(--surface) 50%);
2318
+ }
2319
+
2320
+ .artifact-stop.status-blocked .artifact-dot {
2321
+ border-color: var(--rule-strong);
2322
+ border-style: dashed;
2323
+ }
2324
+
2325
+ .artifact-stop.status-ready .artifact-state {
2326
+ color: var(--ink);
2327
+ font-weight: 700;
2328
+ }
2329
+
2330
+ .artifact-id {
2331
+ font-weight: 650;
2332
+ }
2333
+
2334
+ .artifact-state {
2335
+ font-size: 12px;
2336
+ color: var(--muted);
2337
+ }
2338
+
2339
+ .lock-note {
2340
+ display: flex;
2341
+ align-items: center;
2342
+ gap: 8px;
2343
+ margin: 12px 0 4px;
2344
+ padding: 8px 12px;
2345
+ border-radius: 8px;
2346
+ background: var(--surface-2);
2347
+ border: 1px solid var(--rule);
2348
+ color: var(--ink-2);
2349
+ font-size: 13px;
2350
+ }
2351
+
2352
+ .task-file {
2353
+ margin: 18px 0 4px;
2354
+ font-size: 12px;
2355
+ color: var(--muted);
2356
+ }
2357
+
2358
+ .task-list {
2359
+ margin: 8px 0 0;
2360
+ padding: 0;
2361
+ list-style: none;
2362
+ }
2363
+
2364
+ .task-item {
2365
+ border-bottom: 1px solid var(--rule);
2366
+ }
2367
+
2368
+ .task-label {
2369
+ display: flex;
2370
+ align-items: baseline;
2371
+ gap: 10px;
2372
+ padding: 7px 0;
2373
+ cursor: pointer;
2374
+ }
2375
+
2376
+ .task-box {
2377
+ flex: none;
2378
+ width: 16px;
2379
+ height: 16px;
2380
+ margin: 0;
2381
+ accent-color: var(--line);
2382
+ transform: translateY(3px);
2383
+ cursor: pointer;
2384
+ }
2385
+
2386
+ .task-item.is-done .task-text {
2387
+ color: var(--muted);
2388
+ text-decoration: line-through;
2389
+ text-decoration-color: var(--rule-strong);
2390
+ }
2391
+
2392
+ .task-item.is-locked .task-label,
2393
+ .task-item.is-locked .task-box {
2394
+ cursor: default;
2395
+ }
2396
+
2397
+ .task-item.is-saving {
2398
+ opacity: 0.6;
2399
+ }
2400
+
2401
+ .task-error {
2402
+ display: block;
2403
+ margin: 0 0 8px 26px;
2404
+ color: var(--error);
2405
+ font-size: 12px;
2406
+ }
2407
+
2408
+ details.file {
2409
+ border-bottom: 1px solid var(--rule);
2410
+ }
2411
+
2412
+ .file-summary {
2413
+ display: flex;
2414
+ align-items: center;
2415
+ gap: 8px;
2416
+ padding: 10px 0;
2417
+ cursor: pointer;
2418
+ list-style: none;
2419
+ }
2420
+
2421
+ .file-summary::-webkit-details-marker {
2422
+ display: none;
2423
+ }
2424
+
2425
+ .file-summary .icon {
2426
+ color: var(--muted);
2427
+ transform: rotate(-90deg);
2428
+ transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
2429
+ }
2430
+
2431
+ details.file[open] > .file-summary .icon {
2432
+ transform: none;
2433
+ }
2434
+
2435
+ .file-path {
2436
+ overflow-wrap: anywhere;
2437
+ }
2438
+
2439
+ details.file > .rendered {
2440
+ padding: 4px 0 20px 22px;
2441
+ }
2442
+
2443
+ /* -- reading ------------------------------------------------------------------------- */
2444
+
2445
+ .rendered {
2446
+ max-width: 75ch;
2447
+ overflow-wrap: anywhere;
2448
+ }
2449
+
2450
+ .rendered h1,
2451
+ .rendered h2,
2452
+ .rendered h3,
2453
+ .rendered h4 {
2454
+ line-height: 1.3;
2455
+ margin: 1.8em 0 0.5em;
2456
+ text-wrap: balance;
2457
+ }
2458
+
2459
+ .rendered h1 {
2460
+ font-size: 22px;
2461
+ }
2462
+
2463
+ .rendered h2 {
2464
+ font-size: 19px;
2465
+ }
2466
+
2467
+ .rendered h3 {
2468
+ font-size: 16px;
2469
+ }
2470
+
2471
+ .rendered h4 {
2472
+ font-size: 14px;
2473
+ }
2474
+
2475
+ .rendered > :first-child {
2476
+ margin-top: 0;
2477
+ }
2478
+
2479
+ .rendered code {
2480
+ font-family: var(--font-mono);
2481
+ font-size: 0.9em;
2482
+ padding: 0.1em 0.35em;
2483
+ border-radius: 4px;
2484
+ background: var(--surface-2);
2485
+ }
2486
+
2487
+ .rendered pre {
2488
+ padding: 12px 14px;
2489
+ border-radius: 8px;
2490
+ background: var(--surface-2);
2491
+ border: 1px solid var(--rule);
2492
+ overflow-x: auto;
2493
+ }
2494
+
2495
+ .rendered pre code {
2496
+ padding: 0;
2497
+ background: none;
2498
+ }
2499
+
2500
+ .rendered table {
2501
+ border-collapse: collapse;
2502
+ font-size: 13px;
2503
+ display: block;
2504
+ overflow-x: auto;
2505
+ }
2506
+
2507
+ .rendered th,
2508
+ .rendered td {
2509
+ border: 1px solid var(--rule);
2510
+ padding: 5px 9px;
2511
+ text-align: left;
2512
+ }
2513
+
2514
+ .rendered blockquote {
2515
+ margin: 1em 0;
2516
+ padding: 2px 0 2px 14px;
2517
+ border-left: 1px solid var(--rule-strong);
2518
+ color: var(--ink-2);
2519
+ }
2520
+
2521
+ .running-head {
2522
+ position: sticky;
2523
+ top: var(--signbar-h);
2524
+ z-index: 3;
2525
+ display: flex;
2526
+ align-items: center;
2527
+ gap: 10px;
2528
+ margin: 16px 0 12px;
2529
+ padding: 8px 0;
2530
+ background: var(--ground);
2531
+ border-bottom: 1px solid var(--rule);
2532
+ font-size: 13px;
2533
+ font-weight: 650;
2534
+ color: var(--ink-2);
2535
+ }
2536
+
2537
+ .running-head::before {
2538
+ content: '';
2539
+ flex: none;
2540
+ width: 18px;
2541
+ height: 6px;
2542
+ border-radius: 3px;
2543
+ background: var(--line);
2544
+ }
2545
+
2546
+ .running-head.is-empty {
2547
+ visibility: hidden;
2548
+ }
2549
+
2550
+ .doc-layout {
2551
+ display: grid;
2552
+ grid-template-columns: 220px minmax(0, 1fr);
2553
+ gap: 40px;
2554
+ align-items: start;
2555
+ }
2556
+
2557
+ .doc-toc {
2558
+ position: sticky;
2559
+ top: calc(var(--signbar-h) + 52px);
2560
+ max-height: calc(100vh - var(--signbar-h) - 72px);
2561
+ overflow-y: auto;
2562
+ }
2563
+
2564
+ .toc-title {
2565
+ margin: 0 0 6px;
2566
+ font-size: 12px;
2567
+ color: var(--muted);
2568
+ }
2569
+
2570
+ .toc-list {
2571
+ margin: 0;
2572
+ padding: 0;
2573
+ list-style: none;
2574
+ }
2575
+
2576
+ .toc-link {
2577
+ display: block;
2578
+ width: 100%;
2579
+ padding: 5px 8px;
2580
+ border: 0;
2581
+ border-radius: 5px;
2582
+ background: none;
2583
+ text-align: left;
2584
+ font-size: 13px;
2585
+ line-height: 1.4;
2586
+ color: var(--ink-2);
2587
+ cursor: pointer;
2588
+ }
2589
+
2590
+ .toc-link:hover {
2591
+ background: var(--surface-2);
2592
+ color: var(--ink);
2593
+ }
2594
+
2595
+ .doc-layout:has(.doc-toc[hidden]) {
2596
+ grid-template-columns: minmax(0, 1fr);
2597
+ }
2598
+
2599
+ .decision-layout {
2600
+ display: grid;
2601
+ grid-template-columns: 300px minmax(0, 1fr);
2602
+ gap: 40px;
2603
+ align-items: start;
2604
+ margin-top: 20px;
2605
+ }
2606
+
2607
+ .decision-index {
2608
+ position: sticky;
2609
+ top: calc(var(--signbar-h) + 16px);
2610
+ display: flex;
2611
+ flex-direction: column;
2612
+ max-height: calc(100vh - var(--signbar-h) - 32px);
2613
+ }
2614
+
2615
+ .search-wrap {
2616
+ display: flex;
2617
+ align-items: center;
2618
+ gap: 8px;
2619
+ padding: 0 10px;
2620
+ border: 1px solid var(--rule-strong);
2621
+ border-radius: 8px;
2622
+ background: var(--surface);
2623
+ color: var(--muted);
2624
+ }
2625
+
2626
+ .search-wrap:focus-within {
2627
+ outline: 2px solid var(--focus);
2628
+ outline-offset: 1px;
2629
+ }
2630
+
2631
+ .search {
2632
+ width: 100%;
2633
+ padding: 8px 0;
2634
+ border: 0;
2635
+ background: transparent;
2636
+ outline: none;
2637
+ }
2638
+
2639
+ .search::placeholder {
2640
+ color: var(--muted);
2641
+ }
2642
+
2643
+ .decision-list {
2644
+ min-height: 0;
2645
+ margin: 10px 0 0;
2646
+ padding: 0;
2647
+ overflow-y: auto;
2648
+ list-style: none;
2649
+ }
2650
+
2651
+ .decision-link {
2652
+ display: block;
2653
+ padding: 8px 10px;
2654
+ border-radius: 8px;
2655
+ text-decoration: none;
2656
+ }
2657
+
2658
+ .decision-link:hover {
2659
+ background: var(--surface-2);
2660
+ }
2661
+
2662
+ .decision-link[aria-current='page'] {
2663
+ background: var(--surface);
2664
+ box-shadow: inset 0 0 0 1px var(--rule-strong);
2665
+ }
2666
+
2667
+ .decision-title {
2668
+ display: block;
2669
+ font-weight: 650;
2670
+ line-height: 1.35;
2671
+ }
2672
+
2673
+ .decision-meta {
2674
+ display: flex;
2675
+ align-items: center;
2676
+ gap: 8px;
2677
+ margin-top: 3px;
2678
+ font-size: 11px;
2679
+ color: var(--muted);
2680
+ }
2681
+
2682
+ .reader-title {
2683
+ margin: 0;
2684
+ font-size: 22px;
2685
+ line-height: 1.3;
2686
+ text-wrap: balance;
2687
+ }
2688
+
2689
+ .qa-list {
2690
+ margin: 0;
2691
+ max-width: 75ch;
2692
+ }
2693
+
2694
+ .qa-q {
2695
+ margin-top: 16px;
2696
+ font-weight: 700;
2697
+ }
2698
+
2699
+ .qa-a {
2700
+ margin: 4px 0 0;
2701
+ color: var(--ink-2);
2702
+ white-space: pre-line;
2703
+ }
2704
+
2705
+ /* -- buttons ------------------------------------------------------------------------ */
2706
+
2707
+ .button {
2708
+ display: inline-flex;
2709
+ align-items: center;
2710
+ justify-content: center;
2711
+ gap: 6px;
2712
+ min-height: 32px;
2713
+ padding: 0 14px;
2714
+ border: 1px solid var(--rule-strong);
2715
+ border-radius: 6px;
2716
+ background: var(--surface);
2717
+ color: var(--ink);
2718
+ font-weight: 650;
2719
+ cursor: pointer;
2720
+ }
2721
+
2722
+ .button:hover:not(:disabled) {
2723
+ border-color: var(--ink-2);
2724
+ }
2725
+
2726
+ .button-primary {
2727
+ border-color: var(--ink);
2728
+ background: var(--ink);
2729
+ color: var(--surface);
2730
+ }
2731
+
2732
+ .button-primary:hover:not(:disabled) {
2733
+ border-color: var(--ink-2);
2734
+ background: var(--ink-2);
2735
+ }
2736
+
2737
+ .button-small {
2738
+ min-height: 28px;
2739
+ padding: 0 10px;
2740
+ font-size: 12px;
2741
+ }
2742
+
2743
+ .button:disabled {
2744
+ cursor: not-allowed;
2745
+ opacity: 0.5;
2746
+ }
2747
+
2748
+ /* -- a project line's sessions, and a line with a session at work --------------------- */
2749
+
2750
+ .line-sessions {
2751
+ display: flex;
2752
+ flex-direction: column;
2753
+ gap: 2px;
2754
+ margin: 6px 0 0 -6px;
2755
+ padding: 0;
2756
+ list-style: none;
2757
+ }
2758
+
2759
+ .session-chip {
2760
+ display: flex;
2761
+ align-items: center;
2762
+ gap: 7px;
2763
+ max-width: 100%;
2764
+ min-width: 0;
2765
+ padding: 3px 6px;
2766
+ border: 0;
2767
+ border-radius: 5px;
2768
+ background: transparent;
2769
+ font-size: 12px;
2770
+ text-align: left;
2771
+ cursor: pointer;
2772
+ }
2773
+
2774
+ .session-chip:hover {
2775
+ background: var(--surface-2);
2776
+ }
2777
+
2778
+ .session-chip-state {
2779
+ flex: none;
2780
+ font-weight: 650;
2781
+ color: var(--ink-2);
2782
+ }
2783
+
2784
+ .session-chip-detail {
2785
+ min-width: 0;
2786
+ overflow: hidden;
2787
+ text-overflow: ellipsis;
2788
+ white-space: nowrap;
2789
+ color: var(--muted);
2790
+ }
2791
+
2792
+ .session-chip.is-working .session-chip-detail {
2793
+ font-family: var(--font-mono);
2794
+ font-size: 11.5px;
2795
+ color: var(--ink-2);
2796
+ }
2797
+
2798
+ .session-chip.is-waiting .session-chip-state {
2799
+ color: var(--ink);
2800
+ }
2801
+
2802
+ /* The whole line flows while a session works: a moving sheen along the track,
2803
+ in the line's own colour, so motion and not a new colour says "now". */
2804
+ .line-row.is-working .track {
2805
+ background-image: repeating-linear-gradient(90deg, transparent 0 18px, color-mix(in oklab, var(--surface) 55%, transparent) 18px 26px);
2806
+ background-size: 26px 100%;
2807
+ animation: run-flow-wide 0.9s linear infinite;
2808
+ }
2809
+
2810
+ @keyframes run-flow-wide {
2811
+ from {
2812
+ background-position: 0 0;
2813
+ }
2814
+ to {
2815
+ background-position: 26px 0;
2816
+ }
2817
+ }
2818
+
2819
+ .line-row.is-working .line-title .line-swatch {
2820
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--live) 35%, transparent);
2821
+ }
2822
+
2823
+ .notice-wait {
2824
+ margin: 0 -10px;
2825
+ padding-left: 10px;
2826
+ padding-right: 10px;
2827
+ border-radius: 8px;
2828
+ background: color-mix(in oklab, var(--wait) 9%, var(--surface));
2829
+ }
2830
+
2831
+ .notice-wait .activity-dot {
2832
+ justify-self: center;
2833
+ }
2834
+
2835
+ button.notice-subject {
2836
+ padding: 0;
2837
+ border: 0;
2838
+ background: none;
2839
+ font: inherit;
2840
+ font-weight: 650;
2841
+ text-align: left;
2842
+ text-decoration: underline;
2843
+ text-decoration-color: var(--rule-strong);
2844
+ text-underline-offset: 3px;
2845
+ cursor: pointer;
2846
+ }
2847
+
2848
+ button.notice-subject:hover {
2849
+ text-decoration-color: currentColor;
2850
+ }
2851
+
2852
+ .notice-wait .notice-text {
2853
+ color: var(--ink-2);
2854
+ font-weight: 600;
2855
+ }
2856
+
2857
+ /* -- the session panel: beside the page, never over the part being read ------------- */
2858
+
2859
+ .session-panel {
2860
+ position: fixed;
2861
+ top: var(--signbar-h);
2862
+ right: 0;
2863
+ bottom: 0;
2864
+ z-index: 28;
2865
+ display: grid;
2866
+ grid-template-rows: auto minmax(0, 1fr) auto auto;
2867
+ width: min(460px, 100vw);
2868
+ background: var(--surface);
2869
+ border-left: 1px solid var(--rule);
2870
+ box-shadow: var(--shadow-tip);
2871
+ }
2872
+
2873
+ .session-panel[hidden] {
2874
+ display: none;
2875
+ }
2876
+
2877
+ /* Wide windows make room for it instead of letting it cover the page. */
2878
+ @media (min-width: 1200px) {
2879
+ .has-session-panel .shell {
2880
+ margin-right: 460px;
2881
+ }
2882
+ }
2883
+
2884
+ .sp-head {
2885
+ padding: 12px 14px 10px 16px;
2886
+ border-bottom: 1px solid var(--rule);
2887
+ }
2888
+
2889
+ .sp-head-row {
2890
+ display: grid;
2891
+ grid-template-columns: auto minmax(0, 1fr) auto;
2892
+ align-items: center;
2893
+ gap: 10px;
2894
+ }
2895
+
2896
+ .sp-dot {
2897
+ display: inline-flex;
2898
+ }
2899
+
2900
+ .sp-title {
2901
+ margin: 0;
2902
+ font-size: 16px;
2903
+ font-weight: 750;
2904
+ }
2905
+
2906
+ .sp-title:focus {
2907
+ outline: none;
2908
+ }
2909
+
2910
+ .sp-status {
2911
+ display: flex;
2912
+ align-items: center;
2913
+ flex-wrap: wrap;
2914
+ gap: 4px 10px;
2915
+ margin: 6px 0 0;
2916
+ font-size: 13px;
2917
+ }
2918
+
2919
+ .sp-detail {
2920
+ min-width: 0;
2921
+ color: var(--muted);
2922
+ overflow-wrap: anywhere;
2923
+ }
2924
+
2925
+ .sp-scroll {
2926
+ overflow-y: auto;
2927
+ overscroll-behavior: contain;
2928
+ padding: 8px 0 12px;
2929
+ }
2930
+
2931
+ .sp-log-note {
2932
+ margin: 8px 16px;
2933
+ font-size: 12px;
2934
+ color: var(--muted);
2935
+ }
2936
+
2937
+ .sp-log-note:empty {
2938
+ display: none;
2939
+ }
2940
+
2941
+ .sp-log {
2942
+ margin: 0;
2943
+ padding: 0;
2944
+ list-style: none;
2945
+ }
2946
+
2947
+ .sp-entry {
2948
+ display: grid;
2949
+ grid-template-columns: 58px 64px minmax(0, 1fr);
2950
+ gap: 8px;
2951
+ padding: 5px 16px;
2952
+ font-size: 12.5px;
2953
+ line-height: 1.5;
2954
+ }
2955
+
2956
+ .sp-time {
2957
+ padding-top: 1px;
2958
+ font-size: 11.5px;
2959
+ color: var(--muted);
2960
+ }
2961
+
2962
+ .sp-who {
2963
+ overflow: hidden;
2964
+ text-overflow: ellipsis;
2965
+ white-space: nowrap;
2966
+ font-weight: 700;
2967
+ color: var(--ink-2);
2968
+ }
2969
+
2970
+ .sp-body {
2971
+ min-width: 0;
2972
+ overflow-wrap: anywhere;
2973
+ white-space: pre-line;
2974
+ }
2975
+
2976
+ .sp-entry.kind-prompt {
2977
+ background: var(--surface-2);
2978
+ }
2979
+
2980
+ .sp-entry.kind-prompt .sp-who {
2981
+ color: var(--ink);
2982
+ }
2983
+
2984
+ .sp-entry.kind-tool .sp-who {
2985
+ font-size: 11.5px;
2986
+ }
2987
+
2988
+ .sp-entry.kind-tool .sp-body {
2989
+ display: flex;
2990
+ align-items: baseline;
2991
+ gap: 8px;
2992
+ white-space: normal;
2993
+ }
2994
+
2995
+ .sp-target {
2996
+ min-width: 0;
2997
+ overflow-wrap: anywhere;
2998
+ color: var(--ink-2);
2999
+ }
3000
+
3001
+ .sp-mark {
3002
+ flex: none;
3003
+ margin-left: auto;
3004
+ font-size: 11px;
3005
+ color: var(--muted);
3006
+ }
3007
+
3008
+ .sp-entry.is-fail .sp-mark {
3009
+ font-weight: 700;
3010
+ color: var(--error);
3011
+ }
3012
+
3013
+ .sp-entry.kind-ask,
3014
+ .sp-entry.kind-permission {
3015
+ box-shadow: inset 3px 0 0 var(--wait);
3016
+ }
3017
+
3018
+ .sp-ask {
3019
+ max-height: 46vh;
3020
+ overflow-y: auto;
3021
+ padding: 12px 16px;
3022
+ border-top: 1px solid var(--rule);
3023
+ background: color-mix(in oklab, var(--wait) 8%, var(--surface));
3024
+ }
3025
+
3026
+ .sp-ask-hint {
3027
+ margin: -4px 0 10px;
3028
+ }
3029
+
3030
+ .sp-ask-title {
3031
+ margin: 0 0 8px;
3032
+ font-size: 13px;
3033
+ font-weight: 750;
3034
+ }
3035
+
3036
+ .sp-question {
3037
+ margin: 0 0 12px;
3038
+ padding: 0;
3039
+ border: 0;
3040
+ }
3041
+
3042
+ .sp-question legend {
3043
+ margin-bottom: 6px;
3044
+ padding: 0;
3045
+ font-weight: 650;
3046
+ }
3047
+
3048
+ .sp-option {
3049
+ display: grid;
3050
+ grid-template-columns: 18px minmax(0, 1fr);
3051
+ align-items: start;
3052
+ gap: 8px;
3053
+ padding: 5px 4px;
3054
+ border-radius: 6px;
3055
+ cursor: pointer;
3056
+ }
3057
+
3058
+ .sp-option:hover {
3059
+ background: var(--surface);
3060
+ }
3061
+
3062
+ .sp-option input {
3063
+ margin: 3px 0 0;
3064
+ }
3065
+
3066
+ .sp-option-desc {
3067
+ display: block;
3068
+ font-size: 12px;
3069
+ color: var(--muted);
3070
+ }
3071
+
3072
+ .sp-option-other {
3073
+ align-items: center;
3074
+ }
3075
+
3076
+ .sp-other {
3077
+ width: 100%;
3078
+ padding: 6px 8px;
3079
+ border: 1px solid var(--rule-strong);
3080
+ border-radius: 6px;
3081
+ background: var(--surface);
3082
+ }
3083
+
3084
+ .sp-permission {
3085
+ margin: 0 0 6px;
3086
+ overflow-wrap: anywhere;
3087
+ }
3088
+
3089
+ .sp-actions {
3090
+ display: flex;
3091
+ justify-content: flex-end;
3092
+ gap: 8px;
3093
+ margin-top: 8px;
3094
+ }
3095
+
3096
+ /* Says what the panel will not do: the terminal stays where a session is told what to do. */
3097
+ .sp-foot {
3098
+ margin: 0;
3099
+ padding: 10px 16px 12px;
3100
+ border-top: 1px solid var(--rule);
3101
+ font-size: 12px;
3102
+ color: var(--muted);
3103
+ }
3104
+
3105
+ .sp-form-foot {
3106
+ display: flex;
3107
+ align-items: center;
3108
+ justify-content: space-between;
3109
+ gap: 12px;
3110
+ margin-top: 8px;
3111
+ }
3112
+
3113
+ .sp-hint {
3114
+ margin: 0;
3115
+ font-size: 12px;
3116
+ color: var(--muted);
3117
+ }
3118
+
3119
+ /* -- toasts: a session needs you, or has finished ------------------------------------ */
3120
+
3121
+ /* Bottom right, clear of the session panel: beside it on a wide window, on
3122
+ the other side of the screen where the panel covers the page. */
3123
+ .toasts {
3124
+ position: fixed;
3125
+ right: 16px;
3126
+ bottom: 16px;
3127
+ z-index: 40;
3128
+ display: flex;
3129
+ flex-direction: column;
3130
+ align-items: flex-end;
3131
+ gap: 8px;
3132
+ width: min(380px, calc(100vw - 32px));
3133
+ pointer-events: none;
3134
+ }
3135
+
3136
+ .has-session-panel .toasts {
3137
+ right: auto;
3138
+ left: 16px;
3139
+ }
3140
+
3141
+ @media (min-width: 1200px) {
3142
+ .has-session-panel .toasts {
3143
+ left: auto;
3144
+ right: 476px;
3145
+ }
3146
+ }
3147
+
3148
+ .toast {
3149
+ pointer-events: auto;
3150
+ display: grid;
3151
+ grid-template-columns: minmax(0, 1fr) auto;
3152
+ align-items: start;
3153
+ gap: 6px;
3154
+ width: 100%;
3155
+ padding: 10px 8px 10px 12px;
3156
+ border: 1px solid var(--rule-strong);
3157
+ border-left-width: 4px;
3158
+ border-radius: 10px;
3159
+ background: var(--surface);
3160
+ box-shadow: var(--shadow-tip);
3161
+ animation: toast-in 0.24s cubic-bezier(0.16, 1, 0.3, 1);
3162
+ }
3163
+
3164
+ .toast-wait {
3165
+ border-left-color: var(--wait);
3166
+ }
3167
+
3168
+ .toast-idle {
3169
+ border-left-color: var(--muted);
3170
+ }
3171
+
3172
+ @keyframes toast-in {
3173
+ from {
3174
+ opacity: 0;
3175
+ transform: translateY(8px);
3176
+ }
3177
+ }
3178
+
3179
+ .toast-main {
3180
+ display: flex;
3181
+ flex-direction: column;
3182
+ gap: 4px;
3183
+ min-width: 0;
3184
+ padding: 0;
3185
+ border: 0;
3186
+ background: none;
3187
+ text-align: left;
3188
+ cursor: pointer;
3189
+ }
3190
+
3191
+ .toast-head {
3192
+ display: flex;
3193
+ align-items: center;
3194
+ flex-wrap: wrap;
3195
+ gap: 4px 8px;
3196
+ font-size: 13px;
3197
+ }
3198
+
3199
+ .toast-main:hover strong {
3200
+ text-decoration: underline;
3201
+ text-underline-offset: 3px;
3202
+ }
3203
+
3204
+ .toast-text {
3205
+ display: -webkit-box;
3206
+ overflow: hidden;
3207
+ -webkit-box-orient: vertical;
3208
+ -webkit-line-clamp: 3;
3209
+ font-size: 12.5px;
3210
+ color: var(--ink-2);
3211
+ overflow-wrap: anywhere;
3212
+ }
3213
+
3214
+ .toast-close {
3215
+ display: grid;
3216
+ place-items: center;
3217
+ width: 24px;
3218
+ height: 24px;
3219
+ padding: 0;
3220
+ border: 0;
3221
+ border-radius: 5px;
3222
+ background: transparent;
3223
+ color: var(--muted);
3224
+ cursor: pointer;
3225
+ }
3226
+
3227
+ .toast-close:hover {
3228
+ background: var(--surface-2);
3229
+ color: var(--ink);
3230
+ }
3231
+
3232
+ /* The notification switch reads as on by its fill, not only by its icon. */
3233
+ .sign-button[aria-pressed='true'] {
3234
+ border-color: color-mix(in oklab, var(--sign-ink) 55%, transparent);
3235
+ background: color-mix(in oklab, var(--sign-ink) 14%, var(--sign-2));
3236
+ }
3237
+
3238
+ /* -- narrow: the page's own width, then the window's ------------------------------- */
3239
+
3240
+ @container view (max-width: 820px) {
3241
+ .charts,
3242
+ .project-lists {
3243
+ grid-template-columns: minmax(0, 1fr);
3244
+ }
3245
+
3246
+ .doc-layout,
3247
+ .decision-layout {
3248
+ grid-template-columns: minmax(0, 1fr);
3249
+ gap: 20px;
3250
+ }
3251
+
3252
+ .doc-toc {
3253
+ display: none;
3254
+ }
3255
+
3256
+ .decision-index {
3257
+ position: static;
3258
+ max-height: 42vh;
3259
+ }
3260
+
3261
+ .notice {
3262
+ grid-template-columns: 16px minmax(0, 1fr);
3263
+ }
3264
+
3265
+ .notice > :nth-child(n + 3) {
3266
+ grid-column: 2;
3267
+ }
3268
+
3269
+ .session-row {
3270
+ grid-template-columns: minmax(0, 1fr) auto auto;
3271
+ }
3272
+
3273
+ .session-row .session-main {
3274
+ grid-column: 1 / -1;
3275
+ grid-row: 2;
3276
+ }
3277
+ }
3278
+
3279
+ @container view (max-width: 600px) {
3280
+ .page-title {
3281
+ font-size: 22px;
3282
+ }
3283
+
3284
+ .train {
3285
+ grid-template-columns: 96px minmax(0, 1fr);
3286
+ column-gap: 10px;
3287
+ }
3288
+
3289
+ .mini-route {
3290
+ column-gap: 9px;
3291
+ }
3292
+
3293
+ .mini-route::before {
3294
+ width: 63px;
3295
+ }
3296
+
3297
+ .train-drawer {
3298
+ margin-left: 0;
3299
+ }
3300
+
3301
+ /* The inner line turns vertical: wrapped rows left connectors pointing at
3302
+ empty space. */
3303
+ .artifact-route {
3304
+ flex-direction: column;
3305
+ row-gap: 0;
3306
+ }
3307
+
3308
+ .artifact-stop {
3309
+ flex-direction: row;
3310
+ align-items: baseline;
3311
+ gap: 10px;
3312
+ min-width: 0;
3313
+ padding: 0 0 14px 30px;
3314
+ }
3315
+
3316
+ .artifact-stop:not(:last-child)::before {
3317
+ top: 18px;
3318
+ left: 7px;
3319
+ right: auto;
3320
+ width: 4px;
3321
+ height: calc(100% - 18px);
3322
+ }
3323
+ }
3324
+
3325
+ /* The sign bar and the page's own padding follow the window: a container
3326
+ query styles what is inside the page, never the page box itself. */
3327
+ @media (max-width: 640px) {
3328
+ .signbar {
3329
+ gap: 12px;
3330
+ padding: 0 12px;
3331
+ }
3332
+
3333
+ .btn-text,
3334
+ .crumbs {
3335
+ display: none;
3336
+ }
3337
+
3338
+ .hub-status {
3339
+ gap: 5px;
3340
+ }
3341
+
3342
+ /* The station-dot mark alone still leads home and is labelled; the words
3343
+ give their width to the back link. */
3344
+ .wordmark {
3345
+ font-size: 0;
3346
+ gap: 0;
3347
+ }
3348
+
3349
+ .crumb-back:not([hidden]) {
3350
+ display: inline-flex;
3351
+ }
3352
+
3353
+ .theme-field select {
3354
+ max-width: 84px;
3355
+ padding: 0 6px;
3356
+ }
3357
+
3358
+ .sign-button {
3359
+ width: 32px;
3360
+ padding: 0;
3361
+ justify-content: center;
3362
+ }
3363
+
3364
+ .view {
3365
+ padding: 20px 14px 56px;
3366
+ }
3367
+ }
3368
+
3369
+ @media (prefers-reduced-motion: reduce) {
3370
+ .run-segment,
3371
+ .sign-button:disabled .icon,
3372
+ .activity-working::after,
3373
+ .activity-waiting,
3374
+ .line-row.is-working .track,
3375
+ .toast {
3376
+ animation: none;
3377
+ }
3378
+
3379
+ .train-toggle .icon,
3380
+ .side-toggle .icon,
3381
+ .sidebar,
3382
+ .sidebar.is-open,
3383
+ .file-summary .icon,
3384
+ .chart-table summary .icon {
3385
+ transition: none;
3386
+ }
3387
+ }
3388
+
3389
+ @media (forced-colors: active) {
3390
+ .track,
3391
+ .station-dot,
3392
+ .line-swatch {
3393
+ forced-color-adjust: none;
955
3394
  }
956
3395
  }