blockyard 0.0.9 → 0.1.1
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/CHANGELOG.md +359 -1
- package/README.md +48 -27
- package/SECURITY.md +2 -2
- package/bin/blockyard.js +2 -1
- package/docs/API.md +17 -15
- package/docs/ARCHITECTURE.md +128 -10
- package/docs/CONFIGURATION.md +39 -30
- package/docs/DEFECTS.md +4 -1
- package/docs/GETTING-STARTED.md +18 -8
- package/docs/INSTALL.md +97 -37
- package/docs/MEASUREMENTS.md +147 -0
- package/docs/PLAN-SCORCHED-YARD.md +456 -0
- package/docs/PLAN-SKIES.md +142 -0
- package/docs/SECURITY-AUDIT-2026-09-16.md +647 -0
- package/docs/SECURITY.md +58 -22
- package/docs/TROUBLESHOOTING.md +44 -5
- package/docs/USER-GUIDE.md +505 -35
- package/package.json +4 -2
- package/public/404.html +1 -1
- package/public/css/app.css +393 -82
- package/public/donate-qr.png +0 -0
- package/public/index.html +353 -109
- package/public/js/agents.js +228 -51
- package/public/js/app.js +131 -16
- package/public/js/blockanoid.js +15 -7
- package/public/js/blockout.js +15 -7
- package/public/js/blockscene3d.js +230 -38
- package/public/js/charts.js +21 -21
- package/public/js/depthchart.js +31 -27
- package/public/js/details3d.js +1481 -73
- package/public/js/doom.js +31 -0
- package/public/js/dosaudio.js +48 -0
- package/public/js/dosgame.js +389 -0
- package/public/js/dosio.js +186 -0
- package/public/js/dospc.js +1353 -0
- package/public/js/dosworker.js +196 -0
- package/public/js/explorer.js +7 -1
- package/public/js/livingsky.js +494 -0
- package/public/js/login.js +8 -2
- package/public/js/markets.js +46 -8
- package/public/js/mining.js +314 -36
- package/public/js/panels.js +41 -28
- package/public/js/pricechart.js +14 -13
- package/public/js/quake.js +20 -0
- package/public/js/safenext.js +14 -0
- package/public/js/scorched.js +1051 -0
- package/public/js/scorchedai.js +227 -0
- package/public/js/scorchedair.js +286 -0
- package/public/js/scorchedfx.js +376 -0
- package/public/js/scorchedshop.js +105 -0
- package/public/js/scorchedwind.js +69 -0
- package/public/js/scorchedyard.js +1338 -0
- package/public/js/settings.js +368 -100
- package/public/js/soundcard.js +459 -0
- package/public/js/tetrust.js +15 -6
- package/public/js/tetsound.js +35 -5
- package/public/js/theme.js +235 -0
- package/public/js/wolf3d.js +22 -0
- package/public/js/x86.js +1978 -0
- package/scripts/check.js +46 -0
- package/scripts/donate-qr.py +12 -9
- package/scripts/dos-bench.js +56 -0
- package/scripts/index-build.js +9 -2
- package/scripts/pool-map.js +152 -36
- package/scripts/setup.js +142 -22
- package/scripts/shots.mjs +27 -0
- package/scripts/smoke.sh +7 -6
- package/scripts/tls.js +31 -0
- package/scripts/ui.js +4 -2
- package/server/auth/sessions.js +33 -13
- package/server/chain/blockfile.js +64 -5
- package/server/chain/index/build.js +451 -58
- package/server/chain/index/heights.js +29 -3
- package/server/chain/index/live.js +13 -7
- package/server/chain/index/rows.js +6 -1
- package/server/chain/index/store.js +28 -5
- package/server/chain/index/worker.js +23 -11
- package/server/collect/logparse.js +65 -18
- package/server/collect/markets.js +76 -7
- package/server/collect/mining.js +32 -0
- package/server/collect/monitor.js +54 -12
- package/server/collect/network.js +305 -0
- package/server/config.js +53 -22
- package/server/http/api.js +119 -18
- package/server/http/games.js +77 -0
- package/server/http/server.js +30 -5
- package/server/http/sse.js +53 -7
- package/server/main.js +66 -11
- package/server/rpc/allowlist.js +26 -0
- package/server/rpc/client.js +30 -2
- package/server/store/audit.js +6 -1
- package/server/store/history.js +19 -3
- package/server/store/ledger.js +15 -4
- package/server/tls/selfsigned.js +160 -0
- package/systemd/blockyard.service +41 -8
- package/docs/PRIVATE-LEADERBOARD.md +0 -230
- package/docs/STATE-2026-09-09.md +0 -200
package/public/css/app.css
CHANGED
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
--purple: #a78bfa;
|
|
23
23
|
--cyan: #4dd0e1;
|
|
24
24
|
--pink: #f06ba7;
|
|
25
|
+
/* APPEARANCE (theme.js, 2026-09-16): every colour above and these below are rewritten on <html>
|
|
26
|
+
when a theme is chosen; the values here are the shipped dark look, which is the default theme */
|
|
27
|
+
--bg-0: #0c0e11; /* the well: inputs, bars, code */
|
|
28
|
+
--accent-ink: #17110a; /* text on an accent button */
|
|
29
|
+
--hover: rgba(255, 255, 255, 0.025);
|
|
30
|
+
--scrim: rgba(2, 5, 9, 0.62);
|
|
31
|
+
color-scheme: dark;
|
|
25
32
|
--radius: 10px;
|
|
26
33
|
--radius-sm: 6px;
|
|
27
34
|
--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
@@ -72,13 +79,13 @@ header.top {
|
|
|
72
79
|
/* THE MONOGRAM. The tile, its gradient and the three courses of blocks along the bottom all
|
|
73
80
|
live in the SVG itself, so the mark is one object and the favicon is the same drawing --
|
|
74
81
|
no CSS needed to make it look right, which is what a favicon cannot have anyway. */
|
|
75
|
-
.brand .mark { width: 22px; height: 22px; display: block; flex: 0 0 auto; border-radius: 6px; box-shadow: 0 0 14px
|
|
82
|
+
.brand .mark { width: 22px; height: 22px; display: block; flex: 0 0 auto; border-radius: 6px; box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 27%, transparent); }
|
|
76
83
|
.wordmark { font-weight: 600; letter-spacing: .2px; }
|
|
77
84
|
.wordmark b { font-weight: 750; color: var(--accent); }
|
|
78
85
|
/* The brand is a <button> now (it routes to About), so the browser's button chrome has to go:
|
|
79
86
|
without this the header grows a border, a background and the UA's own font. */
|
|
80
87
|
button.brand { background: none; border: 0; padding: 0; margin: 0; color: inherit; font: inherit; cursor: pointer; text-align: left; }
|
|
81
|
-
button.brand:hover .wordmark b { color: #
|
|
88
|
+
button.brand:hover .wordmark b { color: color-mix(in srgb, var(--accent) 70%, #fff); }
|
|
82
89
|
button.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
|
|
83
90
|
|
|
84
91
|
/* ==========================================================================
|
|
@@ -86,9 +93,13 @@ button.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3
|
|
|
86
93
|
the one view with no data for it to sit behind, so the sky canvas fills the
|
|
87
94
|
panel and the text floats over it -- the same arrangement Tetrust uses.
|
|
88
95
|
========================================================================== */
|
|
89
|
-
|
|
96
|
+
/* the same packing every tab got (2026-09-15, "same treatment on the about page"): the sky fills the
|
|
97
|
+
window to its bottom edge, the inner air is tighter, and the GitHub link and the tip pill share a
|
|
98
|
+
row -- so the whole page, credit line included, sits on one screen with no scroll */
|
|
99
|
+
.aboutwrap { position: relative; border-radius: var(--radius); overflow: hidden; background: #000; border: 1px solid var(--line-soft); min-height: calc(100vh - 100px); }
|
|
90
100
|
.absky { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
|
|
91
|
-
.aboutinner { position: relative; z-index: 1; padding:
|
|
101
|
+
.aboutinner { position: relative; z-index: 1; padding: 28px clamp(20px, 5vw, 64px) 22px; display: flex; flex-direction: column; gap: 18px; max-width: 1080px; margin: 0 auto; min-height: calc(100vh - 100px); box-sizing: border-box; }
|
|
102
|
+
.ablinks { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
|
|
92
103
|
.abhead { display: flex; align-items: flex-start; gap: 18px; }
|
|
93
104
|
.ablogo { width: 64px; height: 64px; flex: 0 0 auto; border-radius: 14px; box-shadow: 0 0 28px #f7931a55; }
|
|
94
105
|
.abhead h1 { margin: 0 0 6px; font-size: 34px; font-weight: 600; letter-spacing: .3px; text-shadow: 0 2px 14px #000; }
|
|
@@ -98,9 +109,9 @@ button.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3
|
|
|
98
109
|
BlockYard is, and it sits over a galaxy, so it needs the contrast. */
|
|
99
110
|
.abhead p { margin: 0; max-width: 62ch; color: #ffffff; line-height: 1.6; text-shadow: 0 1px 8px #000; }
|
|
100
111
|
.abcols { display: grid; grid-template-columns: repeat(auto-fit, minmax(238px, 1fr)); gap: 14px; }
|
|
101
|
-
.abcard { background: rgba(8, 12, 18, .72); border: 1px solid #1d2733; border-radius: var(--radius); padding: 14px
|
|
102
|
-
.abcard h3 { margin: 0 0
|
|
103
|
-
.abrow { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding:
|
|
112
|
+
.abcard { background: rgba(8, 12, 18, .72); border: 1px solid #1d2733; border-radius: var(--radius); padding: 11px 14px; }
|
|
113
|
+
.abcard h3 { margin: 0 0 7px; font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--fg-faint); font-weight: 600; }
|
|
114
|
+
.abrow { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 2px 0; font-family: var(--mono); font-size: 12.5px; }
|
|
104
115
|
.abrow span { color: var(--fg-dim); }
|
|
105
116
|
.abrow b { font-weight: 600; color: var(--fg); text-align: right; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
|
|
106
117
|
.abgh { display: inline-flex; align-items: center; gap: 10px; align-self: flex-start; padding: 9px 15px; border-radius: 999px;
|
|
@@ -109,7 +120,7 @@ button.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3
|
|
|
109
120
|
/* the donation address: the same pill, and the whole thing is the copy button */
|
|
110
121
|
.abdon { display: inline-flex; align-items: center; gap: 16px; align-self: flex-start; padding: 12px 18px 12px 12px; border-radius: 16px;
|
|
111
122
|
border: 1px solid #2a3543; background: rgba(8, 12, 18, .8); color: var(--fg); font: inherit; font-size: 13px; cursor: pointer; text-align: left; }
|
|
112
|
-
.abdon .abqr { flex: 0 0 auto; width:
|
|
123
|
+
.abdon .abqr { flex: 0 0 auto; width: 112px; height: 112px; border-radius: 6px; image-rendering: pixelated; image-rendering: crisp-edges; background: #fff; }
|
|
113
124
|
.abdon .abdontext { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
114
125
|
.abdon .abdonlbl { display: inline-flex; align-items: center; gap: 8px; }
|
|
115
126
|
.abdon code { font-size: 12px; letter-spacing: .2px; color: var(--accent); word-break: break-all; }
|
|
@@ -121,7 +132,7 @@ button.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3
|
|
|
121
132
|
@media (max-width: 620px) { .abdon { flex-direction: column; align-items: flex-start; } }
|
|
122
133
|
/* Solid white, not the dim grey the other captions use (operator, 2026-09-12) -- it is the
|
|
123
134
|
one line on the page that is a statement rather than a reading. */
|
|
124
|
-
.abcredit { margin: 0; padding-top: 6px; color: #ffffff; font-size: 13px; font-style: italic; letter-spacing: .3px; text-shadow: 0 1px 8px #000; }
|
|
135
|
+
.abcredit { margin: auto 0 0; padding-top: 6px; color: #ffffff; font-size: 13px; font-style: italic; letter-spacing: .3px; text-shadow: 0 1px 8px #000; }
|
|
125
136
|
@media (max-width: 620px) { .abhead { flex-direction: column; gap: 12px; } .abhead h1 { font-size: 27px; } }
|
|
126
137
|
#loginCard h1 b, .login h1 b { color: var(--accent); }
|
|
127
138
|
.brand small { color: var(--fg-faint); font-weight: 500; }
|
|
@@ -182,7 +193,7 @@ nav.pages button.on { background: var(--bg-3, #12161c); color: var(--accent); bo
|
|
|
182
193
|
border-radius: var(--radius-sm); padding: 4px 8px; font: inherit; font-size: 12px; cursor: pointer;
|
|
183
194
|
}
|
|
184
195
|
.btn:hover { border-color: var(--fg-faint); }
|
|
185
|
-
.btn.primary { background: var(--accent); color:
|
|
196
|
+
.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: #0000; font-weight: 650; }
|
|
186
197
|
.btn.danger { color: var(--bad); }
|
|
187
198
|
.btn:disabled { opacity: .45; cursor: not-allowed; }
|
|
188
199
|
|
|
@@ -200,11 +211,13 @@ main::-webkit-scrollbar-thumb { background: var(--bg-3, #12161c); border-radius:
|
|
|
200
211
|
|
|
201
212
|
/* ---------------------------------------------------------------- cards */
|
|
202
213
|
|
|
203
|
-
.grid { display: grid; gap: 12px; grid-template-columns: repeat(12, 1fr); }
|
|
214
|
+
.grid { display: grid; gap: 12px; grid-template-columns: repeat(12, 1fr); align-items: start; } /* start, not stretch: a short card beside a tall one keeps its own height (2026-09-15) */
|
|
204
215
|
.card {
|
|
205
216
|
grid-column: span 4;
|
|
206
217
|
background: var(--bg-1); border: 1px solid var(--line-soft); border-radius: var(--radius);
|
|
207
|
-
|
|
218
|
+
/* 9/11/8, not 12/13 (operator, 2026-09-15, after Mining, Overview and Block space one by one:
|
|
219
|
+
"same treatment on all the ... tabs"): every card packs tight, the heading closer to its body */
|
|
220
|
+
padding: 9px 11px 8px; box-shadow: var(--shadow); min-width: 0;
|
|
208
221
|
}
|
|
209
222
|
.card.w3 { grid-column: span 3; } .card.w4 { grid-column: span 4; } .card.w5 { grid-column: span 5; }
|
|
210
223
|
.card.w6 { grid-column: span 6; } .card.w7 { grid-column: span 7; } .card.w8 { grid-column: span 8; }
|
|
@@ -213,7 +226,7 @@ main::-webkit-scrollbar-thumb { background: var(--bg-3, #12161c); border-radius:
|
|
|
213
226
|
@media (max-width: 860px) { .card { grid-column: span 12 !important; } }
|
|
214
227
|
|
|
215
228
|
.card > h3 {
|
|
216
|
-
margin: 0 0
|
|
229
|
+
margin: 0 0 6px; font-size: 11px; font-weight: 700; letter-spacing: .09em;
|
|
217
230
|
text-transform: uppercase; color: var(--fg-faint);
|
|
218
231
|
display: flex; align-items: center; gap: 8px;
|
|
219
232
|
}
|
|
@@ -251,13 +264,13 @@ canvas.chart.short { height: 84px; }
|
|
|
251
264
|
nothing was happening. Numbers are tabular so the row does not shimmer. */
|
|
252
265
|
.sync {
|
|
253
266
|
grid-column: span 12;
|
|
254
|
-
background: linear-gradient(180deg,
|
|
267
|
+
background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%);
|
|
255
268
|
border: 1px solid var(--line, #262c35); border-radius: var(--radius);
|
|
256
269
|
padding: 8px 12px 9px; box-shadow: var(--shadow); position: relative;
|
|
257
270
|
}
|
|
258
271
|
.sync::after {
|
|
259
272
|
content: ''; position: absolute; inset: 0; pointer-events: none; border-radius: var(--radius);
|
|
260
|
-
background: radial-gradient(140% 220% at 4% -60%,
|
|
273
|
+
background: radial-gradient(140% 220% at 4% -60%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 55%);
|
|
261
274
|
}
|
|
262
275
|
.strip { display: flex; align-items: baseline; gap: 4px 13px; flex-wrap: wrap; font-family: var(--mono); font-size: 12px; position: relative; z-index: 1; }
|
|
263
276
|
.sf { display: inline-flex; align-items: baseline; gap: 5px; white-space: nowrap; }
|
|
@@ -270,23 +283,23 @@ canvas.chart.short { height: 84px; }
|
|
|
270
283
|
.sf.accent b { color: var(--accent); } .sf.ok b { color: var(--ok); } .sf.bad b { color: var(--bad); }
|
|
271
284
|
.sf.warn b { color: var(--warn); }
|
|
272
285
|
.sf.jump { background: none; border: 0; border-left: 1px solid var(--line-soft); padding: 0 0 0 13px; cursor: pointer; font: inherit; }
|
|
273
|
-
.sf.jump b { color: var(--info); text-decoration: underline dotted
|
|
274
|
-
.sf.jump:hover b { color:
|
|
286
|
+
.sf.jump b { color: var(--info); text-decoration: underline dotted color-mix(in srgb, var(--info) 40%, transparent); text-underline-offset: 3px; }
|
|
287
|
+
.sf.jump:hover b { color: color-mix(in srgb, var(--info) 55%, var(--fg)); }
|
|
275
288
|
.strip-tail { margin-left: auto; display: inline-flex; align-items: center; gap: 9px; }
|
|
276
289
|
.sf.note-count { cursor: pointer; }
|
|
277
290
|
.sf.note-count b { text-decoration: underline dotted currentColor; text-underline-offset: 3px; }
|
|
278
291
|
|
|
279
292
|
.bar {
|
|
280
293
|
margin-top: 7px; height: 6px; border-radius: 4px; position: relative;
|
|
281
|
-
background:
|
|
294
|
+
background: var(--bg-0); border: 1px solid var(--line, #262c35); box-shadow: inset 0 1px 2px color-mix(in srgb, var(--bg-0) 60%, #000); overflow: hidden;
|
|
282
295
|
}
|
|
283
296
|
.bar .fill {
|
|
284
297
|
position: absolute; inset: 0 auto 0 0; width: 0;
|
|
285
|
-
background: linear-gradient(90deg,
|
|
298
|
+
background: linear-gradient(90deg, var(--accent-dim), var(--accent));
|
|
286
299
|
transition: width .6s cubic-bezier(.22, .61, .36, 1);
|
|
287
300
|
}
|
|
288
|
-
.bar .fill.done { background: linear-gradient(90deg,
|
|
289
|
-
.bar .fill.stall { background: linear-gradient(90deg,
|
|
301
|
+
.bar .fill.done { background: linear-gradient(90deg, color-mix(in srgb, var(--ok) 60%, var(--bg)), var(--ok)); }
|
|
302
|
+
.bar .fill.stall { background: linear-gradient(90deg, color-mix(in srgb, var(--bad) 60%, var(--bg)), var(--bad)); }
|
|
290
303
|
/* the node's own difficulty-weighted estimate, as a separate marker: the two
|
|
291
304
|
percentages measure different things and are never merged into one number */
|
|
292
305
|
.bar .vp-tick { position: absolute; top: -1px; bottom: -1px; width: 2px; background: #58a6ffee; box-shadow: 0 0 6px #58a6ff99; }
|
|
@@ -297,11 +310,14 @@ canvas.chart.short { height: 84px; }
|
|
|
297
310
|
|
|
298
311
|
.caveat {
|
|
299
312
|
margin-top: 6px; padding: 6px 10px; border-radius: var(--radius-sm);
|
|
300
|
-
background:
|
|
313
|
+
background: color-mix(in srgb, var(--warn) 9%, var(--bg-1)); border: 1px solid color-mix(in srgb, var(--warn) 32%, var(--bg-1)); color: color-mix(in srgb, var(--warn) 70%, var(--fg));
|
|
301
314
|
font-size: 11.5px; line-height: 1.45;
|
|
302
315
|
}
|
|
303
|
-
.caveat.bad { background:
|
|
304
|
-
|
|
316
|
+
.caveat.bad { background: color-mix(in srgb, var(--bad) 9%, var(--bg-1)); border-color: color-mix(in srgb, var(--bad) 32%, var(--bg-1)); color: color-mix(in srgb, var(--bad) 65%, var(--fg)); }
|
|
317
|
+
/* Markets with polling off: the note at the top, the board / chart / depth panel folded away */
|
|
318
|
+
.caveat.mkoff { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; font-size: 12.5px; padding: 10px 12px; }
|
|
319
|
+
.mkcard.mk-off .mklayout, .mkcard.mk-off .mkchart, .mkcard.mk-off .mksub, .mkcard.mk-off #mkDepthBar, .mkcard.mk-off #mkDepthNote, .mkcard.mk-off .mkbottom { display: none; }
|
|
320
|
+
.caveat b { color: var(--fg); font-weight: 650; }
|
|
305
321
|
|
|
306
322
|
/* status badges (used across every page, not just the sync strip) */
|
|
307
323
|
.badge {
|
|
@@ -325,7 +341,7 @@ table.t th {
|
|
|
325
341
|
position: sticky; top: 0; background: var(--bg-1); z-index: 1;
|
|
326
342
|
}
|
|
327
343
|
table.t td { padding: 4px 7px; border-bottom: 1px solid var(--line-soft); font-family: var(--mono); font-variant-numeric: tabular-nums; }
|
|
328
|
-
table.t tr:hover td { background:
|
|
344
|
+
table.t tr:hover td { background: var(--hover); }
|
|
329
345
|
table.t td.r { text-align: right; }
|
|
330
346
|
table.t td.w { font-family: var(--sans); }
|
|
331
347
|
|
|
@@ -352,7 +368,7 @@ table.t td.w { font-family: var(--sans); }
|
|
|
352
368
|
(`peer_live_probe`, `dial_failures`, `check_problems`), so the tag overflowed into
|
|
353
369
|
the text column -- reported as "fields carry over from one column to the next".
|
|
354
370
|
Widened, and allowed to wrap rather than truncate: a clipped kind is a lost fact. */
|
|
355
|
-
.feed .row { display: grid; grid-template-columns: 74px 124px minmax(0, 1fr); gap: 8px; padding: 2.5px 0; border-bottom: 1px solid
|
|
371
|
+
.feed .row { display: grid; grid-template-columns: 74px 124px minmax(0, 1fr); gap: 8px; padding: 2.5px 0; border-bottom: 1px solid var(--hover); align-items: baseline; }
|
|
356
372
|
.feed .row .ts { color: var(--fg-faint); font-size: 10.5px; }
|
|
357
373
|
.feed .row .tag { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; opacity: .95; }
|
|
358
374
|
.feed .row .txt { color: var(--fg-dim); min-width: 0; overflow-wrap: anywhere; }
|
|
@@ -361,23 +377,23 @@ table.t td.w { font-family: var(--sans); }
|
|
|
361
377
|
column with overflow-wrap: anywhere). 124 px holds it; anything longer is trimmed with an
|
|
362
378
|
ellipsis and named in full in its title. */
|
|
363
379
|
.feed .row .tag { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
|
|
364
|
-
.feed .row.warn .txt { color:
|
|
380
|
+
.feed .row.warn .txt { color: color-mix(in srgb, var(--warn) 60%, var(--fg)); }
|
|
365
381
|
.feed .row.warn .tag { color: var(--warn); }
|
|
366
382
|
.feed .row.error .txt, .feed .row.error .tag { color: var(--bad); }
|
|
367
383
|
.feed .row.info .tag { color: var(--info); }
|
|
368
384
|
.feed .row.new { animation: flash .9s ease-out; }
|
|
369
|
-
@keyframes flash { from { background:
|
|
385
|
+
@keyframes flash { from { background: color-mix(in srgb, var(--accent) 13%, transparent); } to { background: transparent; } }
|
|
370
386
|
|
|
371
387
|
.rowform { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
|
|
372
388
|
input.f, select.f, textarea.f {
|
|
373
|
-
background:
|
|
389
|
+
background: var(--bg-0); border: 1px solid var(--line, #262c35); color: var(--fg);
|
|
374
390
|
border-radius: var(--radius-sm); padding: 5px 8px; font: inherit; font-size: 12px;
|
|
375
391
|
}
|
|
376
392
|
input.f:focus, select.f:focus, textarea.f:focus { outline: none; border-color: var(--accent-dim); }
|
|
377
393
|
textarea.f { width: 100%; min-height: 74px; font-family: var(--mono); resize: vertical; }
|
|
378
394
|
|
|
379
395
|
.note { font-size: 11.5px; color: var(--fg-dim); line-height: 1.5; }
|
|
380
|
-
.note.warn { color:
|
|
396
|
+
.note.warn { color: color-mix(in srgb, var(--warn) 60%, var(--fg)); }
|
|
381
397
|
.hr { height: 1px; background: var(--line-soft); margin: 10px 0; }
|
|
382
398
|
|
|
383
399
|
.toast {
|
|
@@ -394,7 +410,7 @@ textarea.f { width: 100%; min-height: 74px; font-family: var(--mono); resize: ve
|
|
|
394
410
|
|
|
395
411
|
.offline-bar {
|
|
396
412
|
grid-column: span 12; padding: 9px 12px; border-radius: var(--radius);
|
|
397
|
-
background:
|
|
413
|
+
background: color-mix(in srgb, var(--bad) 9%, var(--bg-1)); border: 1px solid color-mix(in srgb, var(--bad) 32%, var(--bg-1)); color: color-mix(in srgb, var(--bad) 65%, var(--fg)); font-size: 12px;
|
|
398
414
|
}
|
|
399
415
|
.hidden { display: none !important; }
|
|
400
416
|
|
|
@@ -403,25 +419,26 @@ textarea.f { width: 100%; min-height: 74px; font-family: var(--mono); resize: ve
|
|
|
403
419
|
.login-body { display: grid; place-items: center; height: 100vh; overflow: auto; padding: 20px; }
|
|
404
420
|
.login-card {
|
|
405
421
|
width: 100%; max-width: 372px; background: var(--bg-1); border: 1px solid var(--line, #262c35);
|
|
406
|
-
border-radius: 12px; padding:
|
|
422
|
+
border-radius: 12px; padding: 20px 22px 18px; box-shadow: var(--shadow); /* packed (2026-09-15): 20/22 not 26 */
|
|
407
423
|
}
|
|
408
|
-
.login-card h1 { margin: 0 0
|
|
409
|
-
.login-card p.sub { margin: 0 0
|
|
410
|
-
.
|
|
424
|
+
.login-card h1 { margin: 0 0 2px; font-size: 19px; letter-spacing: -.2px; }
|
|
425
|
+
.login-card p.sub { margin: 0 0 14px; color: var(--fg-faint); font-size: 12px; }
|
|
426
|
+
.login-card .note { margin-top: 10px; }
|
|
427
|
+
.field { margin-bottom: 10px; }
|
|
411
428
|
.field label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--fg-faint); margin-bottom: 4px; }
|
|
412
429
|
.field input {
|
|
413
|
-
width: 100%; background:
|
|
414
|
-
border-radius: var(--radius-sm); padding:
|
|
430
|
+
width: 100%; background: var(--bg-0); border: 1px solid var(--line, #262c35); color: var(--fg);
|
|
431
|
+
border-radius: var(--radius-sm); padding: 8px 10px; font: 14px var(--mono);
|
|
415
432
|
}
|
|
416
|
-
.field input:focus { outline: none; border-color: var(--accent-dim); box-shadow: 0 0 0 3px
|
|
417
|
-
.err { background:
|
|
418
|
-
.locked { background:
|
|
433
|
+
.field input:focus { outline: none; border-color: var(--accent-dim); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 10%, transparent); }
|
|
434
|
+
.err { background: color-mix(in srgb, var(--bad) 9%, var(--bg-1)); border: 1px solid color-mix(in srgb, var(--bad) 32%, var(--bg-1)); color: color-mix(in srgb, var(--bad) 65%, var(--fg)); padding: 8px 10px; border-radius: var(--radius-sm); font-size: 12px; margin-bottom: 12px; }
|
|
435
|
+
.locked { background: color-mix(in srgb, var(--warn) 9%, var(--bg-1)); border-color: color-mix(in srgb, var(--warn) 32%, var(--bg-1)); color: color-mix(in srgb, var(--warn) 70%, var(--fg)); }
|
|
419
436
|
|
|
420
437
|
|
|
421
438
|
/* ----------------------------------------------------------------- extras */
|
|
422
439
|
|
|
423
440
|
.offline-bar { grid-column: span 12; padding: 9px 12px; border-radius: var(--radius);
|
|
424
|
-
background:
|
|
441
|
+
background: color-mix(in srgb, var(--bad) 9%, var(--bg-1)); border: 1px solid color-mix(in srgb, var(--bad) 32%, var(--bg-1)); color: color-mix(in srgb, var(--bad) 65%, var(--fg)); font-size: 12px; }
|
|
425
442
|
.hidden { display: none !important; }
|
|
426
443
|
|
|
427
444
|
|
|
@@ -453,15 +470,17 @@ textarea.f { width: 100%; min-height: 74px; font-family: var(--mono); resize: ve
|
|
|
453
470
|
.minw-200 { min-width: 200px; }
|
|
454
471
|
|
|
455
472
|
.scroll.sm { max-height: 220px; }
|
|
473
|
+
/* the Network tab's sources table takes what the window has left under the two stacks (2026-09-15) */
|
|
474
|
+
.page[data-page="network"] #ntSources .scroll { max-height: max(200px, calc(100vh - 470px)); }
|
|
456
475
|
.scroll.md { max-height: 250px; }
|
|
457
476
|
.scroll.lg { max-height: 300px; }
|
|
458
|
-
.feed.tall { max-height: calc(100vh -
|
|
477
|
+
.feed.tall { max-height: calc(100vh - 178px); } /* to the window's bottom edge (2026-09-15: "same treatment on the events tab" -- it stopped 100px short) */
|
|
459
478
|
canvas.chart.meter { height: 112px; }
|
|
460
479
|
|
|
461
480
|
pre.pre-block { margin: 6px 0 0; white-space: pre-wrap; }
|
|
462
481
|
pre.output-box {
|
|
463
482
|
max-height: 260px; overflow: auto; margin: 0; padding: 8px;
|
|
464
|
-
background:
|
|
483
|
+
background: var(--bg-0); border: 1px solid var(--line, #262c35); border-radius: var(--radius-sm);
|
|
465
484
|
white-space: pre-wrap;
|
|
466
485
|
}
|
|
467
486
|
.btn.block { width: 100%; padding: 9px; }
|
|
@@ -844,11 +863,17 @@ canvas.treemap { width: 100%; height: 240px; display: block; background: var(--b
|
|
|
844
863
|
/* the two distributions share a row inside the right column */
|
|
845
864
|
.mprow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; align-items: start; }
|
|
846
865
|
.mprow .card { grid-column: auto !important; }
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
866
|
+
/* the same packing every tab got (2026-09-15: "same treatment on the mempool tab"): the page already
|
|
867
|
+
fit one screen with room over, so the room goes to the charts -- the four time series and the
|
|
868
|
+
scatter a fifth taller -- and the note cards under them sit tight to their one line */
|
|
869
|
+
.page[data-page="mempool"] canvas.chart:not(.tall):not(.short):not(.meter) { height: 156px; }
|
|
870
|
+
.page[data-page="mempool"] .mpusage { gap: 8px; }
|
|
871
|
+
.page[data-page="mempool"] #mpAcceptCard .note, .page[data-page="mempool"] #mpOrphansCard .note { margin-top: 2px; }
|
|
872
|
+
|
|
873
|
+
/* two columns down to 900px (it stacked from 1100, which put a 1093px window -- the operator's -- on one
|
|
874
|
+
long column); the two distributions share their row down to 760 */
|
|
875
|
+
@media (max-width: 900px) { .mpcols { grid-template-columns: minmax(0, 1fr); } }
|
|
876
|
+
@media (max-width: 760px) { .mprow { grid-template-columns: minmax(0, 1fr); } }
|
|
852
877
|
|
|
853
878
|
/* A LOG-DERIVED PANEL ON A MONITOR WITH NO LOG is one sentence, and it should not hold a 130px
|
|
854
879
|
empty chart open underneath it. Measured: two such cards at 187px each, for two lines of text.
|
|
@@ -992,7 +1017,7 @@ canvas.chart.xs, .chart.xs { height: 86px }
|
|
|
992
1017
|
}
|
|
993
1018
|
.chainlink svg {
|
|
994
1019
|
display: block; width: 100%; height: 100%; overflow: visible;
|
|
995
|
-
filter: drop-shadow(0 0 3px
|
|
1020
|
+
filter: drop-shadow(0 0 3px color-mix(in srgb, var(--accent) 55%, transparent)) drop-shadow(0 1px 1px rgba(0, 0, 0, .6));
|
|
996
1021
|
}
|
|
997
1022
|
.chainlink .cl-base, .chainlink .cl-hi { fill: none; stroke-linecap: round; }
|
|
998
1023
|
.chainlink .cl-base { stroke: var(--accent-dim); stroke-width: 3.4; }
|
|
@@ -1179,7 +1204,10 @@ canvas.chart.xs, .chart.xs { height: 86px }
|
|
|
1179
1204
|
always on screen without scrolling. Under 980 px the panel stacks below. */
|
|
1180
1205
|
.spacelayout { display: flex; gap: 16px; align-items: flex-start; }
|
|
1181
1206
|
.treemapwrap.space { position: relative; flex: 0 0 auto; aspect-ratio: 1 / 1;
|
|
1182
|
-
|
|
1207
|
+
/* the whole card on one screen (operator, 2026-09-15: "same treatment on the block space page"):
|
|
1208
|
+
the header, the card's padding, its heading and the note under the board come to ~195px */
|
|
1209
|
+
width: min(calc(100vw - 470px), calc(100vh - 195px)); min-width: 320px; }
|
|
1210
|
+
.page[data-page="space"] .spacelayout { gap: 12px; }
|
|
1183
1211
|
.treemapwrap.space canvas.treemap { position: absolute; inset: 0; width: 100%; height: 100%; }
|
|
1184
1212
|
.spacehud { flex: 1 1 300px; min-width: 260px; max-width: 420px; display: flex; flex-direction: column; gap: 12px; }
|
|
1185
1213
|
.hud { border: 1px solid rgba(60, 255, 150, .18); border-radius: 6px; padding: 10px 12px;
|
|
@@ -1251,6 +1279,97 @@ canvas.chart.xs, .chart.xs { height: 86px }
|
|
|
1251
1279
|
packages table (203 of 330 px). Stacks never stretch a card to a neighbour; the Detailed
|
|
1252
1280
|
reference text folds away until asked for. */
|
|
1253
1281
|
.mncols { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 12px; align-items: start; }
|
|
1282
|
+
/* the network row on Mining (2026-09-15): big figures in threes, a donut with its legend, the year chart */
|
|
1283
|
+
.netstats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px 14px; padding: 4px 0 8px; }
|
|
1284
|
+
.netstats .ns { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
1285
|
+
.netstats .ns .k { font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--fg-faint); }
|
|
1286
|
+
.netstats .ns .v { font-size: 22px; font-weight: 650; color: var(--fg); font-variant-numeric: tabular-nums; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1287
|
+
.netstats .ns .v small { font-size: 11px; font-weight: 400; color: var(--fg-dim); margin-left: 4px; }
|
|
1288
|
+
.netstats .ns .s { font-size: 11px; color: var(--fg-dim); font-family: var(--mono); }
|
|
1289
|
+
.netstats .ns .s .usd { display: block; color: var(--ok); font-size: 13px; font-weight: 600; }
|
|
1290
|
+
.netstats .usdnote { grid-column: 1 / -1; }
|
|
1291
|
+
.netstats .up { color: var(--ok); } .netstats .down { color: var(--bad); }
|
|
1292
|
+
/* THE PIE AND THE YEAR CHART TAKE WHAT THE WINDOW HAS (operator, 2026-09-15, of a 945px-tall
|
|
1293
|
+
window: "This all needs to comfortably fit on one page. I can't even see the View More for pools
|
|
1294
|
+
view"): their height follows the viewport so the flow, the two figure cards and the two chart
|
|
1295
|
+
cards -- View more links included -- fit one screen from ~900px tall up, growing to 380/240 */
|
|
1296
|
+
canvas.chart.donut { width: 100%; height: clamp(220px, calc(100vh - 640px), 380px); }
|
|
1297
|
+
.card.mnflow { grid-column: 1 / -1 !important; } /* !important: the 1280px rule forces every .card to span 6 */
|
|
1298
|
+
/* THINNER (operator, 2026-09-15: "The block flow can be thinner vertically for instance" -- then, of
|
|
1299
|
+
Overview, "same treatment"): .flowtight is the flow card on Mining and on Overview.
|
|
1300
|
+
the same cards, narrower and without the being-built card's badge and queue lines, which the
|
|
1301
|
+
packages panel beneath already says in full */
|
|
1302
|
+
.flowtight .bcard { width: 160px; }
|
|
1303
|
+
.flowtight .bcard.next, .flowtight .bcard.next.empty { width: 188px; }
|
|
1304
|
+
.flowtight .bcard.tip { flex-basis: 160px; }
|
|
1305
|
+
.flowtight .bcard .chips, .flowtight .bcard.next .note.tiny { display: none; }
|
|
1306
|
+
.flowtight .bgrid span, .flowtight .brows span { font-size: 9.5px; }
|
|
1307
|
+
.flowtight .flowwrap { padding-bottom: 0; }
|
|
1308
|
+
.flowtight .flow { padding: 2px 2px 0; }
|
|
1309
|
+
/* ...and no dead height (operator: "Too much empty space under the blocks to the panel border"):
|
|
1310
|
+
measured 254px for a card whose blocks are 161 -- the legend row under the flow, the rail's
|
|
1311
|
+
margin, the card's and the blocks' own padding. The legend goes on this page, the rest tightens. */
|
|
1312
|
+
.card.flowtight { padding: 8px 11px 7px; }
|
|
1313
|
+
.mnflow h3 { margin-bottom: 5px; }
|
|
1314
|
+
.flowtight .rail { margin-bottom: 3px; }
|
|
1315
|
+
.flowtight .tiplegend { display: none; }
|
|
1316
|
+
.flowtight .bcard { padding-top: 6px; padding-bottom: 6px; }
|
|
1317
|
+
.flowtight .bcard .bwhen { margin-top: 2px; margin-bottom: 3px; }
|
|
1318
|
+
.flowtight .bcard .bplaque { margin-top: 4px; }
|
|
1319
|
+
/* the whole Mining page packs tighter, the same way -- and Overview with it ("same treatment on overview") */
|
|
1320
|
+
.page[data-page="overview"] .metric .v { font-size: 22px; }
|
|
1321
|
+
/* the Block space square set the right column's height (745px of a 773px column at 1600 wide) and
|
|
1322
|
+
stretched Last blocks and the events to match; capped to the viewport, the board draws wider
|
|
1323
|
+
than tall, as it does on the Kiosk, and the page fits far more of itself on one screen */
|
|
1324
|
+
.page[data-page="overview"] .treemapwrap.sq { max-height: max(360px, calc(100vh - 340px)); }
|
|
1325
|
+
.page[data-page="mining"] .netstats { padding: 2px 0 4px; gap: 6px 12px; }
|
|
1326
|
+
.page[data-page="mining"] .netstats .ns .v { font-size: 20px; }
|
|
1327
|
+
.mn3 { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; align-items: start; }
|
|
1328
|
+
/* mempool.space's two columns (2026-09-15), and our own panels in two beneath */
|
|
1329
|
+
.mn2, .mnextra { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; align-items: start; }
|
|
1330
|
+
.mn2 .card, .mnextra .card { grid-column: auto !important; } /* the page grid's span rules do not apply inside these two-column grids */
|
|
1331
|
+
.mn2 .card { display: flex; flex-direction: column; }
|
|
1332
|
+
.mn2 .card > .viewmore { margin-top: auto; }
|
|
1333
|
+
.viewmore { display: block; text-align: center; padding: 8px 0 2px; color: var(--accent, #4fb3ff); text-decoration: none; font-size: 13px; }
|
|
1334
|
+
.viewmore:hover { text-decoration: underline; }
|
|
1335
|
+
@media (max-width: 900px) { .mn2, .mnextra { grid-template-columns: minmax(0, 1fr); } }
|
|
1336
|
+
/* the full-screen card */
|
|
1337
|
+
.expandwrap { position: fixed; inset: 0; z-index: 60; display: flex; align-items: stretch; justify-content: center; padding: 14px; }
|
|
1338
|
+
.expandwrap.hidden { display: none; }
|
|
1339
|
+
.expand { position: relative; width: min(1500px, 100%); display: flex; flex-direction: column; overflow: hidden; }
|
|
1340
|
+
.expand > h3 { flex: 0 0 auto; }
|
|
1341
|
+
.expand .expandbody { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
|
|
1342
|
+
.expand canvas.chart.donut { flex: 0 0 auto; height: 58vh; width: 100%; } /* a definite height: a flex-grown canvas resized itself every frame */
|
|
1343
|
+
.expand canvas.chart.big { flex: 0 0 auto; height: 72vh; width: 100%; }
|
|
1344
|
+
.expand .netstats .ns .v { font-size: 26px; }
|
|
1345
|
+
.expand table.t { font-size: 13px; }
|
|
1346
|
+
/* three stacks only where each gets 450px or more (operator, 2026-09-15, of an 1146px window
|
|
1347
|
+
where the packages table ran into the landscape and the pie was a coin): two below 1400 */
|
|
1348
|
+
@media (max-width: 1400px) { .mn3 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
|
|
1349
|
+
/* a table wider than its stack scrolls inside its card instead of bleeding into the next */
|
|
1350
|
+
.mn3 .card > div:has(> table), #mnPackages, #mnPools { overflow-x: auto; max-width: 100%; }
|
|
1351
|
+
@media (max-width: 760px) { .mn3 { grid-template-columns: minmax(0, 1fr); } }
|
|
1352
|
+
.donutlegend { display: flex; flex-direction: column; gap: 3px; font-family: var(--mono); font-size: 11.5px; max-height: 230px; overflow: auto; }
|
|
1353
|
+
.donutlegend div { display: flex; align-items: center; gap: 7px; white-space: nowrap; }
|
|
1354
|
+
.donutlegend i { width: 9px; height: 9px; border-radius: 2px; flex: none; }
|
|
1355
|
+
.donutlegend b { color: var(--fg); font-weight: 600; margin-left: auto; font-variant-numeric: tabular-nums; }
|
|
1356
|
+
.donutlegend i.sw0 { background: #e8306a; }
|
|
1357
|
+
.donutlegend i.sw1 { background: #8b3fd9; }
|
|
1358
|
+
.donutlegend i.sw2 { background: #5b4fd6; }
|
|
1359
|
+
.donutlegend i.sw3 { background: #3a7be0; }
|
|
1360
|
+
.donutlegend i.sw4 { background: #2f9ee6; }
|
|
1361
|
+
.donutlegend i.sw5 { background: #26b8c8; }
|
|
1362
|
+
.donutlegend i.sw6 { background: #22b7a0; }
|
|
1363
|
+
.donutlegend i.sw7 { background: #3cba6c; }
|
|
1364
|
+
.donutlegend i.sw8 { background: #8bc34a; }
|
|
1365
|
+
.donutlegend i.sw9 { background: #c9d02a; }
|
|
1366
|
+
.donutlegend i.sw10 { background: #f0c419; }
|
|
1367
|
+
.donutlegend i.sw11 { background: #f39c1f; }
|
|
1368
|
+
.donutlegend i.sw12 { background: #ee7b2f; }
|
|
1369
|
+
.donutlegend i.sw13 { background: #c7c9d1; }
|
|
1370
|
+
.donutlegend i.sw14 { background: #8d93a1; }
|
|
1371
|
+
canvas.chart.tall { height: clamp(150px, calc(100vh - 720px), 240px); }
|
|
1372
|
+
@media (max-width: 700px) { .netstats { grid-template-columns: repeat(2, minmax(0, 1fr)); } canvas.chart.donut { height: 360px; } }
|
|
1254
1373
|
.mncols .card { grid-column: auto !important; }
|
|
1255
1374
|
.mnpair { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 12px; align-items: start; }
|
|
1256
1375
|
.mndetailed > summary { list-style: none; cursor: pointer; }
|
|
@@ -1266,7 +1385,7 @@ canvas.chart.xs, .chart.xs { height: 86px }
|
|
|
1266
1385
|
|
|
1267
1386
|
/* THE PEERS PAGE: one strip, then the table (see index.html). Every row that follows is a
|
|
1268
1387
|
peer, so the table starts under ~150 px of summary instead of ~780. */
|
|
1269
|
-
.prtop { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr); gap: 12px; align-items:
|
|
1388
|
+
.prtop { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr); gap: 12px; align-items: start; }
|
|
1270
1389
|
.prtop .card { grid-column: auto !important; padding: 9px 12px; }
|
|
1271
1390
|
.prsum { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 18px; align-items: center; align-content: start; }
|
|
1272
1391
|
.prsum > h3 { grid-column: 1 / -1; }
|
|
@@ -1276,6 +1395,14 @@ canvas.chart.xs, .chart.xs { height: 86px }
|
|
|
1276
1395
|
.prpeers .note { margin: 0 0 6px; }
|
|
1277
1396
|
table.peertbl th { white-space: nowrap; }
|
|
1278
1397
|
table.peertbl td { padding: 3px 7px; white-space: nowrap; }
|
|
1398
|
+
/* the same packing every tab got (2026-09-15: "same treatment on the peers tab"): a long onion or i2p
|
|
1399
|
+
address made the table wider than the window and the whole PAGE scrolled sideways; the address
|
|
1400
|
+
cell now clips with an ellipsis (the full address is its title) and a table still wider than its
|
|
1401
|
+
card scrolls inside the card. The service badges sit lower and the rows tighter. */
|
|
1402
|
+
#prTable { overflow-x: auto; max-width: 100%; }
|
|
1403
|
+
table.peertbl td.addr { max-width: 34ch; overflow: hidden; text-overflow: ellipsis; }
|
|
1404
|
+
table.peertbl td .badge { padding: 0 5px; font-size: 9.5px; line-height: 15px; }
|
|
1405
|
+
table.peertbl td { padding: 2px 7px; }
|
|
1279
1406
|
@media (max-width: 860px) { .prtop { grid-template-columns: minmax(0, 1fr); } }
|
|
1280
1407
|
|
|
1281
1408
|
/* THE CHAIN & SYNC PAGE, THREE ACROSS (see index.html). Page-scoped, and it beats the site-wide
|
|
@@ -1287,6 +1414,11 @@ table.peertbl td { padding: 3px 7px; white-space: nowrap; }
|
|
|
1287
1414
|
.chgrid .card { padding: 10px 12px; }
|
|
1288
1415
|
.chgrid .card > h3 { margin-bottom: 6px; }
|
|
1289
1416
|
.kv.two { grid-template-columns: auto 1fr auto 1fr; column-gap: 12px; }
|
|
1417
|
+
.kv.two dt { white-space: nowrap; }
|
|
1418
|
+
.kv.two dd { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* a hash or a long uptime keeps to its line */
|
|
1419
|
+
.chgrid .mksum.chtx { font-size: 11.5px; gap: 3px 14px; }
|
|
1420
|
+
.chgrid .mksum.chtx b { font-size: 12.5px; } /* "txs in window" wrapped to two lines and made its card the row's tallest (2026-09-15) */
|
|
1421
|
+
.chgrid .note.tiny { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1290
1422
|
.kv.two dd { padding-right: 6px; }
|
|
1291
1423
|
@media (max-width: 1000px) { .chgrid .card.w4 { grid-column: span 6 !important; } }
|
|
1292
1424
|
@media (max-width: 700px) { .chgrid .card.w4, .chgrid .card.w6 { grid-column: span 12 !important; } .kv.two { grid-template-columns: auto 1fr; } }
|
|
@@ -1399,27 +1531,39 @@ table.peertbl td { padding: 3px 7px; white-space: nowrap; }
|
|
|
1399
1531
|
.mkbar { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; }
|
|
1400
1532
|
.mkgrp { display: flex; gap: 4px; flex-wrap: wrap; }
|
|
1401
1533
|
.mkbtn { font: 12px var(--sans); padding: 4px 10px; border-radius: var(--radius-sm); background: var(--bg-2); color: var(--fg-dim); border: 1px solid var(--line); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
|
|
1402
|
-
.mkbtn.on { color: var(--fg); border-color:
|
|
1534
|
+
.mkbtn.on { color: var(--fg); border-color: color-mix(in srgb, var(--ok) 55%, var(--line)); background: color-mix(in srgb, var(--ok) 14%, var(--bg-1)); }
|
|
1403
1535
|
.mkdot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; background: #8aa0b4; }
|
|
1404
1536
|
.mkdot[data-ex="coinbase"] { background: #4c8dff; }
|
|
1405
1537
|
.mkdot[data-ex="kraken"] { background: #a78bfa; }
|
|
1406
1538
|
.mkdot[data-ex="bitstamp"] { background: #2ecc8f; }
|
|
1407
1539
|
.mkdot[data-ex="bitfinex"] { background: #4dd0e1; }
|
|
1408
1540
|
.mkdot[data-ex="okx"] { background: #f0b429; }
|
|
1409
|
-
canvas.mkchart { width: 100%; height: min(54vh, 480px); min-height: 300px; display: block; background:
|
|
1541
|
+
canvas.mkchart { width: 100%; height: min(54vh, 480px); min-height: 300px; display: block; background: var(--bg-0); /* the theme's well (2026-09-16): the flat chart and the depth chart draw their ink for the theme, so their ground follows too */ border: 1px solid var(--line-soft); border-radius: var(--radius-sm); cursor: crosshair; }
|
|
1410
1542
|
.mksub { margin: 8px 0 0; font-size: 12px; font-weight: 600; color: var(--fg-dim); text-transform: uppercase; letter-spacing: .05em; }
|
|
1411
1543
|
.mksub .faint { text-transform: none; letter-spacing: 0; font-weight: 400; }
|
|
1412
1544
|
.treemapwrap.mkboard { height: min(40vh, 420px); min-height: 280px; }
|
|
1413
|
-
|
|
1545
|
+
/* the board takes what the window leaves after the toolbar, the figures and the table-and-book row
|
|
1546
|
+
beneath (2026-09-15): at 945px tall that is 385, at 1080 it is 520, never more than 600 */
|
|
1547
|
+
.treemapwrap.mkboard { height: min(600px, max(340px, calc(100vh - 578px))); min-height: 340px; }
|
|
1548
|
+
.mkbottom { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4px 16px; align-items: start; }
|
|
1549
|
+
.mkbottom-r .mksub { margin-top: 0; }
|
|
1550
|
+
@media (max-width: 900px) { .mkbottom { grid-template-columns: minmax(0, 1fr); } }
|
|
1551
|
+
/* sharing its row with the book, the table keeps every cell on one line and, under 1400px, drops
|
|
1552
|
+
the pair (BTC-USD throughout; OKX's USDT is in the note) and its two widest columns (the 24 h
|
|
1553
|
+
range and volume -- still in the Markets summary line and the Kiosk); the book's title loses its description at that width and its chart takes what is left */
|
|
1554
|
+
.mkbottom table.mktbl td, .mkbottom table.mktbl th { white-space: nowrap; }
|
|
1555
|
+
.mkbottom .scroll { max-height: none; overflow-x: auto; }
|
|
1556
|
+
@media (max-width: 1400px) { .mkbottom .mktbl .opt { display: none; } .mkbottom-r .mksub .faint { display: none; } }
|
|
1414
1557
|
.mklab { font-size: 11px; color: var(--fg-faint); margin-right: 4px; align-self: center; }
|
|
1415
|
-
canvas.mkchart.mkdepth { height: min(
|
|
1558
|
+
canvas.mkchart.mkdepth { height: min(420px, max(220px, calc(100vh - 725px))); min-height: 220px; }
|
|
1559
|
+
.mkbottom .note.tiny { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* the notes keep to one line beside each other; the full text is in the docs */
|
|
1416
1560
|
|
|
1417
1561
|
/* ---- explorer, round two (operator, 2026-09-11: "Surely we can make our display look at least as
|
|
1418
1562
|
good as mempool. Do better. Make it beautiful") ---- */
|
|
1419
|
-
.xcard { font-family: var(--sans); gap:
|
|
1563
|
+
.xcard { font-family: var(--sans); gap: 10px; }
|
|
1420
1564
|
.xclip { position: fixed; left: -9999px; top: 0; opacity: 0; }
|
|
1421
|
-
.xhero { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin:
|
|
1422
|
-
.xhero h1 { margin: 0; font-size:
|
|
1565
|
+
.xhero { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 2px 0 0; }
|
|
1566
|
+
.xhero h1 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.01em; color: #f4f7fb; display: flex; align-items: center; gap: 10px; }
|
|
1423
1567
|
.xhero .xh { font-variant-numeric: tabular-nums; }
|
|
1424
1568
|
.xhero .xnav { font-size: 20px; line-height: 1; padding: 4px 11px 6px; border-radius: 8px; border: 1px solid #2a3442; color: #9fb0c0; text-decoration: none; }
|
|
1425
1569
|
.xhero .xnav:hover { color: #fff; border-color: #4fd1ff; }
|
|
@@ -1485,14 +1629,17 @@ canvas.mkchart.mkdepth { height: min(46vh, 420px); min-height: 280px; }
|
|
|
1485
1629
|
.xcard .xf-consolidation { background: #0f8a8a; }
|
|
1486
1630
|
.xcard .xf-op_return { background: #59616f; }
|
|
1487
1631
|
.xcard .xf-cb { background: #c28f00; }
|
|
1488
|
-
.xtablecard { background: #121923; border-radius: 12px; border: 1px solid #1d2733; padding:
|
|
1632
|
+
.xtablecard { background: #121923; border-radius: 12px; border: 1px solid #1d2733; padding: 2px 12px 6px; max-height: calc(100vh - 292px); min-height: 160px; overflow: auto; }
|
|
1489
1633
|
table.xtable { width: 100%; border-collapse: collapse; font-size: 14px; }
|
|
1490
|
-
table.xtable th { text-align: left; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #7d8b99; font-weight: 600; padding:
|
|
1634
|
+
table.xtable th { text-align: left; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #7d8b99; font-weight: 600; padding: 9px 8px 8px; border-bottom: 1px solid #1d2733; position: sticky; top: 0; background: #121923; }
|
|
1491
1635
|
table.xtable th.r, table.xtable td.r { text-align: right; }
|
|
1492
|
-
table.xtable td { padding:
|
|
1636
|
+
table.xtable td { padding: 8px 8px; border-bottom: 1px solid #19222e; font-variant-numeric: tabular-nums; color: #e6edf3; white-space: nowrap; }
|
|
1493
1637
|
table.xtable tr:hover td { background: #16202c; }
|
|
1494
1638
|
.xcard .xpager { margin-top: 4px; font-family: var(--sans); font-size: 14px; }
|
|
1495
|
-
|
|
1639
|
+
/* packed (operator, 2026-09-15: "same treatment on the explorer tab"): the strip's padding and the
|
|
1640
|
+
scrollbar's band under it, the title's size, the table's row height, the card's gap -- 70px back
|
|
1641
|
+
to the table, which reaches the window's bottom edge */
|
|
1642
|
+
.xblocks { display: flex; gap: 22px; overflow-x: auto; padding: 8px 8px 10px; scrollbar-width: thin; }
|
|
1496
1643
|
.xblk { flex: 0 0 auto; width: 128px; text-decoration: none; color: #fff; display: flex; flex-direction: column; align-items: center; gap: 9px; }
|
|
1497
1644
|
.xblk-h { color: #4fd1ff; font: 600 15px var(--sans); font-variant-numeric: tabular-nums; }
|
|
1498
1645
|
.xblk-face { position: relative; width: 124px; height: 124px; box-sizing: border-box; padding: 10px 8px; display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center; background: linear-gradient(180deg, #5b6b7d, #3a4757); transition: transform .18s ease, filter .18s ease; }
|
|
@@ -1532,7 +1679,7 @@ table.xtable tr:hover td { background: #16202c; }
|
|
|
1532
1679
|
to min-height and gave a 480 px kiosk in a 782 px window (2026-09-11). The vh fallback covers a
|
|
1533
1680
|
browser without :has(), with room for the bar in both its heights (46 px, or 69 px wrapped). */
|
|
1534
1681
|
section.page:has(> .kiosk) { height: 100%; }
|
|
1535
|
-
.kiosk { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap:
|
|
1682
|
+
.kiosk { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; height: 100%; min-height: min(calc(100vh - 130px), 900px); } /* 100% of main: the bar wraps below 1400 px, so its height is not a constant */
|
|
1536
1683
|
.kiosk:fullscreen { height: 100vh; padding: 10px; box-sizing: border-box; background: #010306; }
|
|
1537
1684
|
/* THE WALL STAYS A WALL DOWN TO 900 px (operator, 2026-09-12: "Try to improve kiosk view for this
|
|
1538
1685
|
resolution", at 1066x760). At 1100 the kiosk dropped to ONE column and `height: auto`, so the
|
|
@@ -1541,15 +1688,17 @@ section.page:has(> .kiosk) { height: 100%; }
|
|
|
1541
1688
|
with room, so the stack is for genuinely narrow screens now. */
|
|
1542
1689
|
@media (max-width: 900px) { .kiosk { grid-template-columns: minmax(0, 1fr); height: auto; } .treemapwrap.kboard { height: 70vh; } }
|
|
1543
1690
|
.kpanel { display: flex; flex-direction: column; min-height: 0; background: #04080c; border: 1px solid #16222c; border-radius: 10px; overflow: hidden; }
|
|
1544
|
-
.khead { padding:
|
|
1691
|
+
.khead { padding: 5px 12px; font: 12px var(--sans); color: #c3cfdb; letter-spacing: .06em; text-transform: uppercase; }
|
|
1545
1692
|
.khead .faint { text-transform: none; letter-spacing: 0; margin-left: 10px; }
|
|
1546
1693
|
.treemapwrap.kboard { flex: 1 1 auto; min-height: 0; }
|
|
1547
1694
|
.treemapwrap.kboard canvas.treemap { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; border-radius: 0; }
|
|
1548
|
-
.
|
|
1695
|
+
.kbf .khead { display: flex; align-items: center; gap: 10px; }
|
|
1696
|
+
.kbf .khead .sp { flex: 1; }
|
|
1697
|
+
.kfull { position: static; font: 12px var(--mono); padding: 3px 10px; text-transform: none; letter-spacing: 0; background: rgba(2,12,8,0.82); color: #8fd8b8; border: 1px solid rgba(60,255,150,0.3); border-radius: 4px; cursor: pointer; }
|
|
1549
1698
|
.kfull:hover { color: #eafff4; }
|
|
1550
1699
|
|
|
1551
1700
|
/* ---- the kiosk's price information panel (markets.js priceInfoHtml) ---- */
|
|
1552
|
-
.kprice { flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-areas: "main" "foot"; gap:
|
|
1701
|
+
.kprice { flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-areas: "main" "foot"; gap: 3px 22px; padding: 8px 14px 4px; border-top: 1px solid #16222c; background: linear-gradient(180deg, #060b10, #04080c); font-family: var(--sans); }
|
|
1553
1702
|
/* THE DEPTH CHART FILLS WHAT IS LEFT of the price panel (operator, 2026-09-12: "change to market
|
|
1554
1703
|
order depth chart that fits within the view"). The panel is a flex column inside a fixed kiosk
|
|
1555
1704
|
grid row, so `flex: 1 1 auto` + `min-height: 0` is what makes the canvas take the remainder
|
|
@@ -1592,10 +1741,10 @@ canvas.kdepth { position: absolute; inset: 0; width: 100%; height: 100%; display
|
|
|
1592
1741
|
its cards drawn at 80% (zoom shrinks the layout box too, so the row's parking maths holds),
|
|
1593
1742
|
and its notice and timing legend are left to the Overview. */
|
|
1594
1743
|
.kiosk { grid-template-rows: minmax(0, 1fr); grid-template-areas: none; }
|
|
1595
|
-
.kcol { display: flex; flex-direction: column; gap:
|
|
1744
|
+
.kcol { display: flex; flex-direction: column; gap: 8px; min-height: 0; min-width: 0; } /* 8, not 12: the same packing every tab got (2026-09-15) */
|
|
1596
1745
|
.kcol > .kmk, .kcol > .ksp { flex: 1 1 auto; min-height: 0; }
|
|
1597
1746
|
.kcol > .kpp { flex: 0 0 auto; }
|
|
1598
|
-
.kcol > .kbf { flex: 0 0 auto; height:
|
|
1747
|
+
.kcol > .kbf { flex: 0 0 auto; height: 170px; } /* the tight flow (.flowtight on the panel): its cards are ~120 at 80% zoom, plus the head and the strip's padding */
|
|
1599
1748
|
/* The price-and-depth panel is sized the same way and for the same reason: a chart cannot be read
|
|
1600
1749
|
in whatever a flex item has left over, so it gets a definite height and the markets board above
|
|
1601
1750
|
takes the remainder. */
|
|
@@ -1611,7 +1760,7 @@ canvas.kdepth { position: absolute; inset: 0; width: 100%; height: 100%; display
|
|
|
1611
1760
|
@media (max-width: 1400px) and (min-width: 901px) {
|
|
1612
1761
|
.kiosk { gap: 8px; }
|
|
1613
1762
|
.kcol { gap: 8px; }
|
|
1614
|
-
.kcol > .kbf { height:
|
|
1763
|
+
.kcol > .kbf { height: 170px; }
|
|
1615
1764
|
.kbf .flowwrap > .flow { zoom: 0.7; }
|
|
1616
1765
|
}
|
|
1617
1766
|
|
|
@@ -1645,31 +1794,40 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1645
1794
|
it changes, and every control applies live. No inline styles anywhere -- CSP forbids them, and
|
|
1646
1795
|
the range fills are drawn by the browser's own widget. */
|
|
1647
1796
|
.cfgwrap { position: fixed; inset: 0; z-index: 60; display: flex; justify-content: flex-end; }
|
|
1648
|
-
.cfgscrim { position: absolute; inset: 0; background:
|
|
1797
|
+
.cfgscrim { position: absolute; inset: 0; background: var(--scrim); }
|
|
1649
1798
|
.cfg {
|
|
1650
|
-
position: relative; width: min(
|
|
1651
|
-
background: var(--bg-1); border-left: 1px solid var(--line); box-shadow: -18px 0 40px
|
|
1799
|
+
position: relative; width: min(470px, 100%); height: 100%; overflow: auto; /* 470, not 420 (2026-09-15): the hints wrap a line less, the switches two across have room */
|
|
1800
|
+
background: var(--bg-1); border-left: 1px solid var(--line); box-shadow: -18px 0 40px color-mix(in srgb, var(--bg) 55%, transparent);
|
|
1652
1801
|
padding: 14px 16px 28px;
|
|
1653
1802
|
}
|
|
1654
1803
|
.cfg h2 { display: flex; align-items: center; gap: 8px; margin: 2px 0 8px; font-size: 13px; letter-spacing: .09em; text-transform: uppercase; color: var(--fg-dim); }
|
|
1655
1804
|
.cfg h2 .sp { flex: 1; }
|
|
1656
|
-
.cfgnote { margin: 0 0
|
|
1805
|
+
.cfgnote { margin: 0 0 10px; color: var(--fg-faint); font-size: 11px; line-height: 1.45; }
|
|
1657
1806
|
.cfgrow input[type="color"] { width: 44px; height: 24px; padding: 0; border: 1px solid var(--line); border-radius: 4px; background: transparent; cursor: pointer; }
|
|
1658
1807
|
/* the tab strip (operator: "tabbed section panel in setup") */
|
|
1659
|
-
.cfgtabs { display: flex; flex-
|
|
1808
|
+
.cfgtabs { display: flex; flex-direction: column; gap: 4px; margin: 0 0 8px; }
|
|
1809
|
+
/* labelled rows (2026-09-16): the boards, their effects, the games last */
|
|
1810
|
+
.cfgtabrow { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
|
|
1811
|
+
.cfgtablbl { flex: 0 0 66px; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint); }
|
|
1660
1812
|
.cfgtab { font: inherit; font-size: 11px; letter-spacing: .04em; padding: 5px 10px; border-radius: 999px;
|
|
1661
1813
|
border: 1px solid var(--line); background: transparent; color: var(--fg-dim); cursor: pointer; }
|
|
1662
1814
|
.cfgtab:hover { color: var(--fg); }
|
|
1663
|
-
.cfgtab.on { border-color: var(--accent); color: var(--accent); background:
|
|
1815
|
+
.cfgtab.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
|
|
1664
1816
|
.cfgbulk { display: flex; gap: 6px; margin: 0 0 8px; }
|
|
1665
1817
|
.cfgbulk .btn { font-size: 10.5px; padding: 3px 8px; }
|
|
1666
|
-
.cfggroup { border: 1px solid var(--line-soft); border-radius: var(--radius); padding: 10px
|
|
1818
|
+
.cfggroup { border: 1px solid var(--line-soft); border-radius: var(--radius); padding: 8px 10px 10px; margin-bottom: 10px; background: var(--bg-2); }
|
|
1667
1819
|
.cfggroup > h3 { margin: 0 0 4px; font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--accent); }
|
|
1668
|
-
.cfggroup > p { margin: 0 0
|
|
1669
|
-
.
|
|
1820
|
+
.cfggroup > p { margin: 0 0 8px; color: var(--fg-faint); font-size: 11px; line-height: 1.4; }
|
|
1821
|
+
.cfggroup > p.cfgheld { color: var(--warn); }
|
|
1822
|
+
/* packed (2026-09-15): rows 5px not 7, hints tighter, and on the effects tabs the switches two across
|
|
1823
|
+
with the hint as the row's tooltip */
|
|
1824
|
+
.cfgrow { display: grid; grid-template-columns: 1fr auto; gap: 3px 10px; align-items: center; padding: 5px 0; border-top: 1px solid var(--line-soft); }
|
|
1825
|
+
.cfgrows2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; border-top: 1px solid var(--line-soft); margin-top: 4px; }
|
|
1826
|
+
.cfgrow.compact { padding: 4px 0; cursor: help; }
|
|
1827
|
+
.cfgrows2 .cfgrow.compact:nth-child(-n+2) { border-top: 0; }
|
|
1670
1828
|
.cfgrow:first-of-type { border-top: 0; }
|
|
1671
1829
|
.cfgrow b { font-weight: 600; font-size: 12px; }
|
|
1672
|
-
.cfgrow i { grid-column: 1 / -1; font-style: normal; color: var(--fg-faint); font-size: 10.5px; line-height: 1.
|
|
1830
|
+
.cfgrow i { grid-column: 1 / -1; font-style: normal; color: var(--fg-faint); font-size: 10.5px; line-height: 1.35; }
|
|
1673
1831
|
.cfgrow select, .cfgrow input[type="range"] { accent-color: var(--accent); }
|
|
1674
1832
|
.cfgrow select { background: var(--bg-3, #12161c); color: var(--fg); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 3px 6px; font: inherit; font-size: 11.5px; }
|
|
1675
1833
|
.cfgrow input[type="range"] { width: 130px; }
|
|
@@ -1681,6 +1839,47 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1681
1839
|
.cfgrow .val { font-family: var(--mono); font-size: 11px; color: var(--fg-dim); display: inline-block; width: 6.5ch; text-align: right; font-variant-numeric: tabular-nums; }
|
|
1682
1840
|
/* the toggle: a checkbox the browser draws, sized up, so it is keyboard-reachable for free */
|
|
1683
1841
|
.cfgrow input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
|
|
1842
|
+
/* THE EXPLORER ON A LIGHT THEME (2026-09-16): its block pages are their own dark design, kept as they
|
|
1843
|
+
are; only what sits on the page itself -- the section titles, the hero's id and its back link --
|
|
1844
|
+
takes the theme's ink, and only when the theme is light, so the shipped look is untouched. */
|
|
1845
|
+
:root[data-theme="light"] .xhero h1, :root[data-theme="light"] .xsect h2 { color: var(--fg); }
|
|
1846
|
+
:root[data-theme="light"] .xhero .xnav { color: var(--fg-dim); border-color: var(--line); }
|
|
1847
|
+
:root[data-theme="light"] .xhero .xnav:hover { color: var(--fg); border-color: var(--accent); }
|
|
1848
|
+
:root[data-theme="light"] .xid, :root[data-theme="light"] .xblk-h { color: var(--info); }
|
|
1849
|
+
:root[data-theme="light"] .xcopy { color: var(--fg-faint); }
|
|
1850
|
+
:root[data-theme="light"] .xhero .xdim, :root[data-theme="light"] .xhero .xago, :root[data-theme="light"] .xtot { color: var(--fg-dim); }
|
|
1851
|
+
/* THE KIOSK ON A LIGHT THEME: its frames, heads and the price panel take the theme's panel, line and
|
|
1852
|
+
ink (the price loses its neon glow: a yellow that lights up a black panel is unreadable on white);
|
|
1853
|
+
the boards inside stay space. Light only, so the shipped kiosk is untouched. */
|
|
1854
|
+
:root[data-theme="light"] .kpanel { background: var(--bg-1); border-color: var(--line); }
|
|
1855
|
+
:root[data-theme="light"] .khead { color: var(--fg-dim); }
|
|
1856
|
+
:root[data-theme="light"] .kprice { background: var(--bg-1); border-top-color: var(--line); }
|
|
1857
|
+
:root[data-theme="light"] .kdepthwrap { background: var(--bg-0); }
|
|
1858
|
+
:root[data-theme="light"] .kp-wait, :root[data-theme="light"] .kp-pair { color: var(--fg-dim); }
|
|
1859
|
+
:root[data-theme="light"] .kp-price { color: var(--accent); text-shadow: none; }
|
|
1860
|
+
/* APPEARANCE (2026-09-16): the mode as a segmented control, the themes as cards -- a swatch strip of
|
|
1861
|
+
the face the mode picks, the name, a line about it -- and the nine custom pickers dimmed until
|
|
1862
|
+
Custom is the theme. Each card carries its face's page, text and line colours as custom properties
|
|
1863
|
+
(set through the CSSOM), so the card previews the theme rather than describing it. */
|
|
1864
|
+
.cfgseg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; background: var(--bg-3); }
|
|
1865
|
+
.cfgsegbtn { font: inherit; font-size: 11px; padding: 4px 11px; border: 0; background: transparent; color: var(--fg-dim); cursor: pointer; }
|
|
1866
|
+
.cfgsegbtn + .cfgsegbtn { border-left: 1px solid var(--line); }
|
|
1867
|
+
.cfgsegbtn:hover { color: var(--fg); }
|
|
1868
|
+
.cfgsegbtn.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
|
|
1869
|
+
.cfgrow.cfgcards { grid-template-columns: 1fr auto; }
|
|
1870
|
+
.thcards { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 2px 0 1px; }
|
|
1871
|
+
.thcard { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; font: inherit; cursor: pointer;
|
|
1872
|
+
padding: 7px 9px 8px; border-radius: var(--radius-sm); border: 1px solid var(--th-line, var(--line)); background: var(--th-bg, var(--bg-3)); color: var(--th-fg, var(--fg)); }
|
|
1873
|
+
.thcard:hover { border-color: var(--fg-dim); }
|
|
1874
|
+
.thcard.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
|
1875
|
+
.thcard b { font-size: 12px; font-weight: 600; }
|
|
1876
|
+
.thcard small { font-size: 10.5px; opacity: .72; line-height: 1.3; }
|
|
1877
|
+
.thsw { display: inline-flex; gap: 0; border-radius: 4px; overflow: hidden; border: 1px solid var(--th-line, var(--line)); }
|
|
1878
|
+
.thsw i { display: block; width: 14px; height: 12px; }
|
|
1879
|
+
.cfgcustomise { font-size: 10.5px; padding: 3px 8px; }
|
|
1880
|
+
.cfgrows2 .cfgrow.compact input[type="color"] { width: 36px; height: 20px; }
|
|
1881
|
+
.cfgrow.idle { opacity: .55; }
|
|
1882
|
+
.cfgrow.idle:hover { opacity: 1; }
|
|
1684
1883
|
/* DIVERSIONS: a pop-down at the end of the nav. The buttons inside are `nav.pages button` like
|
|
1685
1884
|
every other tab, so they inherit the tab look and only the layout is new. */
|
|
1686
1885
|
/* PINNED, because the nav SCROLLS. `nav.pages` is overflow-x:auto with its scrollbar hidden, so
|
|
@@ -1719,7 +1918,11 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1719
1918
|
absolutely beautiful leveraging our framework"). The well is a board3d in a tall
|
|
1720
1919
|
frame; the HUD sits beside it. No inline styles anywhere: the overlay is a class.
|
|
1721
1920
|
========================================================================== */
|
|
1722
|
-
.tetrust { display: grid; grid-template-columns: auto
|
|
1921
|
+
.tetrust { display: grid; grid-template-columns: auto 270px; justify-content: center; gap: 12px; align-items: start; }
|
|
1922
|
+
/* the DOS pages give the screen the whole first column (an `auto` column sized it to nothing once the
|
|
1923
|
+
wrap's width became a min() of its container) */
|
|
1924
|
+
.tetrust.dosgame { grid-template-columns: minmax(0, 1fr) 270px; justify-content: stretch; }
|
|
1925
|
+
.tetrust.dosgame > .doscard { min-width: 0; } /* 270, not 290: the well and the DOS screen get the width (2026-09-15) */
|
|
1723
1926
|
/* .card carries grid-column: span 4 for the page's twelve-column layout; inside this two-column
|
|
1724
1927
|
grid that span forced four tracks and stacked the HUD under the well (measured: both cards
|
|
1725
1928
|
"span 4" in a 72/290/72/72 px grid). The other multi-column panels reset it the same way. */
|
|
@@ -1727,13 +1930,101 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1727
1930
|
/* SIZED TO THE SCREEN, not the card (operator: "the playfield needs to be shrunk so it fits on a
|
|
1728
1931
|
single screen with room. it's way too large now"): the well's HEIGHT comes from the viewport,
|
|
1729
1932
|
and its width follows from the 10x20 shape -- about 330px wide on a 1000px-tall window. */
|
|
1730
|
-
|
|
1933
|
+
/* the well takes the window's height (operator, 2026-09-15: "same treatment on the diversions games
|
|
1934
|
+
pages" -- it stopped at 600px with a fifth of the window dark beneath) */
|
|
1935
|
+
.tetcard .treemapwrap.tetwell { position: relative; z-index: 1; height: min(calc(100vh - 170px), 820px); width: auto; aspect-ratio: 11 / 21; margin: 0 auto; }
|
|
1731
1936
|
/* Blockout's court is 16 x 24 rather than 10 x 20, so it is wider than the Tetris well; the rest
|
|
1732
1937
|
of the furniture (the sky canvas, the overlay, the HUD) is shared with it. */
|
|
1733
1938
|
.tetcard .treemapwrap.tetwell.bowell { aspect-ratio: 17 / 25; }
|
|
1734
1939
|
/* Blockanoid's court is 13 x 26: narrower than Blockout's and taller, which is what gives Vaus a
|
|
1735
1940
|
court you can dig a channel up the side of. Same furniture, its own shape. */
|
|
1736
1941
|
.tetcard .treemapwrap.tetwell.banwell { aspect-ratio: 14 / 27; }
|
|
1942
|
+
/* SCORCHED YARD's field is 96 x 48, wide and low like the original's 640 x 350 screen: it takes
|
|
1943
|
+
the card's width and its height follows (docs/PLAN-SCORCHED-YARD.md). The page gives the field the
|
|
1944
|
+
first column, as the DOS games do, so the HUD sits beside a field that fills the window's width. */
|
|
1945
|
+
#scorched { grid-template-columns: minmax(0, 1fr) 270px; justify-content: stretch; }
|
|
1946
|
+
#scorched > .tetcard { min-width: 0; }
|
|
1947
|
+
.tetcard .treemapwrap.tetwell.seyard { width: min(100%, calc((100vh - 170px) * 2)); height: auto; aspect-ratio: 2 / 1; }
|
|
1948
|
+
/* two canvases stacked: the land under, the actors over, the sky behind both (scorchedyard.js);
|
|
1949
|
+
scaled a little from the bottom centre so the board's own margins leave the frame -- the land
|
|
1950
|
+
meets the bottom edge and runs off both sides, and no sky shows under it (operator, 2026-09-16:
|
|
1951
|
+
"Play field needs to go to the edges") */
|
|
1952
|
+
.seyard { overflow: hidden; }
|
|
1953
|
+
.seyard canvas { position: absolute; inset: 0; transform: scale(1.085); transform-origin: 50% 100%; }
|
|
1954
|
+
/* THE WIND'S OWN PLANE: flat, behind the land, and NOT scaled with the board -- it is not in the
|
|
1955
|
+
scene, it is the air behind it (operator: "drawn behind everything else on a flat plane") */
|
|
1956
|
+
.seyard canvas.sywind { width: 100%; height: 100%; transform: none; }
|
|
1957
|
+
/* the two numbers a player actually tunes: click one and type it */
|
|
1958
|
+
#syStats b.syval { cursor: text; border-bottom: 1px dotted var(--line); }
|
|
1959
|
+
#syStats b.syval:hover { color: var(--accent); }
|
|
1960
|
+
.syrestart { width: 100%; margin-top: 6px; }
|
|
1961
|
+
/* the controls (docs/PLAN-SCORCHED-YARD.md §12): the confirm state, item buttons, the weapon grid, the keys table */
|
|
1962
|
+
.syfire.syconfirm { background: var(--bad); border-color: var(--bad); }
|
|
1963
|
+
button.sypillbtn { cursor: pointer; font: inherit; }
|
|
1964
|
+
button.sypillbtn:hover { border-color: var(--accent); }
|
|
1965
|
+
.syweapons { position: absolute; right: 12px; top: 12px; z-index: 4; width: min(360px, 60%); max-height: 70%; overflow: auto; background: rgba(8, 10, 14, .9); border: 1px solid var(--line); border-radius: 6px; padding: 8px; }
|
|
1966
|
+
.syweapons.hidden { display: none; }
|
|
1967
|
+
.syweaponshead { display: flex; align-items: baseline; gap: 6px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-dim); margin-bottom: 6px; }
|
|
1968
|
+
.syweaponshead small { text-transform: none; letter-spacing: 0; }
|
|
1969
|
+
.syweaponlist { display: grid; gap: 3px; }
|
|
1970
|
+
.syweapon { display: grid; grid-template-columns: 1fr auto auto 1.6em; gap: 8px; align-items: baseline; text-align: left; padding: 4px 6px; background: transparent; border: 1px solid transparent; border-radius: 4px; color: var(--text); font: inherit; font-size: 12px; cursor: pointer; }
|
|
1971
|
+
.syweapon:hover { border-color: var(--line); }
|
|
1972
|
+
.syweapon.on { border-color: var(--accent); }
|
|
1973
|
+
.syweapon i { color: var(--fg-dim); font-style: normal; font-size: 11px; }
|
|
1974
|
+
.syweapon kbd { color: var(--accent); font-family: var(--mono); text-align: center; }
|
|
1975
|
+
table.sykeys { border-collapse: collapse; width: 100%; }
|
|
1976
|
+
table.sykeys th { text-align: left; vertical-align: top; padding: 2px 8px 2px 0; font-weight: 500; color: var(--fg-dim); white-space: nowrap; }
|
|
1977
|
+
table.sykeys td { padding: 2px 0; }
|
|
1978
|
+
/* the Sky tab's map of boards to skies, and the two headings under it (docs/PLAN-SKIES.md) */
|
|
1979
|
+
.skymap { border-collapse: collapse; }
|
|
1980
|
+
.skymap th { text-align: left; font-weight: 500; padding: 3px 14px 3px 0; white-space: nowrap; }
|
|
1981
|
+
.skymap th small { display: block; color: var(--fg-faint); font-size: 11px; font-weight: 400; }
|
|
1982
|
+
.skymap td { padding: 3px 0; }
|
|
1983
|
+
.cfghead { margin: 18px 0 6px; padding-top: 10px; border-top: 1px solid var(--line); }
|
|
1984
|
+
.cfghead b { display: block; font-size: 13px; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); }
|
|
1985
|
+
.cfghead i { display: block; color: var(--fg-dim); font-style: normal; font-size: 12px; margin-top: 2px; }
|
|
1986
|
+
.syedit { width: 5.2em; font: inherit; color: var(--text); background: var(--bg); border: 1px solid var(--accent); border-radius: 3px; padding: 0 2px; text-align: right; }
|
|
1987
|
+
.syfire { width: 100%; margin: 2px 0 10px; }
|
|
1988
|
+
.syfire:disabled { opacity: .45; cursor: default; }
|
|
1989
|
+
.sytanks { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; font-size: 12px; }
|
|
1990
|
+
.sytank { display: grid; grid-template-columns: 10px auto 1fr auto; gap: 3px 7px; align-items: center; padding: 3px 6px; border-radius: var(--radius-sm); border: 1px solid transparent; }
|
|
1991
|
+
.sytank.now { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
|
|
1992
|
+
.sytank.dead { opacity: .45; }
|
|
1993
|
+
.sytank b { font-weight: 600; }
|
|
1994
|
+
.sytank meter { width: 100%; height: 9px; }
|
|
1995
|
+
.sytank span { font-family: var(--mono); font-variant-numeric: tabular-nums; min-width: 3ch; text-align: right; }
|
|
1996
|
+
.sytank small { grid-column: 2 / -1; color: var(--fg-faint); font-size: 10.5px; }
|
|
1997
|
+
.sydot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; background: var(--fg-faint); }
|
|
1998
|
+
/* what a tank says: a bubble over the field at the tank's place (its position is two custom
|
|
1999
|
+
properties set through the CSSOM, never a style attribute -- the CSP) */
|
|
2000
|
+
.sytalk { position: absolute; z-index: 3; left: var(--x, 50%); top: var(--y, 50%); transform: translate(-50%, -100%);
|
|
2001
|
+
padding: 4px 9px; border-radius: 10px; background: rgba(14, 16, 22, .88); border: 1px solid var(--line); color: var(--fg);
|
|
2002
|
+
font-size: 12px; white-space: nowrap; pointer-events: none; }
|
|
2003
|
+
.sytalk.hidden { display: none; }
|
|
2004
|
+
.sydot-0 { background: #f7931a; } .sydot-1 { background: #4d8dff; } .sydot-2 { background: #2ecc8f; }
|
|
2005
|
+
.sydot-3 { background: #ef5a5a; } .sydot-4 { background: #c78bff; } .sydot-5 { background: #f0c419; }
|
|
2006
|
+
/* the items line: pills, lit when armed */
|
|
2007
|
+
.syitems { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 10px; font-size: 11px; min-height: 18px; }
|
|
2008
|
+
.sypill { padding: 2px 7px; border-radius: 999px; border: 1px solid var(--line); color: var(--fg-dim); }
|
|
2009
|
+
.sypill.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
|
|
2010
|
+
/* THE SHOP (M2): in the overlay between rounds, two columns of rows -- name, note, price and pack,
|
|
2011
|
+
what you own, a buy button while you can afford it. Scrolls inside the card on a short window. */
|
|
2012
|
+
.syshop { width: min(100%, 980px); max-height: min(66vh, 620px); overflow: auto; text-align: left; background: rgba(8, 10, 14, .92);
|
|
2013
|
+
border: 1px solid var(--line); border-radius: var(--radius); padding: 8px 12px 10px; font-size: 11.5px; }
|
|
2014
|
+
.syshop.hidden { display: none; }
|
|
2015
|
+
.syshophead { display: flex; align-items: center; gap: 8px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-dim); margin-bottom: 4px; }
|
|
2016
|
+
.syshophead b { color: var(--ok); font-family: var(--mono); letter-spacing: 0; text-transform: none; font-size: 13px; }
|
|
2017
|
+
.sycols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
|
|
2018
|
+
.sycols h4 { margin: 6px 0 2px; font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--accent); }
|
|
2019
|
+
.syrow { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; gap: 1px 8px; align-items: center; padding: 3px 0; border-top: 1px solid var(--line-soft); }
|
|
2020
|
+
.syrow b { font-weight: 600; }
|
|
2021
|
+
.syrow .syhint { grid-column: 1 / -1; grid-row: 2; color: var(--fg-faint); font-size: 10px; }
|
|
2022
|
+
.syrow .syprice { font-family: var(--mono); color: var(--fg-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
2023
|
+
.syrow .syown { color: var(--ok); font-size: 10.5px; min-width: 5ch; text-align: right; }
|
|
2024
|
+
.syrow.poor .syprice { color: var(--fg-faint); }
|
|
2025
|
+
.sybuy { font-size: 10.5px; padding: 2px 8px; }
|
|
2026
|
+
.sybuy:disabled { opacity: .35; cursor: default; }
|
|
2027
|
+
@media (max-width: 900px) { .sycols { grid-template-columns: 1fr; } }
|
|
1737
2028
|
.tetwell canvas { width: 100%; height: 100%; display: block; background: transparent; border: 0; } /* the sky shows through */
|
|
1738
2029
|
/* THE PANEL IS THE SKY (operator: "Have this entire panel filled black and rendering the spiral
|
|
1739
2030
|
galaxy for this display. Have the text floating over the spiral galaxy, and then the playboard
|
|
@@ -1747,7 +2038,7 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1747
2038
|
.tetwell.idle { visibility: hidden; }
|
|
1748
2039
|
.tetswitches { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
1749
2040
|
.tetsw { font: inherit; font-size: 11.5px; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--fg-dim); cursor: pointer; }
|
|
1750
|
-
.tetsw.on { border-color: var(--accent); color: var(--accent); background:
|
|
2041
|
+
.tetsw.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
|
|
1751
2042
|
.tetover { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
|
|
1752
2043
|
background: transparent; text-align: center; padding: 20px; }
|
|
1753
2044
|
.tetover.dim { background: rgba(0, 0, 0, 0.74); }
|
|
@@ -1783,3 +2074,23 @@ body { font-variant-numeric: tabular-nums; }
|
|
|
1783
2074
|
.tetscores td:first-child, .tetscores th:first-child { text-align: left; }
|
|
1784
2075
|
.tetscores tr.now td { color: var(--accent); font-weight: 600; }
|
|
1785
2076
|
@media (max-width: 900px) { .tetrust { grid-template-columns: 1fr; } }
|
|
2077
|
+
/* THE DOS GAMES (dosgame.js: DOOM and Quake): the monitor is a 4:3 box, as a VGA's 320x200 was on
|
|
2078
|
+
the CRT it was drawn for, sized to the screen's height like the courts; the pixels stay pixels
|
|
2079
|
+
unless the smooth switch is on. */
|
|
2080
|
+
.doscard { position: relative; background: #000; }
|
|
2081
|
+
.doscard > h3 { color: var(--fg-dim); }
|
|
2082
|
+
/* the DOS screen is ALWAYS 4:3 and as big as the window allows either way (2026-09-15): sized by
|
|
2083
|
+
height alone, a 1093px window capped its width and the 320x200 picture was drawn squashed into
|
|
2084
|
+
a 761x720 box */
|
|
2085
|
+
.doswrap { position: relative; width: min(100%, calc((100vh - 160px) * 4 / 3), 1067px); height: auto; aspect-ratio: 4 / 3; margin: 0 auto; background: #000; }
|
|
2086
|
+
.doswrap:fullscreen { height: 100vh; width: 100vw; max-width: none; aspect-ratio: auto; display: flex; align-items: center; justify-content: center; }
|
|
2087
|
+
.dosscreen { width: 100%; height: 100%; display: block; image-rendering: pixelated; cursor: crosshair; }
|
|
2088
|
+
.doswrap:fullscreen .dosscreen { width: auto; height: 100%; aspect-ratio: 4 / 3; max-width: 100%; }
|
|
2089
|
+
.dosscreen.smooth { image-rendering: auto; }
|
|
2090
|
+
.dosagain { position: absolute; right: 12px; bottom: 12px; z-index: 3; }
|
|
2091
|
+
/* the way out of full screen, drawn only there (keyboard lock takes Esc for the game's menu) */
|
|
2092
|
+
.dosexit { display: none; }
|
|
2093
|
+
.doswrap:fullscreen .dosexit { display: block; position: absolute; right: 14px; top: 12px; z-index: 4; opacity: .55; font: 12px var(--mono); }
|
|
2094
|
+
.doswrap:fullscreen .dosexit:hover { opacity: 1; }
|
|
2095
|
+
.dosgame .tetkeys code { font-family: var(--mono); font-size: 10.5px; }
|
|
2096
|
+
@media (max-width: 900px) { .doswrap { height: auto; width: 100%; } }
|