@kaizenreport/kensho-viewer 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.
@@ -0,0 +1,357 @@
1
+ /* Kensho Report — UI kit local tokens. Imports global system. */
2
+ @import url("./colors_and_type.css");
3
+
4
+ /* App shell — fixed-height grid; sidebar stays put, only right column scrolls */
5
+ .app { display:grid; grid-template-columns: var(--sidebar-w) 1fr; height:100vh; overflow:hidden; background:var(--bg); color:var(--fg1); }
6
+ .app.collapsed { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }
7
+ .app > .right-col { display:flex; flex-direction:column; min-height:0; overflow:hidden; }
8
+ .app > .right-col > .main { flex:1; overflow:auto; padding:24px; }
9
+
10
+ /* ------- SIDEBAR (sticky, full-height) -------
11
+ Theme-aware: follows the report theme instead of being hardwired dark.
12
+ Light theme → light rail; dark theme → dark rail. Uses the same themed
13
+ tokens (--bg-sunken / --line / --fg*) the rest of the viewer uses, which
14
+ flip under html[data-theme="dark"]. */
15
+ .sb { background: var(--bg-sunken); color: var(--fg2); display:flex; flex-direction:column; border-right:1px solid var(--line); height:100vh; overflow-y:auto; }
16
+ .sb .brand { display:flex; align-items:center; gap:10px; padding:14px 16px; border-bottom:1px solid var(--line); }
17
+ .sb .brand .name { font-family:var(--font-display); font-weight:800; font-size:18px; color:var(--fg1); letter-spacing:-.01em; }
18
+ .sb .brand .name .accent { color: var(--brand-green-400); }
19
+ .sb nav { padding:10px 8px; display:flex; flex-direction:column; gap:2px; flex:1; }
20
+ .sb a { display:flex; align-items:center; gap:12px; height:36px; padding:0 12px; border-radius:var(--r-md); color:var(--fg2); text-decoration:none; font-size:13px; font-weight:500; cursor:pointer; transition:background var(--dur-fast),color var(--dur-fast); }
21
+ .sb a:hover { background:var(--bg-hover); color:var(--fg1); }
22
+ .sb a.active { background:color-mix(in srgb, var(--brand-blue-400) 16%, transparent); color:var(--fg1); box-shadow: inset 2px 0 0 var(--brand-blue-400); }
23
+ .sb a svg { width:18px; height:18px; stroke-width:1.75; }
24
+ .sb .foot { padding:12px 16px; border-top:1px solid var(--line); font-family:var(--font-mono); font-size:11px; color:var(--fg3); }
25
+
26
+ /* ------- TOPBAR ------- */
27
+ .tb { height:var(--topbar-h); background: rgba(255,255,255,.85); backdrop-filter: blur(12px); border-bottom:1px solid var(--line); display:flex; align-items:center; padding:0 24px; gap:16px; position:sticky; top:0; z-index:10; }
28
+ .tb .crumb { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--fg2); font-family:var(--font-body); }
29
+ .tb .crumb b { color:var(--fg1); font-weight:600; }
30
+ .tb .crumb svg { width:14px; height:14px; color:var(--fg4); }
31
+ .tb .grow { flex:1; }
32
+ .tb .runsel { display:flex; align-items:center; gap:8px; height:32px; padding:0 12px; border:1px solid var(--line); border-radius:var(--r-md); background:#fff; font-family:var(--font-mono); font-size:12px; cursor:pointer; }
33
+ .tb .runsel .dot { width:8px; height:8px; border-radius:999px; background:var(--status-passed); }
34
+ .tb .runsel.fail .dot { background:var(--status-failed); }
35
+
36
+ /* ------- BUTTONS ------- */
37
+ .btn { font-family:var(--font-body); font-size:13px; font-weight:600; height:32px; padding:0 12px; border-radius:var(--r-md); display:inline-flex; align-items:center; gap:6px; border:1px solid transparent; cursor:pointer; transition:background var(--dur-fast); letter-spacing:-.005em; }
38
+ .btn svg { width:14px; height:14px; }
39
+ .btn:focus { outline:none; box-shadow:var(--shadow-focus); }
40
+ .btn-primary { background:var(--brand-blue-500); color:#fff; }
41
+ .btn-primary:hover { background:var(--brand-blue-600); }
42
+ .btn-secondary { background:#fff; color:var(--fg1); border-color:var(--line); }
43
+ .btn-secondary:hover { background:var(--bg-hover); border-color:var(--line-strong); }
44
+ .btn-ghost { background:transparent; color:var(--fg2); }
45
+ .btn-ghost:hover { background:var(--bg-hover); color:var(--fg1); }
46
+
47
+ /* ------- CARDS ------- */
48
+ .main { max-width:var(--container-max); }
49
+ .card { background:#fff; border:1px solid var(--line); border-radius:var(--r-lg); padding:20px; }
50
+ .card .hd { display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
51
+ .card .hd h3 { font-size:11px; letter-spacing:.12em; text-transform:uppercase; font-weight:700; color:var(--fg3); margin:0; }
52
+ .card .hd .meta { font-size:12px; color:var(--fg3); font-family:var(--font-mono); }
53
+
54
+ /* ------- BADGES ------- */
55
+ .badge { display:inline-flex; align-items:center; gap:6px; height:22px; padding:0 9px; border-radius:999px; font-size:11px; font-weight:600; }
56
+ .badge .dot { width:6px; height:6px; border-radius:999px; background:currentColor; }
57
+ .b-passed { background:var(--status-passed-bg); color:var(--status-passed); }
58
+ .b-failed { background:var(--status-failed-bg); color:var(--status-failed); }
59
+ .b-broken { background:var(--status-broken-bg); color:var(--status-broken-fg); }
60
+ .b-skipped { background:var(--status-skipped-bg); color:var(--status-skipped-fg); }
61
+
62
+ /* ------- TEST ROW ------- */
63
+ .trow { display:grid; grid-template-columns:24px 1fr 80px 90px 110px 24px; gap:0 12px; padding:0 16px; height:46px; align-items:center; border-bottom:1px solid var(--line); cursor:pointer; transition:background var(--dur-fast); }
64
+ .trow:hover { background:var(--bg-hover); }
65
+ .trow:last-child { border-bottom:0; }
66
+ .trow .id { font-family:var(--font-mono); font-size:12.5px; color:var(--fg1); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
67
+ .trow .id .ns { color:var(--fg3); }
68
+ .trow .dur { font-family:var(--font-mono); font-size:12px; color:var(--fg2); font-variant-numeric:tabular-nums; }
69
+ .s-icon { width:16px; height:16px; border-radius:999px; display:inline-flex; align-items:center; justify-content:center; color:#fff; font-size:9px; font-weight:700; }
70
+ .s-icon.passed { background:var(--status-passed); }
71
+ .s-icon.failed { background:var(--status-failed); }
72
+ .s-icon.broken { background:var(--status-broken); }
73
+ .s-icon.skipped { background:var(--status-skipped); }
74
+
75
+ /* ------- STAT ------- */
76
+ .statnum { font-family:var(--font-display); font-weight:800; font-size:48px; letter-spacing:-.025em; line-height:1; font-variant-numeric:tabular-nums; }
77
+ .statlbl { font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--fg3); font-weight:600; margin-top:4px; }
78
+
79
+ /* ------- ENV TABLE ------- */
80
+ .env { display:grid; grid-template-columns:160px 1fr; }
81
+ .env .k { padding:8px 0; color:var(--fg3); font-family:var(--font-mono); font-size:12px; border-bottom:1px solid var(--line); }
82
+ .env .v { padding:8px 0; color:var(--fg1); font-family:var(--font-mono); font-size:12.5px; border-bottom:1px solid var(--line); }
83
+ .env .k:last-of-type, .env .v:last-of-type { border-bottom:0; }
84
+
85
+ /* ------- TABS ------- */
86
+ .tabs { display:flex; gap:2px; border-bottom:1px solid var(--line); margin-bottom:18px; }
87
+ .tab { padding:10px 14px; font-size:13px; font-weight:600; color:var(--fg3); cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px; transition:color var(--dur-fast); }
88
+ .tab:hover { color:var(--fg1); }
89
+ .tab.active { color:var(--fg1); border-bottom-color:var(--brand-blue-500); }
90
+
91
+ /* ------- ACCENT-SOFT (selection) ------- */
92
+ :root { --accent-soft: rgba(0,114,255,0.06); --bg-2: var(--bg-sunken); }
93
+
94
+ /* ------- STEP TREE ------- */
95
+ .step { border-left:2px solid var(--line); margin-left:6px; padding:6px 0 6px 14px; position:relative; }
96
+ .step.passed { border-color:var(--status-passed); }
97
+ .step.failed { border-color:var(--status-failed); }
98
+ .step.broken { border-color:var(--status-broken); }
99
+ .step .head { display:flex; align-items:center; gap:8px; font-size:13px; }
100
+ .step .head .name { color:var(--fg1); font-weight:500; }
101
+ .step .head .dur { font-family:var(--font-mono); font-size:11px; color:var(--fg3); margin-left:auto; }
102
+ .step .body { margin-top:6px; padding-left:0; font-family:var(--font-mono); font-size:12px; color:var(--fg2); white-space:pre; }
103
+ .step .children { margin-top:6px; }
104
+
105
+ /* ------- LOG ------- */
106
+ .log { background:#0B1220; color:#B7C0D2; border-radius:var(--r-md); padding:12px 14px; font-family:var(--font-mono); font-size:12px; line-height:1.55; overflow:auto; max-height:280px; }
107
+ .log .ts { color:#5C6A86; margin-right:10px; }
108
+ .log .lvl-info { color:#66B0FF; }
109
+ .log .lvl-warn { color:#F5A524; }
110
+ .log .lvl-err { color:#FF7A7E; }
111
+
112
+ /* utility */
113
+ .row { display:flex; gap:8px; align-items:center; }
114
+ .grow { flex:1; }
115
+
116
+ /* ------- SPLIT HANDLE (resizable tree/detail divider) ------- */
117
+ /* 8px wide invisible hit-area centered on a 1px line. The line thickens
118
+ to 3px (and switches to brand blue) on hover/focus/drag. */
119
+ .kv-split-handle {
120
+ position: relative;
121
+ width: 8px;
122
+ height: 100%;
123
+ cursor: col-resize;
124
+ background: transparent;
125
+ border: 0;
126
+ padding: 0;
127
+ outline: none;
128
+ user-select: none;
129
+ touch-action: none;
130
+ z-index: 1;
131
+ }
132
+ .kv-split-handle::before {
133
+ content: "";
134
+ position: absolute;
135
+ top: 0;
136
+ bottom: 0;
137
+ left: 50%;
138
+ width: 1px;
139
+ margin-left: -0.5px;
140
+ background: var(--line);
141
+ transition: background var(--dur-fast), width var(--dur-fast), margin-left var(--dur-fast);
142
+ pointer-events: none;
143
+ }
144
+ .kv-split-handle:hover::before,
145
+ .kv-split-handle:focus-visible::before,
146
+ .kv-split-handle--active::before {
147
+ width: 3px;
148
+ margin-left: -1.5px;
149
+ background: var(--brand-blue-500);
150
+ }
151
+ .kv-split-handle:focus-visible {
152
+ /* keep focus visible for keyboard users without an outer halo */
153
+ outline: none;
154
+ }
155
+
156
+ /* Boot screen — shown before React loads */
157
+ .kv-boot { display:flex; align-items:center; justify-content:center; flex-direction:column; gap:12px; height:100vh; }
158
+ .kv-boot-mark { animation: kv-pulse 1.6s ease-in-out infinite; }
159
+ .kv-boot-text { font-family:var(--font-mono); font-size:12px; color:var(--fg3); letter-spacing:.06em; text-transform:uppercase; }
160
+ @keyframes kv-pulse { 0%,100% { opacity:0.45; transform:scale(1); } 50% { opacity:1; transform:scale(1.05); } }
161
+
162
+ /* Theme toggle */
163
+ .theme-toggle {
164
+ width:32px; height:32px; border-radius:var(--r-md);
165
+ border:1px solid var(--line); background:#fff;
166
+ display:inline-flex; align-items:center; justify-content:center;
167
+ cursor:pointer; color:var(--fg2);
168
+ transition:background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
169
+ }
170
+ .theme-toggle:hover { background:var(--bg-hover); color:var(--fg1); border-color:var(--line-strong); }
171
+ .theme-toggle:focus { outline:none; box-shadow:var(--shadow-focus); }
172
+
173
+ /* ==========================================================================
174
+ DARK THEME — applied via <html data-theme="dark">
175
+ ========================================================================== */
176
+ html[data-theme="dark"] {
177
+ /* Kaizen brand dark — deep navy with the neon mint accent.
178
+ Matches the brand landing page treatment (改善 watermark + jade green
179
+ callout). The jade green is the same brand-green-400 the OSS report
180
+ already uses for status; we just lean into it harder in dark mode. */
181
+ --bg: #050B17; /* deep navy, near-black */
182
+ --bg-elev: #0B1426; /* card surface */
183
+ --bg-sunken: #03070F; /* row stripes / inset wells */
184
+ --bg-hover: #142037;
185
+ --line: #1A2542;
186
+ --line-strong: #283758;
187
+ --fg1: #F2F5FA;
188
+ --fg2: #B7C0D2;
189
+ --fg3: #7C8AA6;
190
+ --fg4: #5A6B8A;
191
+ --bg-2: #03070F;
192
+
193
+ --dark-bg: #03070F;
194
+ --dark-bg-elev: #0B1426;
195
+ --dark-line: #1A2542;
196
+
197
+ /* Brand-green accent ramps into focus rings + selections so the dark
198
+ theme reads as "Kaizen mint" rather than the default Kaizen blue. */
199
+ --accent: var(--brand-green-400);
200
+ --accent-soft: rgba(0, 255, 135, 0.08);
201
+ --shadow-focus: 0 0 0 3px rgba(0, 255, 135, 0.20);
202
+
203
+ --status-passed-bg: rgba(31,168,100,0.14);
204
+ --status-failed-bg: rgba(229,72,77,0.16);
205
+ --status-broken-bg: rgba(245,165,36,0.16);
206
+ --status-skipped-bg: rgba(148,163,184,0.14);
207
+ --status-unknown-bg: rgba(124,92,255,0.18);
208
+
209
+ --status-passed-fg: #6FE0A6;
210
+ --status-failed-fg: #FF9A9D;
211
+ --status-broken-fg: #FFD082;
212
+ --status-skipped-fg: #C2CCE0;
213
+
214
+ --status-passed-border: rgba(31,168,100,0.35);
215
+ --status-failed-border: rgba(229,72,77,0.4);
216
+ --status-broken-border: rgba(245,165,36,0.4);
217
+ --status-skipped-border: rgba(148,163,184,0.3);
218
+
219
+ --accent-soft: rgba(0,114,255,0.14);
220
+
221
+ --shadow-xs: 0 1px 1px rgba(0,0,0,0.3);
222
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.35), 0 1px 1px rgba(0,0,0,0.25);
223
+ --shadow-md: 0 4px 12px rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.3);
224
+ --shadow-lg: 0 12px 32px rgba(0,0,0,0.55), 0 2px 6px rgba(0,0,0,0.35);
225
+ }
226
+
227
+ html[data-theme="dark"] body { background: var(--bg); color: var(--fg1); }
228
+ html[data-theme="dark"] .app { background: var(--bg); color: var(--fg1); }
229
+
230
+ html[data-theme="dark"] .tb {
231
+ background: rgba(5, 11, 23, 0.82);
232
+ backdrop-filter: blur(14px);
233
+ border-bottom-color: var(--line);
234
+ }
235
+
236
+ /* 改善 watermark — large faded glyph anchored to the bottom-left of the
237
+ right-column scroll area, just like the brand landing page. Decorative
238
+ only; pointer-events:none so it never intercepts clicks. */
239
+ html[data-theme="dark"] .app > .right-col {
240
+ position: relative;
241
+ }
242
+ html[data-theme="dark"] .app > .right-col::before {
243
+ content: '改';
244
+ position: absolute;
245
+ left: -40px;
246
+ bottom: -60px;
247
+ font-family: var(--font-display, 'Manrope'), sans-serif;
248
+ font-size: 380px;
249
+ font-weight: 800;
250
+ color: var(--brand-green-400);
251
+ opacity: 0.025;
252
+ pointer-events: none;
253
+ user-select: none;
254
+ z-index: 0;
255
+ letter-spacing: -0.05em;
256
+ line-height: 0.85;
257
+ }
258
+ html[data-theme="dark"] .app > .right-col > * { position: relative; z-index: 1; }
259
+
260
+ /* Brand-green focus rings + selection in dark mode. */
261
+ html[data-theme="dark"] .btn-primary {
262
+ background: var(--brand-green-500);
263
+ color: var(--brand-blue-900);
264
+ }
265
+ html[data-theme="dark"] .btn-primary:hover { background: var(--brand-green-400); }
266
+ html[data-theme="dark"] ::selection { background: rgba(0, 255, 135, 0.30); color: #fff; }
267
+ html[data-theme="dark"] .tb .crumb { color: var(--fg2); }
268
+ html[data-theme="dark"] .tb .crumb b { color: var(--fg1); }
269
+ html[data-theme="dark"] .tb .runsel {
270
+ background: var(--bg-elev);
271
+ border-color: var(--line);
272
+ color: var(--fg1);
273
+ }
274
+
275
+ html[data-theme="dark"] .btn-secondary {
276
+ background: var(--bg-elev);
277
+ border-color: var(--line);
278
+ color: var(--fg1);
279
+ }
280
+ html[data-theme="dark"] .btn-secondary:hover {
281
+ background: var(--bg-hover);
282
+ border-color: var(--line-strong);
283
+ }
284
+ html[data-theme="dark"] .btn-ghost { color: var(--fg2); }
285
+ html[data-theme="dark"] .btn-ghost:hover { background: var(--bg-hover); color: var(--fg1); }
286
+
287
+ html[data-theme="dark"] .theme-toggle {
288
+ background: var(--bg-elev);
289
+ border-color: var(--line);
290
+ color: var(--fg2);
291
+ }
292
+ html[data-theme="dark"] .theme-toggle:hover {
293
+ background: var(--bg-hover);
294
+ color: var(--brand-green-400);
295
+ border-color: var(--line-strong);
296
+ }
297
+
298
+ html[data-theme="dark"] .card {
299
+ background: var(--bg-elev);
300
+ border-color: var(--line);
301
+ }
302
+ html[data-theme="dark"] .card .hd h3,
303
+ html[data-theme="dark"] .card .hd .meta { color: var(--fg3); }
304
+
305
+ html[data-theme="dark"] .trow { border-bottom-color: var(--line); }
306
+ html[data-theme="dark"] .trow:hover { background: var(--bg-hover); }
307
+ html[data-theme="dark"] .trow .id { color: var(--fg1); }
308
+ html[data-theme="dark"] .trow .id .ns { color: var(--fg3); }
309
+ html[data-theme="dark"] .trow .dur { color: var(--fg2); }
310
+
311
+ html[data-theme="dark"] .tabs { border-bottom-color: var(--line); }
312
+ html[data-theme="dark"] .tab { color: var(--fg3); }
313
+ html[data-theme="dark"] .tab:hover { color: var(--fg1); }
314
+ html[data-theme="dark"] .tab.active { color: var(--fg1); border-bottom-color: var(--brand-blue-400); }
315
+
316
+ html[data-theme="dark"] .env .k { color: var(--fg3); border-bottom-color: var(--line); }
317
+ html[data-theme="dark"] .env .v { color: var(--fg1); border-bottom-color: var(--line); }
318
+
319
+ html[data-theme="dark"] .statnum { color: var(--fg1); }
320
+ html[data-theme="dark"] .statlbl { color: var(--fg3); }
321
+
322
+ html[data-theme="dark"] .step { border-left-color: var(--line); }
323
+ html[data-theme="dark"] .step .head .name { color: var(--fg1); }
324
+ html[data-theme="dark"] .step .head .dur { color: var(--fg3); }
325
+ html[data-theme="dark"] .step .body { color: var(--fg2); }
326
+
327
+ html[data-theme="dark"] .log {
328
+ background: #04080F;
329
+ border: 1px solid var(--line);
330
+ }
331
+
332
+ html[data-theme="dark"] svg .grid-line,
333
+ html[data-theme="dark"] svg .axis-line { stroke: var(--line); }
334
+ html[data-theme="dark"] svg text.axis-label,
335
+ html[data-theme="dark"] svg text.chart-label { fill: var(--fg3); }
336
+ html[data-theme="dark"] svg text.chart-value { fill: var(--fg1); }
337
+
338
+ html[data-theme="dark"] input,
339
+ html[data-theme="dark"] textarea,
340
+ html[data-theme="dark"] select {
341
+ background: var(--bg-elev);
342
+ color: var(--fg1);
343
+ border-color: var(--line);
344
+ }
345
+ html[data-theme="dark"] input::placeholder,
346
+ html[data-theme="dark"] textarea::placeholder { color: var(--fg4); }
347
+
348
+ html[data-theme="dark"] ::-webkit-scrollbar { width: 10px; height: 10px; }
349
+ html[data-theme="dark"] ::-webkit-scrollbar-track { background: var(--bg); }
350
+ html[data-theme="dark"] ::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 6px; }
351
+ html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: var(--fg4); }
352
+
353
+ body, .app, .tb, .card, .sb, .runsel, .btn, .theme-toggle, .trow, .step, .log, .env .k, .env .v {
354
+ transition: background var(--dur-base) var(--ease-out),
355
+ color var(--dur-base) var(--ease-out),
356
+ border-color var(--dur-base) var(--ease-out);
357
+ }