blockyard 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +251 -1
  2. package/README.md +42 -23
  3. package/bin/blockyard.js +2 -1
  4. package/docs/API.md +16 -14
  5. package/docs/ARCHITECTURE.md +92 -5
  6. package/docs/CONFIGURATION.md +33 -26
  7. package/docs/GETTING-STARTED.md +5 -2
  8. package/docs/INSTALL.md +90 -33
  9. package/docs/MEASUREMENTS.md +147 -0
  10. package/docs/SECURITY.md +32 -15
  11. package/docs/TROUBLESHOOTING.md +35 -1
  12. package/docs/USER-GUIDE.md +266 -26
  13. package/package.json +1 -1
  14. package/public/404.html +1 -1
  15. package/public/css/app.css +306 -82
  16. package/public/donate-qr.png +0 -0
  17. package/public/index.html +295 -103
  18. package/public/js/agents.js +228 -51
  19. package/public/js/app.js +82 -8
  20. package/public/js/blockscene3d.js +179 -27
  21. package/public/js/charts.js +21 -21
  22. package/public/js/depthchart.js +31 -27
  23. package/public/js/details3d.js +1456 -71
  24. package/public/js/doom.js +31 -0
  25. package/public/js/dosaudio.js +48 -0
  26. package/public/js/dosgame.js +389 -0
  27. package/public/js/dosio.js +186 -0
  28. package/public/js/dospc.js +1353 -0
  29. package/public/js/dosworker.js +196 -0
  30. package/public/js/login.js +5 -0
  31. package/public/js/markets.js +46 -8
  32. package/public/js/mining.js +310 -32
  33. package/public/js/panels.js +14 -10
  34. package/public/js/pricechart.js +14 -13
  35. package/public/js/quake.js +20 -0
  36. package/public/js/settings.js +103 -21
  37. package/public/js/soundcard.js +459 -0
  38. package/public/js/theme.js +235 -0
  39. package/public/js/wolf3d.js +22 -0
  40. package/public/js/x86.js +1978 -0
  41. package/scripts/donate-qr.py +12 -9
  42. package/scripts/dos-bench.js +56 -0
  43. package/scripts/setup.js +34 -12
  44. package/scripts/shots.mjs +6 -0
  45. package/scripts/smoke.sh +1 -1
  46. package/scripts/tls.js +31 -0
  47. package/server/chain/index/build.js +21 -4
  48. package/server/collect/monitor.js +30 -1
  49. package/server/collect/network.js +295 -0
  50. package/server/config.js +46 -22
  51. package/server/http/api.js +49 -5
  52. package/server/http/games.js +77 -0
  53. package/server/http/server.js +8 -0
  54. package/server/main.js +53 -8
  55. package/server/tls/selfsigned.js +160 -0
  56. package/systemd/blockyard.service +7 -5
  57. package/docs/PRIVATE-LEADERBOARD.md +0 -230
  58. package/docs/STATE-2026-09-09.md +0 -200
@@ -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 #f7931a44; }
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: #ffc061; }
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
- .aboutwrap { position: relative; border-radius: var(--radius); overflow: hidden; background: #000; border: 1px solid var(--line-soft); min-height: min(calc(100vh - 150px), 820px); }
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: 42px clamp(20px, 5vw, 64px); display: flex; flex-direction: column; gap: 26px; max-width: 1080px; margin: 0 auto; }
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 16px; }
102
- .abcard h3 { margin: 0 0 10px; font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--fg-faint); font-weight: 600; }
103
- .abrow { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 3px 0; font-family: var(--mono); font-size: 12.5px; }
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: 132px; height: 132px; border-radius: 6px; }
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: #17110a; border-color: #0000; font-weight: 650; }
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
- padding: 12px 13px; box-shadow: var(--shadow); min-width: 0;
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 9px; font-size: 11px; font-weight: 700; letter-spacing: .09em;
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, #171b22 0%, #12151a 100%);
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%, #f7931a16, transparent 55%);
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 #58a6ff66; text-underline-offset: 3px; }
274
- .sf.jump:hover b { color: #cfe4ff; }
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: #0c0e11; border: 1px solid var(--line, #262c35); box-shadow: inset 0 1px 2px #000000a0; overflow: hidden;
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, #b06c10, var(--accent));
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, #1a8f68, var(--ok)); }
289
- .bar .fill.stall { background: linear-gradient(90deg, #8f2a2a, var(--bad)); }
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: #1b1a12; border: 1px solid #453a15; color: #f3d38a;
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: #1c1214; border-color: #50242a; color: #f0a8ad; }
304
- .caveat b { color: #fff; font-weight: 650; }
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: #ffffff06; }
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 #ffffff05; align-items: baseline; }
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: #e8c987; }
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: #f7931a22; } to { background: transparent; } }
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: #0c0e11; border: 1px solid var(--line, #262c35); color: var(--fg);
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: #e8c987; }
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: #1c1214; border: 1px solid #50242a; color: #f0a8ad; font-size: 12px;
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: 26px; box-shadow: var(--shadow);
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 3px; font-size: 19px; letter-spacing: -.2px; }
409
- .login-card p.sub { margin: 0 0 20px; color: var(--fg-faint); font-size: 12px; }
410
- .field { margin-bottom: 12px; }
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: #0c0e11; border: 1px solid var(--line, #262c35); color: var(--fg);
414
- border-radius: var(--radius-sm); padding: 9px 10px; font: 14px var(--mono);
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 #f7931a1a; }
417
- .err { background: #1c1214; border: 1px solid #50242a; color: #f0a8ad; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 12px; margin-bottom: 12px; }
418
- .locked { background: #1b1a12; border-color: #453a15; color: #f3d38a; }
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: #1c1214; border: 1px solid #50242a; color: #f0a8ad; font-size: 12px; }
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 - 260px); }
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: #0c0e11; border: 1px solid var(--line, #262c35); border-radius: var(--radius-sm);
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
- @media (max-width: 1100px) {
849
- .mpcols { grid-template-columns: minmax(0, 1fr); }
850
- .mprow { grid-template-columns: minmax(0, 1fr); }
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 rgba(247, 147, 26, .55)) drop-shadow(0 1px 1px rgba(0, 0, 0, .6));
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
- width: min(calc(100vw - 470px), calc(100vh - 150px)); min-width: 320px; }
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: stretch; }
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: #4f8f78; background: #12241d; }
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: #0b0e12; border: 1px solid var(--line-soft); border-radius: var(--radius-sm); cursor: crosshair; }
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
- .treemapwrap.mkboard { height: min(60vh, 600px); min-height: 380px; }
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(46vh, 420px); min-height: 280px; }
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: 14px; }
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: 8px 0 0; }
1422
- .xhero h1 { margin: 0; font-size: 30px; font-weight: 700; letter-spacing: -0.01em; color: #f4f7fb; display: flex; align-items: center; gap: 10px; }
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: 4px 14px 8px; max-height: calc(100vh - 320px); min-height: 160px; overflow: auto; }
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: 12px 8px 10px; border-bottom: 1px solid #1d2733; position: sticky; top: 0; background: #121923; }
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: 11px 8px; border-bottom: 1px solid #19222e; font-variant-numeric: tabular-nums; color: #e6edf3; white-space: nowrap; }
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
- .xblocks { display: flex; gap: 26px; overflow-x: auto; padding: 16px 12px 22px; }
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: 12px; 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 */
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: 8px 12px; font: 12px var(--sans); color: #c3cfdb; letter-spacing: .06em; text-transform: uppercase; }
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
- .kfull { position: absolute; right: 14px; bottom: 12px; z-index: 3; font: 12px var(--mono); padding: 5px 11px; background: rgba(2,12,8,0.82); color: #8fd8b8; border: 1px solid rgba(60,255,150,0.3); border-radius: 4px; cursor: pointer; }
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: 4px 22px; padding: 12px 16px 6px; border-top: 1px solid #16222c; background: linear-gradient(180deg, #060b10, #04080c); font-family: var(--sans); }
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: 12px; min-height: 0; min-width: 0; }
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: 240px; }
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: 200px; }
1763
+ .kcol > .kbf { height: 170px; }
1615
1764
  .kbf .flowwrap > .flow { zoom: 0.7; }
1616
1765
  }
1617
1766
 
@@ -1645,31 +1794,39 @@ 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: rgba(2, 5, 9, 0.62); }
1797
+ .cfgscrim { position: absolute; inset: 0; background: var(--scrim); }
1649
1798
  .cfg {
1650
- position: relative; width: min(420px, 100%); height: 100%; overflow: auto;
1651
- background: var(--bg-1); border-left: 1px solid var(--line); box-shadow: -18px 0 40px #0008;
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 14px; color: var(--fg-faint); font-size: 11.5px; line-height: 1.5; }
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-wrap: wrap; gap: 4px; margin: 0 0 12px; }
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: rgba(247, 147, 26, 0.1); }
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 12px 12px; margin-bottom: 12px; background: var(--bg-2); }
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 10px; color: var(--fg-faint); font-size: 11px; line-height: 1.45; }
1669
- .cfgrow { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; padding: 7px 0; border-top: 1px solid var(--line-soft); }
1820
+ .cfggroup > p { margin: 0 0 8px; color: var(--fg-faint); font-size: 11px; line-height: 1.4; }
1821
+ /* packed (2026-09-15): rows 5px not 7, hints tighter, and on the effects tabs the switches two across
1822
+ with the hint as the row's tooltip */
1823
+ .cfgrow { display: grid; grid-template-columns: 1fr auto; gap: 3px 10px; align-items: center; padding: 5px 0; border-top: 1px solid var(--line-soft); }
1824
+ .cfgrows2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; border-top: 1px solid var(--line-soft); margin-top: 4px; }
1825
+ .cfgrow.compact { padding: 4px 0; cursor: help; }
1826
+ .cfgrows2 .cfgrow.compact:nth-child(-n+2) { border-top: 0; }
1670
1827
  .cfgrow:first-of-type { border-top: 0; }
1671
1828
  .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.4; }
1829
+ .cfgrow i { grid-column: 1 / -1; font-style: normal; color: var(--fg-faint); font-size: 10.5px; line-height: 1.35; }
1673
1830
  .cfgrow select, .cfgrow input[type="range"] { accent-color: var(--accent); }
1674
1831
  .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
1832
  .cfgrow input[type="range"] { width: 130px; }
@@ -1681,6 +1838,47 @@ body { font-variant-numeric: tabular-nums; }
1681
1838
  .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
1839
  /* the toggle: a checkbox the browser draws, sized up, so it is keyboard-reachable for free */
1683
1840
  .cfgrow input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
1841
+ /* THE EXPLORER ON A LIGHT THEME (2026-09-16): its block pages are their own dark design, kept as they
1842
+ are; only what sits on the page itself -- the section titles, the hero's id and its back link --
1843
+ takes the theme's ink, and only when the theme is light, so the shipped look is untouched. */
1844
+ :root[data-theme="light"] .xhero h1, :root[data-theme="light"] .xsect h2 { color: var(--fg); }
1845
+ :root[data-theme="light"] .xhero .xnav { color: var(--fg-dim); border-color: var(--line); }
1846
+ :root[data-theme="light"] .xhero .xnav:hover { color: var(--fg); border-color: var(--accent); }
1847
+ :root[data-theme="light"] .xid, :root[data-theme="light"] .xblk-h { color: var(--info); }
1848
+ :root[data-theme="light"] .xcopy { color: var(--fg-faint); }
1849
+ :root[data-theme="light"] .xhero .xdim, :root[data-theme="light"] .xhero .xago, :root[data-theme="light"] .xtot { color: var(--fg-dim); }
1850
+ /* THE KIOSK ON A LIGHT THEME: its frames, heads and the price panel take the theme's panel, line and
1851
+ ink (the price loses its neon glow: a yellow that lights up a black panel is unreadable on white);
1852
+ the boards inside stay space. Light only, so the shipped kiosk is untouched. */
1853
+ :root[data-theme="light"] .kpanel { background: var(--bg-1); border-color: var(--line); }
1854
+ :root[data-theme="light"] .khead { color: var(--fg-dim); }
1855
+ :root[data-theme="light"] .kprice { background: var(--bg-1); border-top-color: var(--line); }
1856
+ :root[data-theme="light"] .kdepthwrap { background: var(--bg-0); }
1857
+ :root[data-theme="light"] .kp-wait, :root[data-theme="light"] .kp-pair { color: var(--fg-dim); }
1858
+ :root[data-theme="light"] .kp-price { color: var(--accent); text-shadow: none; }
1859
+ /* APPEARANCE (2026-09-16): the mode as a segmented control, the themes as cards -- a swatch strip of
1860
+ the face the mode picks, the name, a line about it -- and the nine custom pickers dimmed until
1861
+ Custom is the theme. Each card carries its face's page, text and line colours as custom properties
1862
+ (set through the CSSOM), so the card previews the theme rather than describing it. */
1863
+ .cfgseg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; background: var(--bg-3); }
1864
+ .cfgsegbtn { font: inherit; font-size: 11px; padding: 4px 11px; border: 0; background: transparent; color: var(--fg-dim); cursor: pointer; }
1865
+ .cfgsegbtn + .cfgsegbtn { border-left: 1px solid var(--line); }
1866
+ .cfgsegbtn:hover { color: var(--fg); }
1867
+ .cfgsegbtn.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
1868
+ .cfgrow.cfgcards { grid-template-columns: 1fr auto; }
1869
+ .thcards { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 2px 0 1px; }
1870
+ .thcard { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; font: inherit; cursor: pointer;
1871
+ 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)); }
1872
+ .thcard:hover { border-color: var(--fg-dim); }
1873
+ .thcard.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
1874
+ .thcard b { font-size: 12px; font-weight: 600; }
1875
+ .thcard small { font-size: 10.5px; opacity: .72; line-height: 1.3; }
1876
+ .thsw { display: inline-flex; gap: 0; border-radius: 4px; overflow: hidden; border: 1px solid var(--th-line, var(--line)); }
1877
+ .thsw i { display: block; width: 14px; height: 12px; }
1878
+ .cfgcustomise { font-size: 10.5px; padding: 3px 8px; }
1879
+ .cfgrows2 .cfgrow.compact input[type="color"] { width: 36px; height: 20px; }
1880
+ .cfgrow.idle { opacity: .55; }
1881
+ .cfgrow.idle:hover { opacity: 1; }
1684
1882
  /* DIVERSIONS: a pop-down at the end of the nav. The buttons inside are `nav.pages button` like
1685
1883
  every other tab, so they inherit the tab look and only the layout is new. */
1686
1884
  /* PINNED, because the nav SCROLLS. `nav.pages` is overflow-x:auto with its scrollbar hidden, so
@@ -1719,7 +1917,11 @@ body { font-variant-numeric: tabular-nums; }
1719
1917
  absolutely beautiful leveraging our framework"). The well is a board3d in a tall
1720
1918
  frame; the HUD sits beside it. No inline styles anywhere: the overlay is a class.
1721
1919
  ========================================================================== */
1722
- .tetrust { display: grid; grid-template-columns: auto 290px; justify-content: center; gap: 14px; align-items: start; }
1920
+ .tetrust { display: grid; grid-template-columns: auto 270px; justify-content: center; gap: 12px; align-items: start; }
1921
+ /* the DOS pages give the screen the whole first column (an `auto` column sized it to nothing once the
1922
+ wrap's width became a min() of its container) */
1923
+ .tetrust.dosgame { grid-template-columns: minmax(0, 1fr) 270px; justify-content: stretch; }
1924
+ .tetrust.dosgame > .doscard { min-width: 0; } /* 270, not 290: the well and the DOS screen get the width (2026-09-15) */
1723
1925
  /* .card carries grid-column: span 4 for the page's twelve-column layout; inside this two-column
1724
1926
  grid that span forced four tracks and stacked the HUD under the well (measured: both cards
1725
1927
  "span 4" in a 72/290/72/72 px grid). The other multi-column panels reset it the same way. */
@@ -1727,7 +1929,9 @@ body { font-variant-numeric: tabular-nums; }
1727
1929
  /* SIZED TO THE SCREEN, not the card (operator: "the playfield needs to be shrunk so it fits on a
1728
1930
  single screen with room. it's way too large now"): the well's HEIGHT comes from the viewport,
1729
1931
  and its width follows from the 10x20 shape -- about 330px wide on a 1000px-tall window. */
1730
- .tetcard .treemapwrap.tetwell { position: relative; z-index: 1; height: min(calc(100vh - 230px), 600px); width: auto; aspect-ratio: 11 / 21; margin: 0 auto; }
1932
+ /* the well takes the window's height (operator, 2026-09-15: "same treatment on the diversions games
1933
+ pages" -- it stopped at 600px with a fifth of the window dark beneath) */
1934
+ .tetcard .treemapwrap.tetwell { position: relative; z-index: 1; height: min(calc(100vh - 170px), 820px); width: auto; aspect-ratio: 11 / 21; margin: 0 auto; }
1731
1935
  /* Blockout's court is 16 x 24 rather than 10 x 20, so it is wider than the Tetris well; the rest
1732
1936
  of the furniture (the sky canvas, the overlay, the HUD) is shared with it. */
1733
1937
  .tetcard .treemapwrap.tetwell.bowell { aspect-ratio: 17 / 25; }
@@ -1747,7 +1951,7 @@ body { font-variant-numeric: tabular-nums; }
1747
1951
  .tetwell.idle { visibility: hidden; }
1748
1952
  .tetswitches { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
1749
1953
  .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: rgba(247, 147, 26, 0.1); }
1954
+ .tetsw.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1751
1955
  .tetover { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
1752
1956
  background: transparent; text-align: center; padding: 20px; }
1753
1957
  .tetover.dim { background: rgba(0, 0, 0, 0.74); }
@@ -1783,3 +1987,23 @@ body { font-variant-numeric: tabular-nums; }
1783
1987
  .tetscores td:first-child, .tetscores th:first-child { text-align: left; }
1784
1988
  .tetscores tr.now td { color: var(--accent); font-weight: 600; }
1785
1989
  @media (max-width: 900px) { .tetrust { grid-template-columns: 1fr; } }
1990
+ /* THE DOS GAMES (dosgame.js: DOOM and Quake): the monitor is a 4:3 box, as a VGA's 320x200 was on
1991
+ the CRT it was drawn for, sized to the screen's height like the courts; the pixels stay pixels
1992
+ unless the smooth switch is on. */
1993
+ .doscard { position: relative; background: #000; }
1994
+ .doscard > h3 { color: var(--fg-dim); }
1995
+ /* the DOS screen is ALWAYS 4:3 and as big as the window allows either way (2026-09-15): sized by
1996
+ height alone, a 1093px window capped its width and the 320x200 picture was drawn squashed into
1997
+ a 761x720 box */
1998
+ .doswrap { position: relative; width: min(100%, calc((100vh - 160px) * 4 / 3), 1067px); height: auto; aspect-ratio: 4 / 3; margin: 0 auto; background: #000; }
1999
+ .doswrap:fullscreen { height: 100vh; width: 100vw; max-width: none; aspect-ratio: auto; display: flex; align-items: center; justify-content: center; }
2000
+ .dosscreen { width: 100%; height: 100%; display: block; image-rendering: pixelated; cursor: crosshair; }
2001
+ .doswrap:fullscreen .dosscreen { width: auto; height: 100%; aspect-ratio: 4 / 3; max-width: 100%; }
2002
+ .dosscreen.smooth { image-rendering: auto; }
2003
+ .dosagain { position: absolute; right: 12px; bottom: 12px; z-index: 3; }
2004
+ /* the way out of full screen, drawn only there (keyboard lock takes Esc for the game's menu) */
2005
+ .dosexit { display: none; }
2006
+ .doswrap:fullscreen .dosexit { display: block; position: absolute; right: 14px; top: 12px; z-index: 4; opacity: .55; font: 12px var(--mono); }
2007
+ .doswrap:fullscreen .dosexit:hover { opacity: 1; }
2008
+ .dosgame .tetkeys code { font-family: var(--mono); font-size: 10.5px; }
2009
+ @media (max-width: 900px) { .doswrap { height: auto; width: 100%; } }