-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathviewer.css
More file actions
300 lines (276 loc) · 23.7 KB
/
Copy pathviewer.css
File metadata and controls
300 lines (276 loc) · 23.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* viewer.css — components for the takeover page (html.jk-active) and the viewer page (.jk-page).
Tokens live in tokens.css and must load first. jk-prefixed classes throughout: this stylesheet
is injected into arbitrary pages, and the prefix is the only thing keeping it out of theirs. */
html.jk-active, html.jk-active body { margin:0; height:100%; background:var(--jk-canvas); }
html.jk-active .jk-root { height:100vh; }
.jk-wrap { display:flex; flex-direction:column; height:100%; min-height:0; background:var(--jk-panel); color:var(--jk-fg);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
.jk-mono { font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; }
/* toolbar */
.jk-bar { display:flex; align-items:center; gap:8px; padding:9px 12px; background:var(--jk-bar); border-bottom:1px solid var(--jk-border); flex:0 0 auto; }
.jk-btn { font:inherit; font-size:12.5px; font-weight:540; white-space:nowrap; padding:6px 11px; display:inline-flex; align-items:center; gap:6px;
cursor:pointer; border:1px solid var(--jk-border2); background:var(--jk-panel); color:var(--jk-fg); border-radius:7px; }
.jk-btn:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-btn.jk-icon { padding:6px 9px; font-size:14px; }
.jk-btn.on { border-color:var(--jk-accent); color:var(--jk-accent); background:var(--jk-accent-soft); }
.jk-skin { font:inherit; font-size:12px; padding:6px 6px; border:1px solid var(--jk-border2); border-radius:7px;
background:var(--jk-panel); color:var(--jk-fg); cursor:pointer; }
.jk-btn.jk-primary { background:var(--jk-accent); border-color:var(--jk-accent); color:#fff; }
.jk-btn.jk-primary:hover { color:#fff; filter:brightness(1.06); }
.jk-ic { width:14px; height:14px; }
/* Sorting is remembered across sessions and Copy JSON hands back the sorted order, so the fact
has to live in the strip that never moves — not behind the ⋯ menu. Warning-toned, not error:
sorting is a feature the user asked for, it just must not be invisible. */
.jk-chip-sort { color:var(--jk-num); border-color:color-mix(in srgb, var(--jk-num) 35%, transparent); }
.jk-chip-sort[hidden] { display:none; }
/* overflow menu — where every occasional control lives, and where later features hang theirs.
The popup must sit above the tree (which paints its own rows), hence the z-index. */
.jk-menu { position:relative; flex:0 0 auto; }
.jk-menu-pop { position:absolute; top:calc(100% + 6px); right:0; z-index:20; min-width:200px;
padding:5px; background:var(--jk-panel); border:1px solid var(--jk-border2); border-radius:9px;
box-shadow:var(--jk-shadow); display:flex; flex-direction:column; gap:2px; }
/* display:flex above beats the UA [hidden]{display:none} (same specificity, author sheet wins),
so the menu ignored its hidden attribute and stood permanently open over the tree. The toggle
sets pop.hidden; this is what makes that mean anything. Node's stub has no CSS, so 400 tests
stayed green while the shipped menu never closed — the first real-browser run caught it. */
.jk-menu-pop[hidden] { display:none; }
.jk-menu-g { display:flex; flex-direction:column; gap:2px; }
.jk-menu-g + .jk-menu-g { margin-top:5px; padding-top:5px; border-top:1px solid var(--jk-border); }
.jk-menu-i { font:inherit; font-size:12.5px; text-align:left; white-space:nowrap; padding:6px 9px;
border:0; border-radius:6px; background:transparent; color:var(--jk-fg); cursor:pointer; }
.jk-menu-i:hover { background:var(--jk-panel2); }
.jk-menu-i:focus-visible { outline:2px solid var(--jk-accent); outline-offset:-2px; }
.jk-menu-i.on { color:var(--jk-accent); background:var(--jk-accent-soft); }
.jk-menu-i[hidden] { display:none; }
.jk-menu-row { display:flex; align-items:center; justify-content:space-between; gap:10px; cursor:default; }
.jk-menu-row:hover { background:transparent; }
.jk-seg { display:flex; border:1px solid var(--jk-border2); border-radius:7px; overflow:hidden; }
.jk-seg button { font:inherit; font-size:12.5px; font-weight:540; white-space:nowrap; padding:6px 11px; border:0; background:var(--jk-panel); color:var(--jk-dim); cursor:pointer; }
.jk-seg button.on { background:var(--jk-accent-soft); color:var(--jk-accent); }
.jk-search { flex:1; min-width:120px; display:flex; align-items:center; gap:6px; background:var(--jk-panel); border:1px solid var(--jk-border2); border-radius:7px; padding:0 8px 0 10px; }
.jk-search input { flex:1; border:0; outline:0; background:transparent; color:var(--jk-fg); font:inherit; font-size:12.5px; padding:6px 0; }
.jk-search .jk-ic { width:13px; height:13px; opacity:.45; }
.jk-search kbd { font-family:ui-monospace,monospace; font-size:10px; color:var(--jk-faint); border:1px solid var(--jk-border2); border-radius:4px; padding:0 5px; }
.jk-find-n { font-family:ui-monospace,monospace; font-size:11px; color:var(--jk-faint); white-space:nowrap; }
.jk-find-b { font:inherit; font-size:12px; line-height:1; padding:2px 5px; border:1px solid var(--jk-border2); border-radius:5px; background:var(--jk-panel); color:var(--jk-dim); cursor:pointer; }
.jk-find-b:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-meta { display:flex; align-items:center; gap:10px; font-size:11.5px; color:var(--jk-faint); white-space:nowrap; }
.jk-chip { font-size:10.5px; font-weight:600; color:var(--jk-good); border:1px solid color-mix(in srgb, var(--jk-good) 32%, transparent); border-radius:999px; padding:2px 8px; white-space:nowrap; }
.jk-flash { font-size:12px; font-weight:600; color:var(--jk-accent); white-space:nowrap; }
/* query bar — its own row under the toolbar (see core.js QUERY for why it's not in the toolbar) */
.jk-query { flex:0 0 auto; background:var(--jk-bar); border-bottom:1px solid var(--jk-border); padding:6px 12px; }
.jk-query-row { display:flex; align-items:center; gap:8px; }
.jk-query-sig { color:var(--jk-accent); font-weight:700; font-size:13px; flex:0 0 auto; }
.jk-query-in { flex:1; min-width:0; border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel);
color:var(--jk-fg); font-size:12.5px; padding:5px 10px; outline:0; }
.jk-query-in:focus { border-color:var(--jk-accent); }
.jk-query-in.bad { border-color:var(--jk-bad); }
.jk-query-n { flex:0 0 auto; font-size:11.5px; color:var(--jk-dim); white-space:nowrap; font-variant-numeric:tabular-nums; }
.jk-query-clear { flex:0 0 auto; font:inherit; font-size:13px; line-height:1; padding:3px 8px; cursor:pointer;
border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel); color:var(--jk-dim); }
.jk-query-clear:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
/* Error text uses the same tokened warn color as the rest — it's a message, not a moat signal. */
.jk-query-err { margin-top:6px; font-size:11.5px; color:var(--jk-bad); white-space:pre-wrap; word-break:break-word; }
.jk-query-err[hidden], .jk-query-n[hidden], .jk-query-clear[hidden] { display:none; }
/* breadcrumb */
.jk-crumb { flex:0 0 auto; padding:5px 14px; font-size:11.5px; color:var(--jk-dim); background:var(--jk-panel); border-bottom:1px solid var(--jk-border); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Ancestor segments jump; the current node doesn't (it's where you already are). */
.jk-crumb-i { font:inherit; font-size:11.5px; color:var(--jk-dim); background:transparent; border:0; padding:0; cursor:pointer; border-radius:3px; }
.jk-crumb-i:hover { color:var(--jk-accent); text-decoration:underline; }
.jk-crumb-i:focus-visible { outline:2px solid var(--jk-accent); outline-offset:1px; }
.jk-crumb-cur { color:var(--jk-fg); font-weight:600; }
/* main = source editor | draggable divider | tree/table view (with the STRUCTURE drawer overlaid).
The source moved out of a hidden Raw tab and into a permanent left pane you can edit; the tree on
the right follows what you type (core.js ingest, debounced). */
.jk-main { flex:1 1 auto; display:flex; min-height:0; position:relative; }
/* left: the editable source */
.jk-edit-pane { flex:0 0 42%; display:flex; flex-direction:column; min-width:0; border-right:1px solid var(--jk-border); }
.jk-src { flex:1 1 auto; width:100%; box-sizing:border-box; resize:none; border:0; outline:0; tab-size:2;
background:var(--jk-canvas); color:var(--jk-fg); font-size:12.5px; line-height:1.6; padding:12px 14px; white-space:pre; overflow:auto; }
.jk-src::placeholder { color:var(--jk-faint); }
/* Won't parse: mark the whole source edge, not a character — we know the doc is bad, not where. */
.jk-src.jk-bad { box-shadow: inset 3px 0 0 var(--jk-bad); }
.jk-src-err { flex:0 0 auto; padding:7px 14px; font-size:11.5px; color:var(--jk-bad); background:var(--jk-panel2);
border-top:1px solid var(--jk-border); white-space:pre-wrap; word-break:break-word; }
.jk-src-err[hidden] { display:none; }
/* the divider */
.jk-splitter { flex:0 0 7px; cursor:col-resize; background:var(--jk-border); touch-action:none; }
.jk-splitter:hover, .jk-dragging .jk-splitter { background:var(--jk-accent); }
/* Mid-drag the panes must not eat the pointer — otherwise dragging over the textarea selects its
text instead of resizing, and the release never reaches the divider. */
.jk-dragging { cursor:col-resize; }
.jk-dragging .jk-edit-pane, .jk-dragging .jk-view-pane { pointer-events:none; user-select:none; }
/* right: the tree/table view */
.jk-view-pane { flex:1 1 auto; display:flex; position:relative; min-width:0; }
.jk-scroll { flex:1 1 auto; position:relative; overflow:auto; }
/* right-pane placeholders: large-file build offer, and the empty/invalid prompt */
.jk-heavy, .jk-empty { padding:26px 22px; max-width:460px; color:var(--jk-dim); font-size:13px; line-height:1.6; }
.jk-heavy-t { margin:0 0 12px; }
.jk-heavy-s { margin:12px 0 0; font-size:11.5px; color:var(--jk-faint); }
.jk-empty { color:var(--jk-faint); }
/* STRUCTURE drawer — the ☰ pop-out. Overlays the tree from the left; a permanent rail had no room
once the body became two panes. Item styles (.jk-rail-*) are unchanged; only the container is. */
.jk-drawer { position:absolute; top:0; left:0; bottom:0; z-index:15; width:210px; max-width:70%;
overflow:auto; padding:8px 0; background:var(--jk-rail); border-right:1px solid var(--jk-border2); box-shadow:var(--jk-shadow); }
.jk-drawer[hidden] { display:none; }
.jk-rail-h { font-size:10px; font-weight:700; letter-spacing:.1em; color:var(--jk-faint); padding:4px 14px 8px; }
.jk-rail-i { display:flex; align-items:center; justify-content:space-between; gap:8px; width:100%; text-align:left; font:inherit; font-size:12.5px;
font-family:ui-monospace,Menlo,monospace; color:var(--jk-fg); background:transparent; border:0; border-left:2px solid transparent; padding:5px 14px; cursor:pointer; }
.jk-rail-i:hover { background:color-mix(in srgb, var(--jk-accent) 8%, transparent); }
.jk-rail-i.on { border-left-color:var(--jk-accent); background:var(--jk-accent-soft); color:var(--jk-accent); }
.jk-rail-k { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.jk-rail-n { font-size:11px; color:var(--jk-faint); }
/* Zero hits used to mean every row at 26% opacity plus a bare "0" in the toolbar — the document
looked broken rather than unmatched. Nothing found, nothing dimmed; this says it in words.
Sticky so it stays put if the tree under it is long. */
.jk-nohits { position:sticky; top:0; z-index:2; padding:7px 14px; font-size:12px;
color:var(--jk-dim); background:var(--jk-panel2); border-bottom:1px solid var(--jk-border); }
.jk-nohits[hidden] { display:none; }
/* disabled Table segment (F-106): dimmed, its reason in the tooltip, not clickable */
.jk-seg button:disabled { color:var(--jk-faint); cursor:not-allowed; opacity:.55; }
.jk-seg button:disabled:hover { background:var(--jk-panel); color:var(--jk-faint); }
/* table view (feature 2) */
.jk-table-wrap { padding:0; }
.jk-table { border-collapse:collapse; font-family:ui-monospace,"SF Mono",Menlo,monospace; font-size:12.5px; width:max-content; min-width:100%; }
.jk-th { position:sticky; top:0; z-index:1; text-align:left; font-weight:600; color:var(--jk-dim); background:var(--jk-bar);
border-bottom:1px solid var(--jk-border2); padding:7px 12px; white-space:nowrap; }
.jk-th-idx, .jk-td-idx { color:var(--jk-faint); text-align:right; font-variant-numeric:tabular-nums; }
.jk-td { border-bottom:1px solid var(--jk-guide); padding:5px 12px; white-space:nowrap; vertical-align:top; }
.jk-td-idx { user-select:none; }
/* Missing field: faint, non-selectable em dash — deliberately NOT the same as a null value, which
renders through valueHTML in the --jk-null colour. That contrast is the whole point (F-104). */
.jk-missing { color:var(--jk-faint); opacity:.6; user-select:none; }
.jk-cell-nested { font:inherit; color:var(--jk-accent); background:transparent; border:0; padding:0; cursor:pointer; border-radius:3px; }
.jk-cell-nested:hover { text-decoration:underline; }
.jk-table-more { padding:8px 12px; font-size:11.5px; color:var(--jk-dim); background:var(--jk-panel2); border-top:1px solid var(--jk-border); }
/* side panel (feature 3 export/validate; feature 4 reuses) */
.jk-panel { position:absolute; inset:0; z-index:30; display:flex; justify-content:flex-end;
background:color-mix(in srgb, var(--jk-fg) 22%, transparent); }
.jk-panel-card { display:flex; flex-direction:column; width:min(560px, 92%); height:100%;
background:var(--jk-panel); border-left:1px solid var(--jk-border2); box-shadow:var(--jk-shadow); }
.jk-panel-head { display:flex; align-items:center; gap:10px; padding:11px 14px; border-bottom:1px solid var(--jk-border); background:var(--jk-bar); }
.jk-panel-title { flex:1; font-weight:600; font-size:13px; color:var(--jk-fg); }
.jk-panel-close { flex:0 0 auto; font:inherit; font-size:14px; line-height:1; padding:3px 8px; cursor:pointer;
border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel); color:var(--jk-dim); }
.jk-panel-close:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-panel-body { flex:1 1 auto; overflow:auto; padding:14px; display:flex; flex-direction:column; gap:10px; }
.jk-panel-foot { flex:0 0 auto; display:flex; gap:8px; justify-content:flex-end; padding:10px 14px; border-top:1px solid var(--jk-border); }
.jk-panel-btn { font:inherit; font-size:12.5px; font-weight:540; padding:6px 14px; cursor:pointer;
border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel); color:var(--jk-fg); }
.jk-panel-btn:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-panel-btn.jk-primary { background:var(--jk-accent); border-color:var(--jk-accent); color:#fff; }
.jk-panel-code { margin:0; font-size:12.5px; line-height:1.6; white-space:pre; overflow:auto; color:var(--jk-fg);
background:var(--jk-panel2); border:1px solid var(--jk-border); border-radius:8px; padding:12px; }
.jk-panel-badge { align-self:flex-start; font-size:11px; font-weight:600; color:var(--jk-num);
border:1px solid color-mix(in srgb, var(--jk-num) 35%, transparent); border-radius:999px; padding:2px 10px; }
.jk-panel-input { width:100%; min-height:140px; resize:vertical; font-size:12.5px; padding:10px;
border:1px solid var(--jk-border2); border-radius:8px; background:var(--jk-panel2); color:var(--jk-fg); outline:0; box-sizing:border-box; }
.jk-panel-input:focus { border-color:var(--jk-accent); }
.jk-panel-result { display:flex; flex-direction:column; gap:6px; }
.jk-panel-ok { color:var(--jk-good); font-weight:600; font-size:13px; }
.jk-panel-err { color:var(--jk-bad); font-size:12.5px; white-space:pre-wrap; word-break:break-word; }
.jk-panel-count { font-size:12px; color:var(--jk-dim); font-weight:600; }
.jk-panel-issue { text-align:left; font:inherit; font-size:12px; line-height:1.5; padding:7px 10px; cursor:pointer;
border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel); color:var(--jk-fg); }
.jk-panel-issue:hover { border-color:var(--jk-bad); }
.jk-panel-kw { font-weight:600; color:var(--jk-bad); }
.jk-panel-at { color:var(--jk-dim); }
/* subtree panel — a table's nested cell opens its value here, over the table (F-107) */
.jk-subtree { position:absolute; inset:0; z-index:30; display:flex; align-items:center; justify-content:center;
background:color-mix(in srgb, var(--jk-fg) 22%, transparent); padding:32px; }
.jk-subtree[hidden] { display:none; }
.jk-subtree-card { display:flex; flex-direction:column; max-width:720px; max-height:100%; width:100%;
background:var(--jk-panel); border:1px solid var(--jk-border2); border-radius:11px; box-shadow:var(--jk-shadow); overflow:hidden; }
.jk-subtree-head { display:flex; align-items:center; gap:10px; padding:9px 12px; border-bottom:1px solid var(--jk-border); background:var(--jk-bar); }
.jk-subtree-path { flex:1; min-width:0; font-size:11.5px; color:var(--jk-dim); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.jk-subtree-close { flex:0 0 auto; font:inherit; font-size:13px; line-height:1; padding:3px 8px; cursor:pointer;
border:1px solid var(--jk-border2); border-radius:7px; background:var(--jk-panel); color:var(--jk-dim); }
.jk-subtree-close:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-subtree-body { overflow:auto; }
/* tree */
.jk-tree { font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; font-size:13px; line-height:1.65; padding:8px 0; }
.jk-row { position:relative; display:flex; align-items:flex-start; padding:0 14px; white-space:pre; transition:background .25s; }
.jk-row:hover { background:color-mix(in srgb, var(--jk-accent) 6%, transparent); }
.jk-row.jk-hit { background:color-mix(in srgb, var(--jk-accent) 18%, transparent); }
.jk-row.jk-dim { opacity:.26; }
.jk-row.jk-current { background:var(--jk-cur); box-shadow: inset 2px 0 0 var(--jk-cur-bd); }
/* Schema-validation error (feature 3). A left rail + tinted ground, deliberately using a
different channel than search (search tints the whole background / dims): a row can be both a
search match and invalid, and both must read. inset border on the right stays clear of
jk-current's left inset. */
.jk-row.jk-invalid { background:color-mix(in srgb, var(--jk-bad) 12%, transparent); box-shadow: inset -3px 0 0 var(--jk-bad); }
.jk-gutter { width:44px; flex:0 0 44px; text-align:right; padding-right:12px; color:var(--jk-faint); opacity:.65; user-select:none; font-variant-numeric:tabular-nums; }
.jk-content { flex:1; }
.jk-ind { color:var(--jk-guide); }
.jk-caret { display:inline-block; width:12px; color:var(--jk-faint); cursor:pointer; user-select:none; transition:transform .12s; }
.jk-caret.jk-collapsed { transform:rotate(-90deg); }
.jk-caret.jk-leaf { visibility:hidden; }
.jk-key{color:var(--jk-key);} .jk-str{color:var(--jk-str);} .jk-num{color:var(--jk-num);}
.jk-bool{color:var(--jk-bool);} .jk-null{color:var(--jk-null);} .jk-pun{color:var(--jk-pun);}
.jk-count { color:var(--jk-faint); font-size:11.5px; margin-left:6px; }
/* "0 keys" looks like "8 keys"; an empty container should not be mistaken for a failed render. */
.jk-empty { font-style:italic; }
.jk-prev { color:var(--jk-faint); font-style:italic; }
.jk-precise { text-decoration: underline dotted color-mix(in srgb, var(--jk-num) 55%, transparent); text-underline-offset:3px; cursor:help; }
/* The status bar can only count duplicates; this says which row.
Out of the text flow, like .jk-acts. Anything inline fails here: the row is white-space:pre,
so a long value keeps pushing the marker rightwards while .jk-acts stays pinned to the right
edge — measured, an 80-char value put the warning under the copy buttons and a 120-char one
pushed it off-screen entirely. Margin can't fix that; it only moves where it breaks. Long
values are the common case in real JSON, so the marker anchors to the row instead.
Resolves against .jk-row (position:relative). On hover it steps aside for .jk-acts. */
.jk-dup { position:absolute; right:10px; top:0; z-index:1; font-size:10.5px; font-weight:600;
color:var(--jk-num); background:var(--jk-panel);
border:1px solid color-mix(in srgb, var(--jk-num) 34%, transparent);
border-radius:999px; padding:0 7px; cursor:help; user-select:none;
transition:right .12s; }
.jk-row:hover .jk-dup { right:118px; }
/* per-node hover actions */
.jk-acts { position:absolute; right:0; top:0; height:100%; display:none; align-items:center; gap:4px;
padding:0 12px 0 28px; background:linear-gradient(to right, transparent, var(--jk-panel) 22px); }
.jk-row:hover .jk-acts { display:flex; }
.jk-act { font-family:ui-monospace,monospace; font-size:10.5px; line-height:1; padding:3px 7px; border:1px solid var(--jk-border2);
border-radius:5px; background:var(--jk-panel); color:var(--jk-dim); cursor:pointer; }
.jk-act:hover { border-color:var(--jk-accent); color:var(--jk-accent); }
.jk-raw { margin:0; padding:12px 14px 12px 56px; font-size:12.5px; line-height:1.6; color:var(--jk-fg); white-space:pre; }
/* #d6453c was 4.40:1 on white / 4.12:1 on the dark canvas — under AA on both, and with no
dark variant at all: the same red on every background. It's the parse error, the one string
you most need to read. */
.jk-error { padding:14px 16px; color:var(--jk-bad); font-family:ui-monospace,monospace; font-size:13px; }
/* status bar */
.jk-status { flex:0 0 auto; display:flex; align-items:center; gap:14px; padding:5px 14px; font-size:11px;
background:var(--jk-bar); border-top:1px solid var(--jk-border); color:var(--jk-dim); white-space:nowrap; overflow:hidden; }
.jk-status .jk-ok { color:var(--jk-good); font-weight:600; }
/* min-width:0 + ellipsis is load-bearing, not polish. .jk-status is a nowrap flex row with
overflow:hidden, and a nowrap text item's min-width:auto resolves to min-content — so nothing
shrinks and the row is simply cut off from the right. With 4 duplicate keys at 1080px that
amputated everything downstream: the size note, the Build tree button, and the trust line.
The warning is the one item here that can lose its tail and still do its job. */
/* Was a hard-coded #b8860b: 3.25:1 on white — below AA — for the duplicate-key warning, i.e.
the one line this product exists to show. Now a token, so both themes are picked on purpose
and the two manual dark overrides that used to sit below are gone with it. */
.jk-warn { color:var(--jk-warn); font-weight:600; min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* Nothing downstream of the warning may be shrunk away — .jk-build is the only control in this
bar, and the trust line is a product promise. */
.jk-build, .jk-trust, .jk-status .jk-st { flex:0 0 auto; }
.jk-st b { color:var(--jk-fg); font-weight:600; }
.jk-spacer { flex:1; }
.jk-trust { color:var(--jk-faint); }
/* The demand in "tree built on demand" — without it the sentence states a policy and offers
no way to invoke it. Accent-bordered because it's the one actionable thing down here. */
.jk-build { font:inherit; font-size:11px; font-weight:600; padding:2px 9px; cursor:pointer;
color:var(--jk-accent); background:transparent; border:1px solid var(--jk-accent); border-radius:11px; }
.jk-build:hover { background:var(--jk-accent-soft); }
/* Skeleton shown while a large tree builds (see core.js buildDeferred). Deliberately not a
spinner: a spinner says "wait", this says "a tree is coming, and roughly this shape". */
.jk-skel { padding:10px 14px; display:flex; flex-direction:column; gap:9px; }
.jk-skel-row { height:11px; border-radius:3px; background:var(--jk-border2); animation:jk-pulse 1.3s ease-in-out infinite; }
@keyframes jk-pulse { 0%,100% { opacity:.4 } 50% { opacity:.85 } }
/* The pulse carries no information the static bars don't — first thing to drop when asked. */
@media (prefers-reduced-motion: reduce) { .jk-skel-row { animation:none; opacity:.6; } }
/* standalone viewer page — a full-height mount now. The separate paste box on top is gone: the
viewer's own left pane IS the editor, so the page is just the viewer filling the tab. */
html, body.jk-page { height:100%; }
.jk-page { margin:0; background:var(--jk-canvas); color:var(--jk-fg); font-family: system-ui, sans-serif; }
.jk-fullmount { height:100vh; }
.jk-fullmount .jk-wrap { height:100%; }