storymapper 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +334 -0
- package/LICENSE +201 -0
- package/NOTICE +6 -0
- package/README.md +239 -0
- package/frontend/css/storymap.css +4637 -0
- package/frontend/js/adapters.js +423 -0
- package/frontend/js/card-animate.js +384 -0
- package/frontend/js/core/graph.js +825 -0
- package/frontend/js/core.js +3908 -0
- package/frontend/js/dialog-ticket-import.js +506 -0
- package/frontend/js/dnd.js +322 -0
- package/frontend/js/filter.js +215 -0
- package/frontend/js/main.js +2499 -0
- package/frontend/js/project-io.js +109 -0
- package/frontend/js/query-autocomplete.js +196 -0
- package/frontend/js/query-engine.js +339 -0
- package/frontend/js/query.js +280 -0
- package/frontend/js/renderer-card.js +639 -0
- package/frontend/js/renderer-dependencies.js +974 -0
- package/frontend/js/renderer-kanban.js +505 -0
- package/frontend/js/renderer-storymap.js +2530 -0
- package/frontend/js/renderer-ticket-editor.js +455 -0
- package/frontend/js/renderer-ticket-modal.js +758 -0
- package/frontend/js/save-pipeline.js +170 -0
- package/frontend/js/smartbar-autocomplete.js +162 -0
- package/frontend/js/store.js +197 -0
- package/frontend/js/ticket-editor-boot.js +24 -0
- package/frontend/js/ticket-form.js +2095 -0
- package/frontend/js/ticket-import.js +477 -0
- package/frontend/js/ui-shell.js +441 -0
- package/frontend/js/view-process-steps.js +233 -0
- package/frontend/js/view-requirements.js +361 -0
- package/frontend/js/view-settings.js +1864 -0
- package/frontend/js/view-table.js +659 -0
- package/frontend/js/wheel-pan.js +65 -0
- package/frontend/storymap.html +87 -0
- package/frontend/ticket-editor.html +29 -0
- package/package.json +76 -0
- package/server/bus.js +16 -0
- package/server/core/graph.js +10 -0
- package/server/core.js +10 -0
- package/server/identity.js +134 -0
- package/server/index.js +283 -0
- package/server/ingest.js +212 -0
- package/server/mcp.js +2510 -0
- package/server/server.js +1599 -0
- package/server/slice.js +103 -0
- package/server/storage.js +571 -0
- package/server/validation.js +225 -0
- package/shared/core/graph.js +825 -0
- package/shared/core.js +3908 -0
- package/shared/project-io.js +109 -0
- package/shared/query-autocomplete.js +196 -0
- package/shared/query-engine.js +339 -0
- package/shared/query.js +280 -0
- package/shared/ticket-import.js +477 -0
- package/skill/SKILL.md +458 -0
- package/skill/reference/anatomy.md +196 -0
- package/skill/reference/spec-evolution.md +52 -0
- package/skill/reference/tools.md +156 -0
- package/skill/reference/workflows.md +203 -0
|
@@ -0,0 +1,4637 @@
|
|
|
1
|
+
/* Storymapper — paperlike theme.
|
|
2
|
+
*
|
|
3
|
+
* The CSS tokens and the modal/menu/button geometry are shared with the
|
|
4
|
+
* companion Concept Mapper project so the two tools look identical. Keep the
|
|
5
|
+
* design language in sync when changing anything here.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital,wght@0,400;0,700;1,400&family=Mona+Sans:wght@400;500;600;700;800;900&display=swap');
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--paper: #F5F1EA;
|
|
12
|
+
--paper-warm: #EDE7DA;
|
|
13
|
+
--ink: #1A1A1A;
|
|
14
|
+
--ink-soft: #717071;
|
|
15
|
+
--ink-faint: #B3B0AD;
|
|
16
|
+
--rule: #DAD7D1;
|
|
17
|
+
--rule-soft: #E8E5DE;
|
|
18
|
+
--accent: #0F5F4F;
|
|
19
|
+
--danger: #B0382B;
|
|
20
|
+
--danger-hover: #8E2C20;
|
|
21
|
+
--selection: rgba(15,95,79,0.22);
|
|
22
|
+
--target: #2E5A52;
|
|
23
|
+
/* SM-257 — Story-Map "backbone spine": the process-step header is a dark
|
|
24
|
+
accent band so it reads distinctly from the warm-paper release band.
|
|
25
|
+
The heavy colour appears once (sticky top); release bands stay quiet. */
|
|
26
|
+
--backbone-bg: #4C8170; /* lighter muted green-slate */
|
|
27
|
+
--backbone-edge: #3C6856; /* darker, bottom rule */
|
|
28
|
+
--backbone-ink: var(--paper); /* light label text */
|
|
29
|
+
--backbone-ink-soft: rgba(245,241,234,0.62); /* grip / empty / secondary */
|
|
30
|
+
--backbone-divider: rgba(245,241,234,0.18); /* column separators */
|
|
31
|
+
--backbone-lift: rgba(245,241,234,0.10); /* hover tint */
|
|
32
|
+
--backbone-lift-strong: rgba(245,241,234,0.20); /* drop-target tint */
|
|
33
|
+
--shadow-lift: 0 2px 4px rgba(26,26,26,0.06), 0 8px 24px rgba(26,26,26,0.06);
|
|
34
|
+
--font-display: 'Libre Caslon Text', Georgia, serif;
|
|
35
|
+
--font-body: 'Mona Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
36
|
+
|
|
37
|
+
/* Cluster-Palette 1:1 aus cmapper (concept_map.html#CLUSTERS).
|
|
38
|
+
Verwendet für ticket-typ-spezifische Karten-Hintergründe. */
|
|
39
|
+
--cluster-blue-fill: #E8EEF5;
|
|
40
|
+
--cluster-blue-border: #2E4665;
|
|
41
|
+
--cluster-blue-ink: #1A2A40;
|
|
42
|
+
--cluster-green-fill: #E7EDE3;
|
|
43
|
+
--cluster-green-border: #3D5639;
|
|
44
|
+
--cluster-green-ink: #22341F;
|
|
45
|
+
--cluster-amber-fill: #F5ECD8;
|
|
46
|
+
--cluster-amber-border: #7A5A1F;
|
|
47
|
+
--cluster-amber-ink: #3F2F11;
|
|
48
|
+
--cluster-rust-fill: #F1DCD2;
|
|
49
|
+
--cluster-rust-border: #7A3E26;
|
|
50
|
+
--cluster-rust-ink: #3F1E12;
|
|
51
|
+
--cluster-plum-fill: #EAE0EA;
|
|
52
|
+
--cluster-plum-border: #5A3957;
|
|
53
|
+
--cluster-plum-ink: #2E1B2D;
|
|
54
|
+
--cluster-slate-fill: #E5E5E2;
|
|
55
|
+
--cluster-slate-border: #3A3A37;
|
|
56
|
+
--cluster-slate-ink: #1A1A18;
|
|
57
|
+
--cluster-teal-fill: #DCE9E7;
|
|
58
|
+
--cluster-teal-border: #2E5A52;
|
|
59
|
+
--cluster-teal-ink: #152C28;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
* { box-sizing: border-box; }
|
|
63
|
+
html, body { height: 100%; margin: 0; padding: 0; }
|
|
64
|
+
body {
|
|
65
|
+
background: var(--paper);
|
|
66
|
+
color: var(--ink);
|
|
67
|
+
font-family: var(--font-body);
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
-webkit-font-smoothing: antialiased;
|
|
70
|
+
/* Global default: deny text selection. The HTML chrome (toolbar, lanes,
|
|
71
|
+
cards, modal headers, drag-handles) shouldn't be selectable — and most
|
|
72
|
+
importantly drag-reorder shouldn't paint a text selection across rows
|
|
73
|
+
while the pointer moves. Elements that DO want selection opt in via
|
|
74
|
+
the whitelist below or via `.selectable`. */
|
|
75
|
+
user-select: none;
|
|
76
|
+
-webkit-user-select: none;
|
|
77
|
+
}
|
|
78
|
+
/* Form controls + things the user authors text into stay selectable.
|
|
79
|
+
`[contenteditable]` covers rich-text fields (none today, future-proof);
|
|
80
|
+
`pre`/`code` cover snippets the user wants to copy out; `.selectable`
|
|
81
|
+
is the explicit opt-in escape hatch for any other content. */
|
|
82
|
+
input,
|
|
83
|
+
textarea,
|
|
84
|
+
select,
|
|
85
|
+
[contenteditable="true"],
|
|
86
|
+
pre,
|
|
87
|
+
code,
|
|
88
|
+
.selectable {
|
|
89
|
+
user-select: text;
|
|
90
|
+
-webkit-user-select: text;
|
|
91
|
+
}
|
|
92
|
+
::selection { background: var(--accent); color: var(--paper); }
|
|
93
|
+
|
|
94
|
+
/* ---------- App-Header (zwei Toolbar-Zeilen) ----------
|
|
95
|
+
Row 1 (.toolbar-menu): Brand + Menü + aktuelles Projekt (rechts).
|
|
96
|
+
Row 2 (.toolbar-action): Create-Buttons + View-Toggle (rechts).
|
|
97
|
+
cmapper-Pattern: Menüs oben, Aktionen unten, klar getrennt. */
|
|
98
|
+
.app-header {
|
|
99
|
+
display: flex; flex-direction: column;
|
|
100
|
+
background: var(--paper-warm);
|
|
101
|
+
border-bottom: 1px solid var(--rule);
|
|
102
|
+
position: sticky; top: 0; z-index: 10;
|
|
103
|
+
}
|
|
104
|
+
.app-header .toolbar {
|
|
105
|
+
display: flex; align-items: center; gap: 8px;
|
|
106
|
+
padding: 8px 16px;
|
|
107
|
+
}
|
|
108
|
+
.app-header .toolbar-menu { padding-bottom: 4px; }
|
|
109
|
+
.app-header .toolbar-action {
|
|
110
|
+
padding-top: 4px;
|
|
111
|
+
border-top: 1px solid var(--rule);
|
|
112
|
+
}
|
|
113
|
+
/* Current-Project anchor rechts in Row 1 (klickbar, öffnet Load-Dialog). */
|
|
114
|
+
.current-project {
|
|
115
|
+
font-size: 12px;
|
|
116
|
+
color: var(--ink-soft);
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
padding: 3px 10px;
|
|
119
|
+
border: 1px solid transparent;
|
|
120
|
+
border-radius: 4px;
|
|
121
|
+
transition: background 100ms, border-color 100ms;
|
|
122
|
+
}
|
|
123
|
+
.current-project:hover {
|
|
124
|
+
background: var(--paper);
|
|
125
|
+
border-color: var(--rule);
|
|
126
|
+
color: var(--ink);
|
|
127
|
+
}
|
|
128
|
+
.current-project:empty { display: none; }
|
|
129
|
+
/* Brand — 1:1 aus cmapper: <span class="brand"><b>X</b><em>Y</em></span> */
|
|
130
|
+
.brand {
|
|
131
|
+
font-family: var(--font-body);
|
|
132
|
+
font-size: 18px;
|
|
133
|
+
letter-spacing: -0.02em;
|
|
134
|
+
margin-right: 4px;
|
|
135
|
+
color: var(--ink);
|
|
136
|
+
}
|
|
137
|
+
.brand b { color: var(--accent); font-weight: 900; font-style: normal; }
|
|
138
|
+
.brand em { font-style: normal; font-weight: 400; color: var(--ink); }
|
|
139
|
+
.toolbar-spacer { flex: 1; }
|
|
140
|
+
.sep {
|
|
141
|
+
display: inline-block;
|
|
142
|
+
width: 1px; height: 22px;
|
|
143
|
+
background: var(--rule);
|
|
144
|
+
margin: 0 4px;
|
|
145
|
+
}
|
|
146
|
+
.app-toolbar {
|
|
147
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Legacy alias for old .toolbar selectors used by other code paths. */
|
|
151
|
+
.toolbar { display: flex; align-items: center; gap: 8px; }
|
|
152
|
+
|
|
153
|
+
/* ---------- Buttons (1:1 cmapper) ---------- */
|
|
154
|
+
.btn {
|
|
155
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
156
|
+
padding: 6px 11px;
|
|
157
|
+
background: transparent;
|
|
158
|
+
border: 1px solid var(--rule);
|
|
159
|
+
border-radius: 4px;
|
|
160
|
+
color: var(--ink);
|
|
161
|
+
font: inherit; font-size: 12px;
|
|
162
|
+
cursor: pointer;
|
|
163
|
+
transition: background 120ms, border-color 120ms;
|
|
164
|
+
white-space: nowrap;
|
|
165
|
+
}
|
|
166
|
+
.btn:hover:not(:disabled) { background: var(--paper-warm); border-color: var(--ink-faint); }
|
|
167
|
+
.btn:disabled { opacity: 0.35; cursor: default; }
|
|
168
|
+
.btn:disabled:hover { background: transparent; border-color: var(--rule); }
|
|
169
|
+
.btn.active { background: var(--ink); color: var(--paper); border-color: var(--ink); }
|
|
170
|
+
.btn.primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }
|
|
171
|
+
.btn.primary:hover:not(:disabled) { background: var(--ink-soft); border-color: var(--ink-soft); }
|
|
172
|
+
.btn.destructive {
|
|
173
|
+
background: var(--danger);
|
|
174
|
+
border-color: var(--danger);
|
|
175
|
+
color: #FFFFFF;
|
|
176
|
+
}
|
|
177
|
+
.btn.destructive:hover:not(:disabled) {
|
|
178
|
+
background: var(--danger-hover);
|
|
179
|
+
border-color: var(--danger-hover);
|
|
180
|
+
}
|
|
181
|
+
/* SM-244: Cancel-ticket action — SOLID amber (filled like the red Delete, but
|
|
182
|
+
warning-yellow not danger-red). Dark ink text reads with high contrast on
|
|
183
|
+
amber (~9:1), clearly more visible than an outline button. */
|
|
184
|
+
.btn.warn {
|
|
185
|
+
background: #F59E0B;
|
|
186
|
+
border-color: #F59E0B;
|
|
187
|
+
color: #1A1A1A;
|
|
188
|
+
font-weight: 600;
|
|
189
|
+
}
|
|
190
|
+
.btn.warn:hover:not(:disabled) {
|
|
191
|
+
background: #D97706;
|
|
192
|
+
border-color: #D97706;
|
|
193
|
+
color: #1A1A1A;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Native form controls match the paperlike palette */
|
|
197
|
+
select, input[type="text"], input[type="number"], input[type="password"], textarea {
|
|
198
|
+
background: var(--paper);
|
|
199
|
+
color: var(--ink);
|
|
200
|
+
border: 1px solid var(--rule);
|
|
201
|
+
border-radius: 4px;
|
|
202
|
+
padding: 5px 8px;
|
|
203
|
+
font: inherit;
|
|
204
|
+
font-size: 12px;
|
|
205
|
+
}
|
|
206
|
+
select { min-width: 160px; }
|
|
207
|
+
select:focus, input:focus, textarea:focus { outline: none; border-color: var(--ink); }
|
|
208
|
+
|
|
209
|
+
.badge {
|
|
210
|
+
font-size: 11px;
|
|
211
|
+
padding: 2px 8px;
|
|
212
|
+
border: 1px solid var(--rule);
|
|
213
|
+
border-radius: 999px;
|
|
214
|
+
background: var(--paper);
|
|
215
|
+
color: var(--ink-soft);
|
|
216
|
+
letter-spacing: 0.02em;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Build-Tag neben dem Brand — zeigt git-Commit + Subject als Tooltip.
|
|
220
|
+
Bei jeder Code-Änderung sichtbar im UI, sodass "ich sehe die neue
|
|
221
|
+
Version nicht"-Verwirrungen sich in 1 Sekunde klären lassen. */
|
|
222
|
+
.build-tag {
|
|
223
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
224
|
+
font-size: 10px;
|
|
225
|
+
color: var(--ink-faint);
|
|
226
|
+
padding: 2px 6px;
|
|
227
|
+
background: var(--rule-soft);
|
|
228
|
+
border-radius: 3px;
|
|
229
|
+
letter-spacing: 0.04em;
|
|
230
|
+
cursor: help;
|
|
231
|
+
user-select: all;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* ---------- Main / View host ---------- */
|
|
235
|
+
/* App-Grid: header (auto) | main (1fr) | statusbar (auto). */
|
|
236
|
+
body {
|
|
237
|
+
display: grid;
|
|
238
|
+
grid-template-rows: auto 1fr auto;
|
|
239
|
+
height: 100vh;
|
|
240
|
+
}
|
|
241
|
+
main {
|
|
242
|
+
display: grid;
|
|
243
|
+
grid-template-columns: 1fr 0;
|
|
244
|
+
transition: grid-template-columns 0.18s ease;
|
|
245
|
+
overflow: hidden;
|
|
246
|
+
}
|
|
247
|
+
main.sidebar-open { grid-template-columns: 1fr 360px; }
|
|
248
|
+
/* Scroll-Container: KEIN padding-top (sticky Backbone klebt direkt an
|
|
249
|
+
die Toolbar) und KEIN seitliches padding — sonst weichen die Spalten
|
|
250
|
+
der Backbone von den Release-Cells ab (das Grid `auto-fit` der beiden
|
|
251
|
+
Container produziert dann unterschiedliche Breiten). Inhalt erhält
|
|
252
|
+
seine Atem-Räume über die jeweiligen inneren Paddings: `.sm-cell`
|
|
253
|
+
intern 10px, Kanban-Board separates Side-Padding für Lanes. */
|
|
254
|
+
#view-host { overflow: auto; padding: 0 0 16px; }
|
|
255
|
+
/* SM-281 (Wiedergänger von SM-280, diesmal mit korrekter Diagnose): macOS-
|
|
256
|
+
Overlay-Scrollbalken erscheinen NUR für die gerade gescrollte Achse. Eine
|
|
257
|
+
Maus mit rein vertikalem Scrollrad erzeugt nie ein horizontales Delta —
|
|
258
|
+
der horizontale Balken taucht also nie auf und ist auch nicht greifbar;
|
|
259
|
+
Process-Steps rechts außerhalb des Viewports sind dann unerreichbar.
|
|
260
|
+
::-webkit-scrollbar-Styling opt-out't aus dem Overlay → dauerhaft sicht-
|
|
261
|
+
und greifbare klassische Balken (Safari/Chrome). Bewusst schlanker als der
|
|
262
|
+
revertierte SM-280-Wurf (10px, zarter Thumb, transparenter Track), damit
|
|
263
|
+
es nicht "heavy und un-Safari-like" wirkt. Ergänzend übersetzt
|
|
264
|
+
js/wheel-pan.js Shift+Scrollrad in horizontales Scrollen. */
|
|
265
|
+
#view-host::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
266
|
+
#view-host::-webkit-scrollbar-thumb {
|
|
267
|
+
background: rgba(26, 26, 26, 0.22);
|
|
268
|
+
border-radius: 5px;
|
|
269
|
+
border: 2px solid var(--paper);
|
|
270
|
+
}
|
|
271
|
+
#view-host::-webkit-scrollbar-thumb:hover { background: rgba(26, 26, 26, 0.42); }
|
|
272
|
+
#view-host::-webkit-scrollbar-track { background: transparent; }
|
|
273
|
+
#view-host::-webkit-scrollbar-corner { background: transparent; }
|
|
274
|
+
#sidebar-host {
|
|
275
|
+
overflow: auto;
|
|
276
|
+
border-left: 1px solid var(--rule);
|
|
277
|
+
background: var(--paper);
|
|
278
|
+
padding: 16px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* ---------- Statusbar (am Boden, fixiert) ---------- */
|
|
282
|
+
.statusbar {
|
|
283
|
+
display: flex; align-items: center; gap: 8px;
|
|
284
|
+
padding: 4px 16px;
|
|
285
|
+
border-top: 1px solid var(--rule);
|
|
286
|
+
background: var(--paper-warm);
|
|
287
|
+
font-size: 11px;
|
|
288
|
+
color: var(--ink-soft);
|
|
289
|
+
min-height: 24px;
|
|
290
|
+
}
|
|
291
|
+
.statusbar-spacer { flex: 1; }
|
|
292
|
+
|
|
293
|
+
/* ---------- Empty state ---------- */
|
|
294
|
+
.empty-state {
|
|
295
|
+
display: flex; flex-direction: column;
|
|
296
|
+
align-items: center; justify-content: center;
|
|
297
|
+
padding: 60px 20px;
|
|
298
|
+
color: var(--ink-soft);
|
|
299
|
+
text-align: center;
|
|
300
|
+
}
|
|
301
|
+
.empty-state h2 {
|
|
302
|
+
margin: 0 0 8px;
|
|
303
|
+
font-weight: 600;
|
|
304
|
+
font-size: 14px;
|
|
305
|
+
}
|
|
306
|
+
.empty-state p { margin: 0 0 16px; max-width: 480px; }
|
|
307
|
+
|
|
308
|
+
/* ============================================================
|
|
309
|
+
UI-Shell — Modal, Popover, Menu, Flash (1:1 cmapper)
|
|
310
|
+
============================================================ */
|
|
311
|
+
|
|
312
|
+
/* Single host that contains at most one modal at a time. */
|
|
313
|
+
#modal-host { position: relative; z-index: 100; }
|
|
314
|
+
|
|
315
|
+
.modal-overlay {
|
|
316
|
+
position: fixed; inset: 0;
|
|
317
|
+
background: rgba(26,26,26,0.35);
|
|
318
|
+
display: flex; align-items: center; justify-content: center;
|
|
319
|
+
z-index: 100;
|
|
320
|
+
}
|
|
321
|
+
.modal {
|
|
322
|
+
background: var(--paper);
|
|
323
|
+
border: 1px solid var(--rule);
|
|
324
|
+
border-radius: 6px;
|
|
325
|
+
box-shadow: var(--shadow-lift);
|
|
326
|
+
padding: 22px 24px;
|
|
327
|
+
width: 580px; max-width: 92vw; max-height: 85vh;
|
|
328
|
+
display: flex; flex-direction: column;
|
|
329
|
+
}
|
|
330
|
+
.modal h2, .modal .modal-title {
|
|
331
|
+
font-family: var(--font-display);
|
|
332
|
+
font-size: 20px; font-weight: 700;
|
|
333
|
+
margin: 0 0 4px 0; letter-spacing: -0.01em;
|
|
334
|
+
color: var(--ink);
|
|
335
|
+
}
|
|
336
|
+
.modal .modal-sub {
|
|
337
|
+
font-size: 12px; color: var(--ink-soft);
|
|
338
|
+
margin-bottom: 14px; line-height: 1.5;
|
|
339
|
+
}
|
|
340
|
+
.modal .modal-body { display: flex; flex-direction: column; }
|
|
341
|
+
.modal textarea {
|
|
342
|
+
flex: 1; min-height: 80px; width: 100%;
|
|
343
|
+
border: 1px solid var(--rule);
|
|
344
|
+
border-radius: 4px;
|
|
345
|
+
padding: 10px 12px;
|
|
346
|
+
background: #FFFFFF;
|
|
347
|
+
font-family: var(--font-body);
|
|
348
|
+
font-size: 11px; color: var(--ink-soft);
|
|
349
|
+
line-height: 1.55;
|
|
350
|
+
letter-spacing: 0.01em;
|
|
351
|
+
resize: vertical;
|
|
352
|
+
}
|
|
353
|
+
.modal textarea:focus { outline: none; border-color: var(--ink); }
|
|
354
|
+
.modal-actions {
|
|
355
|
+
display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* Generic form row used inside modals (label + control). */
|
|
359
|
+
.modal-row {
|
|
360
|
+
display: flex; align-items: center; gap: 8px;
|
|
361
|
+
margin: 8px 0;
|
|
362
|
+
}
|
|
363
|
+
.modal-row label {
|
|
364
|
+
flex: 0 0 140px;
|
|
365
|
+
color: var(--ink-soft);
|
|
366
|
+
font-size: 12px;
|
|
367
|
+
}
|
|
368
|
+
.modal-row input[type="text"],
|
|
369
|
+
.modal-row input[type="number"],
|
|
370
|
+
.modal-row input[type="password"],
|
|
371
|
+
.modal-row select,
|
|
372
|
+
.modal-row textarea {
|
|
373
|
+
flex: 1;
|
|
374
|
+
padding: 5px 8px;
|
|
375
|
+
border: 1px solid var(--rule);
|
|
376
|
+
border-radius: 4px;
|
|
377
|
+
background: var(--paper);
|
|
378
|
+
font: inherit; font-size: 12px;
|
|
379
|
+
color: var(--ink);
|
|
380
|
+
}
|
|
381
|
+
.modal-row textarea { min-height: 60px; resize: vertical; }
|
|
382
|
+
.modal-row .row-hint {
|
|
383
|
+
flex: 0 0 100%;
|
|
384
|
+
margin-left: 148px;
|
|
385
|
+
font-size: 11px; color: var(--ink-faint);
|
|
386
|
+
margin-top: 2px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* DoR/DoD-Gate-Fehler-Liste in Modals */
|
|
390
|
+
.missing-list {
|
|
391
|
+
list-style: none; margin: 8px 0 0; padding: 8px 12px;
|
|
392
|
+
background: rgba(176,56,43,0.08);
|
|
393
|
+
border-left: 3px solid var(--danger);
|
|
394
|
+
border-radius: 4px;
|
|
395
|
+
font-size: 12px;
|
|
396
|
+
}
|
|
397
|
+
.missing-list li { padding: 2px 0; color: var(--ink); }
|
|
398
|
+
.missing-list li::before { content: "○ "; color: var(--danger); }
|
|
399
|
+
|
|
400
|
+
/* ---------- Context menu (SM-30) ---------- */
|
|
401
|
+
.context-menu {
|
|
402
|
+
position: fixed;
|
|
403
|
+
z-index: 60;
|
|
404
|
+
min-width: 180px;
|
|
405
|
+
background: var(--paper);
|
|
406
|
+
border: 1px solid var(--rule);
|
|
407
|
+
border-radius: 6px;
|
|
408
|
+
box-shadow: var(--shadow-lift);
|
|
409
|
+
padding: 4px 0;
|
|
410
|
+
}
|
|
411
|
+
.context-menu-list { display: flex; flex-direction: column; }
|
|
412
|
+
.context-menu-item {
|
|
413
|
+
appearance: none;
|
|
414
|
+
border: 0;
|
|
415
|
+
background: transparent;
|
|
416
|
+
text-align: left;
|
|
417
|
+
padding: 6px 14px;
|
|
418
|
+
font-size: 12px;
|
|
419
|
+
color: var(--ink);
|
|
420
|
+
cursor: pointer;
|
|
421
|
+
font-family: inherit;
|
|
422
|
+
}
|
|
423
|
+
.context-menu-item:hover { background: var(--accent-soft); color: var(--ink); }
|
|
424
|
+
.context-menu-item-disabled {
|
|
425
|
+
cursor: not-allowed;
|
|
426
|
+
color: var(--ink-soft);
|
|
427
|
+
}
|
|
428
|
+
.context-menu-item-disabled:hover { background: transparent; }
|
|
429
|
+
|
|
430
|
+
/* ---------- Settings popover (anchored) ---------- */
|
|
431
|
+
.settings-popover {
|
|
432
|
+
position: fixed;
|
|
433
|
+
z-index: 50;
|
|
434
|
+
min-width: 240px;
|
|
435
|
+
max-width: min(360px, 92vw);
|
|
436
|
+
padding: 12px 14px;
|
|
437
|
+
background: var(--paper);
|
|
438
|
+
border: 1px solid var(--rule);
|
|
439
|
+
border-radius: 6px;
|
|
440
|
+
box-shadow: var(--shadow-lift);
|
|
441
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
442
|
+
}
|
|
443
|
+
.sp-title {
|
|
444
|
+
font-size: 13px; font-weight: 600;
|
|
445
|
+
color: var(--ink);
|
|
446
|
+
}
|
|
447
|
+
.sp-row {
|
|
448
|
+
display: grid;
|
|
449
|
+
grid-template-columns: 96px 1fr 56px;
|
|
450
|
+
align-items: center;
|
|
451
|
+
gap: 10px;
|
|
452
|
+
font-size: 12px;
|
|
453
|
+
}
|
|
454
|
+
.sp-row label { color: var(--ink-soft); }
|
|
455
|
+
.sp-row input[type="range"] { accent-color: var(--accent); }
|
|
456
|
+
.sp-out {
|
|
457
|
+
font-variant-numeric: tabular-nums;
|
|
458
|
+
text-align: right;
|
|
459
|
+
color: var(--ink);
|
|
460
|
+
}
|
|
461
|
+
.sp-hint { font-size: 11px; color: var(--ink-faint); line-height: 1.45; }
|
|
462
|
+
.sp-footer { display: flex; justify-content: flex-end; }
|
|
463
|
+
.sp-reset {
|
|
464
|
+
background: none; border: none;
|
|
465
|
+
color: var(--accent);
|
|
466
|
+
font: inherit; cursor: pointer;
|
|
467
|
+
padding: 2px 4px;
|
|
468
|
+
}
|
|
469
|
+
.sp-reset:hover { text-decoration: underline; }
|
|
470
|
+
|
|
471
|
+
/* ---------- Menu Bar (1:1 cmapper) ---------- */
|
|
472
|
+
.menu-bar {
|
|
473
|
+
display: inline-flex; align-items: center; gap: 2px;
|
|
474
|
+
}
|
|
475
|
+
.menu-item {
|
|
476
|
+
background: transparent;
|
|
477
|
+
border: 1px solid transparent;
|
|
478
|
+
border-radius: 4px;
|
|
479
|
+
padding: 5px 10px;
|
|
480
|
+
font-family: var(--font-body);
|
|
481
|
+
font-size: 12px;
|
|
482
|
+
color: var(--ink);
|
|
483
|
+
cursor: pointer;
|
|
484
|
+
line-height: 1.2;
|
|
485
|
+
user-select: none;
|
|
486
|
+
transition: background 100ms, border-color 100ms;
|
|
487
|
+
}
|
|
488
|
+
.menu-item:hover { background: var(--paper-warm); border-color: var(--rule); }
|
|
489
|
+
.menu-item.open {
|
|
490
|
+
background: var(--ink); color: var(--paper); border-color: var(--ink);
|
|
491
|
+
}
|
|
492
|
+
.menu-dropdown {
|
|
493
|
+
position: fixed;
|
|
494
|
+
z-index: 70;
|
|
495
|
+
min-width: 220px;
|
|
496
|
+
padding: 4px 0;
|
|
497
|
+
background: var(--paper);
|
|
498
|
+
border: 1px solid var(--rule);
|
|
499
|
+
border-radius: 6px;
|
|
500
|
+
box-shadow: var(--shadow-lift);
|
|
501
|
+
font-family: var(--font-body);
|
|
502
|
+
font-size: 12px;
|
|
503
|
+
color: var(--ink);
|
|
504
|
+
}
|
|
505
|
+
.menu-dropdown-item {
|
|
506
|
+
/* SM-205: [check gutter | label | shortcut] grid so labels share one column
|
|
507
|
+
and the active item's ✓ sits in the gutter (not inline with the text). */
|
|
508
|
+
display: grid;
|
|
509
|
+
grid-template-columns: 11px 1fr auto;
|
|
510
|
+
align-items: center;
|
|
511
|
+
column-gap: 5px;
|
|
512
|
+
padding: 6px 14px 6px 9px;
|
|
513
|
+
cursor: pointer;
|
|
514
|
+
color: var(--ink);
|
|
515
|
+
background: transparent;
|
|
516
|
+
border: none;
|
|
517
|
+
width: 100%;
|
|
518
|
+
text-align: left;
|
|
519
|
+
font: inherit;
|
|
520
|
+
line-height: 1.3;
|
|
521
|
+
}
|
|
522
|
+
.menu-dropdown-item:hover:not(.disabled) { background: var(--paper-warm); }
|
|
523
|
+
.menu-dropdown-item.disabled {
|
|
524
|
+
color: var(--ink-faint);
|
|
525
|
+
cursor: default;
|
|
526
|
+
background: transparent;
|
|
527
|
+
}
|
|
528
|
+
.menu-dropdown-item .menu-check {
|
|
529
|
+
width: 11px; text-align: center; color: var(--accent);
|
|
530
|
+
font-size: 11px; line-height: 1;
|
|
531
|
+
}
|
|
532
|
+
.menu-dropdown-item .menu-label { white-space: nowrap; }
|
|
533
|
+
.menu-dropdown-item .menu-shortcut {
|
|
534
|
+
font-family: var(--font-body);
|
|
535
|
+
font-size: 11px;
|
|
536
|
+
color: var(--ink-faint);
|
|
537
|
+
letter-spacing: 0.04em;
|
|
538
|
+
white-space: nowrap;
|
|
539
|
+
}
|
|
540
|
+
.menu-dropdown-separator {
|
|
541
|
+
height: 1px;
|
|
542
|
+
background: var(--rule);
|
|
543
|
+
margin: 4px 6px;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/* ---------- Flash status (bottom-left toast) ---------- */
|
|
547
|
+
.flash {
|
|
548
|
+
position: fixed;
|
|
549
|
+
bottom: 16px; left: 16px;
|
|
550
|
+
background: var(--ink);
|
|
551
|
+
color: var(--paper);
|
|
552
|
+
padding: 6px 12px;
|
|
553
|
+
border-radius: 999px;
|
|
554
|
+
font-size: 12px;
|
|
555
|
+
letter-spacing: 0.01em;
|
|
556
|
+
box-shadow: var(--shadow-lift);
|
|
557
|
+
display: inline-flex;
|
|
558
|
+
align-items: center;
|
|
559
|
+
gap: 8px;
|
|
560
|
+
z-index: 80;
|
|
561
|
+
animation: flashIn 140ms ease-out;
|
|
562
|
+
}
|
|
563
|
+
@keyframes flashIn { from { transform: translateY(8px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
|
|
564
|
+
.flash-error { background: var(--danger); color: #FFFFFF; }
|
|
565
|
+
.flash-ok { background: var(--accent); color: #FFFFFF; }
|
|
566
|
+
.flash-spinner {
|
|
567
|
+
display: inline-block;
|
|
568
|
+
width: 12px; height: 12px;
|
|
569
|
+
border: 2px solid currentColor;
|
|
570
|
+
border-top-color: transparent;
|
|
571
|
+
border-radius: 50%;
|
|
572
|
+
animation: spin 0.8s linear infinite;
|
|
573
|
+
}
|
|
574
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
575
|
+
|
|
576
|
+
/* ============================================================
|
|
577
|
+
Story-Map (E9c) — 3-Ebenen: ProcessSteps × Releases → Epics → Stories
|
|
578
|
+
============================================================
|
|
579
|
+
CSS-Variablen --sm-* werden vom Renderer aus STORY_MAP_LAYOUT gesetzt,
|
|
580
|
+
damit Werte zentral aus JS gepflegt werden können. */
|
|
581
|
+
|
|
582
|
+
.sm-grid {
|
|
583
|
+
/* SM-257 Safari fix: block flow, NOT flex-column. The children are
|
|
584
|
+
full-width rows that simply stack, so block is visually identical to a
|
|
585
|
+
gap:0 flex column in Chrome — but it removes the "sticky element is a
|
|
586
|
+
flex item" condition, which Safari renders incorrectly (the sticky
|
|
587
|
+
.sm-backbone flex child inside this width:max-content parent silently
|
|
588
|
+
fails to paint / position). A plain sticky block child is the
|
|
589
|
+
best-supported sticky scenario across engines. */
|
|
590
|
+
display: block;
|
|
591
|
+
/* SM-55 follow-up: make the grid container as wide as its widest child
|
|
592
|
+
(the cells-row with explicit pixel grid-columns summing past the
|
|
593
|
+
viewport). Without this, label-rows + the sm-backbone background paint
|
|
594
|
+
only up to the viewport edge — when the user scrolls horizontally to
|
|
595
|
+
reveal off-screen process steps, the background ends where the viewport
|
|
596
|
+
ended, not at the actual column width. `min-width: 100%` keeps the
|
|
597
|
+
grid filling the viewport when content is narrower. */
|
|
598
|
+
width: max-content;
|
|
599
|
+
min-width: 100%;
|
|
600
|
+
--sm-backbone-col-w: 240px;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/* ---------- Feature-Backbone (sticky top) ----------
|
|
604
|
+
grid-template-columns wird vom Renderer inline gesetzt: pro PS-Spalte
|
|
605
|
+
eine eigene Breite = calc(multiplier * var(--sm-backbone-col-w)).
|
|
606
|
+
Hier nur ein sinnvoller Fallback, falls Inline-Style fehlt. */
|
|
607
|
+
.sm-backbone {
|
|
608
|
+
display: grid;
|
|
609
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--sm-backbone-col-w), 1fr));
|
|
610
|
+
background: #4C8170; /* literal fallback — paints even if a
|
|
611
|
+
browser stumbles on the custom prop */
|
|
612
|
+
background: var(--backbone-bg);
|
|
613
|
+
border-bottom: 2px solid var(--backbone-edge);
|
|
614
|
+
position: sticky; top: 0; z-index: 2;
|
|
615
|
+
}
|
|
616
|
+
.sm-backbone-col {
|
|
617
|
+
padding: 10px 12px;
|
|
618
|
+
font-size: 13px; font-weight: 600;
|
|
619
|
+
color: var(--backbone-ink);
|
|
620
|
+
letter-spacing: -0.01em;
|
|
621
|
+
border-right: 1px solid var(--backbone-divider);
|
|
622
|
+
text-align: center;
|
|
623
|
+
cursor: grab;
|
|
624
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
625
|
+
transition: background 120ms, box-shadow 120ms;
|
|
626
|
+
}
|
|
627
|
+
.sm-backbone-col:hover { background: var(--backbone-lift); }
|
|
628
|
+
.sm-backbone-col.sm-dragging { opacity: 0.4; cursor: grabbing; }
|
|
629
|
+
.sm-backbone-col.sm-col-drop-target {
|
|
630
|
+
background: var(--backbone-lift-strong);
|
|
631
|
+
box-shadow: inset 3px 0 0 var(--paper);
|
|
632
|
+
}
|
|
633
|
+
.sm-backbone-col.sm-col-shadow {
|
|
634
|
+
opacity: 0.45;
|
|
635
|
+
background: var(--backbone-lift);
|
|
636
|
+
outline: 1px dashed var(--paper);
|
|
637
|
+
outline-offset: -2px;
|
|
638
|
+
}
|
|
639
|
+
.sm-col-grip {
|
|
640
|
+
color: var(--backbone-ink-soft);
|
|
641
|
+
font-size: 11px;
|
|
642
|
+
letter-spacing: -2px;
|
|
643
|
+
cursor: grab;
|
|
644
|
+
user-select: none;
|
|
645
|
+
}
|
|
646
|
+
.sm-col-label { /* keeps label naming explicit */ }
|
|
647
|
+
/* SM-272: process-step column collapse — chevron + narrow collapsed column. */
|
|
648
|
+
.sm-col-chevron {
|
|
649
|
+
appearance: none;
|
|
650
|
+
background: transparent;
|
|
651
|
+
border: none;
|
|
652
|
+
color: var(--backbone-ink-soft);
|
|
653
|
+
cursor: pointer;
|
|
654
|
+
font-size: 9px;
|
|
655
|
+
line-height: 1;
|
|
656
|
+
padding: 2px 1px;
|
|
657
|
+
flex: 0 0 auto;
|
|
658
|
+
}
|
|
659
|
+
.sm-col-chevron:hover { color: var(--backbone-ink); }
|
|
660
|
+
.sm-backbone-col.sm-col-collapsed {
|
|
661
|
+
padding: 10px 3px;
|
|
662
|
+
gap: 2px;
|
|
663
|
+
}
|
|
664
|
+
.sm-backbone-col.sm-col-collapsed .sm-col-grip { display: none; }
|
|
665
|
+
.sm-backbone-col.sm-col-collapsed .sm-col-label {
|
|
666
|
+
font-size: 11px;
|
|
667
|
+
overflow: hidden;
|
|
668
|
+
text-overflow: ellipsis;
|
|
669
|
+
white-space: nowrap;
|
|
670
|
+
max-width: 100%;
|
|
671
|
+
min-width: 0;
|
|
672
|
+
}
|
|
673
|
+
.sm-cell.sm-cell-collapsed {
|
|
674
|
+
display: flex;
|
|
675
|
+
align-items: flex-start;
|
|
676
|
+
justify-content: center;
|
|
677
|
+
padding: 8px 4px;
|
|
678
|
+
}
|
|
679
|
+
.sm-cell-collapsed-count {
|
|
680
|
+
font-size: 11px;
|
|
681
|
+
font-weight: 700;
|
|
682
|
+
color: var(--ink-soft, #717071);
|
|
683
|
+
background: rgba(0, 0, 0, 0.05);
|
|
684
|
+
border-radius: 8px;
|
|
685
|
+
padding: 2px 8px;
|
|
686
|
+
white-space: nowrap;
|
|
687
|
+
}
|
|
688
|
+
.sm-backbone-col.sm-empty {
|
|
689
|
+
font-size: 12px;
|
|
690
|
+
color: var(--backbone-ink-soft);
|
|
691
|
+
font-weight: normal;
|
|
692
|
+
font-style: italic;
|
|
693
|
+
cursor: default;
|
|
694
|
+
}
|
|
695
|
+
.sm-backbone-col.sm-empty:hover { background: transparent; }
|
|
696
|
+
|
|
697
|
+
/* Add-Column-Dropzone am rechten Rand des Backbones — Klick = neuer
|
|
698
|
+
ProcessStep, Drop von Epic = neuer ProcessStep + Epic-Move atomic. */
|
|
699
|
+
.sm-backbone-col.sm-add-col {
|
|
700
|
+
display: flex; align-items: center; justify-content: center; gap: 6px;
|
|
701
|
+
background: transparent;
|
|
702
|
+
color: var(--backbone-ink-soft);
|
|
703
|
+
font-weight: 500;
|
|
704
|
+
font-size: 12px;
|
|
705
|
+
cursor: pointer;
|
|
706
|
+
border-left: 1px dashed var(--backbone-divider);
|
|
707
|
+
border-right: none;
|
|
708
|
+
min-width: 120px;
|
|
709
|
+
transition: background 120ms, color 120ms, box-shadow 120ms;
|
|
710
|
+
}
|
|
711
|
+
.sm-backbone-col.sm-add-col:hover {
|
|
712
|
+
background: var(--backbone-lift);
|
|
713
|
+
color: var(--backbone-ink);
|
|
714
|
+
}
|
|
715
|
+
.sm-backbone-col.sm-add-col .sm-add-icon {
|
|
716
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
717
|
+
width: 16px; height: 16px;
|
|
718
|
+
background: var(--backbone-lift-strong);
|
|
719
|
+
color: var(--backbone-ink);
|
|
720
|
+
border-radius: 50%;
|
|
721
|
+
font-size: 12px;
|
|
722
|
+
font-weight: 700;
|
|
723
|
+
line-height: 1;
|
|
724
|
+
}
|
|
725
|
+
.sm-backbone-col.sm-add-col:hover .sm-add-icon { background: var(--paper); color: var(--accent); }
|
|
726
|
+
.sm-backbone-col.sm-add-col.sm-drop-target {
|
|
727
|
+
background: var(--backbone-lift-strong);
|
|
728
|
+
color: var(--backbone-ink);
|
|
729
|
+
box-shadow: inset 0 0 0 3px var(--paper);
|
|
730
|
+
}
|
|
731
|
+
.sm-backbone-col.sm-add-col.sm-drop-target .sm-add-icon { background: var(--paper); color: var(--accent); }
|
|
732
|
+
|
|
733
|
+
/* ---------- Release-Cells-Zeile ----------
|
|
734
|
+
grid-template-columns: inline vom Renderer (eine Spalte pro PS, plus
|
|
735
|
+
auto-Filler für den Add-Step-Slot der Backbone). Kein Release-Label-
|
|
736
|
+
Slot mehr — das Label sitzt in der Zeile darunter. */
|
|
737
|
+
.sm-release-row.sm-release-cells {
|
|
738
|
+
display: grid;
|
|
739
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--sm-backbone-col-w), 1fr));
|
|
740
|
+
min-height: 120px;
|
|
741
|
+
background: var(--paper);
|
|
742
|
+
}
|
|
743
|
+
.sm-row-filler {
|
|
744
|
+
background: transparent;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* ---------- Release-Label-Zeile (unter den Cells) ---------- */
|
|
748
|
+
.sm-release-label-row {
|
|
749
|
+
display: flex;
|
|
750
|
+
align-items: center;
|
|
751
|
+
gap: 10px;
|
|
752
|
+
padding: 6px 12px;
|
|
753
|
+
background: var(--paper-warm);
|
|
754
|
+
border-top: 1px solid var(--rule);
|
|
755
|
+
border-bottom: 2px solid var(--rule); /* visuelle Trennung zwischen Releases */
|
|
756
|
+
}
|
|
757
|
+
/* SM-178: the chevron + name + pill cluster. In the Story-Map it sticks to the
|
|
758
|
+
left edge so it stays visible while scrolling horizontally through wide
|
|
759
|
+
process steps (orientation). The Kanban swimlane header uses the same DOM
|
|
760
|
+
but does NOT pin it — the sticky rule is scoped to `.sm-grid`. */
|
|
761
|
+
.sm-release-label-main {
|
|
762
|
+
display: inline-flex;
|
|
763
|
+
align-items: center;
|
|
764
|
+
gap: 10px;
|
|
765
|
+
}
|
|
766
|
+
.sm-grid .sm-release-label-main {
|
|
767
|
+
position: sticky;
|
|
768
|
+
left: 0;
|
|
769
|
+
z-index: 1;
|
|
770
|
+
background: var(--paper-warm);
|
|
771
|
+
/* paint a little to the right so the pinned cluster reads cleanly over the
|
|
772
|
+
row content scrolling underneath it */
|
|
773
|
+
padding-right: 8px;
|
|
774
|
+
border-radius: 0 4px 4px 0;
|
|
775
|
+
}
|
|
776
|
+
.sm-release-label {
|
|
777
|
+
font-size: 13px; font-weight: 600;
|
|
778
|
+
color: var(--ink);
|
|
779
|
+
letter-spacing: -0.01em;
|
|
780
|
+
cursor: pointer;
|
|
781
|
+
padding: 4px 8px;
|
|
782
|
+
border-radius: 4px;
|
|
783
|
+
transition: background 120ms;
|
|
784
|
+
/* SM-277: fixed title column so the progress/pill/Add badges line up in stable
|
|
785
|
+
columns across every release row instead of fluttering with the title
|
|
786
|
+
length. Longer titles truncate with an ellipsis (full name in the tooltip).
|
|
787
|
+
--sm-release-label-w comes from RELEASE_LABEL_WIDTH_PX (set on .sm-grid). */
|
|
788
|
+
flex: 0 0 var(--sm-release-label-w, 300px);
|
|
789
|
+
max-width: var(--sm-release-label-w, 300px);
|
|
790
|
+
box-sizing: border-box;
|
|
791
|
+
white-space: nowrap;
|
|
792
|
+
overflow: hidden;
|
|
793
|
+
text-overflow: ellipsis;
|
|
794
|
+
}
|
|
795
|
+
.sm-release-label:hover { background: var(--paper); }
|
|
796
|
+
|
|
797
|
+
/* SM-80 — Release-Lifecycle visual markers. Completed and cancelled
|
|
798
|
+
releases get a dimmed style + status pill so they're recognisable
|
|
799
|
+
without the filter being active. */
|
|
800
|
+
.sm-release-label[data-status="completed"],
|
|
801
|
+
.sm-release-label[data-status="cancelled"] {
|
|
802
|
+
color: var(--ink-soft);
|
|
803
|
+
text-decoration: line-through;
|
|
804
|
+
text-decoration-color: var(--ink-faint);
|
|
805
|
+
text-decoration-thickness: 1px;
|
|
806
|
+
}
|
|
807
|
+
.sm-release-cells[data-status="completed"],
|
|
808
|
+
.sm-release-cells[data-status="cancelled"] {
|
|
809
|
+
opacity: 0.55;
|
|
810
|
+
filter: saturate(0.7);
|
|
811
|
+
}
|
|
812
|
+
/* SM-83: scope the hover-restore so it does NOT fight the collapsed-cells
|
|
813
|
+
opacity:0 (which would reveal content when the user hovers over the
|
|
814
|
+
collapsed row's box). */
|
|
815
|
+
.sm-release-cells[data-status="completed"]:not(.sm-release-collapsed-cells):hover,
|
|
816
|
+
.sm-release-cells[data-status="cancelled"]:not(.sm-release-collapsed-cells):hover { opacity: 0.85; }
|
|
817
|
+
.sm-release-pill {
|
|
818
|
+
display: inline-block;
|
|
819
|
+
padding: 1px 8px;
|
|
820
|
+
border-radius: 9px;
|
|
821
|
+
font-size: 10px; font-weight: 700;
|
|
822
|
+
text-transform: uppercase; letter-spacing: 0.05em;
|
|
823
|
+
line-height: 16px;
|
|
824
|
+
}
|
|
825
|
+
.sm-release-pill-completed {
|
|
826
|
+
background: var(--accent-soft, rgba(15, 95, 79, 0.16));
|
|
827
|
+
color: var(--accent);
|
|
828
|
+
border: 1px solid var(--accent);
|
|
829
|
+
}
|
|
830
|
+
.sm-release-pill-cancelled {
|
|
831
|
+
background: rgba(180, 60, 60, 0.12);
|
|
832
|
+
color: var(--danger, #B43C3C);
|
|
833
|
+
border: 1px solid var(--danger, #B43C3C);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/* SM-239 — release progress badge "X/Y". Neutral by default; turns green
|
|
837
|
+
(accent) when every work item is done. Shared by the Story-Map release
|
|
838
|
+
label rows AND the Kanban swimlane headers (one renderReleaseLabelRow). */
|
|
839
|
+
.sm-release-progress {
|
|
840
|
+
display: inline-block;
|
|
841
|
+
padding: 1px 8px;
|
|
842
|
+
border-radius: 9px;
|
|
843
|
+
font-size: 11px; font-weight: 700;
|
|
844
|
+
line-height: 16px;
|
|
845
|
+
font-variant-numeric: tabular-nums;
|
|
846
|
+
background: var(--ink-soft-bg, rgba(0, 0, 0, 0.06));
|
|
847
|
+
color: var(--ink-soft, #717071);
|
|
848
|
+
border: 1px solid transparent;
|
|
849
|
+
/* SM-277: fixed min-width + centered so "8/9" and "10/10" occupy the same
|
|
850
|
+
slot — the status pill after it doesn't shift when the count changes. */
|
|
851
|
+
min-width: 44px;
|
|
852
|
+
box-sizing: border-box;
|
|
853
|
+
text-align: center;
|
|
854
|
+
}
|
|
855
|
+
.sm-release-progress.complete {
|
|
856
|
+
background: var(--accent-soft, rgba(15, 95, 79, 0.16));
|
|
857
|
+
color: var(--accent);
|
|
858
|
+
border-color: var(--accent);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/* SM-83 — Collapsible release rows. Chevron sits at the start of the
|
|
862
|
+
label row; toggling collapses the cells-row (animated via max-height)
|
|
863
|
+
and visually compacts the label row so closed releases take less
|
|
864
|
+
vertical space. */
|
|
865
|
+
.sm-release-chevron {
|
|
866
|
+
appearance: none;
|
|
867
|
+
background: transparent;
|
|
868
|
+
border: 1px solid transparent;
|
|
869
|
+
border-radius: 4px;
|
|
870
|
+
color: var(--ink-soft);
|
|
871
|
+
cursor: pointer;
|
|
872
|
+
/* Larger size — at 12px the ▾/▸ glyphs read as dots. ▼/▶ at 14px is
|
|
873
|
+
unambiguous as a disclosure triangle. */
|
|
874
|
+
font-size: 14px;
|
|
875
|
+
line-height: 1;
|
|
876
|
+
padding: 3px 8px;
|
|
877
|
+
min-width: 24px;
|
|
878
|
+
display: inline-flex;
|
|
879
|
+
align-items: center;
|
|
880
|
+
justify-content: center;
|
|
881
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
882
|
+
}
|
|
883
|
+
.sm-release-chevron:hover {
|
|
884
|
+
background: var(--paper);
|
|
885
|
+
color: var(--ink);
|
|
886
|
+
border-color: var(--rule);
|
|
887
|
+
}
|
|
888
|
+
.sm-release-label-row.sm-release-collapsed {
|
|
889
|
+
padding: 2px 12px; /* tighter vertical when collapsed */
|
|
890
|
+
border-bottom-width: 1px; /* the heavy 2px separator only fits expanded */
|
|
891
|
+
}
|
|
892
|
+
.sm-release-label-row.sm-release-collapsed .sm-release-label {
|
|
893
|
+
font-size: 12px;
|
|
894
|
+
padding: 2px 8px;
|
|
895
|
+
}
|
|
896
|
+
/* Animated collapse: the cells-row stays in the DOM and animates via
|
|
897
|
+
max-height + opacity + padding + border-width. main.js owns the
|
|
898
|
+
inline max-height — it sets scrollHeight → 0 on collapse and
|
|
899
|
+
0 → scrollHeight on expand, then clears the inline value after
|
|
900
|
+
transitionend so future content growth isn't clipped. We deliberately
|
|
901
|
+
do NOT set max-height in the .sm-release-collapsed-cells class
|
|
902
|
+
(especially not !important) — that would clobber the inline start
|
|
903
|
+
value and Safari would skip the transition entirely. overflow:hidden
|
|
904
|
+
is permanent on the row so the animation looks clean on either edge. */
|
|
905
|
+
.sm-release-cells {
|
|
906
|
+
overflow: hidden;
|
|
907
|
+
transition:
|
|
908
|
+
max-height 240ms ease,
|
|
909
|
+
opacity 200ms ease,
|
|
910
|
+
padding 240ms ease,
|
|
911
|
+
border-top-width 240ms ease,
|
|
912
|
+
border-bottom-width 240ms ease;
|
|
913
|
+
}
|
|
914
|
+
.sm-release-cells.sm-release-collapsed-cells {
|
|
915
|
+
opacity: 0;
|
|
916
|
+
/* .sm-release-row.sm-release-cells has min-height:120px so an empty
|
|
917
|
+
cells-row still shows a sensible drop-target. When collapsed, we
|
|
918
|
+
need to override that — otherwise max-height:0 has no effect and
|
|
919
|
+
the row keeps reserving 120px of empty space. */
|
|
920
|
+
min-height: 0;
|
|
921
|
+
border-top-width: 0;
|
|
922
|
+
border-bottom-width: 0;
|
|
923
|
+
padding-top: 0;
|
|
924
|
+
padding-bottom: 0;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/* "+ Add Release" — Ghost-Variant, nur neben dem letzten Release-Label. */
|
|
928
|
+
.sm-add-release-btn {
|
|
929
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
930
|
+
padding: 4px 10px;
|
|
931
|
+
font: inherit; font-size: 11px;
|
|
932
|
+
color: var(--ink-faint);
|
|
933
|
+
background: transparent;
|
|
934
|
+
border: 1px dashed var(--rule);
|
|
935
|
+
border-radius: 4px;
|
|
936
|
+
cursor: pointer;
|
|
937
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
938
|
+
}
|
|
939
|
+
.sm-add-release-btn:hover {
|
|
940
|
+
background: var(--paper);
|
|
941
|
+
color: var(--ink);
|
|
942
|
+
border-color: var(--ink-faint);
|
|
943
|
+
border-style: solid;
|
|
944
|
+
}
|
|
945
|
+
.sm-add-release-btn .sm-add-icon {
|
|
946
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
947
|
+
width: 14px; height: 14px;
|
|
948
|
+
background: var(--ink-faint);
|
|
949
|
+
color: var(--paper);
|
|
950
|
+
border-radius: 50%;
|
|
951
|
+
font-size: 11px;
|
|
952
|
+
font-weight: 700;
|
|
953
|
+
line-height: 1;
|
|
954
|
+
}
|
|
955
|
+
.sm-add-release-btn:hover .sm-add-icon { background: var(--accent); }
|
|
956
|
+
|
|
957
|
+
/* Phantom-Row CTA — zeigt nur den +Add-Button, kein Label dahinter. */
|
|
958
|
+
.sm-release-label-row.sm-phantom-label-row {
|
|
959
|
+
border-top: none;
|
|
960
|
+
justify-content: flex-start;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/* ---------- Cell pro (Release × ProcessStep) ---------- */
|
|
964
|
+
/* SM-55 follow-up: cell padding shrunk 10 → 4px each side so the cell's
|
|
965
|
+
content area equals exactly BACKBONE_COL_WIDTH_PX − 2×4 = 240px =
|
|
966
|
+
STORY_CARD_WIDTH_PX. Means a 1-sub-col Epic-card fits flush into a
|
|
967
|
+
1-sub-col cell with 4px breathing room on each side. */
|
|
968
|
+
.sm-cell {
|
|
969
|
+
background: var(--paper);
|
|
970
|
+
padding: 4px;
|
|
971
|
+
border-right: 1px solid var(--rule);
|
|
972
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
973
|
+
/* SM-136: absorb any sub-pixel horizontal overflow of the column-row. Use
|
|
974
|
+
`clip`, NOT `auto`: `auto` makes every cell a horizontal SCROLL container,
|
|
975
|
+
so a 1px sub-pixel overflow is enough for Safari to route a horizontal
|
|
976
|
+
trackpad swipe INTO the cell instead of chaining it to #view-host — the map
|
|
977
|
+
then can't be scrolled horizontally to reach off-screen process steps
|
|
978
|
+
(SM-281). `clip` absorbs the same overflow without becoming a scroll
|
|
979
|
+
container, so the gesture reaches the map. */
|
|
980
|
+
overflow-x: clip;
|
|
981
|
+
min-height: 160px;
|
|
982
|
+
transition: background-color 120ms, box-shadow 120ms;
|
|
983
|
+
position: relative;
|
|
984
|
+
box-shadow: inset 0 0 0 1px transparent;
|
|
985
|
+
}
|
|
986
|
+
/* SM-223 (a), gated (SM-274 follow-up): skip layout/paint for cells below the
|
|
987
|
+
fold — ONLY on very large boards (renderInto adds .sm-grid-virtualized past
|
|
988
|
+
VIRTUALIZE_TICKET_THRESHOLD). `auto` keeps the last-rendered size once a cell
|
|
989
|
+
has been on screen; the fallback estimate (backbone column width ×
|
|
990
|
+
min-height-ish) only matters before first paint. FLIP rect-capture is
|
|
991
|
+
no-op-safe for 0-rects (E24) and drag hit-testing only targets on-screen
|
|
992
|
+
cells. Gated because content-visibility makes WebKit/Gecko estimate
|
|
993
|
+
off-screen cell heights and only settle the grid row height when the cell
|
|
994
|
+
scrolls into view — a visible height jump on normal boards. */
|
|
995
|
+
.sm-grid-virtualized .sm-cell {
|
|
996
|
+
content-visibility: auto;
|
|
997
|
+
contain-intrinsic-size: auto var(--sm-backbone-col-w, 248px) auto 300px;
|
|
998
|
+
}
|
|
999
|
+
.sm-cell:nth-of-type(odd) { background: var(--paper); }
|
|
1000
|
+
.sm-cell:nth-of-type(even) { background: #FBF6E8; } /* spürbar wärmere Streifen */
|
|
1001
|
+
.sm-cell:last-child { border-right: none; }
|
|
1002
|
+
.sm-cell:hover {
|
|
1003
|
+
background: var(--paper-warm);
|
|
1004
|
+
box-shadow: inset 0 0 0 1px var(--ink-faint);
|
|
1005
|
+
}
|
|
1006
|
+
.sm-cell.sm-empty {
|
|
1007
|
+
grid-column: 3 / -1;
|
|
1008
|
+
color: var(--ink-faint);
|
|
1009
|
+
font-style: italic;
|
|
1010
|
+
padding: 14px;
|
|
1011
|
+
}
|
|
1012
|
+
.sm-cell.sm-drop-target {
|
|
1013
|
+
background: rgba(15, 95, 79, 0.16);
|
|
1014
|
+
box-shadow: inset 0 0 0 3px var(--accent);
|
|
1015
|
+
}
|
|
1016
|
+
.sm-cell.sm-drop-target::after {
|
|
1017
|
+
content: "Drop here";
|
|
1018
|
+
position: absolute;
|
|
1019
|
+
inset: 0;
|
|
1020
|
+
display: flex; align-items: center; justify-content: center;
|
|
1021
|
+
color: var(--accent);
|
|
1022
|
+
font-weight: 600;
|
|
1023
|
+
font-size: 13px;
|
|
1024
|
+
letter-spacing: 0.05em;
|
|
1025
|
+
text-transform: uppercase;
|
|
1026
|
+
pointer-events: none;
|
|
1027
|
+
background: rgba(15, 95, 79, 0.06);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/* Per-Cell-Add-Button — Ghost-Variant, sticky bottom, prominenter +-Icon */
|
|
1031
|
+
.sm-add-ticket {
|
|
1032
|
+
margin-top: auto; /* sticky bottom of cell */
|
|
1033
|
+
display: inline-flex;
|
|
1034
|
+
align-items: center;
|
|
1035
|
+
gap: 4px;
|
|
1036
|
+
align-self: stretch;
|
|
1037
|
+
padding: 5px 10px;
|
|
1038
|
+
font-size: 11px;
|
|
1039
|
+
color: var(--ink-faint);
|
|
1040
|
+
background: transparent;
|
|
1041
|
+
border: 1px dashed var(--rule);
|
|
1042
|
+
border-radius: 4px;
|
|
1043
|
+
cursor: pointer;
|
|
1044
|
+
font: inherit; font-size: 11px;
|
|
1045
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
1046
|
+
}
|
|
1047
|
+
.sm-add-ticket:hover {
|
|
1048
|
+
background: var(--paper-warm);
|
|
1049
|
+
color: var(--ink);
|
|
1050
|
+
border-color: var(--ink-faint);
|
|
1051
|
+
border-style: solid;
|
|
1052
|
+
}
|
|
1053
|
+
.sm-add-ticket .sm-add-icon {
|
|
1054
|
+
display: inline-flex;
|
|
1055
|
+
align-items: center; justify-content: center;
|
|
1056
|
+
width: 14px; height: 14px;
|
|
1057
|
+
background: var(--ink-faint);
|
|
1058
|
+
color: var(--paper);
|
|
1059
|
+
border-radius: 50%;
|
|
1060
|
+
font-size: 11px;
|
|
1061
|
+
line-height: 1;
|
|
1062
|
+
font-weight: 700;
|
|
1063
|
+
}
|
|
1064
|
+
.sm-add-ticket:hover .sm-add-icon {
|
|
1065
|
+
background: var(--accent);
|
|
1066
|
+
}
|
|
1067
|
+
.sm-add-ticket .sm-add-label { letter-spacing: 0.02em; }
|
|
1068
|
+
|
|
1069
|
+
/* ---------- Cluster-Klassen (paperlike, 1:1 aus cmapper) ----------- */
|
|
1070
|
+
.sm-cluster-blue { background: var(--cluster-blue-fill); border-color: var(--cluster-blue-border); color: var(--cluster-blue-ink); }
|
|
1071
|
+
.sm-cluster-green { background: var(--cluster-green-fill); border-color: var(--cluster-green-border); color: var(--cluster-green-ink); }
|
|
1072
|
+
.sm-cluster-amber { background: var(--cluster-amber-fill); border-color: var(--cluster-amber-border); color: var(--cluster-amber-ink); }
|
|
1073
|
+
.sm-cluster-rust { background: var(--cluster-rust-fill); border-color: var(--cluster-rust-border); color: var(--cluster-rust-ink); }
|
|
1074
|
+
.sm-cluster-plum { background: var(--cluster-plum-fill); border-color: var(--cluster-plum-border); color: var(--cluster-plum-ink); }
|
|
1075
|
+
.sm-cluster-slate { background: var(--cluster-slate-fill); border-color: var(--cluster-slate-border); color: var(--cluster-slate-ink); }
|
|
1076
|
+
.sm-cluster-teal { background: var(--cluster-teal-fill); border-color: var(--cluster-teal-border); color: var(--cluster-teal-ink); }
|
|
1077
|
+
|
|
1078
|
+
/* ---------- Cell-Layout: schlanke Säulen nebeneinander (SM-136) ----------
|
|
1079
|
+
Epic-Säulen UND die Loose-Säule stehen in EINER horizontalen, nicht-
|
|
1080
|
+
wrappenden Reihe. Die Cell-Breite ist via columnMultiplier so bemessen,
|
|
1081
|
+
dass alle Säulen hineinpassen; overflow-x:clip auf .sm-cell ist ein
|
|
1082
|
+
defensives Netz (clip statt auto — SM-281: kein Scroll-Container, sonst
|
|
1083
|
+
fängt die Zelle die horizontale Trackpad-Geste ab). align-items:stretch
|
|
1084
|
+
(SM-134) gleicht die Säulen-
|
|
1085
|
+
Unterkanten an. */
|
|
1086
|
+
.sm-cell-epics {
|
|
1087
|
+
display: flex;
|
|
1088
|
+
flex-direction: row;
|
|
1089
|
+
flex-wrap: nowrap; /* SM-136: keine zweite Reihe — alles nebeneinander */
|
|
1090
|
+
align-items: stretch; /* SM-134: Säulen auf gleiche Höhe → Unterkanten alignen */
|
|
1091
|
+
flex: 1; /* füllt die Zell-Höhe (= Release-Row-Höhe via Grid-Stretch) */
|
|
1092
|
+
gap: 8px;
|
|
1093
|
+
}
|
|
1094
|
+
/* SM-136: Loose-Säule — visuell wie eine Epic-Karte (Papier + Lift), aber
|
|
1095
|
+
mit neutralem Header-Band statt Plum. Breite wird inline auf
|
|
1096
|
+
STORY_CARD_WIDTH_PX gesetzt (Konstante bleibt Single-Source). */
|
|
1097
|
+
.sm-loose-card {
|
|
1098
|
+
display: flex;
|
|
1099
|
+
flex-direction: column;
|
|
1100
|
+
flex: 0 0 auto;
|
|
1101
|
+
background: var(--paper);
|
|
1102
|
+
border-radius: 6px;
|
|
1103
|
+
overflow: hidden;
|
|
1104
|
+
box-shadow: var(--shadow-lift);
|
|
1105
|
+
}
|
|
1106
|
+
.sm-loose-header {
|
|
1107
|
+
display: flex; align-items: center; gap: 8px;
|
|
1108
|
+
padding: 8px 10px;
|
|
1109
|
+
height: var(--sm-epic-header-h); /* SM-136: gleiche Höhe wie Epic-Header → Baseline */
|
|
1110
|
+
box-sizing: border-box;
|
|
1111
|
+
overflow: hidden;
|
|
1112
|
+
background: rgba(26, 26, 26, 0.05);
|
|
1113
|
+
border-bottom: 1px solid var(--rule);
|
|
1114
|
+
font-size: 12px;
|
|
1115
|
+
}
|
|
1116
|
+
.sm-loose-title {
|
|
1117
|
+
font-weight: 600;
|
|
1118
|
+
color: var(--ink-soft);
|
|
1119
|
+
font-size: 12px;
|
|
1120
|
+
letter-spacing: 0.01em;
|
|
1121
|
+
}
|
|
1122
|
+
/* SM-136: Loose-Stories als Single-Column-Grid — identische Rhythmik wie
|
|
1123
|
+
.sm-stories-grid (feste Karten-Höhe, gleiche Gaps/Paddings), damit die
|
|
1124
|
+
losen Karten Zeile für Zeile mit den Epic-Stories fluchten. Die einzige
|
|
1125
|
+
Spaltenbreite wird inline gesetzt (epicW − 2×Padding). */
|
|
1126
|
+
.sm-cell-loose {
|
|
1127
|
+
display: grid;
|
|
1128
|
+
grid-auto-flow: row;
|
|
1129
|
+
grid-auto-rows: var(--sm-card-h);
|
|
1130
|
+
gap: 4px;
|
|
1131
|
+
padding: 6px;
|
|
1132
|
+
background: transparent;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/* ---------- Epic-Karte (Container für Stories) ---------- */
|
|
1136
|
+
.sm-epic-card {
|
|
1137
|
+
/* Kein flächiger Plum-BG mehr — sonst entstand ein "Klammer"-Effekt
|
|
1138
|
+
unterhalb des Story-Grids. Stattdessen Papierhintergrund + Header
|
|
1139
|
+
trägt die Cluster-Farbe als oberer Akzent. */
|
|
1140
|
+
border: 0;
|
|
1141
|
+
background: var(--paper);
|
|
1142
|
+
border-radius: 6px;
|
|
1143
|
+
overflow: hidden; /* clip Header-Plum an den abgerundeten Ecken */
|
|
1144
|
+
cursor: grab;
|
|
1145
|
+
box-shadow: var(--shadow-lift);
|
|
1146
|
+
transition: transform 0.1s, box-shadow 0.1s;
|
|
1147
|
+
flex: 0 1 auto; /* shrink-to-fit innerhalb von .sm-cell-epics */
|
|
1148
|
+
width: fit-content;
|
|
1149
|
+
min-width: 292px; /* eine Story-Spaltenbreite (280) + Padding */
|
|
1150
|
+
max-width: 100%; /* SM-55: niemals breiter als die Cell */
|
|
1151
|
+
}
|
|
1152
|
+
.sm-epic-card:hover {
|
|
1153
|
+
transform: translateY(-1px);
|
|
1154
|
+
box-shadow: 0 4px 8px rgba(26,26,26,0.08), 0 10px 28px rgba(26,26,26,0.08);
|
|
1155
|
+
}
|
|
1156
|
+
.sm-epic-card.sm-dragging { opacity: 0.4; cursor: grabbing; }
|
|
1157
|
+
.sm-epic-card.sm-drop-target {
|
|
1158
|
+
box-shadow: inset 0 0 0 3px var(--accent), 0 4px 12px rgba(15, 95, 79, 0.30);
|
|
1159
|
+
transform: scale(1.01);
|
|
1160
|
+
}
|
|
1161
|
+
/* SM-131: uniform-grid Layout-Tokens (spiegeln STORY_MAP_LAYOUT). */
|
|
1162
|
+
.sm-grid {
|
|
1163
|
+
--sm-card-h: 72px;
|
|
1164
|
+
--sm-epic-header-h: 56px;
|
|
1165
|
+
--sm-gap: 8px;
|
|
1166
|
+
--sm-pad: 6px;
|
|
1167
|
+
}
|
|
1168
|
+
.sm-epic-header {
|
|
1169
|
+
display: flex; align-items: center; gap: 8px;
|
|
1170
|
+
padding: 8px 10px;
|
|
1171
|
+
height: var(--sm-epic-header-h); /* SM-131: feste Header-Höhe */
|
|
1172
|
+
box-sizing: border-box;
|
|
1173
|
+
overflow: hidden;
|
|
1174
|
+
background: var(--cluster-plum-fill);
|
|
1175
|
+
border-bottom: 1px solid rgba(90, 57, 87, 0.18);
|
|
1176
|
+
font-size: 12px;
|
|
1177
|
+
cursor: pointer;
|
|
1178
|
+
}
|
|
1179
|
+
.sm-epic-header:hover { background: rgba(90, 57, 87, 0.10); }
|
|
1180
|
+
/* SM-138: kompaktes „+" im Epic-Header (oben rechts), neben dem Chevron. */
|
|
1181
|
+
.sm-epic-add {
|
|
1182
|
+
appearance: none;
|
|
1183
|
+
background: transparent;
|
|
1184
|
+
border: 1px solid transparent;
|
|
1185
|
+
border-radius: 4px;
|
|
1186
|
+
color: var(--cluster-plum-ink);
|
|
1187
|
+
cursor: pointer;
|
|
1188
|
+
font-size: 14px; font-weight: 700; line-height: 1;
|
|
1189
|
+
padding: 2px 6px;
|
|
1190
|
+
min-width: 22px;
|
|
1191
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1192
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
1193
|
+
}
|
|
1194
|
+
.sm-epic-add:hover {
|
|
1195
|
+
background: rgba(90, 57, 87, 0.10);
|
|
1196
|
+
border-color: var(--cluster-plum-border);
|
|
1197
|
+
}
|
|
1198
|
+
.sm-epic-info {
|
|
1199
|
+
display: flex; flex-direction: column; gap: 1px;
|
|
1200
|
+
flex: 1; min-width: 0;
|
|
1201
|
+
}
|
|
1202
|
+
.sm-epic-title {
|
|
1203
|
+
font-weight: 600;
|
|
1204
|
+
color: var(--cluster-plum-ink);
|
|
1205
|
+
font-size: 12px;
|
|
1206
|
+
line-height: 1.25;
|
|
1207
|
+
overflow-wrap: anywhere;
|
|
1208
|
+
word-break: break-word;
|
|
1209
|
+
/* SM-131: fest auf 2 Zeilen + Ellipse (statt freiem Umbruch). */
|
|
1210
|
+
display: -webkit-box;
|
|
1211
|
+
-webkit-line-clamp: 2;
|
|
1212
|
+
-webkit-box-orient: vertical;
|
|
1213
|
+
overflow: hidden;
|
|
1214
|
+
text-overflow: ellipsis;
|
|
1215
|
+
}
|
|
1216
|
+
.sm-epic-key {
|
|
1217
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
1218
|
+
font-size: 10px;
|
|
1219
|
+
color: var(--ink-faint);
|
|
1220
|
+
letter-spacing: 0.02em;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
/* + Story Button am Boden jeder Epic-Karte */
|
|
1224
|
+
.sm-add-story {
|
|
1225
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1226
|
+
margin: 6px 8px 8px;
|
|
1227
|
+
padding: 4px 8px;
|
|
1228
|
+
font: inherit; font-size: 11px;
|
|
1229
|
+
color: var(--ink-faint);
|
|
1230
|
+
background: transparent;
|
|
1231
|
+
border: 1px dashed rgba(90, 57, 87, 0.4);
|
|
1232
|
+
border-radius: 4px;
|
|
1233
|
+
cursor: pointer;
|
|
1234
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
1235
|
+
}
|
|
1236
|
+
.sm-add-story:hover {
|
|
1237
|
+
background: rgba(90, 57, 87, 0.08);
|
|
1238
|
+
color: var(--cluster-plum-ink);
|
|
1239
|
+
border-color: var(--cluster-plum-border);
|
|
1240
|
+
border-style: solid;
|
|
1241
|
+
}
|
|
1242
|
+
.sm-add-story .sm-add-icon {
|
|
1243
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1244
|
+
width: 12px; height: 12px;
|
|
1245
|
+
background: rgba(90, 57, 87, 0.5);
|
|
1246
|
+
color: var(--paper);
|
|
1247
|
+
border-radius: 50%;
|
|
1248
|
+
font-size: 9px;
|
|
1249
|
+
font-weight: 700;
|
|
1250
|
+
line-height: 1;
|
|
1251
|
+
}
|
|
1252
|
+
.sm-add-story:hover .sm-add-icon { background: var(--cluster-plum-border); }
|
|
1253
|
+
|
|
1254
|
+
/* ---------- Stories-Grid unter dem Epic (Single-Column, SM-135) -----------
|
|
1255
|
+
Inline-Styles vom Renderer setzen:
|
|
1256
|
+
grid-auto-flow: row
|
|
1257
|
+
grid-template-columns: <inside-story-width>
|
|
1258
|
+
grid-auto-rows: var(--sm-card-h)
|
|
1259
|
+
Stories stapeln einspaltig vertikal und wachsen beliebig nach unten —
|
|
1260
|
+
kein Sub-Spalten-Wrap mehr (jedes Epic ist eine schlanke Säule). */
|
|
1261
|
+
.sm-stories-grid {
|
|
1262
|
+
display: grid;
|
|
1263
|
+
gap: 4px;
|
|
1264
|
+
padding: 6px;
|
|
1265
|
+
background: transparent; /* erbt --paper vom .sm-epic-card, kein Plum unten */
|
|
1266
|
+
/* SM-84: animated collapse — the grid stays in the DOM and animates via
|
|
1267
|
+
max-height + opacity + padding. main.js owns the inline max-height
|
|
1268
|
+
(scrollHeight → 0 on collapse, 0 → scrollHeight on expand, then cleared
|
|
1269
|
+
after transitionend so future story additions aren't clipped). We do
|
|
1270
|
+
NOT set max-height in the .sm-stories-grid-collapsed class — that
|
|
1271
|
+
would clobber the inline start value and Safari would skip the
|
|
1272
|
+
transition. overflow:hidden is permanent for clean animation edges. */
|
|
1273
|
+
overflow: hidden;
|
|
1274
|
+
transition:
|
|
1275
|
+
max-height 240ms ease,
|
|
1276
|
+
opacity 200ms ease,
|
|
1277
|
+
padding 240ms ease;
|
|
1278
|
+
}
|
|
1279
|
+
.sm-stories-grid.sm-stories-grid-collapsed {
|
|
1280
|
+
opacity: 0;
|
|
1281
|
+
padding-top: 0;
|
|
1282
|
+
padding-bottom: 0;
|
|
1283
|
+
}
|
|
1284
|
+
/* SM-84 — collapse chevron in the epic header. Sits at the rightmost
|
|
1285
|
+
end, after .sm-epic-info (flex:1) and .sm-epic-badges. Small + neutral
|
|
1286
|
+
so it doesn't compete with the title or badges for attention. */
|
|
1287
|
+
.sm-epic-chevron {
|
|
1288
|
+
appearance: none;
|
|
1289
|
+
background: transparent;
|
|
1290
|
+
border: 1px solid transparent;
|
|
1291
|
+
border-radius: 4px;
|
|
1292
|
+
color: var(--ink-soft);
|
|
1293
|
+
cursor: pointer;
|
|
1294
|
+
font-size: 11px;
|
|
1295
|
+
line-height: 1;
|
|
1296
|
+
padding: 2px 6px;
|
|
1297
|
+
min-width: 22px;
|
|
1298
|
+
display: inline-flex;
|
|
1299
|
+
align-items: center;
|
|
1300
|
+
justify-content: center;
|
|
1301
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
1302
|
+
}
|
|
1303
|
+
.sm-epic-chevron:hover {
|
|
1304
|
+
background: var(--paper);
|
|
1305
|
+
color: var(--ink);
|
|
1306
|
+
border-color: var(--rule);
|
|
1307
|
+
}
|
|
1308
|
+
.sm-epic-card.sm-epic-card-collapsed .sm-epic-header {
|
|
1309
|
+
border-bottom-color: transparent;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
/* ---------- Story-Karte (paperlike, cluster-coloured) -------------
|
|
1313
|
+
Width wird inline aus STORY_CARD_WIDTH_PX gesetzt. Kein Border —
|
|
1314
|
+
das Cluster-Fill kodiert den Type. */
|
|
1315
|
+
.sm-story-card {
|
|
1316
|
+
border: 0;
|
|
1317
|
+
border-radius: 4px;
|
|
1318
|
+
padding: 6px 8px;
|
|
1319
|
+
height: var(--sm-card-h); /* SM-131: feste Höhe → uniformes Raster */
|
|
1320
|
+
overflow: hidden;
|
|
1321
|
+
cursor: grab;
|
|
1322
|
+
font-size: 11px;
|
|
1323
|
+
line-height: 1.35;
|
|
1324
|
+
transition: transform 0.08s, box-shadow 0.08s;
|
|
1325
|
+
flex-shrink: 0;
|
|
1326
|
+
box-sizing: border-box;
|
|
1327
|
+
}
|
|
1328
|
+
.sm-story-card:hover {
|
|
1329
|
+
transform: translateY(-1px);
|
|
1330
|
+
box-shadow: var(--shadow-lift);
|
|
1331
|
+
}
|
|
1332
|
+
.sm-story-card.sm-dragging { opacity: 0.4; cursor: grabbing; }
|
|
1333
|
+
|
|
1334
|
+
/* Drag-Live-Preview: Origin verschwindet, eine Schatten-Karte erscheint
|
|
1335
|
+
an der Insertion-Position im Drop-Target. Gestricheltes 2px-Border +
|
|
1336
|
+
gedimmt — wie svelte-dnd-action in der alten StoryBrain. */
|
|
1337
|
+
.sm-card-shadow {
|
|
1338
|
+
border: 2px dashed var(--accent) !important;
|
|
1339
|
+
background: var(--paper-warm) !important;
|
|
1340
|
+
opacity: 0.55;
|
|
1341
|
+
pointer-events: none;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
.sm-card-info { display: flex; flex-direction: column; gap: 1px; }
|
|
1345
|
+
|
|
1346
|
+
.sm-story-key {
|
|
1347
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
1348
|
+
font-size: 9px;
|
|
1349
|
+
color: currentColor;
|
|
1350
|
+
opacity: 0.55;
|
|
1351
|
+
letter-spacing: 0.02em;
|
|
1352
|
+
}
|
|
1353
|
+
.sm-story-title {
|
|
1354
|
+
font-weight: 500;
|
|
1355
|
+
color: currentColor;
|
|
1356
|
+
line-height: 1.35;
|
|
1357
|
+
height: calc(2 * 1.35em); /* SM-131: 2-Zeilen-Slot, 1-Zeiler füllt ihn auch */
|
|
1358
|
+
overflow: hidden; text-overflow: ellipsis;
|
|
1359
|
+
display: -webkit-box;
|
|
1360
|
+
-webkit-line-clamp: 2;
|
|
1361
|
+
-webkit-box-orient: vertical;
|
|
1362
|
+
}
|
|
1363
|
+
.sm-card-meta {
|
|
1364
|
+
display: flex; gap: 4px; flex-wrap: nowrap; align-items: center;
|
|
1365
|
+
margin-top: 4px;
|
|
1366
|
+
overflow: hidden; /* einzeilig — die breiteren Karten (280px) fassen alle Badges in eine Zeile */
|
|
1367
|
+
font-size: 10px; color: var(--ink-soft);
|
|
1368
|
+
}
|
|
1369
|
+
.sm-card-status {
|
|
1370
|
+
padding: 1px 7px;
|
|
1371
|
+
border-radius: 999px;
|
|
1372
|
+
font-size: 9px; font-weight: 500;
|
|
1373
|
+
text-transform: capitalize;
|
|
1374
|
+
white-space: nowrap; /* Status-Pille nie intern umbrechen (z.B. "In-Progress") */
|
|
1375
|
+
}
|
|
1376
|
+
.sm-card-release-tag {
|
|
1377
|
+
display: inline-block;
|
|
1378
|
+
padding: 0 6px;
|
|
1379
|
+
border-radius: 4px;
|
|
1380
|
+
background: var(--paper-warm);
|
|
1381
|
+
border: 1px solid var(--rule);
|
|
1382
|
+
font-size: 10px;
|
|
1383
|
+
color: var(--ink);
|
|
1384
|
+
font-weight: 500;
|
|
1385
|
+
letter-spacing: 0.01em;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/* Status-Pill colours (alt-StoryBrain-Palette) */
|
|
1389
|
+
.sm-status-pill-backlog { background: #e5e7eb; color: #374151; }
|
|
1390
|
+
.sm-status-pill-ready { background: #dbeafe; color: #1e40af; }
|
|
1391
|
+
.sm-status-pill-in-progress { background: #fef3c7; color: #92400e; }
|
|
1392
|
+
.sm-status-pill-review { background: #ede9fe; color: #5b21b6; }
|
|
1393
|
+
.sm-status-pill-done { background: #d1fae5; color: #065f46; }
|
|
1394
|
+
/* SM-244: cancelled = terminal, deliberately dropped. Muted + struck through. */
|
|
1395
|
+
.sm-status-pill-cancelled { background: #e7e5e4; color: #78716c; text-decoration: line-through; }
|
|
1396
|
+
|
|
1397
|
+
/* SM-244: a cancelled card is dimmed and its title struck through — visible
|
|
1398
|
+
(Cancel ≠ Delete) but clearly out of scope. Applies on both views (the
|
|
1399
|
+
shared card carries .sm-status-cancelled; the epic card too). */
|
|
1400
|
+
.sm-story-card.sm-status-cancelled,
|
|
1401
|
+
.sm-epic-card.sm-status-cancelled { opacity: 0.6; }
|
|
1402
|
+
.sm-story-card.sm-status-cancelled .sm-story-title,
|
|
1403
|
+
.sm-epic-card.sm-status-cancelled .sm-epic-title { text-decoration: line-through; }
|
|
1404
|
+
|
|
1405
|
+
.sm-badge {
|
|
1406
|
+
padding: 1px 5px;
|
|
1407
|
+
border-radius: 3px;
|
|
1408
|
+
background: var(--paper-warm);
|
|
1409
|
+
border: 1px solid var(--rule);
|
|
1410
|
+
font-size: 9px;
|
|
1411
|
+
}
|
|
1412
|
+
.sm-badge-dor { color: var(--target); }
|
|
1413
|
+
.sm-badge-dod { color: var(--accent); }
|
|
1414
|
+
|
|
1415
|
+
/* SM-170: card-aging badge — surfaces cards sitting too long in an active
|
|
1416
|
+
status. Amber at WARN, red at STALE (thresholds in renderer-card.js). */
|
|
1417
|
+
.sm-card-age { font-weight: 700; letter-spacing: 0.02em; }
|
|
1418
|
+
.sm-card-age-warn {
|
|
1419
|
+
color: #8A5A12;
|
|
1420
|
+
background: rgba(214, 158, 46, 0.16);
|
|
1421
|
+
border-color: rgba(214, 158, 46, 0.55);
|
|
1422
|
+
}
|
|
1423
|
+
.sm-card-age-stale {
|
|
1424
|
+
color: var(--danger, #B43C3C);
|
|
1425
|
+
background: rgba(180, 60, 60, 0.14);
|
|
1426
|
+
border-color: rgba(180, 60, 60, 0.55);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/* SM-49: link badges (forward / backward dependency counts) */
|
|
1430
|
+
.sm-link-badge {
|
|
1431
|
+
cursor: pointer;
|
|
1432
|
+
font-weight: 500;
|
|
1433
|
+
border-color: transparent;
|
|
1434
|
+
}
|
|
1435
|
+
.sm-link-badge-sem-blocking { background: #FCE4E4; color: #8A1F1F; }
|
|
1436
|
+
.sm-link-badge-sem-precedence { background: #DCE6F5; color: #1E3A6B; }
|
|
1437
|
+
.sm-link-badge-sem-sequence { background: #E5E7EB; color: #374151; }
|
|
1438
|
+
.sm-link-badge-sem-containment { background: #DEF0E3; color: #1F5530; }
|
|
1439
|
+
.sm-link-badge-sem-validation { background: #FCEFD3; color: #8A5A14; }
|
|
1440
|
+
.sm-link-badge-sem-freeform { background: #E5E7EB; color: #4B5563; }
|
|
1441
|
+
.sm-link-badge-sem-mixed { background: #ECE4F2; color: #4A2860; }
|
|
1442
|
+
.sm-link-badge:hover { filter: brightness(0.96); }
|
|
1443
|
+
.sm-link-badge-backward { font-style: italic; opacity: 0.92; }
|
|
1444
|
+
|
|
1445
|
+
/* SM-60: last-execution outcome badge (test-definition cards only).
|
|
1446
|
+
Cursor:pointer because clicking opens the linked execution modal.
|
|
1447
|
+
Colours roughly match the in-modal outcome pill so the user sees the
|
|
1448
|
+
same encoding everywhere. */
|
|
1449
|
+
.sm-exec-badge {
|
|
1450
|
+
cursor: pointer;
|
|
1451
|
+
font-weight: 600;
|
|
1452
|
+
text-transform: uppercase;
|
|
1453
|
+
letter-spacing: 0.04em;
|
|
1454
|
+
border-color: transparent;
|
|
1455
|
+
}
|
|
1456
|
+
.sm-exec-badge:hover { filter: brightness(0.95); }
|
|
1457
|
+
.sm-exec-badge-passed { background: rgba(34, 139, 34, 0.16); color: #1F5530; }
|
|
1458
|
+
.sm-exec-badge-failed { background: rgba(180, 60, 60, 0.18); color: #8A1F1F; }
|
|
1459
|
+
.sm-exec-badge-blocked { background: rgba(230, 180, 50, 0.24); color: #8A5A14; }
|
|
1460
|
+
.sm-exec-badge-skipped { background: rgba(150, 150, 150, 0.18); color: #4B5563; }
|
|
1461
|
+
.sm-exec-badge-pending { background: var(--paper-warm); color: var(--ink-soft); }
|
|
1462
|
+
.sm-exec-badge-untested {
|
|
1463
|
+
background: transparent;
|
|
1464
|
+
color: var(--ink-faint);
|
|
1465
|
+
border: 1px dashed var(--rule);
|
|
1466
|
+
cursor: default;
|
|
1467
|
+
font-style: italic;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.sm-epic-badges {
|
|
1471
|
+
display: inline-flex; gap: 4px; align-items: center; margin-left: 8px;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
/* ---------- Drag-Affordance + Ghost (E9f, Pointer-Events) ---------- */
|
|
1475
|
+
.sm-epic-card, .sm-story-card {
|
|
1476
|
+
cursor: grab;
|
|
1477
|
+
user-select: none; /* keine Text-Selektion beim Drag */
|
|
1478
|
+
-webkit-user-select: none;
|
|
1479
|
+
touch-action: none; /* Browser darf kein Scroll bei Drag */
|
|
1480
|
+
}
|
|
1481
|
+
.sm-epic-card.sm-dragging, .sm-story-card.sm-dragging {
|
|
1482
|
+
opacity: 0.35;
|
|
1483
|
+
cursor: grabbing;
|
|
1484
|
+
}
|
|
1485
|
+
.sm-drag-ghost {
|
|
1486
|
+
pointer-events: none;
|
|
1487
|
+
transition: none;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
/* ---------- Phantom-Release-Row (E9g) — wenn ProcessSteps aber kein Release */
|
|
1491
|
+
.sm-phantom-row { opacity: 0.85; }
|
|
1492
|
+
.sm-phantom-label {
|
|
1493
|
+
background: var(--rule-soft);
|
|
1494
|
+
padding: 10px;
|
|
1495
|
+
justify-content: center;
|
|
1496
|
+
}
|
|
1497
|
+
.sm-phantom-cta {
|
|
1498
|
+
font-size: 11px;
|
|
1499
|
+
padding: 6px 10px;
|
|
1500
|
+
border-style: dashed;
|
|
1501
|
+
background: transparent;
|
|
1502
|
+
}
|
|
1503
|
+
.sm-phantom-cta:hover {
|
|
1504
|
+
border-style: solid;
|
|
1505
|
+
background: var(--paper-warm);
|
|
1506
|
+
}
|
|
1507
|
+
.sm-phantom-cell {
|
|
1508
|
+
background: repeating-linear-gradient(
|
|
1509
|
+
45deg,
|
|
1510
|
+
var(--rule-soft),
|
|
1511
|
+
var(--rule-soft) 8px,
|
|
1512
|
+
transparent 8px,
|
|
1513
|
+
transparent 16px
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
.sm-phantom-cell::after {
|
|
1517
|
+
content: "";
|
|
1518
|
+
display: block;
|
|
1519
|
+
height: 100%;
|
|
1520
|
+
min-height: 80px;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/* ---------- Backlog-Section unten (Epics ohne Release) ---------- */
|
|
1524
|
+
/* SM-253: per-release holding strip — release-assigned-but-unplaced tickets sit
|
|
1525
|
+
in a compact strip under their release's cells row (drag into a step to place;
|
|
1526
|
+
drop here / on the release header to unplace). No global backlog anymore. */
|
|
1527
|
+
.sm-release-unplaced-row {
|
|
1528
|
+
display: flex;
|
|
1529
|
+
align-items: flex-start;
|
|
1530
|
+
gap: 10px;
|
|
1531
|
+
padding: 6px 12px 10px;
|
|
1532
|
+
margin-bottom: 2px;
|
|
1533
|
+
background: var(--rule-soft);
|
|
1534
|
+
}
|
|
1535
|
+
.sm-release-unplaced-row.sm-drop-target,
|
|
1536
|
+
.sm-release-label-row.sm-drop-target {
|
|
1537
|
+
box-shadow: inset 3px 0 0 var(--accent);
|
|
1538
|
+
background: var(--accent-soft);
|
|
1539
|
+
}
|
|
1540
|
+
.sm-release-unplaced-label {
|
|
1541
|
+
flex: 0 0 auto;
|
|
1542
|
+
padding-top: 6px;
|
|
1543
|
+
font-size: 10px;
|
|
1544
|
+
letter-spacing: 0.04em;
|
|
1545
|
+
text-transform: uppercase;
|
|
1546
|
+
color: var(--ink-faint);
|
|
1547
|
+
white-space: nowrap;
|
|
1548
|
+
}
|
|
1549
|
+
.sm-release-unplaced-list {
|
|
1550
|
+
display: flex;
|
|
1551
|
+
flex-wrap: wrap;
|
|
1552
|
+
gap: 8px;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.sm-backlog-section {
|
|
1556
|
+
margin-top: 24px;
|
|
1557
|
+
padding: 12px 16px 24px;
|
|
1558
|
+
border-top: 2px solid var(--rule);
|
|
1559
|
+
background: var(--rule-soft);
|
|
1560
|
+
}
|
|
1561
|
+
.sm-backlog-title {
|
|
1562
|
+
font-size: 13px; font-weight: 700;
|
|
1563
|
+
margin: 0 0 10px;
|
|
1564
|
+
color: var(--ink-soft);
|
|
1565
|
+
letter-spacing: 0.04em;
|
|
1566
|
+
text-transform: uppercase;
|
|
1567
|
+
}
|
|
1568
|
+
.sm-add-backlog-item {
|
|
1569
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1570
|
+
margin-top: 8px;
|
|
1571
|
+
padding: 5px 12px;
|
|
1572
|
+
font: inherit; font-size: 11px;
|
|
1573
|
+
color: var(--ink-faint);
|
|
1574
|
+
background: transparent;
|
|
1575
|
+
border: 1px dashed var(--rule);
|
|
1576
|
+
border-radius: 4px;
|
|
1577
|
+
cursor: pointer;
|
|
1578
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
1579
|
+
align-self: flex-start;
|
|
1580
|
+
}
|
|
1581
|
+
.sm-add-backlog-item:hover {
|
|
1582
|
+
background: var(--paper-warm);
|
|
1583
|
+
color: var(--ink);
|
|
1584
|
+
border-color: var(--ink-faint);
|
|
1585
|
+
border-style: solid;
|
|
1586
|
+
}
|
|
1587
|
+
.sm-add-backlog-item .sm-add-icon {
|
|
1588
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1589
|
+
width: 14px; height: 14px;
|
|
1590
|
+
background: var(--ink-faint);
|
|
1591
|
+
color: var(--paper);
|
|
1592
|
+
border-radius: 50%;
|
|
1593
|
+
font-size: 11px;
|
|
1594
|
+
font-weight: 700;
|
|
1595
|
+
line-height: 1;
|
|
1596
|
+
}
|
|
1597
|
+
.sm-add-backlog-item:hover .sm-add-icon { background: var(--accent); }
|
|
1598
|
+
/* Backlog ist eine PRIORISIERTE Liste (oben = höchste Priorität). Stack
|
|
1599
|
+
vertikal, per Drag & Drop sortierbar. Maximalbreite, damit die Karten
|
|
1600
|
+
nicht über die ganze Map ausufern. */
|
|
1601
|
+
.sm-backlog-list {
|
|
1602
|
+
display: flex;
|
|
1603
|
+
flex-direction: column;
|
|
1604
|
+
gap: 6px;
|
|
1605
|
+
max-width: 720px;
|
|
1606
|
+
}
|
|
1607
|
+
.sm-backlog-list .sm-story-card,
|
|
1608
|
+
.sm-backlog-list .sm-epic-card {
|
|
1609
|
+
width: 100%;
|
|
1610
|
+
max-width: 100%;
|
|
1611
|
+
}
|
|
1612
|
+
/* SM-193: multi-column backlog — CSS columns balance card heights; the
|
|
1613
|
+
column-count + max-width are set inline from the layout constants. The 8px
|
|
1614
|
+
below mirrors STORY_MAP_LAYOUT.TICKET_GAP_PX (the inline max-width math in
|
|
1615
|
+
applyBacklogWrap assumes the same gap — keep both in sync if it changes). */
|
|
1616
|
+
.sm-backlog-list-multicol {
|
|
1617
|
+
display: block; /* override the flex column so cards flow into columns */
|
|
1618
|
+
column-gap: 8px; /* == TICKET_GAP_PX */
|
|
1619
|
+
}
|
|
1620
|
+
.sm-backlog-list-multicol .sm-story-card,
|
|
1621
|
+
.sm-backlog-list-multicol .sm-epic-card {
|
|
1622
|
+
break-inside: avoid; /* never split a card across a column boundary */
|
|
1623
|
+
-webkit-column-break-inside: avoid;
|
|
1624
|
+
margin-bottom: 8px; /* == TICKET_GAP_PX (flex `gap` doesn't apply in block/column flow) */
|
|
1625
|
+
}
|
|
1626
|
+
.sm-backlog-empty {
|
|
1627
|
+
color: var(--ink-faint);
|
|
1628
|
+
font-style: italic;
|
|
1629
|
+
font-size: 12px;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
/* ============================================================
|
|
1633
|
+
E10 — Ticket-Detail-Modal
|
|
1634
|
+
============================================================ */
|
|
1635
|
+
|
|
1636
|
+
/* Widen the standard modal when it hosts the ticket-detail body. */
|
|
1637
|
+
.modal-overlay .modal:has(.tm-body-host) {
|
|
1638
|
+
width: 760px;
|
|
1639
|
+
max-width: 92vw;
|
|
1640
|
+
}
|
|
1641
|
+
.tm-body-host {
|
|
1642
|
+
display: flex; flex-direction: column;
|
|
1643
|
+
gap: 6px;
|
|
1644
|
+
overflow-y: auto;
|
|
1645
|
+
max-height: 68vh;
|
|
1646
|
+
padding-right: 4px;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
.tm-header {
|
|
1650
|
+
display: flex; align-items: center; gap: 8px;
|
|
1651
|
+
margin: -4px 0 8px;
|
|
1652
|
+
}
|
|
1653
|
+
.tm-key {
|
|
1654
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
1655
|
+
font-size: 11px;
|
|
1656
|
+
color: var(--ink-soft);
|
|
1657
|
+
background: var(--paper-warm);
|
|
1658
|
+
border: 1px solid var(--rule);
|
|
1659
|
+
border-radius: 3px;
|
|
1660
|
+
padding: 1px 6px;
|
|
1661
|
+
}
|
|
1662
|
+
.tm-type-badge {
|
|
1663
|
+
font-size: 11px;
|
|
1664
|
+
color: var(--ink-soft);
|
|
1665
|
+
text-transform: lowercase;
|
|
1666
|
+
letter-spacing: 0.02em;
|
|
1667
|
+
background: var(--rule-soft);
|
|
1668
|
+
border-radius: 3px;
|
|
1669
|
+
padding: 1px 6px;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
.tm-error-banner {
|
|
1673
|
+
font-size: 12px;
|
|
1674
|
+
background: rgba(180, 60, 60, 0.10);
|
|
1675
|
+
color: var(--danger, #B43C3C);
|
|
1676
|
+
border: 1px solid var(--danger, #B43C3C);
|
|
1677
|
+
border-radius: 4px;
|
|
1678
|
+
padding: 8px 10px;
|
|
1679
|
+
margin: 0 0 6px;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/* Form row layout — mirrors .modal-row but namespaced. */
|
|
1683
|
+
.tm-row {
|
|
1684
|
+
display: flex; align-items: center; gap: 8px;
|
|
1685
|
+
margin: 6px 0;
|
|
1686
|
+
}
|
|
1687
|
+
.tm-label {
|
|
1688
|
+
flex: 0 0 130px;
|
|
1689
|
+
color: var(--ink-soft);
|
|
1690
|
+
font-size: 12px;
|
|
1691
|
+
}
|
|
1692
|
+
.tm-input {
|
|
1693
|
+
flex: 1;
|
|
1694
|
+
padding: 5px 8px;
|
|
1695
|
+
border: 1px solid var(--rule);
|
|
1696
|
+
border-radius: 4px;
|
|
1697
|
+
background: var(--paper);
|
|
1698
|
+
font: inherit; font-size: 12px;
|
|
1699
|
+
color: var(--ink);
|
|
1700
|
+
}
|
|
1701
|
+
.tm-input:focus { outline: none; border-color: var(--ink); }
|
|
1702
|
+
.tm-input:disabled {
|
|
1703
|
+
opacity: 0.7;
|
|
1704
|
+
background: var(--paper-soft, var(--paper));
|
|
1705
|
+
cursor: not-allowed;
|
|
1706
|
+
}
|
|
1707
|
+
/* SM-238 — epic derived-status: a read-only pill + the derivation breakdown,
|
|
1708
|
+
in place of the editable status <select>. The epic's status is rolled up
|
|
1709
|
+
from its stories, so there is nothing to pick here. */
|
|
1710
|
+
.tm-status-derived-wrap { flex: 1; display: flex; flex-direction: column; gap: 3px; }
|
|
1711
|
+
.tm-status-derived {
|
|
1712
|
+
align-self: flex-start;
|
|
1713
|
+
padding: 2px 10px;
|
|
1714
|
+
border-radius: 9px;
|
|
1715
|
+
font-size: 11px; font-weight: 700;
|
|
1716
|
+
background: var(--accent-soft, rgba(15, 95, 79, 0.16));
|
|
1717
|
+
color: var(--accent);
|
|
1718
|
+
border: 1px solid var(--accent);
|
|
1719
|
+
}
|
|
1720
|
+
.tm-status-breakdown { font-size: 11px; color: var(--ink-soft, #717071); }
|
|
1721
|
+
/* SM-67: inherited-position hint shown under Release/ProcessStep when a
|
|
1722
|
+
story is contained by an epic. Standalone row (not a child of .tm-row). */
|
|
1723
|
+
.tm-field-hint {
|
|
1724
|
+
margin: -2px 0 6px 138px;
|
|
1725
|
+
font-size: 11px;
|
|
1726
|
+
color: var(--ink-soft);
|
|
1727
|
+
font-style: italic;
|
|
1728
|
+
}
|
|
1729
|
+
.tm-field-hint:empty { display: none; }
|
|
1730
|
+
.tm-textarea {
|
|
1731
|
+
flex: 1;
|
|
1732
|
+
min-height: 90px;
|
|
1733
|
+
padding: 8px 10px;
|
|
1734
|
+
border: 1px solid var(--rule);
|
|
1735
|
+
border-radius: 4px;
|
|
1736
|
+
background: var(--paper);
|
|
1737
|
+
font: inherit; font-size: 12px;
|
|
1738
|
+
line-height: 1.5;
|
|
1739
|
+
color: var(--ink);
|
|
1740
|
+
resize: vertical;
|
|
1741
|
+
}
|
|
1742
|
+
.tm-textarea:focus { outline: none; border-color: var(--ink); }
|
|
1743
|
+
|
|
1744
|
+
/* SM-119: plain-text contentEditable Description. Grows with content — no
|
|
1745
|
+
max-height, no inner scrollbar. white-space: pre-wrap keeps user newlines.
|
|
1746
|
+
Shared by the modal and the full-page editor (both build it from
|
|
1747
|
+
ticket-form.js#buildDescriptionField). */
|
|
1748
|
+
.tm-description-edit {
|
|
1749
|
+
min-height: 90px;
|
|
1750
|
+
padding: 8px 10px;
|
|
1751
|
+
line-height: 1.5;
|
|
1752
|
+
white-space: pre-wrap;
|
|
1753
|
+
overflow-wrap: anywhere;
|
|
1754
|
+
word-break: break-word;
|
|
1755
|
+
cursor: text;
|
|
1756
|
+
}
|
|
1757
|
+
.tm-description-edit:empty::before {
|
|
1758
|
+
content: attr(data-placeholder);
|
|
1759
|
+
color: var(--ink-soft);
|
|
1760
|
+
pointer-events: none;
|
|
1761
|
+
}
|
|
1762
|
+
/* SM-157: Jira-style inline confirm/cancel for the description. The row wraps so
|
|
1763
|
+
the ✓/✗ sit on their own line under the editable, aligned with it (label is
|
|
1764
|
+
flex 0 0 130px + 8px gap = 138px). Hidden until the text differs from saved. */
|
|
1765
|
+
.tm-row:has(.tm-description-edit) { flex-wrap: wrap; align-items: flex-start; }
|
|
1766
|
+
.tm-desc-actions {
|
|
1767
|
+
flex-basis: 100%;
|
|
1768
|
+
margin-left: 138px;
|
|
1769
|
+
margin-top: 6px;
|
|
1770
|
+
display: flex;
|
|
1771
|
+
gap: 6px;
|
|
1772
|
+
}
|
|
1773
|
+
.tm-desc-save, .tm-desc-cancel {
|
|
1774
|
+
width: 26px; height: 26px;
|
|
1775
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1776
|
+
border: 1px solid var(--rule);
|
|
1777
|
+
border-radius: 4px;
|
|
1778
|
+
background: var(--paper);
|
|
1779
|
+
font-size: 13px; line-height: 1;
|
|
1780
|
+
cursor: pointer;
|
|
1781
|
+
}
|
|
1782
|
+
.tm-desc-save { color: var(--accent); border-color: var(--accent); }
|
|
1783
|
+
.tm-desc-save:hover { background: var(--accent); color: var(--paper); }
|
|
1784
|
+
.tm-desc-cancel { color: var(--ink-soft); }
|
|
1785
|
+
.tm-desc-cancel:hover { border-color: var(--ink); color: var(--ink); }
|
|
1786
|
+
|
|
1787
|
+
/* Section headings inside the modal. */
|
|
1788
|
+
.tm-section-title {
|
|
1789
|
+
font-family: var(--font-body);
|
|
1790
|
+
font-size: 11px;
|
|
1791
|
+
font-weight: 700;
|
|
1792
|
+
text-transform: uppercase;
|
|
1793
|
+
letter-spacing: 0.06em;
|
|
1794
|
+
color: var(--ink-soft);
|
|
1795
|
+
margin: 14px 0 6px;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
/* SM-185 — Attachments section (ticket-scoped dropzone + list) */
|
|
1799
|
+
.tm-attachments-section { margin-top: 14px; }
|
|
1800
|
+
.tm-attach-dropzone {
|
|
1801
|
+
border: 1px dashed var(--rule);
|
|
1802
|
+
border-radius: 6px;
|
|
1803
|
+
padding: 14px;
|
|
1804
|
+
text-align: center;
|
|
1805
|
+
color: var(--ink-faint);
|
|
1806
|
+
font-size: 12px;
|
|
1807
|
+
cursor: pointer;
|
|
1808
|
+
transition: background 120ms, border-color 120ms, color 120ms;
|
|
1809
|
+
}
|
|
1810
|
+
.tm-attach-dropzone:hover,
|
|
1811
|
+
.tm-attach-dropzone-over {
|
|
1812
|
+
background: var(--paper-warm);
|
|
1813
|
+
border-color: var(--accent);
|
|
1814
|
+
color: var(--ink);
|
|
1815
|
+
}
|
|
1816
|
+
.tm-attach-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
1817
|
+
.tm-attach-empty { color: var(--ink-faint); font-size: 12px; font-style: italic; padding: 2px 6px; }
|
|
1818
|
+
.tm-attach-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 4px 6px; border-radius: 4px; }
|
|
1819
|
+
.tm-attach-item:hover { background: var(--paper-warm); }
|
|
1820
|
+
.tm-attach-name { color: var(--accent); text-decoration: none; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1821
|
+
.tm-attach-name:hover { text-decoration: underline; }
|
|
1822
|
+
.tm-attach-size { color: var(--ink-faint); font-family: ui-monospace, SFMono-Regular, monospace; font-size: 11px; }
|
|
1823
|
+
.tm-attach-del {
|
|
1824
|
+
appearance: none; background: transparent; border: none; cursor: pointer;
|
|
1825
|
+
color: var(--ink-faint); font-size: 12px; line-height: 1; padding: 2px 6px; border-radius: 4px;
|
|
1826
|
+
}
|
|
1827
|
+
.tm-attach-del:hover { color: var(--danger, #B43C3C); background: var(--paper); }
|
|
1828
|
+
|
|
1829
|
+
/* SM-195 — attachment dropzone inside the New-project dialog row (fills the
|
|
1830
|
+
modal-row's second column next to the label). */
|
|
1831
|
+
.np-attach-row { align-items: flex-start; }
|
|
1832
|
+
.np-attach-wrap { flex: 1; }
|
|
1833
|
+
|
|
1834
|
+
/* Checklists (DoR / DoD). */
|
|
1835
|
+
.tm-checklist {
|
|
1836
|
+
border-top: 1px dashed var(--rule);
|
|
1837
|
+
padding: 4px 0 0;
|
|
1838
|
+
}
|
|
1839
|
+
.tm-checklist-empty {
|
|
1840
|
+
color: var(--ink-faint);
|
|
1841
|
+
font-size: 12px;
|
|
1842
|
+
font-style: italic;
|
|
1843
|
+
padding: 4px 0;
|
|
1844
|
+
}
|
|
1845
|
+
.tm-checkitem {
|
|
1846
|
+
display: flex; align-items: center;
|
|
1847
|
+
padding: 3px 0;
|
|
1848
|
+
font-size: 12px;
|
|
1849
|
+
}
|
|
1850
|
+
.tm-checkitem-label {
|
|
1851
|
+
display: inline-flex; align-items: center; gap: 8px;
|
|
1852
|
+
cursor: pointer;
|
|
1853
|
+
flex: 1;
|
|
1854
|
+
}
|
|
1855
|
+
.tm-checkitem-text { color: var(--ink); }
|
|
1856
|
+
.tm-required-tag {
|
|
1857
|
+
font-size: 10px;
|
|
1858
|
+
letter-spacing: 0.05em;
|
|
1859
|
+
text-transform: uppercase;
|
|
1860
|
+
color: var(--ink-faint);
|
|
1861
|
+
background: var(--rule-soft);
|
|
1862
|
+
border-radius: 3px;
|
|
1863
|
+
padding: 1px 5px;
|
|
1864
|
+
margin-left: auto;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
/* Acceptance criteria — small inline list editor. */
|
|
1868
|
+
.tm-ac-section {
|
|
1869
|
+
border-top: 1px dashed var(--rule);
|
|
1870
|
+
padding: 4px 0 0;
|
|
1871
|
+
}
|
|
1872
|
+
.tm-ac-list { display: flex; flex-direction: column; gap: 4px; }
|
|
1873
|
+
.tm-ac-row {
|
|
1874
|
+
display: flex; align-items: center; gap: 6px;
|
|
1875
|
+
padding: 2px 4px;
|
|
1876
|
+
border-radius: 3px;
|
|
1877
|
+
transition: background 100ms, box-shadow 100ms;
|
|
1878
|
+
}
|
|
1879
|
+
.tm-ac-row.sm-dragging { opacity: 0.4; }
|
|
1880
|
+
.tm-ac-row.tm-ac-drop-target {
|
|
1881
|
+
background: var(--paper-warm);
|
|
1882
|
+
box-shadow: inset 0 2px 0 var(--accent);
|
|
1883
|
+
}
|
|
1884
|
+
.tm-ac-grip {
|
|
1885
|
+
flex: 0 0 auto;
|
|
1886
|
+
color: var(--ink-faint);
|
|
1887
|
+
font-size: 11px;
|
|
1888
|
+
letter-spacing: -2px;
|
|
1889
|
+
cursor: grab;
|
|
1890
|
+
user-select: none;
|
|
1891
|
+
padding: 0 2px;
|
|
1892
|
+
}
|
|
1893
|
+
.tm-ac-grip:active { cursor: grabbing; }
|
|
1894
|
+
.tm-ac-row input[type="checkbox"] { flex: 0 0 auto; }
|
|
1895
|
+
.tm-ac-text { flex: 1; }
|
|
1896
|
+
.tm-ac-remove {
|
|
1897
|
+
flex: 0 0 auto;
|
|
1898
|
+
background: transparent;
|
|
1899
|
+
border: 1px solid var(--rule);
|
|
1900
|
+
border-radius: 3px;
|
|
1901
|
+
width: 22px; height: 22px;
|
|
1902
|
+
font-size: 14px;
|
|
1903
|
+
line-height: 1;
|
|
1904
|
+
color: var(--ink-faint);
|
|
1905
|
+
cursor: pointer;
|
|
1906
|
+
}
|
|
1907
|
+
.tm-ac-remove:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
1908
|
+
.tm-ac-add {
|
|
1909
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1910
|
+
margin-top: 6px;
|
|
1911
|
+
padding: 4px 10px;
|
|
1912
|
+
font: inherit; font-size: 11px;
|
|
1913
|
+
color: var(--ink-faint);
|
|
1914
|
+
background: transparent;
|
|
1915
|
+
border: 1px dashed var(--rule);
|
|
1916
|
+
border-radius: 4px;
|
|
1917
|
+
cursor: pointer;
|
|
1918
|
+
align-self: flex-start;
|
|
1919
|
+
}
|
|
1920
|
+
.tm-ac-add:hover {
|
|
1921
|
+
background: var(--paper-warm); color: var(--ink);
|
|
1922
|
+
border-color: var(--ink-faint); border-style: solid;
|
|
1923
|
+
}
|
|
1924
|
+
.tm-ac-add .sm-add-icon {
|
|
1925
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1926
|
+
width: 14px; height: 14px;
|
|
1927
|
+
background: var(--ink-faint); color: var(--paper);
|
|
1928
|
+
border-radius: 50%; font-size: 11px; font-weight: 700; line-height: 1;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/* Project-Load-Dialog (cmapper-Pattern). Liste von Cards mit Counts. */
|
|
1932
|
+
.project-list-cards {
|
|
1933
|
+
display: grid;
|
|
1934
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
1935
|
+
gap: 10px;
|
|
1936
|
+
max-height: 60vh;
|
|
1937
|
+
overflow-y: auto;
|
|
1938
|
+
padding: 4px 2px;
|
|
1939
|
+
}
|
|
1940
|
+
.project-list-empty,
|
|
1941
|
+
.project-list-empty-filtered {
|
|
1942
|
+
color: var(--ink-faint);
|
|
1943
|
+
font-style: italic;
|
|
1944
|
+
font-size: 12px;
|
|
1945
|
+
padding: 12px 0;
|
|
1946
|
+
}
|
|
1947
|
+
/* SM-209 — project picker search + sort toolbar (cmapper parity). */
|
|
1948
|
+
.project-picker-toolbar {
|
|
1949
|
+
display: flex;
|
|
1950
|
+
gap: 8px;
|
|
1951
|
+
align-items: center;
|
|
1952
|
+
margin-bottom: 10px;
|
|
1953
|
+
}
|
|
1954
|
+
.project-picker-toolbar .project-search {
|
|
1955
|
+
flex: 1 1 auto;
|
|
1956
|
+
font-size: 12px;
|
|
1957
|
+
padding: 5px 9px;
|
|
1958
|
+
border: 1px solid var(--rule);
|
|
1959
|
+
border-radius: 4px;
|
|
1960
|
+
background: var(--paper);
|
|
1961
|
+
color: var(--ink);
|
|
1962
|
+
}
|
|
1963
|
+
.project-picker-toolbar .project-search:focus {
|
|
1964
|
+
outline: none;
|
|
1965
|
+
border-color: var(--accent);
|
|
1966
|
+
}
|
|
1967
|
+
.project-picker-toolbar .project-sort {
|
|
1968
|
+
flex: 0 0 auto;
|
|
1969
|
+
font-size: 12px;
|
|
1970
|
+
padding: 5px 8px;
|
|
1971
|
+
border: 1px solid var(--rule);
|
|
1972
|
+
border-radius: 4px;
|
|
1973
|
+
background: var(--paper);
|
|
1974
|
+
color: var(--ink);
|
|
1975
|
+
cursor: pointer;
|
|
1976
|
+
}
|
|
1977
|
+
.project-card-desc {
|
|
1978
|
+
font-size: 11px;
|
|
1979
|
+
color: var(--ink-soft);
|
|
1980
|
+
margin-top: 4px;
|
|
1981
|
+
line-height: 1.35;
|
|
1982
|
+
display: -webkit-box;
|
|
1983
|
+
-webkit-line-clamp: 2;
|
|
1984
|
+
-webkit-box-orient: vertical;
|
|
1985
|
+
overflow: hidden;
|
|
1986
|
+
}
|
|
1987
|
+
.project-card-mtime {
|
|
1988
|
+
font-size: 10px;
|
|
1989
|
+
color: var(--ink-faint);
|
|
1990
|
+
margin-top: 4px;
|
|
1991
|
+
}
|
|
1992
|
+
.project-card {
|
|
1993
|
+
position: relative;
|
|
1994
|
+
background: var(--paper);
|
|
1995
|
+
border: 1px solid var(--rule);
|
|
1996
|
+
border-radius: 6px;
|
|
1997
|
+
padding: 12px 14px;
|
|
1998
|
+
cursor: pointer;
|
|
1999
|
+
transition: background 100ms, border-color 100ms, transform 80ms;
|
|
2000
|
+
}
|
|
2001
|
+
.project-card:hover {
|
|
2002
|
+
background: var(--paper-warm);
|
|
2003
|
+
border-color: var(--ink-faint);
|
|
2004
|
+
transform: translateY(-1px);
|
|
2005
|
+
}
|
|
2006
|
+
.project-card.current {
|
|
2007
|
+
cursor: default;
|
|
2008
|
+
border-color: var(--accent);
|
|
2009
|
+
background: var(--paper-warm);
|
|
2010
|
+
}
|
|
2011
|
+
.project-card.current:hover { transform: none; }
|
|
2012
|
+
.project-card-header {
|
|
2013
|
+
display: flex; align-items: baseline; gap: 8px;
|
|
2014
|
+
margin-bottom: 4px;
|
|
2015
|
+
}
|
|
2016
|
+
.project-card-name {
|
|
2017
|
+
font-size: 13px;
|
|
2018
|
+
font-weight: 600;
|
|
2019
|
+
color: var(--ink);
|
|
2020
|
+
}
|
|
2021
|
+
.project-card-id {
|
|
2022
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
2023
|
+
font-size: 10px;
|
|
2024
|
+
color: var(--ink-faint);
|
|
2025
|
+
}
|
|
2026
|
+
.project-card-current-badge {
|
|
2027
|
+
margin-left: auto;
|
|
2028
|
+
font-size: 10px;
|
|
2029
|
+
letter-spacing: 0.04em;
|
|
2030
|
+
text-transform: uppercase;
|
|
2031
|
+
color: var(--accent);
|
|
2032
|
+
background: rgba(15, 95, 79, 0.10);
|
|
2033
|
+
border-radius: 3px;
|
|
2034
|
+
padding: 1px 6px;
|
|
2035
|
+
}
|
|
2036
|
+
.project-card-counts {
|
|
2037
|
+
font-size: 11px;
|
|
2038
|
+
color: var(--ink-soft);
|
|
2039
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
2040
|
+
}
|
|
2041
|
+
.project-card-delete {
|
|
2042
|
+
position: absolute;
|
|
2043
|
+
top: 8px; right: 10px;
|
|
2044
|
+
padding: 2px 8px;
|
|
2045
|
+
font-size: 10px;
|
|
2046
|
+
display: none; /* hidden until hover */
|
|
2047
|
+
}
|
|
2048
|
+
.project-card:hover .project-card-delete { display: inline-block; }
|
|
2049
|
+
|
|
2050
|
+
/* E13 — History-Dialog (Revisions-Liste, cmapper-Pattern). */
|
|
2051
|
+
.hist-list {
|
|
2052
|
+
display: flex; flex-direction: column;
|
|
2053
|
+
gap: 4px;
|
|
2054
|
+
max-height: 60vh;
|
|
2055
|
+
overflow-y: auto;
|
|
2056
|
+
padding: 2px;
|
|
2057
|
+
}
|
|
2058
|
+
.hist-empty {
|
|
2059
|
+
color: var(--ink-faint);
|
|
2060
|
+
font-style: italic;
|
|
2061
|
+
font-size: 12px;
|
|
2062
|
+
padding: 12px 0;
|
|
2063
|
+
}
|
|
2064
|
+
.hist-row {
|
|
2065
|
+
display: flex; align-items: center; gap: 10px;
|
|
2066
|
+
padding: 6px 10px;
|
|
2067
|
+
background: var(--paper);
|
|
2068
|
+
border: 1px solid var(--rule);
|
|
2069
|
+
border-radius: 4px;
|
|
2070
|
+
transition: background 100ms, border-color 100ms;
|
|
2071
|
+
}
|
|
2072
|
+
.hist-row:hover {
|
|
2073
|
+
background: var(--paper-warm);
|
|
2074
|
+
border-color: var(--ink-faint);
|
|
2075
|
+
}
|
|
2076
|
+
.hist-row-main {
|
|
2077
|
+
display: flex; align-items: center; gap: 10px;
|
|
2078
|
+
flex: 1; min-width: 0;
|
|
2079
|
+
}
|
|
2080
|
+
.hist-timestamp {
|
|
2081
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
2082
|
+
font-size: 11px;
|
|
2083
|
+
color: var(--ink);
|
|
2084
|
+
}
|
|
2085
|
+
.hist-op-pill {
|
|
2086
|
+
font-size: 10px;
|
|
2087
|
+
letter-spacing: 0.04em;
|
|
2088
|
+
color: var(--ink-soft);
|
|
2089
|
+
background: var(--rule-soft);
|
|
2090
|
+
border-radius: 3px;
|
|
2091
|
+
padding: 1px 6px;
|
|
2092
|
+
}
|
|
2093
|
+
.hist-actor {
|
|
2094
|
+
font-size: 11px;
|
|
2095
|
+
color: var(--ink-faint);
|
|
2096
|
+
margin-left: auto;
|
|
2097
|
+
margin-right: 8px;
|
|
2098
|
+
}
|
|
2099
|
+
.hist-restore { padding: 3px 10px; font-size: 11px; }
|
|
2100
|
+
|
|
2101
|
+
/* Type-Picker (small modal that opens BEFORE the create-modal). */
|
|
2102
|
+
.tm-type-picker {
|
|
2103
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
2104
|
+
padding: 6px 0 0;
|
|
2105
|
+
}
|
|
2106
|
+
.tm-type-pick-btn {
|
|
2107
|
+
display: flex; align-items: center; gap: 10px;
|
|
2108
|
+
padding: 10px 14px;
|
|
2109
|
+
font: inherit; font-size: 13px;
|
|
2110
|
+
color: var(--ink);
|
|
2111
|
+
background: var(--paper);
|
|
2112
|
+
border: 1px solid var(--rule);
|
|
2113
|
+
border-radius: 4px;
|
|
2114
|
+
cursor: pointer;
|
|
2115
|
+
text-align: left;
|
|
2116
|
+
transition: background 100ms, border-color 100ms;
|
|
2117
|
+
}
|
|
2118
|
+
.tm-type-pick-btn:hover {
|
|
2119
|
+
background: var(--paper-warm);
|
|
2120
|
+
border-color: var(--ink-faint);
|
|
2121
|
+
}
|
|
2122
|
+
.tm-type-pick-name {
|
|
2123
|
+
font-weight: 600;
|
|
2124
|
+
letter-spacing: 0.01em;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
/* ============================================================
|
|
2128
|
+
E11 — View-Toggle (Map / Kanban)
|
|
2129
|
+
============================================================ */
|
|
2130
|
+
|
|
2131
|
+
.view-toggle {
|
|
2132
|
+
display: inline-flex;
|
|
2133
|
+
border: 1px solid var(--rule);
|
|
2134
|
+
border-radius: 6px;
|
|
2135
|
+
overflow: hidden;
|
|
2136
|
+
background: var(--paper);
|
|
2137
|
+
}
|
|
2138
|
+
.view-toggle-btn {
|
|
2139
|
+
appearance: none;
|
|
2140
|
+
background: transparent;
|
|
2141
|
+
border: none;
|
|
2142
|
+
padding: 5px 12px;
|
|
2143
|
+
font: inherit; font-size: 12px;
|
|
2144
|
+
color: var(--ink-soft);
|
|
2145
|
+
cursor: pointer;
|
|
2146
|
+
transition: background 100ms, color 100ms;
|
|
2147
|
+
}
|
|
2148
|
+
.view-toggle-btn + .view-toggle-btn { border-left: 1px solid var(--rule); }
|
|
2149
|
+
.view-toggle-btn:hover {
|
|
2150
|
+
background: var(--paper-warm);
|
|
2151
|
+
color: var(--ink);
|
|
2152
|
+
}
|
|
2153
|
+
.view-toggle-btn.active {
|
|
2154
|
+
background: var(--ink);
|
|
2155
|
+
color: var(--paper);
|
|
2156
|
+
font-weight: 600;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
/* ============================================================
|
|
2160
|
+
SM-82 — Filter Button + Popover
|
|
2161
|
+
============================================================ */
|
|
2162
|
+
|
|
2163
|
+
/* SM-16 — toolbar ticket search */
|
|
2164
|
+
.ticket-search {
|
|
2165
|
+
appearance: none;
|
|
2166
|
+
width: 240px;
|
|
2167
|
+
background: var(--paper);
|
|
2168
|
+
border: 1px solid var(--rule);
|
|
2169
|
+
border-radius: 6px;
|
|
2170
|
+
padding: 5px 10px;
|
|
2171
|
+
margin-right: 8px;
|
|
2172
|
+
font: inherit; font-size: 12px;
|
|
2173
|
+
color: var(--ink);
|
|
2174
|
+
transition: width 120ms ease, border-color 100ms;
|
|
2175
|
+
}
|
|
2176
|
+
/* SM-191: the search box is the unified smart-bar — queries are longer than a
|
|
2177
|
+
word, so it grows wider on focus. */
|
|
2178
|
+
.ticket-search:focus { outline: none; border-color: var(--accent); width: 420px; }
|
|
2179
|
+
.ticket-search::placeholder { color: var(--ink-soft); }
|
|
2180
|
+
.smartbar-status {
|
|
2181
|
+
font-size: 11px;
|
|
2182
|
+
margin-right: 8px;
|
|
2183
|
+
white-space: nowrap;
|
|
2184
|
+
max-width: 280px;
|
|
2185
|
+
overflow: hidden;
|
|
2186
|
+
text-overflow: ellipsis;
|
|
2187
|
+
}
|
|
2188
|
+
.smartbar-status-ok { color: var(--ink-soft); }
|
|
2189
|
+
.smartbar-status-error { color: var(--danger, #a23); }
|
|
2190
|
+
/* SM-216: Jira-style autocomplete dropdown (fixed-positioned under the bar). */
|
|
2191
|
+
.smartbar-ac {
|
|
2192
|
+
position: fixed;
|
|
2193
|
+
z-index: 200;
|
|
2194
|
+
max-height: 280px;
|
|
2195
|
+
overflow-y: auto;
|
|
2196
|
+
background: var(--paper);
|
|
2197
|
+
border: 1px solid var(--rule);
|
|
2198
|
+
border-radius: 6px;
|
|
2199
|
+
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.12);
|
|
2200
|
+
padding: 4px;
|
|
2201
|
+
font-size: 12px;
|
|
2202
|
+
}
|
|
2203
|
+
.smartbar-ac-item {
|
|
2204
|
+
display: flex;
|
|
2205
|
+
align-items: baseline;
|
|
2206
|
+
justify-content: space-between;
|
|
2207
|
+
gap: 12px;
|
|
2208
|
+
padding: 4px 8px;
|
|
2209
|
+
border-radius: 4px;
|
|
2210
|
+
cursor: pointer;
|
|
2211
|
+
white-space: nowrap;
|
|
2212
|
+
}
|
|
2213
|
+
.smartbar-ac-item.active,
|
|
2214
|
+
.smartbar-ac-item:hover { background: var(--paper-warm); }
|
|
2215
|
+
.smartbar-ac-label { color: var(--ink); }
|
|
2216
|
+
.smartbar-ac-kind { color: var(--ink-faint); font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
2217
|
+
|
|
2218
|
+
/* SM-16 — live search highlight: matched cards pop, non-matched fade. */
|
|
2219
|
+
.sm-story-card.sm-search-dim { opacity: 0.22; }
|
|
2220
|
+
.sm-story-card.sm-search-hit { box-shadow: 0 0 0 2px var(--accent); }
|
|
2221
|
+
.sm-story-card.sm-search-dim,
|
|
2222
|
+
.sm-story-card.sm-search-hit { transition: opacity 140ms ease, box-shadow 140ms ease; }
|
|
2223
|
+
/* SM-208 — epic cards ring on match too. They are never dimmed (their opacity
|
|
2224
|
+
cascades to contained story cards), so only the hit-ring applies. */
|
|
2225
|
+
.sm-epic-card.sm-search-hit { box-shadow: 0 0 0 2px var(--accent); }
|
|
2226
|
+
.sm-epic-card.sm-search-hit { transition: box-shadow 140ms ease; }
|
|
2227
|
+
|
|
2228
|
+
/* SM-167 — release-completion warning (reactive inline list in Edit Release). */
|
|
2229
|
+
.er-open-warning {
|
|
2230
|
+
margin-top: 10px;
|
|
2231
|
+
border: 1px solid var(--danger, #b04a3a);
|
|
2232
|
+
border-radius: 6px;
|
|
2233
|
+
background: var(--danger-soft, rgba(176,74,58,0.08));
|
|
2234
|
+
padding: 8px 10px;
|
|
2235
|
+
font-size: 12px;
|
|
2236
|
+
}
|
|
2237
|
+
.er-open-head { color: var(--ink); margin-bottom: 6px; }
|
|
2238
|
+
.er-open-list { list-style: none; margin: 0; padding: 0; max-height: 160px; overflow-y: auto; }
|
|
2239
|
+
.er-open-list li { display: flex; align-items: baseline; gap: 8px; padding: 2px 0; }
|
|
2240
|
+
.er-open-key { font-weight: 600; color: var(--ink); flex: 0 0 auto; }
|
|
2241
|
+
.er-open-title { color: var(--ink-soft); flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2242
|
+
.er-open-status { flex: 0 0 auto; font-size: 11px; color: var(--ink-soft); border: 1px solid var(--rule); border-radius: 10px; padding: 0 7px; }
|
|
2243
|
+
|
|
2244
|
+
.filter-btn {
|
|
2245
|
+
appearance: none;
|
|
2246
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
2247
|
+
background: var(--paper);
|
|
2248
|
+
border: 1px solid var(--rule);
|
|
2249
|
+
border-radius: 6px;
|
|
2250
|
+
padding: 5px 12px;
|
|
2251
|
+
margin-right: 8px;
|
|
2252
|
+
font: inherit; font-size: 12px;
|
|
2253
|
+
color: var(--ink-soft);
|
|
2254
|
+
cursor: pointer;
|
|
2255
|
+
transition: background 100ms, color 100ms, border-color 100ms;
|
|
2256
|
+
}
|
|
2257
|
+
.filter-btn:hover { background: var(--paper-warm); color: var(--ink); border-color: var(--ink-faint); }
|
|
2258
|
+
.filter-btn.active {
|
|
2259
|
+
background: var(--accent-soft, rgba(15, 95, 79, 0.10));
|
|
2260
|
+
color: var(--accent);
|
|
2261
|
+
border-color: var(--accent);
|
|
2262
|
+
font-weight: 600;
|
|
2263
|
+
}
|
|
2264
|
+
.filter-badge {
|
|
2265
|
+
display: inline-block;
|
|
2266
|
+
min-width: 18px; height: 18px;
|
|
2267
|
+
padding: 0 5px;
|
|
2268
|
+
border-radius: 9px;
|
|
2269
|
+
background: var(--accent);
|
|
2270
|
+
color: var(--paper);
|
|
2271
|
+
font-size: 11px; font-weight: 700; line-height: 18px;
|
|
2272
|
+
text-align: center;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
#filter-popover {
|
|
2276
|
+
position: fixed;
|
|
2277
|
+
background: var(--paper);
|
|
2278
|
+
border: 1px solid var(--rule);
|
|
2279
|
+
border-radius: 6px;
|
|
2280
|
+
box-shadow: var(--shadow-lift, 0 8px 24px rgba(0,0,0,0.12));
|
|
2281
|
+
padding: 14px 16px;
|
|
2282
|
+
width: 280px;
|
|
2283
|
+
max-height: 70vh;
|
|
2284
|
+
overflow-y: auto;
|
|
2285
|
+
z-index: 80;
|
|
2286
|
+
}
|
|
2287
|
+
#filter-popover[hidden] { display: none; }
|
|
2288
|
+
.filter-popover-section { margin-bottom: 14px; }
|
|
2289
|
+
.filter-popover-section:last-of-type { margin-bottom: 6px; }
|
|
2290
|
+
.filter-popover-section-header {
|
|
2291
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
2292
|
+
margin-bottom: 6px;
|
|
2293
|
+
}
|
|
2294
|
+
.filter-popover-section-title {
|
|
2295
|
+
font-size: 11px; font-weight: 700;
|
|
2296
|
+
text-transform: uppercase; letter-spacing: 0.05em;
|
|
2297
|
+
color: var(--ink-soft);
|
|
2298
|
+
}
|
|
2299
|
+
.filter-popover-section-actions {
|
|
2300
|
+
display: inline-flex; gap: 4px;
|
|
2301
|
+
}
|
|
2302
|
+
.filter-popover-bulk {
|
|
2303
|
+
appearance: none;
|
|
2304
|
+
background: transparent;
|
|
2305
|
+
border: 1px solid var(--rule);
|
|
2306
|
+
border-radius: 3px;
|
|
2307
|
+
padding: 1px 6px;
|
|
2308
|
+
font: inherit; font-size: 10px;
|
|
2309
|
+
color: var(--ink-soft);
|
|
2310
|
+
cursor: pointer;
|
|
2311
|
+
text-transform: lowercase;
|
|
2312
|
+
}
|
|
2313
|
+
.filter-popover-bulk:hover { color: var(--accent); border-color: var(--accent); }
|
|
2314
|
+
.filter-popover-checkrow {
|
|
2315
|
+
display: flex; align-items: center; gap: 8px;
|
|
2316
|
+
padding: 3px 0;
|
|
2317
|
+
cursor: pointer;
|
|
2318
|
+
font-size: 12px;
|
|
2319
|
+
color: var(--ink);
|
|
2320
|
+
}
|
|
2321
|
+
.filter-popover-checkrow input { margin: 0; cursor: pointer; }
|
|
2322
|
+
.filter-popover-checkrow:hover { color: var(--accent); }
|
|
2323
|
+
.filter-popover-footer {
|
|
2324
|
+
display: flex; justify-content: flex-end;
|
|
2325
|
+
margin-top: 8px;
|
|
2326
|
+
padding-top: 8px;
|
|
2327
|
+
border-top: 1px dashed var(--rule);
|
|
2328
|
+
}
|
|
2329
|
+
.filter-popover-reset {
|
|
2330
|
+
appearance: none;
|
|
2331
|
+
background: transparent;
|
|
2332
|
+
border: none;
|
|
2333
|
+
font: inherit; font-size: 12px;
|
|
2334
|
+
color: var(--ink-soft);
|
|
2335
|
+
cursor: pointer;
|
|
2336
|
+
text-decoration: underline dotted;
|
|
2337
|
+
padding: 2px 4px;
|
|
2338
|
+
}
|
|
2339
|
+
.filter-popover-reset:hover { color: var(--danger, #B43C3C); }
|
|
2340
|
+
|
|
2341
|
+
/* ============================================================
|
|
2342
|
+
E11 — Kanban-Board
|
|
2343
|
+
============================================================ */
|
|
2344
|
+
|
|
2345
|
+
/* SM-169 — full-bleed like the Story-Map (no page-edge margin); release rows
|
|
2346
|
+
stack flush, separated by the shared release-label-row borders. */
|
|
2347
|
+
#kanban-host { padding: 0; }
|
|
2348
|
+
.km-board {
|
|
2349
|
+
display: flex; flex-direction: column;
|
|
2350
|
+
}
|
|
2351
|
+
/* Per-release column header (repeats Backlog / Ready / … / Done inside every
|
|
2352
|
+
expanded swimlane). Shares the cells' grid template so columns line up, and
|
|
2353
|
+
the same nth-of-type stripes so the tinted bands run header→cards. */
|
|
2354
|
+
.km-col-header {
|
|
2355
|
+
display: grid;
|
|
2356
|
+
background: var(--paper);
|
|
2357
|
+
border-bottom: 1px solid var(--rule);
|
|
2358
|
+
}
|
|
2359
|
+
.km-col-head-cell {
|
|
2360
|
+
font-size: 12px;
|
|
2361
|
+
font-weight: 700;
|
|
2362
|
+
text-transform: uppercase;
|
|
2363
|
+
letter-spacing: 0.06em;
|
|
2364
|
+
color: var(--ink-soft);
|
|
2365
|
+
padding: 6px 12px;
|
|
2366
|
+
border-right: 1px solid var(--rule);
|
|
2367
|
+
}
|
|
2368
|
+
.km-col-head-cell:last-child { border-right: none; }
|
|
2369
|
+
.km-col-head-cell:nth-of-type(even) { background: #FBF6E8; }
|
|
2370
|
+
.km-col-head-cell.km-col-orphan { color: var(--danger, #7A3E26); }
|
|
2371
|
+
|
|
2372
|
+
/* SM-169: a swimlane stacks like the Story-Map's release rows — the header is
|
|
2373
|
+
the SHARED `.sm-release-label-row` component (chevron + name + pill, fully
|
|
2374
|
+
styled over in the Story-Map section), so no card chrome of its own. */
|
|
2375
|
+
.km-swimlane { background: transparent; }
|
|
2376
|
+
/* The count badge rides along in the shared header's `trailing` slot. Pushed
|
|
2377
|
+
to the right so the release name + pill stay left-aligned like the Map. */
|
|
2378
|
+
.km-swimlane .km-swimlane-count {
|
|
2379
|
+
margin-left: auto;
|
|
2380
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
2381
|
+
font-size: 11px;
|
|
2382
|
+
color: var(--ink-faint);
|
|
2383
|
+
background: var(--rule-soft);
|
|
2384
|
+
border-radius: 3px;
|
|
2385
|
+
padding: 0 5px;
|
|
2386
|
+
}
|
|
2387
|
+
.km-swimlane-cells {
|
|
2388
|
+
display: grid;
|
|
2389
|
+
align-items: stretch;
|
|
2390
|
+
}
|
|
2391
|
+
/* Tinted column bands mirror the Story-Map's `.sm-cell` striping so the
|
|
2392
|
+
status columns read as distinct lanes (paper / warm) with a divider rule. */
|
|
2393
|
+
.km-cell {
|
|
2394
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
2395
|
+
padding: 8px;
|
|
2396
|
+
min-height: 80px;
|
|
2397
|
+
background: var(--paper);
|
|
2398
|
+
border-right: 1px solid var(--rule);
|
|
2399
|
+
transition: background-color 120ms, box-shadow 120ms;
|
|
2400
|
+
}
|
|
2401
|
+
.km-cell:nth-of-type(even) { background: #FBF6E8; }
|
|
2402
|
+
.km-cell:last-child { border-right: none; }
|
|
2403
|
+
.km-cell:hover { background: var(--paper-warm); }
|
|
2404
|
+
.km-cell.km-cell-drop-target {
|
|
2405
|
+
background: rgba(15, 95, 79, 0.16);
|
|
2406
|
+
box-shadow: inset 0 0 0 2px var(--accent);
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
/* Karten in der Kanban-Zelle sind die GLEICHEN `.sm-story-card`-Elemente
|
|
2410
|
+
wie in der Story-Map (renderer-card.js liefert beide Views). Hier nur
|
|
2411
|
+
eine kleine Anpassung: in der Zelle füllen sie die volle Breite. */
|
|
2412
|
+
.km-cell .sm-story-card {
|
|
2413
|
+
width: 100%;
|
|
2414
|
+
box-sizing: border-box;
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
/* "+ Add Item" am Ende jeder Lane — Ghost-Variante, gleicher Stil wie
|
|
2418
|
+
die Per-Cell-Add-Buttons in der Story-Map (.sm-add-ticket). */
|
|
2419
|
+
.km-add-item {
|
|
2420
|
+
margin-top: auto;
|
|
2421
|
+
display: inline-flex;
|
|
2422
|
+
align-items: center;
|
|
2423
|
+
gap: 4px;
|
|
2424
|
+
align-self: stretch;
|
|
2425
|
+
padding: 5px 10px;
|
|
2426
|
+
font: inherit; font-size: 11px;
|
|
2427
|
+
color: var(--ink-faint);
|
|
2428
|
+
background: transparent;
|
|
2429
|
+
border: 1px dashed var(--rule);
|
|
2430
|
+
border-radius: 4px;
|
|
2431
|
+
cursor: pointer;
|
|
2432
|
+
transition: background 120ms, color 120ms, border-color 120ms;
|
|
2433
|
+
}
|
|
2434
|
+
.km-add-item:hover {
|
|
2435
|
+
background: var(--paper-warm);
|
|
2436
|
+
color: var(--ink);
|
|
2437
|
+
border-color: var(--ink-faint);
|
|
2438
|
+
border-style: solid;
|
|
2439
|
+
}
|
|
2440
|
+
.km-add-item .sm-add-icon {
|
|
2441
|
+
display: inline-flex;
|
|
2442
|
+
align-items: center; justify-content: center;
|
|
2443
|
+
width: 14px; height: 14px;
|
|
2444
|
+
background: var(--ink-faint);
|
|
2445
|
+
color: var(--paper);
|
|
2446
|
+
border-radius: 50%;
|
|
2447
|
+
font-size: 11px; line-height: 1; font-weight: 700;
|
|
2448
|
+
}
|
|
2449
|
+
.km-add-item:hover .sm-add-icon { background: var(--accent); }
|
|
2450
|
+
.km-add-item .sm-add-label { letter-spacing: 0.02em; }
|
|
2451
|
+
|
|
2452
|
+
/* SM-2/SM-3 — DoR/DoD editor inside the settings view (replaced the
|
|
2453
|
+
deprecated dialog version that used to live here, SM-3). */
|
|
2454
|
+
.vs-def-root { display: flex; flex-direction: column; gap: 14px; }
|
|
2455
|
+
.vs-def-block-title {
|
|
2456
|
+
font-family: var(--font-display, "Libre Caslon Text"), Georgia, serif;
|
|
2457
|
+
font-size: 15px; font-weight: 600;
|
|
2458
|
+
margin: 8px 0 4px;
|
|
2459
|
+
letter-spacing: -0.01em;
|
|
2460
|
+
}
|
|
2461
|
+
.vs-def-block { display: flex; flex-direction: column; gap: 4px; }
|
|
2462
|
+
.vs-def-block-title {
|
|
2463
|
+
font-size: 12px; font-weight: 600;
|
|
2464
|
+
color: var(--ink-soft);
|
|
2465
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
2466
|
+
margin: 4px 0 2px;
|
|
2467
|
+
}
|
|
2468
|
+
.vs-def-globals, .vs-def-per-type {
|
|
2469
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
2470
|
+
}
|
|
2471
|
+
.vs-def-type-block {
|
|
2472
|
+
border: 1px solid var(--rule);
|
|
2473
|
+
border-radius: 4px;
|
|
2474
|
+
padding: 10px 12px;
|
|
2475
|
+
background: var(--paper-warm, #FAF7F0);
|
|
2476
|
+
}
|
|
2477
|
+
.vs-def-type-title {
|
|
2478
|
+
font-family: var(--font-display, "Libre Caslon Text"), Georgia, serif;
|
|
2479
|
+
font-size: 13px; font-weight: 600;
|
|
2480
|
+
margin: 0 0 6px;
|
|
2481
|
+
}
|
|
2482
|
+
.vs-def-gate-block { margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--rule); }
|
|
2483
|
+
.vs-def-gate-block:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
|
|
2484
|
+
.vs-def-gate-header { display: flex; align-items: center; gap: 8px; }
|
|
2485
|
+
.vs-def-gate-toggle {
|
|
2486
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
2487
|
+
font-size: 12px;
|
|
2488
|
+
cursor: pointer;
|
|
2489
|
+
}
|
|
2490
|
+
.vs-def-gate-body {
|
|
2491
|
+
padding: 6px 0 0 22px;
|
|
2492
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
2493
|
+
}
|
|
2494
|
+
.vs-def-mode-row { display: flex; align-items: center; gap: 8px; font-size: 12px; }
|
|
2495
|
+
.vs-def-mode-label { color: var(--ink-soft); }
|
|
2496
|
+
.vs-def-items-list { display: flex; flex-direction: column; gap: 4px; }
|
|
2497
|
+
.vs-def-item-row {
|
|
2498
|
+
display: flex; align-items: center; gap: 6px;
|
|
2499
|
+
padding: 2px 4px;
|
|
2500
|
+
border-radius: 3px;
|
|
2501
|
+
transition: background 100ms, box-shadow 100ms;
|
|
2502
|
+
}
|
|
2503
|
+
.vs-def-item-row.sm-dragging { opacity: 0.4; }
|
|
2504
|
+
.vs-def-item-row.vs-def-item-drop-target {
|
|
2505
|
+
background: var(--paper);
|
|
2506
|
+
box-shadow: inset 0 2px 0 var(--accent);
|
|
2507
|
+
}
|
|
2508
|
+
.vs-def-item-grip {
|
|
2509
|
+
flex: 0 0 auto;
|
|
2510
|
+
color: var(--ink-faint);
|
|
2511
|
+
font-size: 11px;
|
|
2512
|
+
letter-spacing: -2px;
|
|
2513
|
+
cursor: grab;
|
|
2514
|
+
user-select: none;
|
|
2515
|
+
padding: 0 2px;
|
|
2516
|
+
}
|
|
2517
|
+
.vs-def-item-grip:active { cursor: grabbing; }
|
|
2518
|
+
.vs-def-item-required-wrap {
|
|
2519
|
+
display: inline-flex; align-items: center; gap: 3px;
|
|
2520
|
+
flex: 0 0 auto;
|
|
2521
|
+
font-size: 10px;
|
|
2522
|
+
color: var(--ink-soft);
|
|
2523
|
+
text-transform: uppercase; letter-spacing: 0.05em;
|
|
2524
|
+
cursor: pointer;
|
|
2525
|
+
user-select: none;
|
|
2526
|
+
}
|
|
2527
|
+
.vs-def-item-required-hint { font-size: 10px; }
|
|
2528
|
+
.vs-def-item-label {
|
|
2529
|
+
flex: 1;
|
|
2530
|
+
border: 1px solid var(--rule);
|
|
2531
|
+
border-radius: 3px;
|
|
2532
|
+
padding: 4px 6px;
|
|
2533
|
+
background: var(--paper);
|
|
2534
|
+
font: inherit; font-size: 12px;
|
|
2535
|
+
}
|
|
2536
|
+
.vs-def-item-label:focus { outline: none; border-color: var(--ink); }
|
|
2537
|
+
.vs-def-item-remove {
|
|
2538
|
+
flex: 0 0 auto;
|
|
2539
|
+
background: transparent;
|
|
2540
|
+
border: 1px solid var(--rule);
|
|
2541
|
+
border-radius: 3px;
|
|
2542
|
+
width: 22px; height: 22px;
|
|
2543
|
+
font-size: 14px;
|
|
2544
|
+
line-height: 1;
|
|
2545
|
+
color: var(--ink-faint);
|
|
2546
|
+
cursor: pointer;
|
|
2547
|
+
}
|
|
2548
|
+
.vs-def-item-remove:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
2549
|
+
.vs-def-add-item {
|
|
2550
|
+
align-self: flex-start;
|
|
2551
|
+
margin-top: 4px;
|
|
2552
|
+
padding: 3px 10px;
|
|
2553
|
+
font-size: 11px;
|
|
2554
|
+
color: var(--ink-faint);
|
|
2555
|
+
background: transparent;
|
|
2556
|
+
border: 1px dashed var(--rule);
|
|
2557
|
+
border-radius: 4px;
|
|
2558
|
+
cursor: pointer;
|
|
2559
|
+
}
|
|
2560
|
+
.vs-def-add-item:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
2561
|
+
|
|
2562
|
+
/* E19-followup — DoR/DoD per-Ticket-Editor (editable rows analog AC) */
|
|
2563
|
+
.tm-checklist-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
2564
|
+
.tm-checkitem-row {
|
|
2565
|
+
display: flex; align-items: center; gap: 6px;
|
|
2566
|
+
padding: 2px 4px;
|
|
2567
|
+
border-radius: 3px;
|
|
2568
|
+
transition: background 100ms, box-shadow 100ms;
|
|
2569
|
+
}
|
|
2570
|
+
.tm-checkitem-row.sm-dragging { opacity: 0.4; }
|
|
2571
|
+
.tm-checkitem-row.tm-checkitem-drop-target {
|
|
2572
|
+
background: var(--paper-warm);
|
|
2573
|
+
box-shadow: inset 0 2px 0 var(--accent);
|
|
2574
|
+
}
|
|
2575
|
+
.tm-checkitem-grip {
|
|
2576
|
+
flex: 0 0 auto;
|
|
2577
|
+
color: var(--ink-faint);
|
|
2578
|
+
font-size: 11px;
|
|
2579
|
+
letter-spacing: -2px;
|
|
2580
|
+
cursor: grab;
|
|
2581
|
+
user-select: none;
|
|
2582
|
+
padding: 0 2px;
|
|
2583
|
+
}
|
|
2584
|
+
.tm-checkitem-grip:active { cursor: grabbing; }
|
|
2585
|
+
.tm-checkitem-checked { flex: 0 0 auto; }
|
|
2586
|
+
.tm-checkitem-text-input { flex: 1; }
|
|
2587
|
+
.tm-checkitem-required-wrap {
|
|
2588
|
+
display: inline-flex; align-items: center; gap: 3px;
|
|
2589
|
+
flex: 0 0 auto;
|
|
2590
|
+
font-size: 10px;
|
|
2591
|
+
color: var(--ink-soft);
|
|
2592
|
+
text-transform: uppercase; letter-spacing: 0.05em;
|
|
2593
|
+
cursor: pointer;
|
|
2594
|
+
user-select: none;
|
|
2595
|
+
}
|
|
2596
|
+
.tm-checkitem-required-hint { font-size: 10px; }
|
|
2597
|
+
.tm-checkitem-remove {
|
|
2598
|
+
flex: 0 0 auto;
|
|
2599
|
+
background: transparent;
|
|
2600
|
+
border: 1px solid var(--rule);
|
|
2601
|
+
border-radius: 3px;
|
|
2602
|
+
width: 22px; height: 22px;
|
|
2603
|
+
font-size: 14px; line-height: 1;
|
|
2604
|
+
color: var(--ink-faint);
|
|
2605
|
+
cursor: pointer;
|
|
2606
|
+
}
|
|
2607
|
+
.tm-checkitem-remove:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
2608
|
+
.tm-checklist-add {
|
|
2609
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
2610
|
+
margin-top: 6px;
|
|
2611
|
+
padding: 4px 10px;
|
|
2612
|
+
font: inherit; font-size: 11px;
|
|
2613
|
+
color: var(--ink-faint);
|
|
2614
|
+
background: transparent;
|
|
2615
|
+
border: 1px dashed var(--rule);
|
|
2616
|
+
border-radius: 4px;
|
|
2617
|
+
cursor: pointer;
|
|
2618
|
+
}
|
|
2619
|
+
.tm-checklist-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
2620
|
+
|
|
2621
|
+
/* ---------------------------------------------------------------------------
|
|
2622
|
+
SM-54 — Prerequisites + Steps editor sections (test-definition type)
|
|
2623
|
+
Visually parallel to DoR/DoD (.tm-checkitem-row) so the editor feels
|
|
2624
|
+
uniform; Steps gets a 3-column grid because step / data / expected
|
|
2625
|
+
are three independent fields.
|
|
2626
|
+
--------------------------------------------------------------------------- */
|
|
2627
|
+
|
|
2628
|
+
.tm-prereqs { border-top: 1px dashed var(--rule); padding: 4px 0 0; }
|
|
2629
|
+
.tm-prereq-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
2630
|
+
.tm-prereq-row {
|
|
2631
|
+
display: flex; align-items: center; gap: 6px;
|
|
2632
|
+
padding: 2px 4px;
|
|
2633
|
+
border-radius: 3px;
|
|
2634
|
+
transition: background 100ms, box-shadow 100ms;
|
|
2635
|
+
}
|
|
2636
|
+
.tm-prereq-row.sm-dragging { opacity: 0.4; }
|
|
2637
|
+
.tm-prereq-row.tm-prereq-drop-target {
|
|
2638
|
+
background: var(--paper-warm);
|
|
2639
|
+
box-shadow: inset 0 2px 0 var(--accent);
|
|
2640
|
+
}
|
|
2641
|
+
.tm-prereq-grip {
|
|
2642
|
+
flex: 0 0 auto;
|
|
2643
|
+
color: var(--ink-faint);
|
|
2644
|
+
font-size: 11px;
|
|
2645
|
+
letter-spacing: -2px;
|
|
2646
|
+
cursor: grab;
|
|
2647
|
+
user-select: none;
|
|
2648
|
+
padding: 0 2px;
|
|
2649
|
+
}
|
|
2650
|
+
.tm-prereq-grip:active { cursor: grabbing; }
|
|
2651
|
+
.tm-prereq-checked { flex: 0 0 auto; }
|
|
2652
|
+
.tm-prereq-text-input { flex: 1; }
|
|
2653
|
+
.tm-prereq-required-wrap {
|
|
2654
|
+
display: inline-flex; align-items: center; gap: 3px;
|
|
2655
|
+
flex: 0 0 auto;
|
|
2656
|
+
font-size: 10px;
|
|
2657
|
+
color: var(--ink-soft);
|
|
2658
|
+
text-transform: uppercase; letter-spacing: 0.05em;
|
|
2659
|
+
cursor: pointer;
|
|
2660
|
+
user-select: none;
|
|
2661
|
+
}
|
|
2662
|
+
.tm-prereq-required-hint { font-size: 10px; }
|
|
2663
|
+
.tm-prereq-remove {
|
|
2664
|
+
flex: 0 0 auto;
|
|
2665
|
+
background: transparent;
|
|
2666
|
+
border: 1px solid var(--rule);
|
|
2667
|
+
border-radius: 3px;
|
|
2668
|
+
width: 22px; height: 22px;
|
|
2669
|
+
font-size: 14px; line-height: 1;
|
|
2670
|
+
color: var(--ink-faint);
|
|
2671
|
+
cursor: pointer;
|
|
2672
|
+
}
|
|
2673
|
+
.tm-prereq-remove:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
2674
|
+
.tm-prereq-add {
|
|
2675
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
2676
|
+
margin-top: 6px;
|
|
2677
|
+
padding: 4px 10px;
|
|
2678
|
+
font: inherit; font-size: 11px;
|
|
2679
|
+
color: var(--ink-faint);
|
|
2680
|
+
background: transparent;
|
|
2681
|
+
border: 1px dashed var(--rule);
|
|
2682
|
+
border-radius: 4px;
|
|
2683
|
+
cursor: pointer;
|
|
2684
|
+
}
|
|
2685
|
+
.tm-prereq-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
2686
|
+
|
|
2687
|
+
.tm-test-steps { border-top: 1px dashed var(--rule); padding: 4px 0 0; }
|
|
2688
|
+
/* Table header + rows share the SAME 6-column grid so labels sit exactly
|
|
2689
|
+
above their inputs: [grip] [Step] [Data] [Expected Result] [insert] [delete].
|
|
2690
|
+
SM-54-followup. */
|
|
2691
|
+
.tm-test-step-head {
|
|
2692
|
+
display: grid;
|
|
2693
|
+
grid-template-columns: 20px 1fr 1fr 1fr 26px 26px;
|
|
2694
|
+
gap: 6px;
|
|
2695
|
+
align-items: center;
|
|
2696
|
+
margin-top: 4px;
|
|
2697
|
+
padding: 2px 4px 4px;
|
|
2698
|
+
font-size: 10px;
|
|
2699
|
+
text-transform: uppercase;
|
|
2700
|
+
letter-spacing: 0.05em;
|
|
2701
|
+
color: var(--ink-soft);
|
|
2702
|
+
border-bottom: 1px solid var(--rule);
|
|
2703
|
+
}
|
|
2704
|
+
.tm-test-step-head-cell { text-align: left; }
|
|
2705
|
+
.tm-test-step-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
2706
|
+
.tm-test-step-row {
|
|
2707
|
+
display: grid;
|
|
2708
|
+
grid-template-columns: 20px 1fr 1fr 1fr 26px 26px;
|
|
2709
|
+
gap: 6px;
|
|
2710
|
+
/* Align tops so multi-line textareas grow downward without pushing the
|
|
2711
|
+
grip / button cells off-axis. */
|
|
2712
|
+
align-items: start;
|
|
2713
|
+
padding: 2px 4px;
|
|
2714
|
+
border-radius: 3px;
|
|
2715
|
+
transition: background 100ms, box-shadow 100ms;
|
|
2716
|
+
}
|
|
2717
|
+
.tm-test-step-row.sm-dragging { opacity: 0.4; }
|
|
2718
|
+
.tm-test-step-row.tm-test-step-drop-target {
|
|
2719
|
+
background: var(--paper-warm);
|
|
2720
|
+
box-shadow: inset 0 2px 0 var(--accent);
|
|
2721
|
+
}
|
|
2722
|
+
.tm-test-step-grip {
|
|
2723
|
+
color: var(--ink-faint);
|
|
2724
|
+
font-size: 11px;
|
|
2725
|
+
letter-spacing: -2px;
|
|
2726
|
+
cursor: grab;
|
|
2727
|
+
user-select: none;
|
|
2728
|
+
padding: 6px 2px 0; /* nudges down to align with first textarea row */
|
|
2729
|
+
}
|
|
2730
|
+
.tm-test-step-grip:active { cursor: grabbing; }
|
|
2731
|
+
/* Multi-line textareas, auto-grown by JS. min-height matches an input. */
|
|
2732
|
+
.tm-test-step-step,
|
|
2733
|
+
.tm-test-step-data,
|
|
2734
|
+
.tm-test-step-expected {
|
|
2735
|
+
width: 100%;
|
|
2736
|
+
min-height: 32px;
|
|
2737
|
+
font: inherit; font-size: 12px;
|
|
2738
|
+
padding: 4px 6px;
|
|
2739
|
+
border: 1px solid var(--rule);
|
|
2740
|
+
border-radius: 3px;
|
|
2741
|
+
background: var(--paper);
|
|
2742
|
+
resize: none; /* JS handles the resize via scrollHeight */
|
|
2743
|
+
line-height: 1.35;
|
|
2744
|
+
overflow-y: auto;
|
|
2745
|
+
box-sizing: border-box;
|
|
2746
|
+
}
|
|
2747
|
+
.tm-test-step-insert,
|
|
2748
|
+
.tm-test-step-remove {
|
|
2749
|
+
background: transparent;
|
|
2750
|
+
border: 1px solid var(--rule);
|
|
2751
|
+
border-radius: 3px;
|
|
2752
|
+
width: 22px; height: 22px;
|
|
2753
|
+
font-size: 12px; line-height: 1;
|
|
2754
|
+
color: var(--ink-faint);
|
|
2755
|
+
cursor: pointer;
|
|
2756
|
+
margin-top: 4px; /* tops with the textarea inner padding */
|
|
2757
|
+
padding: 0;
|
|
2758
|
+
}
|
|
2759
|
+
.tm-test-step-insert:hover { color: var(--accent); border-color: var(--accent); }
|
|
2760
|
+
.tm-test-step-remove:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
2761
|
+
.tm-test-step-add {
|
|
2762
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
2763
|
+
margin-top: 6px;
|
|
2764
|
+
padding: 4px 10px;
|
|
2765
|
+
font: inherit; font-size: 11px;
|
|
2766
|
+
color: var(--ink-faint);
|
|
2767
|
+
background: transparent;
|
|
2768
|
+
border: 1px dashed var(--rule);
|
|
2769
|
+
border-radius: 4px;
|
|
2770
|
+
cursor: pointer;
|
|
2771
|
+
}
|
|
2772
|
+
.tm-test-step-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
2773
|
+
|
|
2774
|
+
/* ---------------------------------------------------------------------------
|
|
2775
|
+
SM-57 — Test-Execution sections in ticket-detail modal
|
|
2776
|
+
--------------------------------------------------------------------------- */
|
|
2777
|
+
|
|
2778
|
+
/* Header pill: "executes → DEF-KEY: Title". Sits just under the description. */
|
|
2779
|
+
.tm-exec-header {
|
|
2780
|
+
margin: 6px 0 0;
|
|
2781
|
+
display: flex;
|
|
2782
|
+
align-items: center;
|
|
2783
|
+
}
|
|
2784
|
+
.tm-exec-header-pill {
|
|
2785
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
2786
|
+
background: var(--paper-warm);
|
|
2787
|
+
border: 1px solid var(--rule);
|
|
2788
|
+
border-radius: 999px;
|
|
2789
|
+
padding: 3px 10px;
|
|
2790
|
+
font-size: 12px;
|
|
2791
|
+
cursor: pointer;
|
|
2792
|
+
color: var(--ink);
|
|
2793
|
+
transition: background 120ms, border-color 120ms;
|
|
2794
|
+
}
|
|
2795
|
+
.tm-exec-header-pill:hover { background: var(--paper); border-color: var(--ink-faint); }
|
|
2796
|
+
.tm-exec-header-arrow { color: var(--ink-soft); font-size: 11px; }
|
|
2797
|
+
.tm-exec-header-key { font-weight: 600; }
|
|
2798
|
+
.tm-exec-header-title { color: var(--ink-soft); }
|
|
2799
|
+
.tm-exec-header-missing {
|
|
2800
|
+
color: var(--ink-faint);
|
|
2801
|
+
font-style: italic;
|
|
2802
|
+
font-size: 12px;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
/* Metadata strip: three small cells, label above value. */
|
|
2806
|
+
.tm-exec-meta {
|
|
2807
|
+
display: flex;
|
|
2808
|
+
gap: 18px;
|
|
2809
|
+
margin: 6px 0;
|
|
2810
|
+
padding: 6px 0;
|
|
2811
|
+
border-bottom: 1px dashed var(--rule);
|
|
2812
|
+
}
|
|
2813
|
+
.tm-exec-meta-cell { display: flex; flex-direction: column; gap: 1px; }
|
|
2814
|
+
.tm-exec-meta-label {
|
|
2815
|
+
font-size: 10px;
|
|
2816
|
+
text-transform: uppercase;
|
|
2817
|
+
letter-spacing: 0.05em;
|
|
2818
|
+
color: var(--ink-soft);
|
|
2819
|
+
}
|
|
2820
|
+
.tm-exec-meta-value { font-size: 12px; color: var(--ink); }
|
|
2821
|
+
|
|
2822
|
+
/* Execution-steps table: header + rows share a 6-column grid.
|
|
2823
|
+
[Step] [Data] [Expected] [Actual] [Status] [Note] */
|
|
2824
|
+
.tm-exec-steps { border-top: 1px dashed var(--rule); padding: 4px 0 0; margin-top: 8px; }
|
|
2825
|
+
.tm-exec-step-head {
|
|
2826
|
+
display: grid;
|
|
2827
|
+
grid-template-columns: 1fr 1fr 1fr 1fr 120px 1fr;
|
|
2828
|
+
gap: 6px;
|
|
2829
|
+
align-items: center;
|
|
2830
|
+
margin-top: 4px;
|
|
2831
|
+
padding: 2px 4px 4px;
|
|
2832
|
+
font-size: 10px;
|
|
2833
|
+
text-transform: uppercase;
|
|
2834
|
+
letter-spacing: 0.05em;
|
|
2835
|
+
color: var(--ink-soft);
|
|
2836
|
+
border-bottom: 1px solid var(--rule);
|
|
2837
|
+
}
|
|
2838
|
+
.tm-exec-step-head-cell { text-align: left; }
|
|
2839
|
+
.tm-exec-step-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
2840
|
+
.tm-exec-step-row {
|
|
2841
|
+
display: grid;
|
|
2842
|
+
grid-template-columns: 1fr 1fr 1fr 1fr 120px 1fr;
|
|
2843
|
+
gap: 6px;
|
|
2844
|
+
align-items: start;
|
|
2845
|
+
padding: 2px 4px;
|
|
2846
|
+
border-radius: 3px;
|
|
2847
|
+
}
|
|
2848
|
+
/* All step-row textareas share the multi-line look. The frozen ones
|
|
2849
|
+
(.tm-exec-step-ro) get a paper-warm background so it's obvious they
|
|
2850
|
+
can't be edited. */
|
|
2851
|
+
.tm-exec-step-step,
|
|
2852
|
+
.tm-exec-step-data,
|
|
2853
|
+
.tm-exec-step-expected,
|
|
2854
|
+
.tm-exec-step-actual,
|
|
2855
|
+
.tm-exec-step-note {
|
|
2856
|
+
width: 100%;
|
|
2857
|
+
min-height: 36px;
|
|
2858
|
+
font: inherit; font-size: 12px;
|
|
2859
|
+
padding: 4px 6px;
|
|
2860
|
+
border: 1px solid var(--rule);
|
|
2861
|
+
border-radius: 3px;
|
|
2862
|
+
background: var(--paper);
|
|
2863
|
+
resize: vertical;
|
|
2864
|
+
line-height: 1.35;
|
|
2865
|
+
box-sizing: border-box;
|
|
2866
|
+
}
|
|
2867
|
+
.tm-exec-step-ro {
|
|
2868
|
+
background: var(--paper-warm) !important;
|
|
2869
|
+
color: var(--ink-soft);
|
|
2870
|
+
cursor: not-allowed;
|
|
2871
|
+
}
|
|
2872
|
+
.tm-exec-step-status {
|
|
2873
|
+
font: inherit; font-size: 12px;
|
|
2874
|
+
padding: 4px 6px;
|
|
2875
|
+
border: 1px solid var(--rule);
|
|
2876
|
+
border-radius: 3px;
|
|
2877
|
+
background: var(--paper);
|
|
2878
|
+
width: 100%;
|
|
2879
|
+
height: 32px;
|
|
2880
|
+
box-sizing: border-box;
|
|
2881
|
+
}
|
|
2882
|
+
/* Status-coloured backgrounds: only on the picker itself, subtle so it
|
|
2883
|
+
doesn't fight the rest of the row. */
|
|
2884
|
+
.tm-exec-step-status[data-status="passed"] { background: rgba(34, 139, 34, 0.12); border-color: rgba(34, 139, 34, 0.5); }
|
|
2885
|
+
.tm-exec-step-status[data-status="failed"] { background: rgba(180, 60, 60, 0.12); border-color: rgba(180, 60, 60, 0.55); }
|
|
2886
|
+
.tm-exec-step-status[data-status="blocked"] { background: rgba(230, 180, 50, 0.18); border-color: rgba(180, 130, 30, 0.55); }
|
|
2887
|
+
.tm-exec-step-status[data-status="skipped"] { background: rgba(150, 150, 150, 0.14); border-color: rgba(120, 120, 120, 0.45); }
|
|
2888
|
+
.tm-exec-step-status[data-status="pending"] { background: var(--paper-warm); border-color: var(--rule); }
|
|
2889
|
+
|
|
2890
|
+
/* Outcome section: derived display + override picker. */
|
|
2891
|
+
.tm-exec-outcome { border-top: 1px dashed var(--rule); padding: 8px 0 0; margin-top: 8px; }
|
|
2892
|
+
.tm-exec-outcome-derived,
|
|
2893
|
+
.tm-exec-outcome-override-row {
|
|
2894
|
+
display: flex;
|
|
2895
|
+
align-items: center;
|
|
2896
|
+
gap: 8px;
|
|
2897
|
+
margin-top: 4px;
|
|
2898
|
+
font-size: 12px;
|
|
2899
|
+
}
|
|
2900
|
+
.tm-exec-outcome-derived-label {
|
|
2901
|
+
flex: 0 0 70px;
|
|
2902
|
+
font-size: 11px;
|
|
2903
|
+
color: var(--ink-soft);
|
|
2904
|
+
text-transform: uppercase;
|
|
2905
|
+
letter-spacing: 0.05em;
|
|
2906
|
+
}
|
|
2907
|
+
.tm-exec-outcome-pill {
|
|
2908
|
+
display: inline-block;
|
|
2909
|
+
padding: 2px 10px;
|
|
2910
|
+
border-radius: 999px;
|
|
2911
|
+
font-size: 12px; font-weight: 600;
|
|
2912
|
+
background: var(--paper-warm);
|
|
2913
|
+
border: 1px solid var(--rule);
|
|
2914
|
+
}
|
|
2915
|
+
.tm-exec-outcome-pill[data-outcome="passed"] { background: rgba(34, 139, 34, 0.16); border-color: rgba(34, 139, 34, 0.55); }
|
|
2916
|
+
.tm-exec-outcome-pill[data-outcome="failed"] { background: rgba(180, 60, 60, 0.16); border-color: rgba(180, 60, 60, 0.6); }
|
|
2917
|
+
.tm-exec-outcome-pill[data-outcome="blocked"] { background: rgba(230, 180, 50, 0.22); border-color: rgba(180, 130, 30, 0.6); }
|
|
2918
|
+
.tm-exec-outcome-pill[data-outcome="skipped"] { background: rgba(150, 150, 150, 0.18); border-color: rgba(120, 120, 120, 0.5); }
|
|
2919
|
+
.tm-exec-outcome-override {
|
|
2920
|
+
flex: 0 0 auto;
|
|
2921
|
+
font: inherit; font-size: 12px;
|
|
2922
|
+
padding: 4px 8px;
|
|
2923
|
+
border: 1px solid var(--rule);
|
|
2924
|
+
border-radius: 3px;
|
|
2925
|
+
background: var(--paper);
|
|
2926
|
+
}
|
|
2927
|
+
.tm-exec-outcome-override-hint {
|
|
2928
|
+
color: var(--accent);
|
|
2929
|
+
font-style: italic;
|
|
2930
|
+
font-size: 11px;
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
/* ---------------------------------------------------------------------------
|
|
2934
|
+
SM-48 — Links section in ticket-detail modal
|
|
2935
|
+
--------------------------------------------------------------------------- */
|
|
2936
|
+
|
|
2937
|
+
.tm-links {
|
|
2938
|
+
margin-top: 16px;
|
|
2939
|
+
padding-top: 12px;
|
|
2940
|
+
border-top: 1px solid var(--rule);
|
|
2941
|
+
}
|
|
2942
|
+
.tm-links-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
2943
|
+
.tm-links-subhead {
|
|
2944
|
+
font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
2945
|
+
font-size: 11px;
|
|
2946
|
+
font-weight: 600;
|
|
2947
|
+
text-transform: uppercase;
|
|
2948
|
+
letter-spacing: 0.04em;
|
|
2949
|
+
color: var(--ink-soft);
|
|
2950
|
+
margin: 12px 0 4px;
|
|
2951
|
+
}
|
|
2952
|
+
.tm-link-row {
|
|
2953
|
+
display: grid;
|
|
2954
|
+
grid-template-columns: auto 1fr 28px;
|
|
2955
|
+
gap: 8px;
|
|
2956
|
+
align-items: center;
|
|
2957
|
+
padding: 4px 6px;
|
|
2958
|
+
border: 1px solid transparent;
|
|
2959
|
+
border-radius: 3px;
|
|
2960
|
+
}
|
|
2961
|
+
.tm-link-row:hover { background: var(--ink-faint-bg, #FAF8F2); border-color: var(--rule); }
|
|
2962
|
+
.tm-link-row-readonly { grid-template-columns: auto 1fr; }
|
|
2963
|
+
.tm-link-pill {
|
|
2964
|
+
display: inline-block;
|
|
2965
|
+
padding: 1px 8px;
|
|
2966
|
+
font-size: 11px;
|
|
2967
|
+
font-weight: 500;
|
|
2968
|
+
border-radius: 10px;
|
|
2969
|
+
background: var(--ink-faint-bg, #EFEAE0);
|
|
2970
|
+
color: var(--ink);
|
|
2971
|
+
white-space: nowrap;
|
|
2972
|
+
}
|
|
2973
|
+
.tm-link-pill-backward { font-style: italic; }
|
|
2974
|
+
.tm-link-target { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2975
|
+
.tm-link-key {
|
|
2976
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
2977
|
+
font-size: 12px;
|
|
2978
|
+
color: var(--ink-soft);
|
|
2979
|
+
margin-right: 4px;
|
|
2980
|
+
}
|
|
2981
|
+
.tm-link-missing { color: var(--ink-faint); font-style: italic; }
|
|
2982
|
+
.tm-link-title { color: var(--ink); }
|
|
2983
|
+
.tm-link-delete {
|
|
2984
|
+
width: 24px; height: 24px;
|
|
2985
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
2986
|
+
font-size: 16px; line-height: 1;
|
|
2987
|
+
color: var(--ink-faint);
|
|
2988
|
+
background: transparent;
|
|
2989
|
+
border: 1px solid transparent;
|
|
2990
|
+
border-radius: 3px;
|
|
2991
|
+
cursor: pointer; padding: 0;
|
|
2992
|
+
}
|
|
2993
|
+
.tm-link-delete:hover { color: var(--danger, #B43C3C); border-color: var(--danger, #B43C3C); }
|
|
2994
|
+
.tm-links-empty {
|
|
2995
|
+
font-style: italic; font-size: 12px; color: var(--ink-faint); padding: 4px 2px;
|
|
2996
|
+
}
|
|
2997
|
+
.tm-link-add {
|
|
2998
|
+
margin-top: 6px;
|
|
2999
|
+
padding: 4px 10px;
|
|
3000
|
+
font: inherit; font-size: 11px;
|
|
3001
|
+
color: var(--ink-faint);
|
|
3002
|
+
background: transparent;
|
|
3003
|
+
border: 1px dashed var(--rule);
|
|
3004
|
+
border-radius: 4px;
|
|
3005
|
+
cursor: pointer;
|
|
3006
|
+
}
|
|
3007
|
+
.tm-link-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
3008
|
+
|
|
3009
|
+
/* SM-48 (combobox-inline): the Add-Link form lives INSIDE the ticket
|
|
3010
|
+
modal's Links section. No second modal — the ticket the user is editing
|
|
3011
|
+
stays visible. */
|
|
3012
|
+
.tm-link-add-wrap { margin-top: 6px; }
|
|
3013
|
+
.tm-link-add-form {
|
|
3014
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
3015
|
+
padding: 8px 10px; margin-top: 4px;
|
|
3016
|
+
background: var(--paper-warm, #F7F2E8);
|
|
3017
|
+
border: 1px solid var(--rule);
|
|
3018
|
+
border-radius: 4px;
|
|
3019
|
+
}
|
|
3020
|
+
.tm-link-add-row { display: grid; grid-template-columns: 60px 1fr; gap: 10px; align-items: center; }
|
|
3021
|
+
.tm-link-add-row .tm-label { font-size: 12px; color: var(--ink-soft); margin: 0; }
|
|
3022
|
+
.tm-link-add-row select.tm-add-link-type {
|
|
3023
|
+
font: inherit; font-size: 13px;
|
|
3024
|
+
padding: 4px 22px 4px 8px;
|
|
3025
|
+
background: var(--paper);
|
|
3026
|
+
border: 1px solid var(--rule);
|
|
3027
|
+
border-radius: 3px;
|
|
3028
|
+
}
|
|
3029
|
+
.tm-link-combo { position: relative; }
|
|
3030
|
+
.tm-link-combo input.tm-add-link-filter {
|
|
3031
|
+
font: inherit; font-size: 13px;
|
|
3032
|
+
padding: 4px 8px;
|
|
3033
|
+
width: 100%;
|
|
3034
|
+
background: var(--paper);
|
|
3035
|
+
border: 1px solid var(--rule);
|
|
3036
|
+
border-radius: 3px;
|
|
3037
|
+
box-sizing: border-box;
|
|
3038
|
+
}
|
|
3039
|
+
.tm-link-combo-popover {
|
|
3040
|
+
position: absolute;
|
|
3041
|
+
top: calc(100% + 2px);
|
|
3042
|
+
left: 0; right: 0;
|
|
3043
|
+
max-height: 200px;
|
|
3044
|
+
overflow-y: auto;
|
|
3045
|
+
background: var(--paper);
|
|
3046
|
+
border: 1px solid var(--rule);
|
|
3047
|
+
border-radius: 3px;
|
|
3048
|
+
box-shadow: 0 4px 14px rgba(0,0,0,0.12);
|
|
3049
|
+
z-index: 5;
|
|
3050
|
+
}
|
|
3051
|
+
.tm-link-combo-option {
|
|
3052
|
+
padding: 4px 8px;
|
|
3053
|
+
font-size: 12px;
|
|
3054
|
+
color: var(--ink);
|
|
3055
|
+
cursor: pointer;
|
|
3056
|
+
}
|
|
3057
|
+
.tm-link-combo-option:hover { background: var(--ink-faint-bg, #F0EBE0); }
|
|
3058
|
+
.tm-link-add-actions { display: flex; gap: 6px; justify-content: flex-end; }
|
|
3059
|
+
.tm-link-add-actions .btn { font-size: 12px; padding: 4px 12px; }
|
|
3060
|
+
.tm-link-add-submit { background: var(--accent, #0F5F4F); color: var(--paper); border-color: var(--accent, #0F5F4F); }
|
|
3061
|
+
.tm-link-add-submit:hover { filter: brightness(0.93); }
|
|
3062
|
+
|
|
3063
|
+
/* ---------------------------------------------------------------------------
|
|
3064
|
+
E21.D — Settings view
|
|
3065
|
+
--------------------------------------------------------------------------- */
|
|
3066
|
+
|
|
3067
|
+
/* E23.B — Settings as an overlay over Map/Kanban (no longer a third view).
|
|
3068
|
+
Fixed full-screen, paper-tinted backdrop, close-X in the top-right. */
|
|
3069
|
+
#settings-host.vs-overlay {
|
|
3070
|
+
position: fixed;
|
|
3071
|
+
inset: 0;
|
|
3072
|
+
z-index: 90;
|
|
3073
|
+
padding: 24px 32px;
|
|
3074
|
+
overflow-y: auto;
|
|
3075
|
+
background: rgba(245,241,234,0.96);
|
|
3076
|
+
backdrop-filter: blur(2px);
|
|
3077
|
+
-webkit-backdrop-filter: blur(2px);
|
|
3078
|
+
}
|
|
3079
|
+
#settings-host[hidden] { display: none; }
|
|
3080
|
+
.vs-overlay-close {
|
|
3081
|
+
position: fixed;
|
|
3082
|
+
top: 16px;
|
|
3083
|
+
right: 20px;
|
|
3084
|
+
z-index: 91;
|
|
3085
|
+
width: 32px;
|
|
3086
|
+
height: 32px;
|
|
3087
|
+
font: inherit;
|
|
3088
|
+
font-size: 20px;
|
|
3089
|
+
line-height: 1;
|
|
3090
|
+
color: var(--ink-soft);
|
|
3091
|
+
background: var(--paper);
|
|
3092
|
+
border: 1px solid var(--rule);
|
|
3093
|
+
border-radius: 4px;
|
|
3094
|
+
cursor: pointer;
|
|
3095
|
+
}
|
|
3096
|
+
.vs-overlay-close:hover {
|
|
3097
|
+
color: var(--ink);
|
|
3098
|
+
border-color: var(--ink-faint);
|
|
3099
|
+
}
|
|
3100
|
+
.vs-overlay-content {
|
|
3101
|
+
/* Wide enough to host 5 board columns side-by-side at 200px each
|
|
3102
|
+
(5×200 + 4×12 gap = 1048px) with breathing room on the sides. */
|
|
3103
|
+
max-width: 1200px;
|
|
3104
|
+
margin: 0 auto;
|
|
3105
|
+
}
|
|
3106
|
+
.vs-root {
|
|
3107
|
+
/* Width is governed by the outer .vs-overlay-content (1200px). Don't
|
|
3108
|
+
re-cap it here or the board section can't show 5 columns inline. */
|
|
3109
|
+
display: flex;
|
|
3110
|
+
flex-direction: column;
|
|
3111
|
+
gap: 24px;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
/* SM-41: horizontal tab-bar at the top of .vs-root. Pattern is intentionally
|
|
3115
|
+
its own (.vs-tab-bar / .vs-tab-btn) and NOT shared with .view-toggle from
|
|
3116
|
+
the toolbar — different context, different concerns. Sticky so it stays
|
|
3117
|
+
visible when the user scrolls inside a long section. */
|
|
3118
|
+
.vs-tab-bar {
|
|
3119
|
+
display: flex;
|
|
3120
|
+
flex-direction: row;
|
|
3121
|
+
gap: 0;
|
|
3122
|
+
position: sticky;
|
|
3123
|
+
top: 0;
|
|
3124
|
+
z-index: 5;
|
|
3125
|
+
background: var(--paper);
|
|
3126
|
+
border-bottom: 1px solid var(--rule);
|
|
3127
|
+
padding: 4px 0;
|
|
3128
|
+
}
|
|
3129
|
+
.vs-tab-btn {
|
|
3130
|
+
font: inherit; font-size: 13px;
|
|
3131
|
+
color: var(--ink-soft);
|
|
3132
|
+
background: transparent;
|
|
3133
|
+
border: 0;
|
|
3134
|
+
padding: 8px 14px;
|
|
3135
|
+
cursor: pointer;
|
|
3136
|
+
border-bottom: 2px solid transparent;
|
|
3137
|
+
transition: color 120ms, border-color 120ms, background 120ms;
|
|
3138
|
+
}
|
|
3139
|
+
.vs-tab-btn:hover { color: var(--ink); background: var(--paper-warm); }
|
|
3140
|
+
.vs-tab-btn.active {
|
|
3141
|
+
color: var(--ink);
|
|
3142
|
+
border-bottom-color: var(--accent);
|
|
3143
|
+
font-weight: 600;
|
|
3144
|
+
}
|
|
3145
|
+
.vs-section {
|
|
3146
|
+
border: 1px solid var(--rule);
|
|
3147
|
+
border-radius: 6px;
|
|
3148
|
+
background: var(--paper);
|
|
3149
|
+
}
|
|
3150
|
+
/* SM-41: explicit hide for tab-inactive sections. The HTML5 `hidden`
|
|
3151
|
+
attribute should imply `display:none`, but in a flex-column container
|
|
3152
|
+
browsers occasionally still reserve flex-line space / gap for hidden
|
|
3153
|
+
children. Force display:none so only one card is visible at a time —
|
|
3154
|
+
anything else makes the tabs feel like anchor links instead of real
|
|
3155
|
+
tabs. */
|
|
3156
|
+
.vs-section[hidden] { display: none !important; }
|
|
3157
|
+
.vs-section-header {
|
|
3158
|
+
padding: 16px 20px 8px;
|
|
3159
|
+
border-bottom: 1px solid var(--rule);
|
|
3160
|
+
}
|
|
3161
|
+
.vs-section-header h2 {
|
|
3162
|
+
margin: 0 0 4px;
|
|
3163
|
+
font-family: "Libre Caslon Text", Georgia, serif;
|
|
3164
|
+
font-size: 18px;
|
|
3165
|
+
font-weight: 700;
|
|
3166
|
+
color: var(--ink);
|
|
3167
|
+
}
|
|
3168
|
+
.vs-section-hint {
|
|
3169
|
+
margin: 0;
|
|
3170
|
+
font-size: 12px;
|
|
3171
|
+
color: var(--ink-soft);
|
|
3172
|
+
}
|
|
3173
|
+
.vs-section-body {
|
|
3174
|
+
padding: 16px 20px;
|
|
3175
|
+
}
|
|
3176
|
+
.vs-placeholder {
|
|
3177
|
+
margin: 0;
|
|
3178
|
+
font-size: 12px;
|
|
3179
|
+
color: var(--ink-faint);
|
|
3180
|
+
font-style: italic;
|
|
3181
|
+
}
|
|
3182
|
+
.vs-empty {
|
|
3183
|
+
text-align: center;
|
|
3184
|
+
margin: 64px 0;
|
|
3185
|
+
font-size: 13px;
|
|
3186
|
+
color: var(--ink-soft);
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
/* ---------------------------------------------------------------------------
|
|
3190
|
+
E21.E — Status editor in Settings view
|
|
3191
|
+
--------------------------------------------------------------------------- */
|
|
3192
|
+
|
|
3193
|
+
.vs-status-editor {
|
|
3194
|
+
display: flex;
|
|
3195
|
+
flex-direction: column;
|
|
3196
|
+
gap: 6px;
|
|
3197
|
+
}
|
|
3198
|
+
.vs-status-rows {
|
|
3199
|
+
display: flex;
|
|
3200
|
+
flex-direction: column;
|
|
3201
|
+
gap: 4px;
|
|
3202
|
+
}
|
|
3203
|
+
.vs-status-row {
|
|
3204
|
+
display: grid;
|
|
3205
|
+
grid-template-columns: 20px 1fr 160px 28px;
|
|
3206
|
+
align-items: center;
|
|
3207
|
+
gap: 12px;
|
|
3208
|
+
padding: 4px 6px;
|
|
3209
|
+
border: 1px solid transparent;
|
|
3210
|
+
border-radius: 4px;
|
|
3211
|
+
}
|
|
3212
|
+
.vs-status-row:hover { background: var(--ink-faint-bg, #FAF8F2); border-color: var(--rule); }
|
|
3213
|
+
.vs-status-row.vs-status-drop-target { box-shadow: inset 0 3px 0 var(--accent); }
|
|
3214
|
+
.vs-status-row.sm-dragging { opacity: 0.4; }
|
|
3215
|
+
.vs-status-row .vs-grip {
|
|
3216
|
+
color: var(--ink-faint);
|
|
3217
|
+
cursor: grab;
|
|
3218
|
+
user-select: none;
|
|
3219
|
+
font-size: 12px;
|
|
3220
|
+
text-align: center;
|
|
3221
|
+
}
|
|
3222
|
+
.vs-status-row input.vs-status-name {
|
|
3223
|
+
font: inherit;
|
|
3224
|
+
font-size: 13px;
|
|
3225
|
+
padding: 4px 8px;
|
|
3226
|
+
border: 1px solid var(--rule);
|
|
3227
|
+
border-radius: 3px;
|
|
3228
|
+
background: transparent;
|
|
3229
|
+
color: var(--ink);
|
|
3230
|
+
}
|
|
3231
|
+
.vs-status-row input.vs-status-name:focus {
|
|
3232
|
+
outline: none;
|
|
3233
|
+
border-color: var(--accent);
|
|
3234
|
+
background: var(--paper);
|
|
3235
|
+
}
|
|
3236
|
+
.vs-status-row select.vs-status-category {
|
|
3237
|
+
font: inherit;
|
|
3238
|
+
font-size: 12px;
|
|
3239
|
+
padding: 3px 24px 3px 8px;
|
|
3240
|
+
border: 1px solid var(--rule);
|
|
3241
|
+
border-radius: 3px;
|
|
3242
|
+
background: var(--paper);
|
|
3243
|
+
color: var(--ink-soft);
|
|
3244
|
+
text-transform: capitalize;
|
|
3245
|
+
appearance: auto;
|
|
3246
|
+
}
|
|
3247
|
+
.vs-status-row button.vs-status-delete {
|
|
3248
|
+
font: inherit;
|
|
3249
|
+
font-size: 16px;
|
|
3250
|
+
line-height: 1;
|
|
3251
|
+
width: 24px;
|
|
3252
|
+
height: 24px;
|
|
3253
|
+
color: var(--ink-faint);
|
|
3254
|
+
background: transparent;
|
|
3255
|
+
border: 1px solid transparent;
|
|
3256
|
+
border-radius: 3px;
|
|
3257
|
+
cursor: pointer;
|
|
3258
|
+
}
|
|
3259
|
+
.vs-status-row button.vs-status-delete:hover {
|
|
3260
|
+
color: var(--danger, #B43C3C);
|
|
3261
|
+
border-color: var(--danger, #B43C3C);
|
|
3262
|
+
}
|
|
3263
|
+
.vs-status-add {
|
|
3264
|
+
align-self: flex-start;
|
|
3265
|
+
display: inline-flex;
|
|
3266
|
+
align-items: center;
|
|
3267
|
+
gap: 4px;
|
|
3268
|
+
margin-top: 6px;
|
|
3269
|
+
padding: 4px 10px;
|
|
3270
|
+
font: inherit;
|
|
3271
|
+
font-size: 11px;
|
|
3272
|
+
color: var(--ink-faint);
|
|
3273
|
+
background: transparent;
|
|
3274
|
+
border: 1px dashed var(--rule);
|
|
3275
|
+
border-radius: 4px;
|
|
3276
|
+
cursor: pointer;
|
|
3277
|
+
}
|
|
3278
|
+
.vs-status-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
3279
|
+
|
|
3280
|
+
/* ---------------------------------------------------------------------------
|
|
3281
|
+
E21.F — Transition editor in Settings view
|
|
3282
|
+
--------------------------------------------------------------------------- */
|
|
3283
|
+
|
|
3284
|
+
.vs-subhead {
|
|
3285
|
+
font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
3286
|
+
font-size: 12px;
|
|
3287
|
+
font-weight: 600;
|
|
3288
|
+
text-transform: uppercase;
|
|
3289
|
+
letter-spacing: 0.04em;
|
|
3290
|
+
color: var(--ink-soft);
|
|
3291
|
+
margin: 20px 0 8px;
|
|
3292
|
+
padding-bottom: 4px;
|
|
3293
|
+
border-bottom: 1px solid var(--rule);
|
|
3294
|
+
}
|
|
3295
|
+
.vs-subhead:first-child { margin-top: 0; }
|
|
3296
|
+
|
|
3297
|
+
/* SM-107 — read-only "Rules per type" list */
|
|
3298
|
+
.vs-rules-type { margin-bottom: 18px; }
|
|
3299
|
+
.vs-rules-list { list-style: none; margin: 0; padding: 0; }
|
|
3300
|
+
.vs-rules-item {
|
|
3301
|
+
display: flex;
|
|
3302
|
+
align-items: baseline;
|
|
3303
|
+
gap: 8px;
|
|
3304
|
+
padding: 4px 0;
|
|
3305
|
+
font-size: 13px;
|
|
3306
|
+
}
|
|
3307
|
+
.vs-rules-item.inactive { color: var(--ink-soft); opacity: 0.7; }
|
|
3308
|
+
.vs-rules-state { width: 1em; text-align: center; flex: 0 0 auto; }
|
|
3309
|
+
.vs-rules-item.active .vs-rules-state { color: var(--accent); }
|
|
3310
|
+
.vs-rules-id {
|
|
3311
|
+
font-size: 11px;
|
|
3312
|
+
color: var(--ink-soft);
|
|
3313
|
+
background: var(--paper-dim, rgba(0,0,0,0.04));
|
|
3314
|
+
padding: 1px 5px;
|
|
3315
|
+
border-radius: 3px;
|
|
3316
|
+
flex: 0 0 auto;
|
|
3317
|
+
}
|
|
3318
|
+
.vs-rules-label { flex: 1 1 auto; }
|
|
3319
|
+
.vs-rules-na {
|
|
3320
|
+
font-size: 11px;
|
|
3321
|
+
font-style: italic;
|
|
3322
|
+
color: var(--ink-soft);
|
|
3323
|
+
flex: 0 0 auto;
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
.vs-transition-editor {
|
|
3327
|
+
display: flex;
|
|
3328
|
+
flex-direction: column;
|
|
3329
|
+
gap: 6px;
|
|
3330
|
+
}
|
|
3331
|
+
.vs-transition-rows {
|
|
3332
|
+
display: flex;
|
|
3333
|
+
flex-direction: column;
|
|
3334
|
+
gap: 8px;
|
|
3335
|
+
}
|
|
3336
|
+
.vs-transition-row {
|
|
3337
|
+
display: flex;
|
|
3338
|
+
flex-direction: column;
|
|
3339
|
+
gap: 6px;
|
|
3340
|
+
padding: 8px 10px;
|
|
3341
|
+
border: 1px solid var(--rule);
|
|
3342
|
+
border-radius: 4px;
|
|
3343
|
+
background: var(--paper);
|
|
3344
|
+
}
|
|
3345
|
+
.vs-transition-row:hover { border-color: var(--ink-faint); }
|
|
3346
|
+
.vs-transition-row.vs-transition-drop-target { box-shadow: inset 0 3px 0 var(--accent); }
|
|
3347
|
+
.vs-transition-row.sm-dragging { opacity: 0.4; }
|
|
3348
|
+
|
|
3349
|
+
.vs-transition-header {
|
|
3350
|
+
display: grid;
|
|
3351
|
+
grid-template-columns: 20px 1fr 28px;
|
|
3352
|
+
align-items: center;
|
|
3353
|
+
gap: 8px;
|
|
3354
|
+
}
|
|
3355
|
+
.vs-transition-header .vs-grip {
|
|
3356
|
+
color: var(--ink-faint);
|
|
3357
|
+
cursor: grab;
|
|
3358
|
+
user-select: none;
|
|
3359
|
+
text-align: center;
|
|
3360
|
+
font-size: 12px;
|
|
3361
|
+
}
|
|
3362
|
+
.vs-transition-row input.vs-transition-name {
|
|
3363
|
+
font: inherit;
|
|
3364
|
+
font-size: 13px;
|
|
3365
|
+
padding: 4px 8px;
|
|
3366
|
+
border: 1px solid var(--rule);
|
|
3367
|
+
border-radius: 3px;
|
|
3368
|
+
background: transparent;
|
|
3369
|
+
color: var(--ink);
|
|
3370
|
+
}
|
|
3371
|
+
.vs-transition-row input.vs-transition-name:focus {
|
|
3372
|
+
outline: none;
|
|
3373
|
+
border-color: var(--accent);
|
|
3374
|
+
background: var(--paper);
|
|
3375
|
+
}
|
|
3376
|
+
.vs-transition-row button.vs-transition-delete {
|
|
3377
|
+
font: inherit;
|
|
3378
|
+
font-size: 16px;
|
|
3379
|
+
line-height: 1;
|
|
3380
|
+
width: 24px; height: 24px;
|
|
3381
|
+
color: var(--ink-faint);
|
|
3382
|
+
background: transparent;
|
|
3383
|
+
border: 1px solid transparent;
|
|
3384
|
+
border-radius: 3px;
|
|
3385
|
+
cursor: pointer;
|
|
3386
|
+
}
|
|
3387
|
+
.vs-transition-row button.vs-transition-delete:hover {
|
|
3388
|
+
color: var(--danger, #B43C3C);
|
|
3389
|
+
border-color: var(--danger, #B43C3C);
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
.vs-transition-body {
|
|
3393
|
+
display: flex;
|
|
3394
|
+
align-items: center;
|
|
3395
|
+
flex-wrap: wrap;
|
|
3396
|
+
gap: 8px;
|
|
3397
|
+
padding-left: 28px; /* align with name input after grip */
|
|
3398
|
+
font-size: 12px;
|
|
3399
|
+
color: var(--ink-soft);
|
|
3400
|
+
}
|
|
3401
|
+
.vs-transition-arrow { font-size: 14px; color: var(--ink-faint); }
|
|
3402
|
+
.vs-transition-row select.vs-transition-target,
|
|
3403
|
+
.vs-transition-row select.vs-transition-gate {
|
|
3404
|
+
font: inherit;
|
|
3405
|
+
font-size: 12px;
|
|
3406
|
+
padding: 3px 24px 3px 8px;
|
|
3407
|
+
border: 1px solid var(--rule);
|
|
3408
|
+
border-radius: 3px;
|
|
3409
|
+
background: var(--paper);
|
|
3410
|
+
color: var(--ink);
|
|
3411
|
+
appearance: auto;
|
|
3412
|
+
}
|
|
3413
|
+
.vs-transition-gate-label { color: var(--ink-faint); }
|
|
3414
|
+
|
|
3415
|
+
.vs-transition-any-wrap {
|
|
3416
|
+
display: inline-flex;
|
|
3417
|
+
align-items: center;
|
|
3418
|
+
gap: 4px;
|
|
3419
|
+
margin-left: auto;
|
|
3420
|
+
font-size: 12px;
|
|
3421
|
+
color: var(--ink-soft);
|
|
3422
|
+
cursor: pointer;
|
|
3423
|
+
}
|
|
3424
|
+
.vs-transition-any-wrap input[type="checkbox"] { accent-color: var(--accent); }
|
|
3425
|
+
|
|
3426
|
+
.vs-transition-sources {
|
|
3427
|
+
padding-left: 28px;
|
|
3428
|
+
display: flex;
|
|
3429
|
+
flex-wrap: wrap;
|
|
3430
|
+
gap: 4px 12px;
|
|
3431
|
+
font-size: 12px;
|
|
3432
|
+
color: var(--ink-soft);
|
|
3433
|
+
}
|
|
3434
|
+
.vs-transition-sources[hidden] { display: none; }
|
|
3435
|
+
.vs-transition-sources .vs-transition-source-item {
|
|
3436
|
+
display: inline-flex;
|
|
3437
|
+
align-items: center;
|
|
3438
|
+
gap: 4px;
|
|
3439
|
+
cursor: pointer;
|
|
3440
|
+
}
|
|
3441
|
+
.vs-transition-sources input[type="checkbox"] { accent-color: var(--accent); }
|
|
3442
|
+
|
|
3443
|
+
.vs-transition-add {
|
|
3444
|
+
align-self: flex-start;
|
|
3445
|
+
display: inline-flex;
|
|
3446
|
+
align-items: center;
|
|
3447
|
+
gap: 4px;
|
|
3448
|
+
margin-top: 6px;
|
|
3449
|
+
padding: 4px 10px;
|
|
3450
|
+
font: inherit;
|
|
3451
|
+
font-size: 11px;
|
|
3452
|
+
color: var(--ink-faint);
|
|
3453
|
+
background: transparent;
|
|
3454
|
+
border: 1px dashed var(--rule);
|
|
3455
|
+
border-radius: 4px;
|
|
3456
|
+
cursor: pointer;
|
|
3457
|
+
}
|
|
3458
|
+
.vs-transition-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
3459
|
+
|
|
3460
|
+
/* ---------------------------------------------------------------------------
|
|
3461
|
+
E21.G — Board (Kanban-Column) editor in Settings view
|
|
3462
|
+
--------------------------------------------------------------------------- */
|
|
3463
|
+
|
|
3464
|
+
.vs-board-editor {
|
|
3465
|
+
display: flex;
|
|
3466
|
+
flex-direction: column;
|
|
3467
|
+
gap: 16px;
|
|
3468
|
+
}
|
|
3469
|
+
.vs-board-unassigned {
|
|
3470
|
+
padding: 10px 12px;
|
|
3471
|
+
border: 1px dashed var(--rule);
|
|
3472
|
+
border-radius: 4px;
|
|
3473
|
+
background: rgba(218,215,209,0.18);
|
|
3474
|
+
}
|
|
3475
|
+
.vs-board-unassigned-label {
|
|
3476
|
+
font-size: 11px;
|
|
3477
|
+
text-transform: uppercase;
|
|
3478
|
+
letter-spacing: 0.04em;
|
|
3479
|
+
color: var(--ink-soft);
|
|
3480
|
+
margin-bottom: 6px;
|
|
3481
|
+
}
|
|
3482
|
+
.vs-board-unassigned.vs-board-drop-target {
|
|
3483
|
+
box-shadow: inset 0 0 0 2px var(--accent);
|
|
3484
|
+
background: var(--accent-soft, rgba(15,95,79,0.06));
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
.vs-board-columns {
|
|
3488
|
+
/* Wrap columns at fixed 200px so a row that breaks (e.g. 6th column on
|
|
3489
|
+
a 1200px-wide overlay) doesn't stretch to fill the remaining row —
|
|
3490
|
+
it keeps the same lane width as every sibling. */
|
|
3491
|
+
display: flex;
|
|
3492
|
+
gap: 12px;
|
|
3493
|
+
flex-wrap: wrap;
|
|
3494
|
+
/* Pin row direction so the start-aligned items wrap cleanly. */
|
|
3495
|
+
align-items: flex-start;
|
|
3496
|
+
}
|
|
3497
|
+
.vs-board-column {
|
|
3498
|
+
flex: 0 0 200px; /* don't grow, don't shrink — uniform lane width */
|
|
3499
|
+
width: 200px;
|
|
3500
|
+
display: flex;
|
|
3501
|
+
flex-direction: column;
|
|
3502
|
+
gap: 8px;
|
|
3503
|
+
padding: 10px;
|
|
3504
|
+
border: 1px solid var(--rule);
|
|
3505
|
+
border-radius: 4px;
|
|
3506
|
+
background: var(--paper);
|
|
3507
|
+
}
|
|
3508
|
+
.vs-board-column.vs-board-drop-target {
|
|
3509
|
+
border-color: var(--accent);
|
|
3510
|
+
box-shadow: inset 0 0 0 1px var(--accent);
|
|
3511
|
+
}
|
|
3512
|
+
.vs-board-column-header {
|
|
3513
|
+
display: grid;
|
|
3514
|
+
/* minmax(0, 1fr) prevents the input's implicit min-content size from
|
|
3515
|
+
pushing the grid track wider than the lane — without it, a long
|
|
3516
|
+
status name in the input made the delete X overflow the card. */
|
|
3517
|
+
grid-template-columns: minmax(0, 1fr) 24px;
|
|
3518
|
+
gap: 8px;
|
|
3519
|
+
align-items: center;
|
|
3520
|
+
}
|
|
3521
|
+
.vs-board-column input.vs-board-column-name {
|
|
3522
|
+
font: inherit;
|
|
3523
|
+
font-size: 13px;
|
|
3524
|
+
font-weight: 600;
|
|
3525
|
+
padding: 4px 8px;
|
|
3526
|
+
border: 1px solid var(--rule);
|
|
3527
|
+
border-radius: 3px;
|
|
3528
|
+
background: transparent;
|
|
3529
|
+
color: var(--ink);
|
|
3530
|
+
/* Belt-and-suspenders with the grid track above: tell the input it's
|
|
3531
|
+
OK to be narrower than its content. */
|
|
3532
|
+
min-width: 0;
|
|
3533
|
+
width: 100%;
|
|
3534
|
+
}
|
|
3535
|
+
.vs-board-column input.vs-board-column-name:focus {
|
|
3536
|
+
outline: none;
|
|
3537
|
+
border-color: var(--accent);
|
|
3538
|
+
background: var(--paper);
|
|
3539
|
+
}
|
|
3540
|
+
.vs-board-column button.vs-board-column-delete {
|
|
3541
|
+
font: inherit;
|
|
3542
|
+
font-size: 14px;
|
|
3543
|
+
line-height: 1;
|
|
3544
|
+
width: 22px;
|
|
3545
|
+
height: 22px;
|
|
3546
|
+
color: var(--ink-faint);
|
|
3547
|
+
background: transparent;
|
|
3548
|
+
border: 1px solid transparent;
|
|
3549
|
+
border-radius: 3px;
|
|
3550
|
+
cursor: pointer;
|
|
3551
|
+
}
|
|
3552
|
+
.vs-board-column button.vs-board-column-delete:hover {
|
|
3553
|
+
color: var(--danger, #B43C3C);
|
|
3554
|
+
border-color: var(--danger, #B43C3C);
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
.vs-board-chips {
|
|
3558
|
+
display: flex;
|
|
3559
|
+
flex-wrap: wrap;
|
|
3560
|
+
gap: 4px;
|
|
3561
|
+
min-height: 30px;
|
|
3562
|
+
padding: 4px;
|
|
3563
|
+
border: 1px dashed transparent;
|
|
3564
|
+
border-radius: 3px;
|
|
3565
|
+
}
|
|
3566
|
+
.vs-board-column .vs-board-chips:empty::before {
|
|
3567
|
+
content: "Drop a status here";
|
|
3568
|
+
color: var(--ink-faint);
|
|
3569
|
+
font-style: italic;
|
|
3570
|
+
font-size: 11px;
|
|
3571
|
+
padding: 2px 4px;
|
|
3572
|
+
}
|
|
3573
|
+
.vs-board-chip {
|
|
3574
|
+
display: inline-flex;
|
|
3575
|
+
align-items: center;
|
|
3576
|
+
padding: 3px 8px;
|
|
3577
|
+
font-size: 11px;
|
|
3578
|
+
font-weight: 500;
|
|
3579
|
+
color: var(--ink);
|
|
3580
|
+
background: var(--paper-warm);
|
|
3581
|
+
border: 1px solid var(--rule);
|
|
3582
|
+
border-radius: 999px;
|
|
3583
|
+
cursor: grab;
|
|
3584
|
+
}
|
|
3585
|
+
.vs-board-chip.sm-dragging { opacity: 0.4; }
|
|
3586
|
+
.vs-board-empty {
|
|
3587
|
+
font-style: italic;
|
|
3588
|
+
font-size: 11px;
|
|
3589
|
+
color: var(--ink-faint);
|
|
3590
|
+
padding: 2px 4px;
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
.vs-board-add-column {
|
|
3594
|
+
align-self: flex-start;
|
|
3595
|
+
display: inline-flex;
|
|
3596
|
+
align-items: center;
|
|
3597
|
+
gap: 4px;
|
|
3598
|
+
padding: 4px 10px;
|
|
3599
|
+
font: inherit;
|
|
3600
|
+
font-size: 11px;
|
|
3601
|
+
color: var(--ink-faint);
|
|
3602
|
+
background: transparent;
|
|
3603
|
+
border: 1px dashed var(--rule);
|
|
3604
|
+
border-radius: 4px;
|
|
3605
|
+
cursor: pointer;
|
|
3606
|
+
}
|
|
3607
|
+
.vs-board-add-column:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
3608
|
+
|
|
3609
|
+
/* ---------------------------------------------------------------------------
|
|
3610
|
+
E24 — card animations for MCP/WS-driven changes (FLIP + pulse)
|
|
3611
|
+
--------------------------------------------------------------------------- */
|
|
3612
|
+
|
|
3613
|
+
/* Pulse: brief accent-toned glow on cards whose non-position fields just
|
|
3614
|
+
changed via an external commit (MCP, second browser, …). Matches the
|
|
3615
|
+
--accent green so it stays on-theme; rendered with box-shadow so it
|
|
3616
|
+
doesn't shift layout. */
|
|
3617
|
+
@keyframes sm-card-flash {
|
|
3618
|
+
0% { box-shadow: 0 0 0 0 rgba(15, 95, 79, 0.0); }
|
|
3619
|
+
20% { box-shadow: 0 0 0 6px rgba(15, 95, 79, 0.35); }
|
|
3620
|
+
100% { box-shadow: 0 0 0 12px rgba(15, 95, 79, 0.0); }
|
|
3621
|
+
}
|
|
3622
|
+
/* SM-20: the pulse must reach every entity type that the Story-Map renderer
|
|
3623
|
+
registers for animation (tickets/epics/process-steps/releases). Until this
|
|
3624
|
+
was widened, only `.sm-story-card.sm-card-flash` triggered the keyframe,
|
|
3625
|
+
so MCP-driven moves on epic cards, backbone columns, and release rows
|
|
3626
|
+
looked like instant rerenders. The .sm-card-flash class is the single
|
|
3627
|
+
write-target the card-animate helper uses; binding the keyframe to it
|
|
3628
|
+
generically covers everything. */
|
|
3629
|
+
.sm-card-flash {
|
|
3630
|
+
animation: sm-card-flash 900ms ease-out;
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
/* The FLIP helper sets inline `transform: translate(...)` + `transition`,
|
|
3634
|
+
so no CSS rule is needed beyond willChange for performance — but we
|
|
3635
|
+
don't add will-change globally to avoid GPU layer thrash. */
|
|
3636
|
+
|
|
3637
|
+
/* ---------------------------------------------------------------------------
|
|
3638
|
+
SM-47 — Link-Types editor in Settings view
|
|
3639
|
+
--------------------------------------------------------------------------- */
|
|
3640
|
+
|
|
3641
|
+
.vs-linktypes-editor {
|
|
3642
|
+
display: flex;
|
|
3643
|
+
flex-direction: column;
|
|
3644
|
+
gap: 4px;
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
.vs-linktype-row {
|
|
3648
|
+
display: grid;
|
|
3649
|
+
grid-template-columns: 140px 1fr 1fr 140px 36px 28px;
|
|
3650
|
+
align-items: center;
|
|
3651
|
+
gap: 12px;
|
|
3652
|
+
padding: 6px 8px;
|
|
3653
|
+
border: 1px solid transparent;
|
|
3654
|
+
border-radius: 4px;
|
|
3655
|
+
}
|
|
3656
|
+
.vs-linktype-row:hover { background: var(--ink-faint-bg, #FAF8F2); border-color: var(--rule); }
|
|
3657
|
+
.vs-linktype-row.vs-linktype-head:hover { background: transparent; border-color: transparent; }
|
|
3658
|
+
.vs-linktype-head {
|
|
3659
|
+
font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
3660
|
+
font-size: 10px;
|
|
3661
|
+
text-transform: uppercase;
|
|
3662
|
+
letter-spacing: 0.04em;
|
|
3663
|
+
color: var(--ink-soft);
|
|
3664
|
+
padding-bottom: 2px;
|
|
3665
|
+
}
|
|
3666
|
+
.vs-linktype-head .vs-linktype-id { color: var(--ink-soft); cursor: default; }
|
|
3667
|
+
.vs-linktype-id {
|
|
3668
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3669
|
+
font-size: 11px;
|
|
3670
|
+
color: var(--ink-soft);
|
|
3671
|
+
overflow: hidden;
|
|
3672
|
+
text-overflow: ellipsis;
|
|
3673
|
+
white-space: nowrap;
|
|
3674
|
+
cursor: help;
|
|
3675
|
+
}
|
|
3676
|
+
.vs-linktype-row input.vs-linktype-label,
|
|
3677
|
+
.vs-linktype-row input.vs-linktype-inverse {
|
|
3678
|
+
font: inherit;
|
|
3679
|
+
font-size: 13px;
|
|
3680
|
+
padding: 4px 8px;
|
|
3681
|
+
border: 1px solid transparent;
|
|
3682
|
+
border-radius: 3px;
|
|
3683
|
+
background: transparent;
|
|
3684
|
+
color: var(--ink);
|
|
3685
|
+
width: 100%;
|
|
3686
|
+
box-sizing: border-box;
|
|
3687
|
+
}
|
|
3688
|
+
.vs-linktype-row input.vs-linktype-label:hover,
|
|
3689
|
+
.vs-linktype-row input.vs-linktype-inverse:hover { border-color: var(--rule); }
|
|
3690
|
+
.vs-linktype-row input.vs-linktype-label:focus,
|
|
3691
|
+
.vs-linktype-row input.vs-linktype-inverse:focus {
|
|
3692
|
+
outline: none;
|
|
3693
|
+
border-color: var(--accent);
|
|
3694
|
+
background: var(--paper);
|
|
3695
|
+
}
|
|
3696
|
+
.vs-linktype-row select.vs-linktype-semantic {
|
|
3697
|
+
font: inherit;
|
|
3698
|
+
font-size: 12px;
|
|
3699
|
+
padding: 4px 24px 4px 8px;
|
|
3700
|
+
background: var(--paper);
|
|
3701
|
+
border: 1px solid var(--rule);
|
|
3702
|
+
border-radius: 3px;
|
|
3703
|
+
color: var(--ink);
|
|
3704
|
+
}
|
|
3705
|
+
.vs-linktype-row input.vs-linktype-color {
|
|
3706
|
+
width: 32px;
|
|
3707
|
+
height: 24px;
|
|
3708
|
+
padding: 0;
|
|
3709
|
+
border: 1px solid var(--rule);
|
|
3710
|
+
border-radius: 3px;
|
|
3711
|
+
background: transparent;
|
|
3712
|
+
cursor: pointer;
|
|
3713
|
+
}
|
|
3714
|
+
.vs-linktype-row button.vs-linktype-delete {
|
|
3715
|
+
width: 24px;
|
|
3716
|
+
height: 24px;
|
|
3717
|
+
display: inline-flex;
|
|
3718
|
+
align-items: center;
|
|
3719
|
+
justify-content: center;
|
|
3720
|
+
font-size: 16px;
|
|
3721
|
+
line-height: 1;
|
|
3722
|
+
color: var(--ink-faint);
|
|
3723
|
+
background: transparent;
|
|
3724
|
+
border: 1px solid transparent;
|
|
3725
|
+
border-radius: 3px;
|
|
3726
|
+
cursor: pointer;
|
|
3727
|
+
padding: 0;
|
|
3728
|
+
}
|
|
3729
|
+
.vs-linktype-row button.vs-linktype-delete:hover {
|
|
3730
|
+
color: var(--danger, #B33A3A);
|
|
3731
|
+
border-color: var(--danger, #B33A3A);
|
|
3732
|
+
}
|
|
3733
|
+
.vs-linktype-col-label { font: inherit; }
|
|
3734
|
+
|
|
3735
|
+
.vs-linktype-add-wrap { margin-top: 8px; }
|
|
3736
|
+
.vs-linktype-add {
|
|
3737
|
+
display: inline-flex;
|
|
3738
|
+
align-items: center;
|
|
3739
|
+
gap: 4px;
|
|
3740
|
+
padding: 4px 10px;
|
|
3741
|
+
font: inherit;
|
|
3742
|
+
font-size: 11px;
|
|
3743
|
+
color: var(--ink-faint);
|
|
3744
|
+
background: transparent;
|
|
3745
|
+
border: 1px dashed var(--rule);
|
|
3746
|
+
border-radius: 4px;
|
|
3747
|
+
cursor: pointer;
|
|
3748
|
+
}
|
|
3749
|
+
.vs-linktype-add:hover { color: var(--ink); border-style: solid; border-color: var(--ink-faint); }
|
|
3750
|
+
|
|
3751
|
+
/* ---------------------------------------------------------------------------
|
|
3752
|
+
SM-7 — Ticket-Types editor in Settings view
|
|
3753
|
+
--------------------------------------------------------------------------- */
|
|
3754
|
+
|
|
3755
|
+
.vs-tickettypes-editor { display: flex; flex-direction: column; gap: 4px; }
|
|
3756
|
+
.vs-tickettype-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
3757
|
+
.vs-tickettype-row {
|
|
3758
|
+
display: grid;
|
|
3759
|
+
grid-template-columns: 20px 1fr 28px;
|
|
3760
|
+
align-items: center;
|
|
3761
|
+
gap: 12px;
|
|
3762
|
+
padding: 6px 8px;
|
|
3763
|
+
border: 1px solid transparent;
|
|
3764
|
+
border-radius: 4px;
|
|
3765
|
+
}
|
|
3766
|
+
.vs-tickettype-row:hover { background: var(--ink-faint-bg, #FAF8F2); border-color: var(--rule); }
|
|
3767
|
+
.vs-tickettype-row.vs-tickettype-drop-target { box-shadow: inset 0 3px 0 var(--accent); }
|
|
3768
|
+
.vs-tickettype-row.sm-dragging { opacity: 0.4; }
|
|
3769
|
+
.vs-tickettype-row input.vs-tickettype-name {
|
|
3770
|
+
font: inherit;
|
|
3771
|
+
font-size: 13px;
|
|
3772
|
+
padding: 4px 8px;
|
|
3773
|
+
border: 1px solid transparent;
|
|
3774
|
+
border-radius: 3px;
|
|
3775
|
+
background: transparent;
|
|
3776
|
+
color: var(--ink);
|
|
3777
|
+
}
|
|
3778
|
+
.vs-tickettype-row input.vs-tickettype-name:hover { border-color: var(--rule); }
|
|
3779
|
+
.vs-tickettype-row input.vs-tickettype-name:focus {
|
|
3780
|
+
outline: none; border-color: var(--accent); background: var(--paper);
|
|
3781
|
+
}
|
|
3782
|
+
.vs-tickettype-row button.vs-tickettype-delete {
|
|
3783
|
+
width: 24px; height: 24px;
|
|
3784
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
3785
|
+
font-size: 16px; line-height: 1;
|
|
3786
|
+
color: var(--ink-faint);
|
|
3787
|
+
background: transparent;
|
|
3788
|
+
border: 1px solid transparent;
|
|
3789
|
+
border-radius: 3px;
|
|
3790
|
+
cursor: pointer; padding: 0;
|
|
3791
|
+
}
|
|
3792
|
+
.vs-tickettype-row button.vs-tickettype-delete:hover {
|
|
3793
|
+
color: var(--danger, #B33A3A); border-color: var(--danger, #B33A3A);
|
|
3794
|
+
}
|
|
3795
|
+
.vs-tickettype-add, .vs-label-add {
|
|
3796
|
+
align-self: flex-start;
|
|
3797
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
3798
|
+
margin-top: 8px; padding: 4px 10px;
|
|
3799
|
+
font: inherit; font-size: 11px;
|
|
3800
|
+
color: var(--ink-faint);
|
|
3801
|
+
background: transparent;
|
|
3802
|
+
border: 1px dashed var(--rule);
|
|
3803
|
+
border-radius: 4px;
|
|
3804
|
+
cursor: pointer;
|
|
3805
|
+
}
|
|
3806
|
+
.vs-tickettype-add:hover, .vs-label-add:hover {
|
|
3807
|
+
color: var(--ink); border-style: solid; border-color: var(--ink-faint);
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
/* ---------------------------------------------------------------------------
|
|
3811
|
+
SM-8 — Labels editor in Settings view
|
|
3812
|
+
--------------------------------------------------------------------------- */
|
|
3813
|
+
|
|
3814
|
+
.vs-labels-editor { display: flex; flex-direction: column; gap: 4px; }
|
|
3815
|
+
.vs-label-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
3816
|
+
.vs-label-row {
|
|
3817
|
+
display: grid;
|
|
3818
|
+
grid-template-columns: 20px 18px 1fr 36px 28px;
|
|
3819
|
+
align-items: center;
|
|
3820
|
+
gap: 10px;
|
|
3821
|
+
padding: 6px 8px;
|
|
3822
|
+
border: 1px solid transparent;
|
|
3823
|
+
border-radius: 4px;
|
|
3824
|
+
}
|
|
3825
|
+
.vs-label-row:hover { background: var(--ink-faint-bg, #FAF8F2); border-color: var(--rule); }
|
|
3826
|
+
.vs-label-row.vs-label-drop-target { box-shadow: inset 0 3px 0 var(--accent); }
|
|
3827
|
+
.vs-label-row.sm-dragging { opacity: 0.4; }
|
|
3828
|
+
.vs-label-swatch {
|
|
3829
|
+
width: 14px; height: 14px;
|
|
3830
|
+
border-radius: 50%;
|
|
3831
|
+
border: 1px solid var(--rule);
|
|
3832
|
+
display: inline-block;
|
|
3833
|
+
}
|
|
3834
|
+
.vs-label-row input.vs-label-name {
|
|
3835
|
+
font: inherit; font-size: 13px;
|
|
3836
|
+
padding: 4px 8px;
|
|
3837
|
+
border: 1px solid transparent;
|
|
3838
|
+
border-radius: 3px;
|
|
3839
|
+
background: transparent;
|
|
3840
|
+
color: var(--ink);
|
|
3841
|
+
}
|
|
3842
|
+
.vs-label-row input.vs-label-name:hover { border-color: var(--rule); }
|
|
3843
|
+
.vs-label-row input.vs-label-name:focus {
|
|
3844
|
+
outline: none; border-color: var(--accent); background: var(--paper);
|
|
3845
|
+
}
|
|
3846
|
+
.vs-label-row input.vs-label-color {
|
|
3847
|
+
width: 32px; height: 24px;
|
|
3848
|
+
padding: 0;
|
|
3849
|
+
border: 1px solid var(--rule);
|
|
3850
|
+
border-radius: 3px;
|
|
3851
|
+
background: transparent;
|
|
3852
|
+
cursor: pointer;
|
|
3853
|
+
}
|
|
3854
|
+
.vs-label-row button.vs-label-delete {
|
|
3855
|
+
width: 24px; height: 24px;
|
|
3856
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
3857
|
+
font-size: 16px; line-height: 1;
|
|
3858
|
+
color: var(--ink-faint);
|
|
3859
|
+
background: transparent;
|
|
3860
|
+
border: 1px solid transparent;
|
|
3861
|
+
border-radius: 3px;
|
|
3862
|
+
cursor: pointer; padding: 0;
|
|
3863
|
+
}
|
|
3864
|
+
.vs-label-row button.vs-label-delete:hover {
|
|
3865
|
+
color: var(--danger, #B33A3A); border-color: var(--danger, #B33A3A);
|
|
3866
|
+
}
|
|
3867
|
+
|
|
3868
|
+
.vs-empty { color: var(--ink-faint); font-style: italic; padding: 6px 2px; font-size: 12px; }
|
|
3869
|
+
|
|
3870
|
+
/* ============================================================
|
|
3871
|
+
SM-50 — Dependencies View
|
|
3872
|
+
============================================================ */
|
|
3873
|
+
|
|
3874
|
+
#deps-host {
|
|
3875
|
+
position: relative;
|
|
3876
|
+
width: 100%;
|
|
3877
|
+
height: 100%;
|
|
3878
|
+
overflow: auto;
|
|
3879
|
+
background: var(--paper);
|
|
3880
|
+
}
|
|
3881
|
+
.deps-root {
|
|
3882
|
+
display: flex;
|
|
3883
|
+
flex-direction: column;
|
|
3884
|
+
min-height: 100%;
|
|
3885
|
+
}
|
|
3886
|
+
.deps-toolbar {
|
|
3887
|
+
display: flex;
|
|
3888
|
+
gap: 10px;
|
|
3889
|
+
align-items: center;
|
|
3890
|
+
padding: 10px 14px;
|
|
3891
|
+
border-bottom: 1px solid var(--rule);
|
|
3892
|
+
background: var(--paper-warm, var(--paper));
|
|
3893
|
+
position: sticky;
|
|
3894
|
+
top: 0;
|
|
3895
|
+
z-index: 2;
|
|
3896
|
+
}
|
|
3897
|
+
.deps-toolbar select,
|
|
3898
|
+
.deps-toolbar input[type="search"] {
|
|
3899
|
+
font: inherit;
|
|
3900
|
+
font-size: 12px;
|
|
3901
|
+
padding: 4px 8px;
|
|
3902
|
+
border: 1px solid var(--rule);
|
|
3903
|
+
border-radius: 4px;
|
|
3904
|
+
background: var(--paper);
|
|
3905
|
+
color: var(--ink);
|
|
3906
|
+
}
|
|
3907
|
+
.deps-toolbar input[type="search"] {
|
|
3908
|
+
min-width: 220px;
|
|
3909
|
+
}
|
|
3910
|
+
.deps-canvas {
|
|
3911
|
+
flex: 1;
|
|
3912
|
+
overflow: auto;
|
|
3913
|
+
padding: 0;
|
|
3914
|
+
position: relative; /* SM-161: coordinate root for SVG edges + HTML nodes */
|
|
3915
|
+
}
|
|
3916
|
+
.deps-svg {
|
|
3917
|
+
display: block;
|
|
3918
|
+
font-family: inherit;
|
|
3919
|
+
}
|
|
3920
|
+
|
|
3921
|
+
/* ----- Nodes: the SHARED story-cards (SM-161) --------------- */
|
|
3922
|
+
/* The .deps-node wrapper is absolutely positioned (inline left/top/width) and
|
|
3923
|
+
carries the hover/critical/band hooks; the .sm-story-card inside provides the
|
|
3924
|
+
visuals (cluster border, status pill, badges) + the ticket-key editor link. */
|
|
3925
|
+
.deps-node {
|
|
3926
|
+
transition: opacity 120ms ease, filter 120ms ease;
|
|
3927
|
+
}
|
|
3928
|
+
.deps-node .sm-story-card { width: 100% !important; box-sizing: border-box; }
|
|
3929
|
+
|
|
3930
|
+
/* ----- Hover-highlight: ring the hovered + its up/down chain ----- */
|
|
3931
|
+
.deps-node-hovered .sm-story-card {
|
|
3932
|
+
box-shadow: 0 0 0 2px var(--accent, #0F5F4F), 0 2px 8px rgba(15,95,79,0.18);
|
|
3933
|
+
}
|
|
3934
|
+
.deps-node-pred .sm-story-card { box-shadow: 0 0 0 2px #6B8E9B; }
|
|
3935
|
+
.deps-node-succ .sm-story-card { box-shadow: 0 0 0 2px #B88B4A; }
|
|
3936
|
+
/* Dim non-neighbours only while a node is ACTIVELY hovered (JS toggles
|
|
3937
|
+
.deps-hover-active on the canvas). Edges sit in the gaps, not behind card
|
|
3938
|
+
bodies, so a light opacity fade reads cleanly. */
|
|
3939
|
+
.deps-canvas.deps-hover-active .deps-node:not(.deps-node-hovered):not(.deps-node-pred):not(.deps-node-succ) {
|
|
3940
|
+
opacity: 0.4;
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
/* ----- Edges ----------------------------------------------- */
|
|
3944
|
+
/* SM-64-followup: no opacity on edges either — opacity blends edges that
|
|
3945
|
+
pass behind nodes "through" them visually. Use a mid-tone stroke colour
|
|
3946
|
+
as the baseline; semantic-class strokes override per type. */
|
|
3947
|
+
.deps-edge {
|
|
3948
|
+
stroke: #C2B9A5;
|
|
3949
|
+
transition: stroke 120ms ease, stroke-width 120ms ease;
|
|
3950
|
+
}
|
|
3951
|
+
.deps-edge-active {
|
|
3952
|
+
stroke-width: 2.5;
|
|
3953
|
+
}
|
|
3954
|
+
/* Semantic-driven dashes/colour for read-at-a-glance. */
|
|
3955
|
+
.deps-edge-precedence { stroke: var(--accent, #0F5F4F); }
|
|
3956
|
+
.deps-edge-blocking { stroke: #B85C5C; stroke-dasharray: 6 4; }
|
|
3957
|
+
.deps-edge-sequence { stroke: var(--accent, #0F5F4F); stroke-dasharray: 2 4; }
|
|
3958
|
+
.deps-edge-containment { stroke: #B9A0B5; }
|
|
3959
|
+
.deps-edge-validation { stroke: #2E4665; stroke-dasharray: 4 3; }
|
|
3960
|
+
.deps-edge-freeform { stroke: #C2B9A5; }
|
|
3961
|
+
/* Dimmed semantic strokes when SVG is in hover-active mode + edge is
|
|
3962
|
+
not part of the highlighted closure. Pure colour shift, no opacity. */
|
|
3963
|
+
.deps-canvas.deps-hover-active .deps-edge:not(.deps-edge-active):not(.deps-edge-critical) {
|
|
3964
|
+
stroke: #D8D1BE;
|
|
3965
|
+
}
|
|
3966
|
+
|
|
3967
|
+
/* ---------------------------------------------------------------------------
|
|
3968
|
+
SM-50 follow-up — Dep-View separator + isolated-band styling
|
|
3969
|
+
--------------------------------------------------------------------------- */
|
|
3970
|
+
|
|
3971
|
+
.deps-band-separator { stroke: #C7BFAE; }
|
|
3972
|
+
.deps-band-separator-label {
|
|
3973
|
+
font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
3974
|
+
font-size: 11px;
|
|
3975
|
+
font-weight: 600;
|
|
3976
|
+
text-transform: uppercase;
|
|
3977
|
+
letter-spacing: 0.06em;
|
|
3978
|
+
fill: var(--ink-soft, #717071);
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3981
|
+
/* SM-161: isolated nodes read dimmer than the connected backbone (the card
|
|
3982
|
+
itself is unchanged; the wrapper mutes it). */
|
|
3983
|
+
.deps-node-band-isolated { opacity: 0.72; }
|
|
3984
|
+
|
|
3985
|
+
/* ---------------------------------------------------------------------------
|
|
3986
|
+
SM-64 — Analysis controls in the deps-toolbar + critical-path highlight
|
|
3987
|
+
--------------------------------------------------------------------------- */
|
|
3988
|
+
|
|
3989
|
+
/* Critical-path overlay: a warm red ring around the card + a thick red edge so
|
|
3990
|
+
the chain reads through everything. SM-161: ring the card via box-shadow. */
|
|
3991
|
+
.deps-node-critical .sm-story-card {
|
|
3992
|
+
box-shadow: 0 0 0 3px #B85C5C, 0 2px 8px rgba(184,92,92,0.18);
|
|
3993
|
+
}
|
|
3994
|
+
.deps-edge-critical {
|
|
3995
|
+
stroke: #B85C5C !important;
|
|
3996
|
+
stroke-width: 2.5 !important;
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
/* SM-64-followup: containing epic of any critical-path ticket — dashed-ish
|
|
4000
|
+
red accent so it reads as "context" rather than "on the path". */
|
|
4001
|
+
.deps-node-critical-context .sm-story-card {
|
|
4002
|
+
box-shadow: 0 0 0 2px rgba(184,92,92,0.55);
|
|
4003
|
+
}
|
|
4004
|
+
|
|
4005
|
+
/* ----- Status / type legend ------------------------------------------ */
|
|
4006
|
+
.deps-legend {
|
|
4007
|
+
display: flex;
|
|
4008
|
+
align-items: center;
|
|
4009
|
+
gap: 14px;
|
|
4010
|
+
margin-left: auto;
|
|
4011
|
+
padding-right: 8px;
|
|
4012
|
+
font-size: 11px;
|
|
4013
|
+
color: var(--ink-soft);
|
|
4014
|
+
}
|
|
4015
|
+
.deps-legend-item { display: inline-flex; align-items: center; gap: 5px; }
|
|
4016
|
+
.deps-legend-swatch {
|
|
4017
|
+
display: inline-block;
|
|
4018
|
+
width: 14px; height: 10px;
|
|
4019
|
+
border-radius: 3px;
|
|
4020
|
+
background: var(--paper);
|
|
4021
|
+
border: 2px solid var(--rule);
|
|
4022
|
+
box-sizing: border-box;
|
|
4023
|
+
}
|
|
4024
|
+
.deps-legend-swatch.legend-todo { border-color: #B0AAA0; }
|
|
4025
|
+
.deps-legend-swatch.legend-doing { border-color: var(--accent, #0F5F4F); }
|
|
4026
|
+
.deps-legend-swatch.legend-blocked { border-color: #B85C5C; }
|
|
4027
|
+
.deps-legend-swatch.legend-done { border-color: #4F7A4F; background: #F0EBE0; }
|
|
4028
|
+
.deps-legend-swatch.legend-critical { border-color: #B85C5C; border-width: 3px; }
|
|
4029
|
+
.deps-legend-swatch.legend-context { border-color: #B85C5C; border-style: dashed; }
|
|
4030
|
+
|
|
4031
|
+
/* Vertical hairline between toolbar control groups. Inherits the same rule
|
|
4032
|
+
colour as everything else in the toolbar. */
|
|
4033
|
+
.deps-toolbar .deps-toolbar-divider {
|
|
4034
|
+
display: inline-block;
|
|
4035
|
+
width: 1px;
|
|
4036
|
+
align-self: stretch;
|
|
4037
|
+
background: var(--rule);
|
|
4038
|
+
margin: 4px 4px;
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
/* Buttons in the deps-toolbar — match the .btn convention but live in their
|
|
4042
|
+
own namespace so they don't bleed into the main toolbar styling. */
|
|
4043
|
+
.deps-toolbar-action {
|
|
4044
|
+
font: inherit;
|
|
4045
|
+
font-size: 12px;
|
|
4046
|
+
padding: 4px 10px;
|
|
4047
|
+
border: 1px solid var(--rule);
|
|
4048
|
+
border-radius: 4px;
|
|
4049
|
+
background: var(--paper);
|
|
4050
|
+
color: var(--ink);
|
|
4051
|
+
cursor: pointer;
|
|
4052
|
+
}
|
|
4053
|
+
.deps-toolbar-action:hover {
|
|
4054
|
+
background: var(--paper-warm, var(--paper));
|
|
4055
|
+
}
|
|
4056
|
+
.deps-toolbar-action.toggled {
|
|
4057
|
+
background: var(--accent, #0F5F4F);
|
|
4058
|
+
color: var(--paper);
|
|
4059
|
+
border-color: var(--accent, #0F5F4F);
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
/* ---------------------------------------------------------------------------
|
|
4063
|
+
SM-9 — Type Config editor in Settings view
|
|
4064
|
+
--------------------------------------------------------------------------- */
|
|
4065
|
+
|
|
4066
|
+
.vs-typeconfig-editor { display: flex; flex-direction: column; gap: 14px; }
|
|
4067
|
+
.vs-typeconfig-picker-row {
|
|
4068
|
+
display: grid;
|
|
4069
|
+
grid-template-columns: 60px 1fr;
|
|
4070
|
+
gap: 12px;
|
|
4071
|
+
align-items: center;
|
|
4072
|
+
}
|
|
4073
|
+
.vs-typeconfig-picker-row .tm-label { font-size: 12px; color: var(--ink-soft); margin: 0; }
|
|
4074
|
+
.vs-typeconfig-type-select {
|
|
4075
|
+
font: inherit; font-size: 13px;
|
|
4076
|
+
padding: 4px 22px 4px 8px;
|
|
4077
|
+
background: var(--paper);
|
|
4078
|
+
border: 1px solid var(--rule);
|
|
4079
|
+
border-radius: 3px;
|
|
4080
|
+
max-width: 280px;
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
.vs-typeconfig-flags { display: flex; flex-direction: column; gap: 10px; }
|
|
4084
|
+
.vs-typeconfig-flag {
|
|
4085
|
+
display: flex; flex-direction: column; gap: 2px;
|
|
4086
|
+
padding: 8px 10px;
|
|
4087
|
+
border: 1px solid var(--rule);
|
|
4088
|
+
border-radius: 4px;
|
|
4089
|
+
background: var(--paper);
|
|
4090
|
+
}
|
|
4091
|
+
.vs-typeconfig-flag-label {
|
|
4092
|
+
display: inline-flex; align-items: center; gap: 8px;
|
|
4093
|
+
cursor: pointer;
|
|
4094
|
+
font-size: 13px;
|
|
4095
|
+
}
|
|
4096
|
+
.vs-typeconfig-flag-input { margin: 0; cursor: pointer; }
|
|
4097
|
+
.vs-typeconfig-flag-text { color: var(--ink); }
|
|
4098
|
+
.vs-typeconfig-flag-hint {
|
|
4099
|
+
font-size: 11px;
|
|
4100
|
+
color: var(--ink-soft);
|
|
4101
|
+
margin-left: 22px;
|
|
4102
|
+
}
|
|
4103
|
+
.vs-typeconfig-flag-locked { background: var(--ink-faint-bg, #FAF8F2); }
|
|
4104
|
+
.vs-typeconfig-flag-locked .vs-typeconfig-flag-label { cursor: not-allowed; opacity: 0.7; }
|
|
4105
|
+
.vs-typeconfig-flag-locked-note {
|
|
4106
|
+
font-size: 11px;
|
|
4107
|
+
font-style: italic;
|
|
4108
|
+
color: var(--ink-faint);
|
|
4109
|
+
margin-left: 22px;
|
|
4110
|
+
}
|
|
4111
|
+
|
|
4112
|
+
/* SM-71: Test-Execution starter dialog. */
|
|
4113
|
+
.tm-test-exec-host { padding: 4px 0; }
|
|
4114
|
+
.tm-test-exec-banner {
|
|
4115
|
+
background: var(--danger-soft, #FBE3E3);
|
|
4116
|
+
color: var(--danger, #B43C3C);
|
|
4117
|
+
border: 1px solid var(--danger, #B43C3C);
|
|
4118
|
+
padding: 8px 10px;
|
|
4119
|
+
border-radius: 4px;
|
|
4120
|
+
margin-bottom: 8px;
|
|
4121
|
+
font-size: 12px;
|
|
4122
|
+
}
|
|
4123
|
+
.tm-test-exec-empty {
|
|
4124
|
+
padding: 16px;
|
|
4125
|
+
border: 1px dashed var(--rule);
|
|
4126
|
+
border-radius: 4px;
|
|
4127
|
+
text-align: center;
|
|
4128
|
+
color: var(--ink-soft);
|
|
4129
|
+
font-size: 12px;
|
|
4130
|
+
font-style: italic;
|
|
4131
|
+
}
|
|
4132
|
+
.tm-test-exec-def-select,
|
|
4133
|
+
.tm-test-exec-env {
|
|
4134
|
+
flex: 1;
|
|
4135
|
+
padding: 5px 8px;
|
|
4136
|
+
border: 1px solid var(--rule);
|
|
4137
|
+
border-radius: 4px;
|
|
4138
|
+
background: var(--paper);
|
|
4139
|
+
font: inherit; font-size: 12px;
|
|
4140
|
+
color: var(--ink);
|
|
4141
|
+
}
|
|
4142
|
+
.tm-test-exec-def-select:focus,
|
|
4143
|
+
.tm-test-exec-env:focus { outline: none; border-color: var(--ink); }
|
|
4144
|
+
|
|
4145
|
+
/* ---------------------------------------------------------------------------
|
|
4146
|
+
* Full-page ticket editor (Epic B). SM-117 page + SM-118 content-first layout:
|
|
4147
|
+
* the description gets the main column; type/status/position/labels/links sit in
|
|
4148
|
+
* a meta sidebar. Reuses the .tm-* form controls from the modal (shared
|
|
4149
|
+
* builders), so the visual hierarchy can be adopted by the modal too.
|
|
4150
|
+
* ------------------------------------------------------------------------- */
|
|
4151
|
+
.te-page { background: var(--paper); }
|
|
4152
|
+
/* SM-160: the editor is a normal scrolling DOCUMENT, not the board's fixed
|
|
4153
|
+
100vh grid. The global `body { height:100vh; overflow:hidden; display:grid }`
|
|
4154
|
+
and `main { overflow:hidden }` (board chrome) would otherwise clip a long
|
|
4155
|
+
description with no scrollbar. Override both for this page. */
|
|
4156
|
+
body.te-page { display: block; height: auto; min-height: 100vh; overflow: visible; }
|
|
4157
|
+
main.te-host { display: block; overflow: visible; max-width: 1080px; margin: 0 auto; padding: 22px 24px 72px; }
|
|
4158
|
+
.te-root { display: block; }
|
|
4159
|
+
.te-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 14px; }
|
|
4160
|
+
.te-back { font-size: 12px; color: var(--accent); text-decoration: none; font-weight: 600; }
|
|
4161
|
+
.te-back:hover { text-decoration: underline; }
|
|
4162
|
+
.te-key { font-size: 12px; color: var(--ink-soft); font-weight: 700; letter-spacing: 0.04em; }
|
|
4163
|
+
|
|
4164
|
+
/* SM-122/B7: the modal title is a link to the full-page editor. */
|
|
4165
|
+
.tm-fullpage-link { color: inherit; text-decoration: none; }
|
|
4166
|
+
.tm-fullpage-link:hover { text-decoration: underline; }
|
|
4167
|
+
.tm-fullpage-icon { color: var(--ink-soft); font-size: 0.65em; vertical-align: super; }
|
|
4168
|
+
|
|
4169
|
+
/* SM-158: board ticket-key links to the full-page editor (cards + epics). */
|
|
4170
|
+
.sm-key-link { color: inherit; text-decoration: none; cursor: pointer; }
|
|
4171
|
+
.sm-key-link:hover { text-decoration: underline; color: var(--accent); }
|
|
4172
|
+
.te-missing { padding: 40px 0; color: var(--ink-soft); font-size: 14px; }
|
|
4173
|
+
|
|
4174
|
+
/* Two-pane content-first grid. Collapses to one column on narrow viewports. */
|
|
4175
|
+
.te-layout {
|
|
4176
|
+
display: grid;
|
|
4177
|
+
grid-template-columns: minmax(0, 1fr) 320px;
|
|
4178
|
+
gap: 28px;
|
|
4179
|
+
align-items: start;
|
|
4180
|
+
}
|
|
4181
|
+
@media (max-width: 820px) { .te-layout { grid-template-columns: 1fr; } }
|
|
4182
|
+
|
|
4183
|
+
.te-main { min-width: 0; display: block; }
|
|
4184
|
+
.te-side {
|
|
4185
|
+
display: block;
|
|
4186
|
+
border: 1px solid var(--rule);
|
|
4187
|
+
border-radius: 8px;
|
|
4188
|
+
padding: 14px 16px;
|
|
4189
|
+
background: var(--paper-soft, rgba(0,0,0,0.015));
|
|
4190
|
+
position: sticky; top: 16px;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
/* Title hero — borderless, large, label hidden, WRAPS full width (textarea). */
|
|
4194
|
+
.te-title-row { display: block; margin: 0 0 14px; }
|
|
4195
|
+
.te-title-row .tm-label { display: none; }
|
|
4196
|
+
.te-title-row .tm-input {
|
|
4197
|
+
display: block;
|
|
4198
|
+
box-sizing: border-box;
|
|
4199
|
+
width: 100%;
|
|
4200
|
+
font-size: 24px; font-weight: 700; line-height: 1.25;
|
|
4201
|
+
color: var(--ink);
|
|
4202
|
+
border: 1px solid transparent;
|
|
4203
|
+
border-radius: 6px;
|
|
4204
|
+
padding: 4px 6px; margin-left: -6px;
|
|
4205
|
+
background: transparent;
|
|
4206
|
+
}
|
|
4207
|
+
/* The textarea variant wraps + auto-grows (set by buildTitleField). */
|
|
4208
|
+
.te-title-row textarea.tm-input {
|
|
4209
|
+
resize: none; overflow: hidden;
|
|
4210
|
+
white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
|
|
4211
|
+
min-height: 0;
|
|
4212
|
+
}
|
|
4213
|
+
.te-title-row .tm-input:hover { border-color: var(--rule); }
|
|
4214
|
+
.te-title-row .tm-input:focus { border-color: var(--ink); background: var(--paper); }
|
|
4215
|
+
|
|
4216
|
+
/* The description is the hero block in the main column. */
|
|
4217
|
+
.te-main .tm-row:has(.tm-description-edit) { flex-direction: column; align-items: stretch; }
|
|
4218
|
+
.te-main .tm-row:has(.tm-description-edit) > .tm-label {
|
|
4219
|
+
flex: none; margin-bottom: 4px; font-weight: 600; color: var(--ink-soft);
|
|
4220
|
+
}
|
|
4221
|
+
.te-main .tm-description-edit { min-height: 160px; }
|
|
4222
|
+
.te-main .tm-desc-actions { margin-left: 0; }
|
|
4223
|
+
|
|
4224
|
+
/* Sidebar fields stack (label above control) so they fit the narrow column. */
|
|
4225
|
+
.te-side .tm-row { flex-direction: column; align-items: stretch; gap: 3px; margin: 0 0 12px; }
|
|
4226
|
+
.te-side .tm-label { flex: none; font-weight: 600; }
|
|
4227
|
+
.te-side .tm-field-hint { margin-left: 0; }
|
|
4228
|
+
.te-side .tm-links { margin-top: 4px; }
|
|
4229
|
+
/* SM-244: editor action row (Delete + Cancel). */
|
|
4230
|
+
.te-side-actions {
|
|
4231
|
+
display: flex;
|
|
4232
|
+
gap: 8px;
|
|
4233
|
+
margin-top: 16px;
|
|
4234
|
+
padding-top: 12px;
|
|
4235
|
+
border-top: 1px solid var(--rule);
|
|
4236
|
+
}
|
|
4237
|
+
.te-side-actions .btn { flex: 1; }
|
|
4238
|
+
|
|
4239
|
+
/* SM-203 R-7 — Requirements module view (DOORS-style multi-column document).
|
|
4240
|
+
Full-page view (like Map / Kanban / Dependencies), not an overlay. */
|
|
4241
|
+
#requirements-view-host { padding: 18px 24px; }
|
|
4242
|
+
/* SM-206: full page width — the document should use the whole view area. */
|
|
4243
|
+
.vr-root { width: 100%; display: flex; flex-direction: column; gap: 14px; }
|
|
4244
|
+
.vr-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
|
4245
|
+
.vr-title { font-family: "Libre Caslon Text", Georgia, serif; font-size: 20px; }
|
|
4246
|
+
.vr-module-picker { font: inherit; font-size: 12px; padding: 4px 8px; border: 1px solid var(--rule);
|
|
4247
|
+
border-radius: 4px; background: var(--paper); }
|
|
4248
|
+
.vr-note { font-size: 11px; color: var(--ink-soft); }
|
|
4249
|
+
.vr-note-ok { color: #3D5639; }
|
|
4250
|
+
.vr-note-warn { color: #7A3E26; }
|
|
4251
|
+
.vr-empty, .vr-reqs-empty { color: var(--ink-soft); font-size: 13px; padding: 16px 0; }
|
|
4252
|
+
.vr-summary { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
4253
|
+
.vr-chip { font-size: 11px; padding: 2px 8px; border-radius: 10px; border: 1px solid var(--rule); }
|
|
4254
|
+
.vr-chip-total { background: var(--paper-warm); }
|
|
4255
|
+
|
|
4256
|
+
/* The document: a scrollable multi-column grid (Source | ID | Requirement |
|
|
4257
|
+
Coverage). Text columns stay pure; ID + Coverage are separate attributes. */
|
|
4258
|
+
.vr-grid { display: grid; border: 1px solid var(--rule); border-radius: 6px; background: var(--paper);
|
|
4259
|
+
max-height: 72vh; overflow: auto; }
|
|
4260
|
+
/* SM-206: Source default WIDER than Requirement; both flexible, ID + Coverage
|
|
4261
|
+
fixed. The inline gridTemplateColumns (set by the resizer) overrides this. */
|
|
4262
|
+
.vr-grid-doc { grid-template-columns: 0.6fr 52px 0.4fr 112px; }
|
|
4263
|
+
.vr-grid-list { grid-template-columns: 52px minmax(0,1fr) 112px; }
|
|
4264
|
+
/* Draggable Source/Requirement divider on the Source header cell. */
|
|
4265
|
+
.vr-th-resizable { position: relative; }
|
|
4266
|
+
.vr-resizer {
|
|
4267
|
+
position: absolute; top: 0; right: -4px; width: 8px; height: 100%;
|
|
4268
|
+
cursor: col-resize; z-index: 3; touch-action: none;
|
|
4269
|
+
}
|
|
4270
|
+
.vr-resizer::after {
|
|
4271
|
+
content: ""; position: absolute; top: 4px; bottom: 4px; left: 3px; width: 2px;
|
|
4272
|
+
background: var(--rule);
|
|
4273
|
+
}
|
|
4274
|
+
.vr-resizer:hover::after { background: var(--accent); }
|
|
4275
|
+
.vr-cell { padding: 7px 12px; min-width: 0; }
|
|
4276
|
+
.vr-th { position: sticky; top: 0; z-index: 1; background: var(--paper-warm);
|
|
4277
|
+
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); }
|
|
4278
|
+
/* A section's first row gets a top rule that spans all columns. */
|
|
4279
|
+
.vr-section-start { border-top: 1px solid var(--rule); }
|
|
4280
|
+
.vr-grid-doc .vr-th, .vr-grid-list .vr-th { border-top: none; }
|
|
4281
|
+
|
|
4282
|
+
.vr-cell-source { background: rgba(15,95,79,0.02); }
|
|
4283
|
+
.vr-h { display: flex; align-items: baseline; gap: 8px; }
|
|
4284
|
+
.vr-h-path { font-size: 11px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
4285
|
+
.vr-h-text { font-weight: 700; font-size: 13px; }
|
|
4286
|
+
.vr-h1 .vr-h-text { font-size: 15px; }
|
|
4287
|
+
.vr-src-prose { font-size: 12.5px; color: var(--ink); white-space: pre-wrap; line-height: 1.5; margin-top: 3px; }
|
|
4288
|
+
|
|
4289
|
+
.vr-cell-id { font-size: 11px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
4290
|
+
.vr-cell-req { font-size: 13px; }
|
|
4291
|
+
.vr-req-text { line-height: 1.45; }
|
|
4292
|
+
.vr-req-text[contenteditable="true"] { cursor: text; }
|
|
4293
|
+
.vr-req-text:focus { outline: 1px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
|
|
4294
|
+
.vr-clickable { cursor: pointer; }
|
|
4295
|
+
.vr-clickable:hover { background: rgba(15,95,79,0.04); }
|
|
4296
|
+
.vr-cell-req.vr-open { box-shadow: inset 3px 0 0 var(--accent); }
|
|
4297
|
+
.vr-cell-cov { white-space: nowrap; }
|
|
4298
|
+
.vr-gap-cell { background: rgba(176,56,43,0.06); }
|
|
4299
|
+
.vr-gap-text { font-size: 12px; color: #7A3E26; }
|
|
4300
|
+
|
|
4301
|
+
/* Expandable detail: traceability chips (clickable → open ticket) + actions. */
|
|
4302
|
+
.vr-detail { margin-top: 6px; display: flex; flex-direction: column; gap: 5px; }
|
|
4303
|
+
.vr-trace-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
4304
|
+
.vr-trace-rel { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); }
|
|
4305
|
+
.vr-trace-chip { display: inline-flex; align-items: baseline; gap: 6px; font: inherit; font-size: 12px;
|
|
4306
|
+
padding: 2px 8px; border: 1px solid var(--rule); border-radius: 4px; background: var(--paper); cursor: pointer; }
|
|
4307
|
+
.vr-trace-chip:hover { border-color: var(--accent); color: var(--accent); }
|
|
4308
|
+
.vr-trace-key { font-size: 11px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
4309
|
+
.vr-action { font: inherit; font-size: 11px; align-self: flex-start; padding: 3px 10px;
|
|
4310
|
+
border: 1px solid var(--accent); border-radius: 4px; background: transparent; color: var(--accent); cursor: pointer; }
|
|
4311
|
+
.vr-action:hover { background: var(--accent); color: var(--paper); }
|
|
4312
|
+
|
|
4313
|
+
.vr-badge { font-size: 10px; padding: 1px 7px; border-radius: 9px; text-transform: lowercase; white-space: nowrap; }
|
|
4314
|
+
.vr-badge-covered { background: #E7EDE3; color: #3D5639; }
|
|
4315
|
+
.vr-badge-over-covered { background: #E8EEF5; color: #2E4665; }
|
|
4316
|
+
.vr-badge-orphan { background: #F1DCD2; color: #7A3E26; }
|
|
4317
|
+
.vr-badge-suspect { background: #EAE0EA; color: #5A3957; }
|
|
4318
|
+
|
|
4319
|
+
/* ===========================================================================
|
|
4320
|
+
SM-248/256 — Process-Step editor view (.psv-*). A SECOND surface onto the
|
|
4321
|
+
map: process steps render as cards via the SHARED .sm-story-card component
|
|
4322
|
+
(teal cluster) and reorder with the same dnd mechanic as the item cards.
|
|
4323
|
+
Only the layout chrome + quick-add are PS-specific here — there is NO
|
|
4324
|
+
parallel card style (DRY). The journey is ONE horizontal row; the PAGE
|
|
4325
|
+
(#view-host) scrolls, not the row.
|
|
4326
|
+
=========================================================================== */
|
|
4327
|
+
.psv-root { padding: 18px 22px; }
|
|
4328
|
+
.psv-header { margin-bottom: 16px; }
|
|
4329
|
+
.psv-heading { font-size: 18px; margin: 0 0 4px; }
|
|
4330
|
+
.psv-sub { color: var(--ink-soft); font-size: 12px; margin: 0; max-width: 720px; }
|
|
4331
|
+
.psv-empty {
|
|
4332
|
+
color: var(--ink-soft); font-size: 13px; padding: 32px;
|
|
4333
|
+
border: 1px dashed var(--rule); border-radius: 6px; text-align: center;
|
|
4334
|
+
}
|
|
4335
|
+
/* One horizontal row, no wrap. NO overflow here — the row grows to its
|
|
4336
|
+
content width and #view-host (the view scroll container) scrolls the page,
|
|
4337
|
+
so the whole surface moves, not just the strip. */
|
|
4338
|
+
.psv-flow {
|
|
4339
|
+
display: flex; flex-wrap: nowrap; gap: 14px; align-items: flex-start;
|
|
4340
|
+
width: max-content;
|
|
4341
|
+
}
|
|
4342
|
+
/* The step cards wear the SAME colour as the story-map backbone spine (shared
|
|
4343
|
+
--backbone-* tokens): green band + light text. So the two surfaces read as
|
|
4344
|
+
the same process steps — the Map draws them as the header, this view as
|
|
4345
|
+
cards. The `process` cluster carries no own colour; we paint it here. */
|
|
4346
|
+
.psv-flow .sm-story-card[data-process-step-id] {
|
|
4347
|
+
background: var(--backbone-bg);
|
|
4348
|
+
border-color: var(--backbone-edge);
|
|
4349
|
+
color: var(--backbone-ink);
|
|
4350
|
+
cursor: grab;
|
|
4351
|
+
}
|
|
4352
|
+
.psv-flow .sm-story-card[data-process-step-id] .sm-story-title { color: var(--backbone-ink); }
|
|
4353
|
+
/* Quick-add: a dashed end-of-row affordance sized like a step card. */
|
|
4354
|
+
.psv-quickadd {
|
|
4355
|
+
flex: 0 0 220px; width: 220px;
|
|
4356
|
+
display: flex; align-items: center; justify-content: center;
|
|
4357
|
+
border: 1px dashed var(--rule); border-radius: 6px; padding: 10px 12px;
|
|
4358
|
+
background: transparent;
|
|
4359
|
+
}
|
|
4360
|
+
.psv-quickadd-input {
|
|
4361
|
+
width: 100%; box-sizing: border-box; font-size: 13px;
|
|
4362
|
+
border: 1px solid transparent; background: transparent; padding: 6px 4px; border-radius: 4px;
|
|
4363
|
+
}
|
|
4364
|
+
.psv-quickadd-input:hover { border-color: var(--rule); }
|
|
4365
|
+
.psv-quickadd-input:focus { border-color: var(--accent); background: var(--paper-warm); outline: none; }
|
|
4366
|
+
|
|
4367
|
+
/* ===========================================================================
|
|
4368
|
+
SM-274/SM-275: Map-Eingang (Bodenstreifen) — sticky bottom inbox for
|
|
4369
|
+
release-LESS tickets (the work SM-253 dropped from the map; epics can't show
|
|
4370
|
+
in Kanban).
|
|
4371
|
+
|
|
4372
|
+
It is the LAST child of .sm-grid (NOT a sibling of the grid). The grid is
|
|
4373
|
+
`width: max-content` — the full map scroll width — so this plain block child
|
|
4374
|
+
gets `width: auto` = that same width for free: the background spans the whole
|
|
4375
|
+
map with pure CSS, no measured width, and it scrolls horizontally WITH the
|
|
4376
|
+
grid so the background always covers the full width. The card body is a
|
|
4377
|
+
`overflow-x: auto` scroll container, so the cards don't feed back into the
|
|
4378
|
+
grid's max-content width. Row count is viewport-derived (SM-275, JS).
|
|
4379
|
+
|
|
4380
|
+
NOT sticky (SM-276 follow-up): it sits in normal flow BELOW the last release.
|
|
4381
|
+
On a short board the viewport-derived row count fills the space down to the
|
|
4382
|
+
window bottom (no empty gap); on a tall board it sits under the last release
|
|
4383
|
+
and you scroll down to it — it never overlays the release rows.
|
|
4384
|
+
=========================================================================== */
|
|
4385
|
+
.sm-tray {
|
|
4386
|
+
background: var(--paper-warm);
|
|
4387
|
+
border-top: 2px solid var(--rule);
|
|
4388
|
+
/* SM-279: the strip is a block child of the width:max-content grid. With
|
|
4389
|
+
width:auto its wide card row fed its own max-content back into the grid,
|
|
4390
|
+
widening it past the process-step columns and breaking the map's horizontal
|
|
4391
|
+
scroll (the user could no longer reach off-screen process steps). Size
|
|
4392
|
+
containment on the inline axis makes the strip's width independent of its
|
|
4393
|
+
content, so it fills the grid width (background still spans) WITHOUT growing
|
|
4394
|
+
it; its own cards scroll inside .sm-tray-body (overflow-x:auto). */
|
|
4395
|
+
contain: inline-size;
|
|
4396
|
+
width: 100%;
|
|
4397
|
+
}
|
|
4398
|
+
.sm-tray-header {
|
|
4399
|
+
display: flex;
|
|
4400
|
+
align-items: center;
|
|
4401
|
+
gap: 8px;
|
|
4402
|
+
padding: 6px 12px;
|
|
4403
|
+
font-size: 12px;
|
|
4404
|
+
font-weight: 600;
|
|
4405
|
+
color: var(--ink-soft);
|
|
4406
|
+
border-bottom: 1px solid var(--rule);
|
|
4407
|
+
}
|
|
4408
|
+
.sm-tray-collapsed .sm-tray-header { border-bottom: none; }
|
|
4409
|
+
.sm-tray-toggle {
|
|
4410
|
+
border: none;
|
|
4411
|
+
background: transparent;
|
|
4412
|
+
cursor: pointer;
|
|
4413
|
+
font-size: 12px;
|
|
4414
|
+
color: var(--ink-soft);
|
|
4415
|
+
padding: 0 4px;
|
|
4416
|
+
line-height: 1;
|
|
4417
|
+
}
|
|
4418
|
+
.sm-tray-toggle:hover { color: var(--ink); }
|
|
4419
|
+
.sm-tray-title { letter-spacing: -0.01em; }
|
|
4420
|
+
.sm-tray-count {
|
|
4421
|
+
display: inline-flex;
|
|
4422
|
+
align-items: center;
|
|
4423
|
+
justify-content: center;
|
|
4424
|
+
min-width: 18px;
|
|
4425
|
+
height: 18px;
|
|
4426
|
+
padding: 0 5px;
|
|
4427
|
+
background: var(--rule);
|
|
4428
|
+
color: var(--ink);
|
|
4429
|
+
border-radius: 9px;
|
|
4430
|
+
font-size: 11px;
|
|
4431
|
+
font-weight: 600;
|
|
4432
|
+
}
|
|
4433
|
+
.sm-tray-body {
|
|
4434
|
+
overflow-x: auto;
|
|
4435
|
+
overflow-y: hidden;
|
|
4436
|
+
padding: 8px 12px;
|
|
4437
|
+
}
|
|
4438
|
+
.sm-tray-grid {
|
|
4439
|
+
display: grid;
|
|
4440
|
+
grid-auto-flow: column;
|
|
4441
|
+
gap: 8px;
|
|
4442
|
+
align-content: start;
|
|
4443
|
+
width: max-content;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
/* ===========================================================================
|
|
4447
|
+
SM-282 — Table view (.tv-*): Jira-Issue-Navigator-artige Sicht. Eigene
|
|
4448
|
+
Query-Zeile oben (gleiche SM-187-Sprache wie Smart-Bar + MCP query_tickets),
|
|
4449
|
+
Ergebnis-Tabelle darunter. Spalten kommen aus QUERY_FIELDS — der Renderer
|
|
4450
|
+
kennt keine eigene Feld-Logik.
|
|
4451
|
+
=========================================================================== */
|
|
4452
|
+
/* SM-292: full available width (user finding — no max-width cap). */
|
|
4453
|
+
.tv-root { padding: 16px 22px; }
|
|
4454
|
+
.tv-query-row { display: flex; gap: 8px; margin-bottom: 8px; }
|
|
4455
|
+
.tv-query-input {
|
|
4456
|
+
flex: 1;
|
|
4457
|
+
font: 13px ui-monospace, "SF Mono", Menlo, monospace;
|
|
4458
|
+
padding: 7px 10px;
|
|
4459
|
+
border: 1px solid var(--rule);
|
|
4460
|
+
border-radius: 4px;
|
|
4461
|
+
background: var(--paper-warm);
|
|
4462
|
+
color: var(--ink);
|
|
4463
|
+
}
|
|
4464
|
+
.tv-query-input:focus { border-color: var(--accent); outline: none; background: #fff; }
|
|
4465
|
+
.tv-query-error {
|
|
4466
|
+
color: var(--danger, #A3352B);
|
|
4467
|
+
font-size: 12px;
|
|
4468
|
+
padding: 4px 2px 8px;
|
|
4469
|
+
}
|
|
4470
|
+
.tv-table-host { overflow-x: auto; }
|
|
4471
|
+
.tv-table {
|
|
4472
|
+
width: 100%;
|
|
4473
|
+
table-layout: fixed; /* SM-292: colgroup widths rule; title takes the rest */
|
|
4474
|
+
border-collapse: collapse;
|
|
4475
|
+
font-size: 13px;
|
|
4476
|
+
background: #fff;
|
|
4477
|
+
border: 1px solid var(--rule);
|
|
4478
|
+
}
|
|
4479
|
+
.tv-table thead th {
|
|
4480
|
+
text-align: left;
|
|
4481
|
+
font-size: 11px;
|
|
4482
|
+
font-weight: 600;
|
|
4483
|
+
text-transform: uppercase;
|
|
4484
|
+
letter-spacing: 0.04em;
|
|
4485
|
+
color: var(--ink-soft);
|
|
4486
|
+
background: var(--paper-warm);
|
|
4487
|
+
border-bottom: 2px solid var(--rule);
|
|
4488
|
+
padding: 8px 10px;
|
|
4489
|
+
white-space: nowrap;
|
|
4490
|
+
}
|
|
4491
|
+
.tv-table tbody td {
|
|
4492
|
+
padding: 7px 10px;
|
|
4493
|
+
border-bottom: 1px solid var(--rule);
|
|
4494
|
+
vertical-align: top;
|
|
4495
|
+
overflow-wrap: anywhere;
|
|
4496
|
+
}
|
|
4497
|
+
.tv-table tbody td[data-col="key"] { white-space: nowrap; font-weight: 600; color: var(--accent); }
|
|
4498
|
+
.tv-table tbody tr { cursor: pointer; }
|
|
4499
|
+
.tv-table tbody tr:hover { background: var(--accent-soft, #EDF3F1); }
|
|
4500
|
+
.tv-count { color: var(--ink-soft); font-size: 12px; padding: 8px 2px; }
|
|
4501
|
+
|
|
4502
|
+
/* SM-283 — column picker panel */
|
|
4503
|
+
.tv-columns-btn { flex: 0 0 auto; }
|
|
4504
|
+
.tv-columns-panel {
|
|
4505
|
+
border: 1px solid var(--rule);
|
|
4506
|
+
border-radius: 4px;
|
|
4507
|
+
background: #fff;
|
|
4508
|
+
padding: 8px 10px;
|
|
4509
|
+
margin-bottom: 8px;
|
|
4510
|
+
max-width: 420px;
|
|
4511
|
+
}
|
|
4512
|
+
.tv-columns-row {
|
|
4513
|
+
display: grid;
|
|
4514
|
+
grid-template-columns: 20px 20px 1fr;
|
|
4515
|
+
align-items: center;
|
|
4516
|
+
gap: 8px;
|
|
4517
|
+
padding: 3px 2px;
|
|
4518
|
+
font-size: 13px;
|
|
4519
|
+
}
|
|
4520
|
+
.tv-columns-row:not(.tv-columns-row-active) { grid-template-columns: 20px 1fr; color: var(--ink-soft); }
|
|
4521
|
+
.tv-columns-grip { cursor: grab; color: var(--ink-soft); font-size: 11px; }
|
|
4522
|
+
.tv-columns-row.tv-columns-drop-target { box-shadow: inset 0 3px 0 0 var(--accent); }
|
|
4523
|
+
.tv-columns-row.sm-dragging { opacity: 0.4; }
|
|
4524
|
+
.tv-columns-footer { border-top: 1px solid var(--rule); margin-top: 6px; padding-top: 8px; }
|
|
4525
|
+
|
|
4526
|
+
/* SM-284 — sortable headers */
|
|
4527
|
+
.tv-table thead th { cursor: pointer; user-select: none; }
|
|
4528
|
+
.tv-table thead th[data-sort-dir]::after { margin-left: 5px; font-size: 9px; }
|
|
4529
|
+
.tv-table thead th[data-sort-dir="asc"]::after { content: "▲"; }
|
|
4530
|
+
.tv-table thead th[data-sort-dir="desc"]::after { content: "▼"; }
|
|
4531
|
+
|
|
4532
|
+
/* SM-292 — column resize handles + no-wrap columns */
|
|
4533
|
+
.tv-table thead th { position: relative; }
|
|
4534
|
+
.tv-resize-handle {
|
|
4535
|
+
position: absolute;
|
|
4536
|
+
top: 0; right: -4px; bottom: 0;
|
|
4537
|
+
width: 9px;
|
|
4538
|
+
cursor: col-resize;
|
|
4539
|
+
z-index: 1;
|
|
4540
|
+
}
|
|
4541
|
+
.tv-table td[data-col="epic"],
|
|
4542
|
+
.tv-table td[data-col="updated"],
|
|
4543
|
+
.tv-table td[data-col="created"],
|
|
4544
|
+
.tv-table td[data-col="status"] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
4545
|
+
.tv-table td { overflow: hidden; text-overflow: ellipsis; }
|
|
4546
|
+
|
|
4547
|
+
/* SM-293 — Table view: visible column separators + resize affordance,
|
|
4548
|
+
and the global smart-bar row hides while the Table view is active
|
|
4549
|
+
(it has its own query line — two query inputs were confusing). */
|
|
4550
|
+
.toolbar-action[hidden] { display: none; }
|
|
4551
|
+
.tv-table thead th,
|
|
4552
|
+
.tv-table tbody td { border-right: 1px solid var(--rule); }
|
|
4553
|
+
.tv-table thead th:last-child,
|
|
4554
|
+
.tv-table tbody td:last-child { border-right: none; }
|
|
4555
|
+
/* Resize affordance: the handle shows as soon as the header is hovered,
|
|
4556
|
+
not only when the 9px hit zone itself is hit. */
|
|
4557
|
+
.tv-table thead th:hover .tv-resize-handle {
|
|
4558
|
+
background: linear-gradient(90deg, transparent 3px, var(--ink-soft) 3px, var(--ink-soft) 5px, transparent 5px);
|
|
4559
|
+
opacity: 0.5;
|
|
4560
|
+
}
|
|
4561
|
+
.tv-table thead th .tv-resize-handle:hover {
|
|
4562
|
+
background: linear-gradient(90deg, transparent 3px, var(--accent) 3px, var(--accent) 5px, transparent 5px);
|
|
4563
|
+
opacity: 1;
|
|
4564
|
+
}
|
|
4565
|
+
|
|
4566
|
+
/* SM-289 — ticket-import dialog (.ti-*) */
|
|
4567
|
+
.ti-root { display: flex; flex-direction: column; gap: 10px; margin: 12px 0; }
|
|
4568
|
+
.ti-source { display: flex; flex-direction: column; gap: 8px; }
|
|
4569
|
+
.ti-text {
|
|
4570
|
+
font: 12px ui-monospace, "SF Mono", Menlo, monospace;
|
|
4571
|
+
border: 1px solid var(--rule); border-radius: 4px;
|
|
4572
|
+
padding: 8px; background: var(--paper-warm); color: var(--ink);
|
|
4573
|
+
resize: vertical;
|
|
4574
|
+
}
|
|
4575
|
+
.ti-text:focus { border-color: var(--accent); outline: none; background: #fff; }
|
|
4576
|
+
/* SM-298 (review): a hand-enlarged textarea must never squeeze the scroll
|
|
4577
|
+
region to zero and clip the pinned action row. */
|
|
4578
|
+
.ti-text { max-height: 40vh; }
|
|
4579
|
+
.ti-mode { display: flex; gap: 18px; font-size: 13px; }
|
|
4580
|
+
.ti-mode-opt { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
|
|
4581
|
+
.ti-parse-error { color: var(--danger, #A3352B); font-size: 12px; }
|
|
4582
|
+
.ti-summary { font-size: 13px; font-weight: 600; }
|
|
4583
|
+
.ti-preview-host { /* SM-298: scrolls inside .ti-scroll, no nested scroller */ }
|
|
4584
|
+
.ti-preview { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
4585
|
+
.ti-preview th {
|
|
4586
|
+
text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;
|
|
4587
|
+
color: var(--ink-soft); border-bottom: 1px solid var(--rule); padding: 4px 6px;
|
|
4588
|
+
}
|
|
4589
|
+
.ti-preview td { padding: 4px 6px; border-bottom: 1px solid var(--rule); vertical-align: top; overflow-wrap: anywhere; }
|
|
4590
|
+
.ti-row-error td { color: var(--danger, #A3352B); }
|
|
4591
|
+
.ti-row-create td:nth-child(2) { color: var(--accent); font-weight: 600; }
|
|
4592
|
+
.ti-truncated { color: var(--ink-soft); font-size: 12px; padding: 6px 2px; }
|
|
4593
|
+
/* SM-298: the import dialog is content-heavy AND resizable — flex column
|
|
4594
|
+
(title + source fixed, ONE scroll region takes the rest, actions pinned),
|
|
4595
|
+
native resize handle bottom-right with sane bounds. */
|
|
4596
|
+
#modal-host .modal:has(.ti-root) {
|
|
4597
|
+
width: 820px; max-width: 95vw;
|
|
4598
|
+
min-width: 560px; min-height: 420px;
|
|
4599
|
+
max-height: 92vh;
|
|
4600
|
+
resize: both; overflow: hidden;
|
|
4601
|
+
display: flex; flex-direction: column;
|
|
4602
|
+
}
|
|
4603
|
+
#modal-host .modal:has(.ti-root) .modal-actions { margin-top: auto; flex: 0 0 auto; }
|
|
4604
|
+
|
|
4605
|
+
/* SM-295 — unified import (project branch) + export chooser */
|
|
4606
|
+
.ti-project-preview { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border: 1px solid var(--rule); border-radius: 4px; background: var(--paper-warm); font-size: 13px; }
|
|
4607
|
+
.ti-project-counts { color: var(--ink-soft); }
|
|
4608
|
+
.ti-project-conflict { color: var(--danger, #A3352B); font-weight: 600; }
|
|
4609
|
+
.ti-destructive { color: var(--danger, #A3352B); }
|
|
4610
|
+
.ti-export-info { margin: 12px 0; font-size: 13px; color: var(--ink-soft); display: flex; flex-direction: column; gap: 8px; max-width: 520px; }
|
|
4611
|
+
|
|
4612
|
+
/* SM-296 — import column mapping panel */
|
|
4613
|
+
.ti-mapping {
|
|
4614
|
+
border: 1px solid var(--rule); border-radius: 4px;
|
|
4615
|
+
background: var(--paper-warm);
|
|
4616
|
+
padding: 8px 10px;
|
|
4617
|
+
display: flex; flex-direction: column; gap: 4px;
|
|
4618
|
+
/* SM-298: no own mini-scroller — .ti-scroll owns the scrolling */
|
|
4619
|
+
}
|
|
4620
|
+
.ti-mapping-title { font-size: 12px; font-weight: 600; color: var(--ink-soft); margin-bottom: 2px; }
|
|
4621
|
+
.ti-mapping-row {
|
|
4622
|
+
display: grid; grid-template-columns: 1fr 200px;
|
|
4623
|
+
align-items: center; gap: 10px; font-size: 12px; cursor: default;
|
|
4624
|
+
}
|
|
4625
|
+
.ti-mapping-raw { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, Menlo, monospace; }
|
|
4626
|
+
.ti-mapping-select { font-size: 12px; padding: 2px 4px; border: 1px solid var(--rule); border-radius: 3px; background: #fff; }
|
|
4627
|
+
.ti-unused { color: var(--ink-soft); font-size: 12px; padding: 6px 2px; }
|
|
4628
|
+
|
|
4629
|
+
/* SM-298 — resizable import dialog: one scroll region over mapping + preview */
|
|
4630
|
+
.ti-root { flex: 1 1 auto; min-height: 0; }
|
|
4631
|
+
.ti-scroll {
|
|
4632
|
+
flex: 1 1 auto; min-height: 0;
|
|
4633
|
+
overflow-y: auto;
|
|
4634
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
4635
|
+
}
|
|
4636
|
+
.ti-mapping-value-row { padding-left: 26px; }
|
|
4637
|
+
.ti-mapping-value-row .ti-mapping-raw { color: var(--ink-soft); }
|