@tileflow/dev 0.1.0-alpha.32 → 0.1.0-alpha.33

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/dist/server.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  parseTileflowLineBackgroundGlyphPath,
6
6
  tileflowArtifactSessionSchemaVersion,
7
7
  tileflowLineBackgroundGlyphRoute
8
- } from "./chunk-CM6ZTYDJ.js";
8
+ } from "./chunk-WJOF6USY.js";
9
9
  import {
10
10
  getTileflowAssetBasePath,
11
11
  getTileflowAssetFileName,
@@ -13,7 +13,7 @@ import {
13
13
  normalizeTileflowBasePath,
14
14
  resolveTileflowArtifactPublicUrls
15
15
  } from "./chunk-UTRO4IBQ.js";
16
- import "./chunk-F4PLTZS4.js";
16
+ import "./chunk-QYU4OW5A.js";
17
17
  import "./chunk-7C4F6GAX.js";
18
18
  import {
19
19
  TileflowStyleValidationError
@@ -233,14 +233,145 @@ function compilePreviewControls(artifacts, map, theme, text, apiBaseUrl) {
233
233
  import { randomBytes } from "crypto";
234
234
  import { readFile } from "fs/promises";
235
235
 
236
+ // src/devtools/card-styles.ts
237
+ var cardStyles = `
238
+ .devtools-ready .dt-shell {
239
+ --dt-page:color-mix(in srgb,var(--surface) 80%,var(--border));
240
+ --dt-card-heading:color-mix(in srgb,var(--paper) 55%,var(--surface));
241
+ --dt-content-gap:12px;
242
+ }
243
+ .devtools-ready .dt-shell :is(.dt-card-page,.dt-layer-content,.dt-tile-content,.dt-diagnostics-list) {
244
+ padding:14px; background:var(--dt-page);
245
+ }
246
+ .devtools-ready .dt-shell :is(.dt-card,.dt-layer-evidence,.dt-layer-neighbors,.dt-layer-section,.dt-layer-origin,.dt-layer-samples,.dt-tile-content > .dt-kv,.dt-tile-feature,.dt-diagnostic,.dt-diagnostics-empty) {
247
+ min-width:0; margin:0 0 var(--dt-content-gap); border:1px solid var(--border); border-radius:10px; background:var(--paper);
248
+ }
249
+ .devtools-ready .dt-shell .dt-card { padding:0; overflow:hidden; }
250
+ .devtools-ready .dt-shell :is(.dt-card-page,.dt-layer-content,.dt-tile-content,.dt-diagnostics-list) > :last-child { margin-bottom:0; }
251
+ .devtools-ready .dt-shell :is(.dt-card > .dt-section-heading,.dt-card > .controls-section-title,.dt-layer-neighbors > strong) {
252
+ display:block; margin:0; padding:10px 14px; border:0; border-bottom:1px solid var(--border); background:var(--dt-card-heading);
253
+ color:var(--ink); font:600 12px/1.4 var(--ui); letter-spacing:0; text-transform:none;
254
+ }
255
+ .devtools-ready .dt-shell .dt-card-table { overflow:auto; }
256
+ .devtools-ready .dt-shell .dt-card-table :is(.dt-table,.dt-layer-rules) { margin:0; }
257
+ .devtools-ready .dt-shell .dt-card-table th { background:var(--dt-card-heading); padding:9px 14px; text-transform:none; letter-spacing:0; }
258
+ .devtools-ready .dt-shell .dt-card-table td { padding:9px 14px; height:36px; border-bottom-color:var(--border); }
259
+ .devtools-ready .dt-shell :is(.dt-card-table,.dt-layer-samples) tr:last-child td { border-bottom:0; }
260
+ .devtools-ready .dt-shell .dt-subtabs { padding-inline:14px; background:var(--paper); }
261
+
262
+ /* Map: each existing section is one card, with the enabled module fields kept inline. */
263
+ .devtools-ready .dt-shell .dt-scene-content { max-width:none; background:var(--dt-page); }
264
+ .devtools-ready .dt-shell .map-controls { padding:14px!important; background:var(--dt-page); }
265
+ .devtools-ready .dt-shell .controls-grid { display:block; border:0; padding:0; }
266
+ .devtools-ready .dt-shell :is(.controls-selection,.controls-runtime) { border:1px solid var(--border); padding:0; }
267
+ .devtools-ready .dt-shell .controls-selection[hidden] { display:none; }
268
+ .devtools-ready .dt-shell .controls-section-title { margin:0; }
269
+ .devtools-ready .dt-shell .map-controls .control-field {
270
+ grid-template-columns:minmax(120px,180px) minmax(0,1fr); min-height:44px; padding:9px 18px; gap:16px;
271
+ }
272
+ .devtools-ready .dt-shell .map-controls .control-field.dt-palette-field { grid-template-columns:minmax(120px,180px) minmax(0,1fr); }
273
+ .devtools-ready .dt-shell :is(.controls-selection,.controls-runtime) > .control-field:last-child { border-bottom:0; }
274
+ .devtools-ready .dt-shell .control-module { background:transparent; }
275
+ .devtools-ready .dt-shell .control-module:last-child { border-bottom:0; }
276
+ .devtools-ready .dt-shell .control-module-header { min-height:44px; padding:10px 18px; }
277
+ .devtools-ready .dt-shell .control-module-header label { gap:10px; }
278
+ .devtools-ready .dt-shell .control-module-header input { margin-right:0; }
279
+ .devtools-ready .dt-shell .control-module fieldset { padding:0; border-top:1px solid var(--border); background:color-mix(in srgb,var(--paper) 65%,var(--surface)); }
280
+ .devtools-ready .dt-shell .control-module .control-field { padding-left:54px; border-bottom:1px solid var(--border); }
281
+ .devtools-ready .dt-shell .control-module .control-field:last-child { border-bottom:0; }
282
+ .devtools-ready .dt-shell .map-controls :is(select,input[type=number]) { border-radius:5px; }
283
+ .devtools-ready .dt-shell :is(.controls-segments,.dt-palettes button) { border-radius:5px; }
284
+ .devtools-ready .dt-shell .dt-palettes { gap:6px; flex-wrap:wrap; }
285
+ .devtools-ready .dt-shell .dt-palettes button { height:auto; min-height:30px; padding:4px 8px; }
286
+
287
+ /* Layers: preserve the list and tabs, frame each detail block as a card. */
288
+ .devtools-ready .dt-shell .dt-layer-content { container-type:inline-size; }
289
+ .devtools-ready .dt-shell :is(.dt-layer-evidence,.dt-layer-neighbors) { padding:0; overflow:hidden; }
290
+ .devtools-ready .dt-shell .dt-layer-evidence-row { padding:10px 14px; grid-template-columns:16px 110px minmax(0,1fr); }
291
+ .devtools-ready .dt-shell .dt-layer-evidence-row:last-child { border-bottom:0; }
292
+ .devtools-ready .dt-shell .dt-layer-neighbors > div { margin:0; padding:9px 14px; border-bottom:1px solid var(--border); }
293
+ .devtools-ready .dt-shell .dt-layer-neighbors > div:last-child { border-bottom:0; }
294
+ .devtools-ready .dt-shell :is(.dt-layer-section,.dt-layer-origin) { padding:12px 14px; }
295
+ .devtools-ready .dt-shell .dt-layer-section h4 { color:var(--ink); font:600 12px/1.4 var(--ui); text-transform:none; letter-spacing:0; }
296
+ .devtools-ready .dt-shell .dt-layer-content > .dt-tools { margin-bottom:12px; padding:0 0 8px; border:0; background:transparent; }
297
+ .devtools-ready .dt-shell .dt-layer-content > .dt-note { padding:0 2px 12px; }
298
+ .devtools-ready .dt-shell .dt-layer-samples { max-height:240px; }
299
+ .devtools-ready .dt-shell .dt-layer-samples td { padding:8px 12px; }
300
+ .devtools-ready .dt-shell .dt-layer-group-title { height:30px; min-height:30px; background:var(--dt-card-heading)!important; }
301
+ .devtools-ready .dt-shell .dt-layer-group-title strong { text-transform:capitalize; letter-spacing:0; }
302
+ .devtools-ready .dt-shell .dt-layer-row { grid-template-columns:18px 26px minmax(0,1fr) 52px; height:36px; min-height:36px; gap:6px; }
303
+ .devtools-ready .dt-shell .dt-layer-glyph { display:grid; place-items:center; width:26px; height:26px; border:1px solid var(--border); border-radius:6px; background:var(--surface); }
304
+ @container(max-width:400px) {
305
+ .devtools-ready .dt-shell .dt-layer-evidence-row { grid-template-columns:16px minmax(0,1fr); gap:4px 8px; }
306
+ .devtools-ready .dt-shell .dt-layer-evidence-row > :last-child { grid-column:2; }
307
+ }
308
+
309
+ /* Tiles: keep whole tables together and allow long layer names to wrap. */
310
+ .devtools-ready .dt-shell .dt-tile-content > .dt-note { padding:0 2px 10px; }
311
+ .devtools-ready .dt-shell .dt-tile-content .dt-table td { vertical-align:top; white-space:normal; overflow-wrap:anywhere; }
312
+ .devtools-ready .dt-shell .dt-tile-content .dt-tile-chip { display:inline-block; margin:2px 4px 2px 0; max-width:100%; white-space:normal; overflow-wrap:anywhere; text-align:left; border-radius:4px; font-size:10px; }
313
+ .devtools-ready .dt-shell .dt-tile-content > .dt-kv { padding:0; gap:0; overflow:hidden; grid-template-columns:minmax(100px,35%) minmax(0,1fr); }
314
+ .devtools-ready .dt-shell .dt-tile-content > .dt-kv > * { padding:10px 14px; border-bottom:1px solid var(--border); }
315
+ .devtools-ready .dt-shell .dt-tile-content > .dt-kv > :nth-last-child(-n+2) { border-bottom:0; }
316
+ .devtools-ready .dt-shell .dt-tile-feature { padding:10px 14px; }
317
+ .devtools-ready .dt-shell .dt-tile-content > :is(.dt-tile-chip-list,.dt-tile-paging) { padding:0 0 10px; margin-bottom:10px; background:transparent; }
318
+
319
+ /* Debug: overlay controls and resolution controls retain their existing actions. */
320
+ .devtools-ready .dt-shell .dt-card > .dt-debug-overlay { grid-template-columns:76px minmax(0,1fr) auto; padding:10px 18px; gap:14px; }
321
+ .devtools-ready .dt-shell .dt-debug-overlay:last-child { border-bottom:0; }
322
+ .devtools-ready .dt-shell .dt-debug-preview { width:76px; height:50px; border-radius:6px; }
323
+ .devtools-ready .dt-shell .dt-debug-overlay strong { font-weight:500; }
324
+ .devtools-ready .dt-shell .dt-debug-overlay small { margin-top:3px; font-size:11px; }
325
+ .devtools-ready .dt-shell .dt-overdraw-help { max-width:none; padding:10px 18px 12px 108px; }
326
+ .devtools-ready .dt-shell .dt-debug-scale { padding:12px 18px; gap:12px; }
327
+ .devtools-ready .dt-shell .dt-debug-scale > span:first-child { flex:0 0 180px; }
328
+ .devtools-ready .dt-shell .dt-debug-scale > input[type=range] { width:108px; min-width:60px; }
329
+ .devtools-ready .dt-shell .dt-debug-scale > .dt-debug-specimen { flex:1; min-width:160px; }
330
+ .devtools-ready .dt-shell .dt-card > .dt-note { padding:0 18px 12px; }
331
+ .devtools-ready .dt-shell .dt-debug-scale:last-child { border-top:1px solid var(--border); }
332
+
333
+ /* Assets and findings use the same spacing and surfaces as the other pages. */
334
+ .devtools-ready .dt-shell .dt-assets-content { background:var(--dt-page); }
335
+ .devtools-ready .dt-shell .dt-asset-main { padding:14px; }
336
+ .devtools-ready .dt-shell :is(.dt-sprite-grid,.dt-model-grid,.dt-font-list) { gap:10px; background:transparent; }
337
+ .devtools-ready .dt-shell :is(.dt-sprite-card,.dt-model-card,.dt-font-card) { border:1px solid var(--border); border-radius:8px; background:var(--paper); overflow:hidden; }
338
+ .devtools-ready .dt-shell .dt-sprite-card { padding:10px 8px; }
339
+ .devtools-ready .dt-shell .dt-font-list { padding:14px; max-width:none; }
340
+ .devtools-ready .dt-shell .dt-font-card { padding:12px; }
341
+ .devtools-ready .dt-shell .dt-asset-aside { margin:14px 14px 14px 0; border:1px solid var(--border); border-radius:10px; background:var(--paper); }
342
+ .devtools-ready .dt-shell .dt-asset-aside h3 { margin:0; padding:12px 14px; background:var(--dt-card-heading); border-bottom:1px solid var(--border); }
343
+ .devtools-ready .dt-shell .dt-diagnostic { overflow:hidden; }
344
+ .devtools-ready .dt-shell .dt-diagnostic > summary { padding:12px 14px; }
345
+ .devtools-ready .dt-shell .dt-diagnostic[open] > summary { background:var(--dt-card-heading); border-bottom:1px solid var(--border); }
346
+ .devtools-ready .dt-shell .dt-diagnostic-detail { padding:12px 14px 14px 39px; }
347
+ .devtools-ready .dt-shell .dt-diagnostics-empty { padding:20px; max-width:none; }
348
+
349
+ @container(max-width:760px) {
350
+ .devtools-ready .dt-shell .dt-asset-aside { margin:0 14px 14px; }
351
+ }
352
+ @container(max-width:480px) {
353
+ .devtools-ready .dt-shell :is(.dt-card-page,.dt-layer-content,.dt-tile-content,.dt-diagnostics-list,.dt-asset-main,.dt-font-list) { padding:10px; }
354
+ .devtools-ready .dt-shell .map-controls { padding:10px!important; }
355
+ .devtools-ready .dt-shell .map-controls :is(.control-field,.control-field.dt-palette-field) { grid-template-columns:110px minmax(0,1fr); gap:10px; padding-inline:12px; }
356
+ .devtools-ready .dt-shell .control-module .control-field { padding-left:24px; }
357
+ .devtools-ready .dt-shell .dt-debug-scale > span:first-child { flex-basis:100%; }
358
+ .devtools-ready .dt-shell .dt-card > .dt-debug-overlay { grid-template-columns:60px minmax(0,1fr) auto; padding:10px 12px; gap:10px; }
359
+ .devtools-ready .dt-shell .dt-debug-preview { width:60px; height:40px; }
360
+ .devtools-ready .dt-shell .dt-overdraw-help { padding-left:12px; }
361
+ }
362
+ `;
363
+
236
364
  // src/devtools/inspector-styles.ts
237
365
  var inspectorStyles = `
238
366
  body.devtools-ready {
239
367
  --paper:#F8F6F2; --surface:#F0EDE7; --ink:#30251F; --muted:#635449; --faint:#A0907F;
240
368
  --border:#E1DCD3; --border-strong:#C7BFB3; --accent:#38668B; --dt-selected:#E6ECF2;
241
369
  --hover:#E9E5DE; --accent-soft:#DFE8F0; --ok:#2F704B; --ok-soft:#E3EBDB; --warn:#815D21; --warn-soft:#F3E6CF;
242
- --danger:#B13C34; --dt-string:var(--ink); --dt-number:var(--accent); --mono:'JetBrains Mono',ui-monospace,Menlo,monospace;
243
- color-scheme:light; font:13px/1.4 Inter,system-ui,-apple-system,sans-serif; -webkit-font-smoothing:antialiased;
370
+ --danger:#B13C34; --dt-string:var(--ink); --dt-number:var(--accent); --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
371
+ --ui:-apple-system,BlinkMacSystemFont,'Segoe UI',Arial,sans-serif;
372
+ --dt-control-height:22px; --dt-row-height:22px; --dt-nav-height:27px;
373
+ --dt-header-height:44px; --dt-camera-control-height:30px;
374
+ color-scheme:light; font:12px/1.35 var(--ui); -webkit-font-smoothing:antialiased;
244
375
  }
245
376
  body.devtools-ready[data-inspector-theme=dark] {
246
377
  --paper:#1D1816; --surface:#171311; --ink:#F5EDD9; --muted:#C3B7A9; --faint:#857869; --border:#40352F; --border-strong:#5A4B43;
@@ -289,8 +420,8 @@ body.devtools-ready[data-inspector-theme=dark] {
289
420
  .devtools-ready input[role=switch]::before { content:''; position:absolute; width:11px; height:11px; left:2px; top:2px; border-radius:50%; background:#fff; transition:transform .15s; }
290
421
  .devtools-ready input[role=switch]:checked { background:var(--accent); }
291
422
  .devtools-ready input[role=switch]:checked::before { transform:translateX(11px); }
292
- .devtools-ready .dt-layer-split { display:grid; grid-template-columns:minmax(300px,360px) minmax(0,1fr); }
293
- .devtools-ready .dt-layer-sidebar { display:flex; flex-direction:column; min-height:0; border-right:1px solid var(--border); }
423
+ .devtools-ready .dt-layer-split { display:grid; grid-template-columns:minmax(0,min(38%,360px)) minmax(0,1fr); }
424
+ .devtools-ready .dt-layer-sidebar { display:flex; flex-direction:column; min-width:0; min-height:0; overflow:hidden; border-right:1px solid var(--border); }
294
425
  .devtools-ready .dt-layer-list { flex:1; border:0; }.devtools-ready .dt-layer-tools { flex-direction:column; align-items:stretch; }
295
426
  .devtools-ready .dt-layer-tools-row { display:flex; align-items:center; gap:8px; }.devtools-ready .dt-layer-total { margin-left:auto; font:11px var(--mono); }
296
427
  .devtools-ready .dt-layer-visible { font-size:12px; }.devtools-ready .dt-layer-group-title { height:32px; font-size:11px; padding:0 12px 0 8px!important; }
@@ -322,7 +453,7 @@ body.devtools-ready[data-inspector-theme=dark] {
322
453
  .devtools-ready .dt-layer-evidence-row[data-state=pass] .dt-layer-indicator { color:var(--ok); }.devtools-ready .dt-layer-evidence-row[data-state=warn] .dt-layer-indicator { color:var(--warn); }
323
454
  .devtools-ready .dt-layer-json { font:11px/1.6 var(--mono); color:var(--ink); }
324
455
  .devtools-ready .dt-table { font:12px var(--mono); }.devtools-ready .dt-table th { padding:8px 12px; font:11px Inter,system-ui,sans-serif; text-transform:uppercase; border-right:0; }.devtools-ready .dt-table td { height:32px; padding:6px 12px; }.devtools-ready .dt-table tbody tr:nth-child(even) { background:transparent; }
325
- .devtools-ready .dt-network-body { display:grid; grid-template-columns:minmax(300px,360px) minmax(0,1fr); }.dt-tiles-sidebar { display:flex; flex-direction:column; min-height:0; border-right:1px solid var(--border); }.devtools-ready .dt-network-detail { border:0; min-width:0; }
456
+ .devtools-ready .dt-network-body { display:grid; grid-template-columns:minmax(0,min(38%,360px)) minmax(0,1fr); }.dt-tiles-sidebar { display:flex; flex-direction:column; min-width:0; min-height:0; overflow:hidden; border-right:1px solid var(--border); }.devtools-ready .dt-network-detail { border:0; min-width:0; }
326
457
  .devtools-ready .dt-tile-heading { padding:14px 20px 8px; }.dt-tile-heading strong { font:15px var(--mono); }.dt-tile-status { padding:0 20px 10px; color:var(--muted); font-size:12px; }
327
458
  .dt-tile-grid { display:grid; gap:3px; padding:12px; }.devtools-ready .dt-tile-cell { aspect-ratio:1; padding:0; font:10px var(--mono); min-width:0; min-height:20px; border-radius:4px; background:color-mix(in srgb,var(--accent) var(--weight,10%),var(--paper)); }
328
459
  .devtools-ready .dt-tile-cell[aria-pressed=true] { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-soft); }.dt-tile-grid-title { margin:10px 12px 0; color:var(--muted); font-size:11px; }
@@ -336,9 +467,6 @@ body.devtools-ready[data-inspector-theme=dark] {
336
467
  .devtools-ready .controls-section-title { margin:0; padding:8px 20px; background:var(--surface); border-bottom:1px solid var(--border); font-size:11px; letter-spacing:.05em; }.devtools-ready .control-field { display:grid; grid-template-columns:200px 1fr; align-items:center; margin:0; padding:10px 20px; border-bottom:1px solid var(--border); gap:16px; font-size:13px; }.devtools-ready .control-field select { max-width:100%; width:max-content; min-width:132px; }
337
468
  .devtools-ready #controls-modules { display:block; }.devtools-ready .control-module { border:0; border-bottom:1px solid var(--border); border-radius:0; margin:0; background:var(--paper); }.devtools-ready .control-module-header { padding:10px 20px; }.devtools-ready .control-module-header label { justify-content:flex-start; font-size:13px; font-weight:500; }.devtools-ready .control-module-header input { order:-1; margin-right:12px; }.devtools-ready .control-module fieldset { padding:0; background:var(--surface); }.devtools-ready .control-module .control-field { padding-left:58px; border:0; }.devtools-ready .dt-scene-content { max-width:1000px; width:100%; }.dt-palettes { display:flex; gap:8px; flex-wrap:wrap; }.devtools-ready .dt-palette { display:flex; align-items:center; gap:8px; padding:5px 10px 5px 5px; }.dt-palette-swatches { display:grid; grid-template-columns:repeat(2,11px); grid-template-rows:repeat(2,11px); overflow:hidden; border-radius:4px; }
338
469
  @container(max-width:760px) {
339
- .devtools-ready .dt-layer-split,.devtools-ready .dt-network-body { display:flex; flex-direction:column; }
340
- .devtools-ready .dt-layer-sidebar,.devtools-ready .dt-tiles-sidebar { flex:0 0 36%; min-height:150px; border:0; border-bottom:1px solid var(--border); }
341
- .devtools-ready .dt-layer-detail,.devtools-ready .dt-network-detail { flex:1; min-height:0; border:0; }
342
470
  .devtools-ready .dt-layer-title { flex-basis:180px; }.devtools-ready .dt-camera-field input[type=range] { width:80px; }
343
471
  .devtools-ready .dt-layer-rules th:first-child { width:45%; }.devtools-ready .dt-layer-rules td { padding:8px 12px; }
344
472
  .dt-asset-layout { grid-template-columns:1fr; }.dt-asset-aside { border:0; border-top:1px solid var(--border); }
@@ -359,7 +487,109 @@ body.devtools-ready[data-inspector-theme=dark] {
359
487
  .devtools-ready .dt-shell .dt-layer-heading{flex:none}.devtools-ready .dt-shell .dt-layer-title{flex:1 1 180px}
360
488
  .devtools-ready .dt-shell .dt-layer-sidebar .dt-layer-list{flex:1;min-height:0}.devtools-ready .dt-shell .map-controls .control-field{display:grid;grid-template-columns:160px minmax(0,1fr);padding:12px 20px;margin:0}
361
489
  .devtools-ready .dt-shell .control-module-header label{display:flex;gap:12px}.devtools-ready .dt-shell .map-controls input[role=switch]{width:26px!important;height:15px!important;min-height:0;border:0;background:var(--faint)}.devtools-ready .dt-shell .map-controls input[role=switch]:checked{background:var(--accent)}.devtools-ready .dt-shell .map-controls input[role=switch]::before{width:11px;height:11px;top:2px;left:2px;background:white}.devtools-ready .dt-shell .map-controls input[role=switch]:checked::before{transform:translateX(11px)}
362
- @container(max-width:760px){.devtools-ready .dt-shell .dt-layer-sidebar,.devtools-ready .dt-shell .dt-tiles-sidebar{min-height:110px;flex:0 0 38%}.devtools-ready .dt-shell .dt-layer-tools{padding:8px 12px}.devtools-ready .dt-shell .dt-tabs button{padding-inline:7px}.devtools-ready .dt-shell .dt-head{padding-inline:4px}.devtools-ready .dt-shell .dt-camera-field{flex:0 0 auto}}
490
+ @container(max-width:760px){.devtools-ready .dt-shell .dt-layer-tools{padding:8px 12px}.devtools-ready .dt-shell .dt-tabs button{padding-inline:7px}.devtools-ready .dt-shell .dt-head{padding-inline:4px}.devtools-ready .dt-shell .dt-camera-field{flex:0 0 auto}}
491
+
492
+ /* Shared density also wins over panel styles injected after the shell stylesheet. */
493
+ .devtools-ready .dt-shell { font:12px/1.35 var(--ui); }
494
+ .devtools-ready .dt-shell :is(button,input,select,summary) { min-height:var(--dt-control-height); }
495
+ .devtools-ready .dt-shell button { padding:2px 6px; border-radius:3px; }
496
+ .devtools-ready .dt-shell :is(input[type=checkbox],input[type=radio],input[type=range],input[type=color]) { min-height:0; }
497
+ .devtools-ready .dt-shell .dt-head { height:var(--dt-header-height); min-height:var(--dt-header-height); padding:0 4px; }
498
+ .devtools-ready .dt-shell .dt-tabs { gap:0; }
499
+ .devtools-ready .dt-shell .dt-tabs button { height:34px; min-height:34px; padding:0 8px; border-radius:4px; }
500
+ .devtools-ready .dt-shell .dt-head .dt-icon { width:30px; height:30px; min-height:30px; padding:5px; margin-block:0; }
501
+ .devtools-ready .dt-shell > .dt-camera { min-height:48px; padding:8px; gap:6px; }
502
+ .devtools-ready .dt-shell .dt-camera-field { height:var(--dt-camera-control-height); border-radius:5px; }
503
+ .devtools-ready .dt-shell .dt-camera-field > span:first-child { padding-left:6px; }
504
+ .devtools-ready .dt-shell .dt-camera-field input[type=number] { width:48px; min-height:0; padding:0 3px; font-size:12px; }
505
+ .devtools-ready .dt-shell .dt-camera-field input[type=range] { width:88px; margin:0 6px 0 2px; }
506
+ .devtools-ready .dt-shell .dt-unit { padding-right:6px; }
507
+ .devtools-ready .dt-shell .dt-camera-reset { display:inline-flex; align-items:center; justify-content:center; flex:none; width:26px; height:100%; min-height:0; padding:4px; border:0; border-left:1px solid var(--border); border-radius:0; background:transparent; }
508
+ .devtools-ready .dt-shell .dt-camera-reset:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
509
+ .devtools-ready .dt-shell .dt-copy-agent { min-height:var(--dt-camera-control-height); padding:4px 10px; font-size:12px; white-space:nowrap; }
510
+ .devtools-ready .dt-shell .dt-menu { top:var(--dt-header-height); right:4px; width:216px; padding:6px; border-radius:4px; }
511
+ .devtools-ready .dt-shell .dt-dock-options { gap:4px; margin-bottom:6px; }
512
+ .devtools-ready .dt-shell .dt-dock-options button { height:26px; padding:2px; }
513
+ .devtools-ready .dt-shell :is(.dt-segments,.dt-layer-modes,.controls-segments) { padding:1px; gap:1px; border-radius:3px; }
514
+ .devtools-ready .dt-shell :is(.dt-segments,.dt-layer-modes,.controls-segments) button { min-height:20px; padding:1px 6px; border-radius:2px; }
515
+ .devtools-ready .dt-shell .dt-tools { min-height:28px; padding:3px 8px; gap:4px; }
516
+ .devtools-ready .dt-shell .dt-tools input[type=search] { height:var(--dt-control-height); padding:0 6px; border-radius:3px; }
517
+ .devtools-ready .dt-shell .dt-layer-tools-row { min-width:0; min-height:var(--dt-control-height); gap:6px; flex-wrap:wrap; }
518
+ .devtools-ready .dt-shell .dt-layer-modes { max-width:100%; overflow-x:auto; }
519
+ .devtools-ready .dt-shell .dt-subtabs { padding:0 8px; gap:12px; }
520
+ .devtools-ready .dt-shell .dt-subtabs button { min-height:var(--dt-nav-height); padding:3px 0; border-radius:0; }
521
+ .devtools-ready .dt-shell .dt-footer { min-height:20px; padding:2px 8px; gap:8px; }
522
+ .devtools-ready .dt-shell .dt-section-heading { padding:4px 10px; }
523
+ .devtools-ready .dt-shell .dt-kv { gap:3px 8px; padding:6px 8px; font:11px/1.4 var(--mono); }
524
+ .devtools-ready .dt-shell .dt-layer-group-title { height:var(--dt-row-height); min-height:var(--dt-row-height); padding:0 8px 0 6px!important; }
525
+ .devtools-ready .dt-shell .dt-layer-row { grid-template-columns:18px 16px minmax(0,1fr) 52px; height:var(--dt-row-height); min-height:var(--dt-row-height); padding:0 8px 0 4px; gap:4px; border-radius:0; }
526
+ .devtools-ready .dt-shell .dt-layer-glyph { font-size:13px; }
527
+ .devtools-ready .dt-shell .dt-eye { min-height:18px; width:18px; height:18px; padding:0; }
528
+ .devtools-ready .dt-shell .dt-zrange { width:52px; }
529
+ .devtools-ready .dt-shell .dt-layer-heading { padding:8px 10px 4px; }
530
+ .devtools-ready .dt-shell .dt-layer-title strong { font-size:13px; }
531
+ .devtools-ready .dt-shell .dt-layer-status { margin-top:3px; gap:6px; font-size:11px; }
532
+ .devtools-ready .dt-shell .dt-layer-rules th { padding:4px 10px; }
533
+ .devtools-ready .dt-shell .dt-layer-rules td { padding:3px 10px; min-height:24px; }
534
+ .devtools-ready .dt-shell .dt-layer-rules code { font:11px/1.4 var(--mono); }
535
+ .devtools-ready .dt-shell .dt-layer-rule-editor { gap:5px; }
536
+ .devtools-ready .dt-shell .dt-layer-rule-editor :is(input:not([type=color]):not([type=checkbox]):not([type=range]),select) { min-height:20px; font:11px/1.4 var(--mono); border-radius:3px; }
537
+ .devtools-ready .dt-shell .dt-layer-rule-editor input[type=color] { width:18px; height:20px; }
538
+ .devtools-ready .dt-shell .dt-layer-rule-editor input[type=range] { width:88px; min-width:60px; flex-basis:88px; }
539
+ .devtools-ready .dt-shell .dt-rule-toggle { gap:6px; }
540
+ .devtools-ready .dt-shell .dt-rule-choices { border-radius:3px; }
541
+ .devtools-ready .dt-shell .dt-rule-choices button { min-height:20px; padding:1px 5px; border-radius:0; }
542
+ .devtools-ready .dt-shell .dt-rule-spark { gap:6px; margin-bottom:3px; }
543
+ .devtools-ready .dt-shell .dt-rule-spark svg { width:100px; height:22px; }
544
+ .devtools-ready .dt-shell .dt-filter-chips { gap:4px; margin-block:6px; }
545
+ .devtools-ready .dt-shell .dt-filter-chip { padding:2px 6px; }
546
+ .devtools-ready .dt-shell :is(.dt-layer-section,.dt-layer-origin) { padding:6px 10px; }
547
+ .devtools-ready .dt-shell .dt-layer-evidence-row { padding:6px 10px; grid-template-columns:16px 110px minmax(0,1fr); }
548
+ .devtools-ready .dt-shell .dt-table { font:11px/1.4 var(--mono); }
549
+ .devtools-ready .dt-shell .dt-table th { padding:4px 8px; font:11px var(--ui); }
550
+ .devtools-ready .dt-shell .dt-table td { height:var(--dt-row-height); padding:2px 8px; }
551
+ .devtools-ready .dt-shell .dt-tile-heading { padding:8px 10px 4px; }
552
+ .devtools-ready .dt-shell .dt-tile-heading strong { font-size:13px; }
553
+ .devtools-ready .dt-shell .dt-tile-status { padding:0 10px 6px; }
554
+ .devtools-ready .dt-shell .dt-tile-grid { padding:8px; gap:2px; }
555
+ .devtools-ready .dt-shell .dt-tile-cell { padding:0; min-height:20px; }
556
+ .devtools-ready .dt-shell .dt-tile-grid-title { margin:6px 8px 0; }
557
+ .devtools-ready .dt-shell .dt-tile-chip-list { padding:5px 10px; gap:4px; }
558
+ .devtools-ready .dt-shell .dt-asset-main { padding:8px; }
559
+ .devtools-ready .dt-shell .dt-asset-aside h3 { font-size:13px; margin:8px 10px; }
560
+ .devtools-ready .dt-shell .dt-asset-variant { padding:10px 6px; gap:6px; }
561
+ .devtools-ready .dt-shell .dt-sprite-grid { grid-template-columns:repeat(auto-fill,minmax(88px,1fr)); }
562
+ .devtools-ready .dt-shell .dt-sprite-card { padding:6px 4px; border-radius:4px; }
563
+ .devtools-ready .dt-shell .dt-sprite-preview { height:44px; }
564
+ .devtools-ready .dt-shell .dt-sprite-card figcaption { margin-top:4px; }
565
+ .devtools-ready .dt-shell .dt-font-card { padding:8px; }
566
+ .devtools-ready .dt-shell .dt-font-card figcaption { margin-bottom:5px; font:11px/1.4 var(--mono); }
567
+ .devtools-ready .dt-shell .dt-font-loading { padding:8px; }
568
+ .devtools-ready .dt-shell .dt-model-grid { grid-template-columns:repeat(auto-fill,minmax(140px,1fr)); gap:6px; }
569
+ .devtools-ready .dt-shell .dt-model-card { padding:0; border-radius:4px; }
570
+ .devtools-ready .dt-shell .dt-model-card strong { padding:5px 8px 2px; }
571
+ .devtools-ready .dt-shell .dt-model-card small { padding:0 8px 5px; }
572
+ .devtools-ready .dt-shell .dt-debug-overlay { grid-template-columns:60px 1fr auto; gap:8px; padding:6px 10px; }
573
+ .devtools-ready .dt-shell .dt-debug-preview { width:60px; height:40px; border-radius:3px; }
574
+ .devtools-ready .dt-shell .dt-overdraw-help { padding:6px 10px 6px 78px; }
575
+ .devtools-ready .dt-shell .dt-debug-scale { gap:8px; padding:8px 10px; }
576
+ .devtools-ready .dt-shell .dt-debug-specimen { gap:10px; min-height:52px; padding:6px 10px; border-radius:4px; }
577
+ .devtools-ready .dt-shell .controls-section-title { padding:4px 10px; }
578
+ .devtools-ready .dt-shell .map-controls .control-field { grid-template-columns:140px minmax(0,1fr); padding:6px 10px; gap:8px; font-size:12px; }
579
+ .devtools-ready .dt-shell .control-module-header { padding:6px 10px; }
580
+ .devtools-ready .dt-shell .control-module-header label { font-size:12px; gap:6px; }
581
+ .devtools-ready .dt-shell .control-module-header input { margin-right:6px; }
582
+ .devtools-ready .dt-shell .control-module .control-field { padding-left:38px; }
583
+ .devtools-ready .dt-shell .map-controls .control-field.dt-palette-field { grid-template-columns:70px minmax(0,1fr); align-items:center; }
584
+ .devtools-ready .dt-shell .dt-palettes { gap:4px; align-items:center; }
585
+ .devtools-ready .dt-shell .dt-palettes button { flex-direction:row; align-items:center; gap:5px; padding:2px 6px; min-width:0; height:var(--dt-control-height); font-size:11px; white-space:nowrap; }
586
+ .devtools-ready .dt-shell .dt-palette-swatches { width:24px; height:10px; flex:none; border-radius:2px; }
587
+ .devtools-ready .dt-shell .dt-palette-swatches i { min-width:0; }
588
+ @container(max-width:480px) {
589
+ .devtools-ready .dt-shell .map-controls .control-field { grid-template-columns:110px minmax(0,1fr); }
590
+ .devtools-ready .dt-shell .control-module .control-field { padding-left:24px; }
591
+ .devtools-ready .dt-shell .dt-camera-field input[type=range] { width:48px; }
592
+ }
363
593
  `;
364
594
 
365
595
  // src/devtools/styles.ts
@@ -372,8 +602,8 @@ var legacyStyles = `
372
602
  .devtools-ready button[aria-pressed=true] { color:var(--accent); background:var(--dt-selected); }
373
603
  .devtools-ready .tool-icon { width:14px; height:14px; }
374
604
  .devtools-ready .workspace { display:grid; grid-template-columns:minmax(0,1fr); grid-template-rows:minmax(180px,1fr) var(--dt-height,340px); flex:1; min-height:0; }
375
- .devtools-ready .workspace[data-dock=right] { grid-template-columns:minmax(200px,1fr) var(--dt-width,460px); grid-template-rows:minmax(0,1fr); }
376
- .devtools-ready .workspace[data-dock=left] { grid-template-columns:var(--dt-width,460px) minmax(200px,1fr); grid-template-rows:minmax(0,1fr); }
605
+ .devtools-ready .workspace[data-dock=right] { grid-template-columns:minmax(200px,1fr) max(640px,var(--dt-width,760px)); grid-template-rows:minmax(0,1fr); }
606
+ .devtools-ready .workspace[data-dock=left] { grid-template-columns:max(640px,var(--dt-width,760px)) minmax(200px,1fr); grid-template-rows:minmax(0,1fr); }
377
607
  .devtools-ready .workspace[data-dock=left] > .stage { grid-column:2; grid-row:1; }
378
608
  .devtools-ready .workspace[data-dock=left] > .dt-shell { grid-column:1; grid-row:1; border-right:1px solid var(--border); }
379
609
  .devtools-ready .workspace[data-collapsed=true] { grid-template-columns:minmax(0,1fr); grid-template-rows:minmax(0,1fr); }
@@ -497,14 +727,6 @@ var legacyStyles = `
497
727
  .dt-tile-feature summary { cursor:pointer; overflow-wrap:anywhere; font-size:11px; }
498
728
  .dt-tile-feature details { padding-left:12px; }
499
729
  .dt-tile-feature pre { white-space:pre-wrap; overflow-wrap:anywhere; font:11px/1.6 ui-monospace,monospace; color:var(--dt-string); margin:6px 0; }
500
- :is([data-dock=left],[data-dock=right]) .dt-network-body { flex-direction:column; }
501
- :is([data-dock=left],[data-dock=right]) .dt-network-body[data-selected=true] > .dt-scroll { flex:0 0 35%; }
502
- :is([data-dock=left],[data-dock=right]) .dt-network-detail { flex:1; min-width:0; border-left:0; border-top:1px solid var(--border); }
503
- @container(max-width:680px) {
504
- .dt-network-body { flex-direction:column; }
505
- .dt-network-body[data-selected=true] > .dt-scroll { flex:0 0 35%; }
506
- .dt-network-detail { flex:1; min-width:0; border-left:0; border-top:1px solid var(--border); }
507
- }
508
730
  .dt-kv { display:grid; grid-template-columns:minmax(100px,auto) minmax(0,1fr); gap:5px 12px; font:12px/1.5 ui-monospace,monospace; padding:8px; margin:0; }
509
731
  .dt-kv dt { color:var(--muted); overflow-wrap:anywhere; }.dt-kv dd { margin:0; overflow-wrap:anywhere; }
510
732
  .dt-note { color:var(--muted); font-size:11px; padding:6px 8px; margin:0; }
@@ -530,7 +752,7 @@ var legacyStyles = `
530
752
  @media (prefers-reduced-motion:reduce) { .dt-shell .map-controls input[type=checkbox],.dt-shell .map-controls input[type=checkbox]::before { transition:none; } }
531
753
  .dt-shell .control-module { border:0; border-bottom:1px solid var(--border); border-radius:0; background:var(--paper); margin:0; }
532
754
  .dt-shell .control-module-header { padding:5px 0; }.dt-shell .control-module-header label { font-size:12px; font-weight:400; }
533
- .dt-shell .control-module fieldset { min-width:0; padding:0 0 8px 16px; }.dt-shell .control-module summary { padding:2px 0 5px; }
755
+ .dt-shell .control-module fieldset { min-width:0; padding:0 0 8px 16px; }
534
756
  .dt-shell .controls-section-title { margin:10px 0 4px; font-size:11px; letter-spacing:0; text-transform:none; }
535
757
  .dt-shell .control-field { margin:5px 0; }
536
758
  @container(max-width:680px) { .dt-shell .controls-grid,.dt-shell #controls-modules { grid-template-columns:minmax(0,1fr); }.dt-shell .map-controls .control-field,.dt-shell .control-module-header label { grid-template-columns:min(36%,160px) minmax(0,1fr); }.dt-shell .controls-segments button { padding-inline:8px; } }
@@ -567,7 +789,16 @@ var legacyStyles = `
567
789
  .dt-zoom { padding:8px; }.dt-zoom > select { width:100%; margin-bottom:8px; }
568
790
  @container(max-width:680px) { .dt-inspect-grid { display:flex;flex-direction:column; }.dt-tree-column { flex:0 0 32%;border-right:0;border-bottom:1px solid var(--border); }.dt-details { flex:1; } }
569
791
  `;
570
- var devtoolsStyles = legacyStyles + inspectorStyles;
792
+ var devtoolsStyles = legacyStyles + inspectorStyles + cardStyles;
793
+
794
+ // src/devtools/theme-labels.ts
795
+ var themeLabels = {
796
+ light: "Light",
797
+ default: "Default",
798
+ faded: "Faded",
799
+ monochrome: "Monochrome"
800
+ };
801
+ var defaultPaletteMapIds = ["streets", "map-1777"];
571
802
 
572
803
  // src/workbench-client.ts
573
804
  var workbenchClient = String.raw`
@@ -580,6 +811,9 @@ var workbenchClient = String.raw`
580
811
  let wbPickerKey = "";
581
812
  let wbTimeOfDay = "";
582
813
  const wbPaletteColors = new Map();
814
+ const wbThemeLabels = ${JSON.stringify(themeLabels)};
815
+ const wbDefaultPaletteMaps = ${JSON.stringify(defaultPaletteMapIds)};
816
+ const wbThemeLabel = (theme, metadata) => theme === "light" && wbDefaultPaletteMaps.some(id => metadata?.["tileflow:map"] === id || (Array.isArray(metadata?.["tileflow:extends"]) && metadata["tileflow:extends"].includes(id))) ? "Default" : Object.hasOwn(wbThemeLabels,theme) ? wbThemeLabels[theme] : theme.replace(/[-_]/g," ");
583
817
  const wbClient = "view-" + Math.random().toString(36).slice(2);
584
818
  const wb = (id) => document.getElementById("wb-" + id);
585
819
  if (options.workbenchUrl) initializeWorkbench();
@@ -695,13 +929,18 @@ var workbenchClient = String.raw`
695
929
  return;
696
930
  }
697
931
  const variants = owner?.timeOfDay?.[side.workbenchMap] || {};
698
- const key = JSON.stringify([activeSideId, selectedTheme, selections, variants, side.requestedTimeOfDay]);
932
+ const themeMetadata = side.map?.getStyle?.()?.metadata;
933
+ const key = JSON.stringify([activeSideId, selectedTheme, selections, variants, side.requestedTimeOfDay, themeMetadata?.["tileflow:map"], themeMetadata?.["tileflow:extends"]]);
699
934
  if (key === wbPickerKey) return;
700
935
  wbPickerKey = key;
701
936
  const allThemes = [...new Set(selections.map((entry) => entry.theme))];
702
937
  const family = Object.keys(variants).find((name) => Object.values(variants[name]).includes(selectedTheme));
703
938
  const members = new Set(Object.values(variants).flatMap((moments) => Object.values(moments)));
704
939
  const themes = allThemes.filter((name) => !members.has(name) || Object.hasOwn(variants, name));
940
+ if (themeMetadata?.["tileflow:map"] === "streets" || (Array.isArray(themeMetadata?.["tileflow:extends"]) && themeMetadata["tileflow:extends"].includes("streets"))) {
941
+ const streetsOrder = new Map([["light", 0], ["faded", 1], ["monochrome", 2]]);
942
+ themes.sort((left, right) => (streetsOrder.get(left) ?? 3) - (streetsOrder.get(right) ?? 3));
943
+ }
705
944
  const moments = family ? variants[family] : {};
706
945
  wbTimeOfDay = moments[side.requestedTimeOfDay] === selectedTheme ? side.requestedTimeOfDay : Object.keys(moments).find((moment) => moments[moment] === selectedTheme) || "";
707
946
  for (const segment of wb("time-of-day").querySelectorAll("button")) {
@@ -711,20 +950,20 @@ var workbenchClient = String.raw`
711
950
  segment.disabled = !moments[segment.value];
712
951
  }
713
952
  wb("time-of-day-field").hidden = !family;
714
- wb("theme").replaceChildren(...themes.map((theme) => new Option(theme, theme)));
953
+ wb("theme").replaceChildren(...themes.map((theme) => new Option(wbThemeLabel(theme,themeMetadata), theme)));
715
954
  wb("theme").value = family || selectedTheme;
716
955
  wb("theme").disabled = themes.length < 2;
717
956
  wb("palettes").replaceChildren(...themes.map(theme => {
718
957
  const button=document.createElement("button");button.type="button";button.setAttribute("role","radio");button.setAttribute("aria-checked",String(theme===(family||selectedTheme)));
719
958
  const swatches=document.createElement("span");swatches.className="dt-palette-swatches";
720
- const label=document.createElement("span");label.textContent=theme.replace(/[-_]/g," ");button.append(swatches,label);
959
+ const label=document.createElement("span");label.textContent=wbThemeLabel(theme,themeMetadata);button.append(swatches,label);
721
960
  button.onclick=()=>{wb("theme").value=theme;selectWorkbenchAppearance();};
722
961
  const concrete=variants[theme]?.[wbTimeOfDay] || variants[theme]?.day || theme;
723
962
  const fill=colors=>{if(!button.isConnected)return;swatches.replaceChildren(...colors.map(color=>{const swatch=document.createElement("i");swatch.style.background=color;return swatch;}));};
724
963
  if(wbPaletteColors.has(concrete))queueMicrotask(()=>fill(wbPaletteColors.get(concrete)));
725
964
  else {
726
965
  const url=new URL(side.definition.basePath+"/styles/"+side.workbenchMap+"/"+concrete+".json",location.href);
727
- fetch(url).then(response=>{if(!response.ok)throw new Error("Palette unavailable");return response.json();}).then(style=>{
966
+ fetch(url).then(response=>{if(!response.ok)throw new Error("Theme unavailable");return response.json();}).then(style=>{
728
967
  const choices=[/background/,/water/,/land.*(?:park|vegetation)|vegetation/,/building/];
729
968
  const colors=choices.map(pattern=>style.layers.flatMap(layer=>pattern.test(layer.id)||pattern.test(layer.type)?Object.entries(layer.paint||{}).filter(([key,value])=>key.endsWith("-color")&&typeof value==="string").map(([,value])=>value):[])[0]).filter(Boolean);
730
969
  wbPaletteColors.set(concrete,colors);fill(colors);
@@ -765,10 +1004,17 @@ var workbenchClient = String.raw`
765
1004
  const layerObservation = globalThis.__tileflowDevtoolsUI?.layerContext?.();
766
1005
  const selected = !layerObservation && selectedInspection?.side === side ? selectedInspection : undefined;
767
1006
  const feature = selected?.features[selected.featureIndex];
768
- const layer = feature && side.map?.getStyle?.().layers?.find((entry) => entry.id === feature.layerId);
1007
+ const style = side.map?.getStyle?.();
1008
+ const metadata = style?.metadata;
1009
+ const layer = feature && style?.layers?.find((entry) => entry.id === feature.layerId);
769
1010
  const provenance = feature && findSidecarLayer(side.sidecar, feature.layerId);
770
1011
  let definition;
771
1012
  try { definition = currentWorkbenchDefinition(); } catch { /* Loading previews have no camera yet. */ }
1013
+ const themeVariants = wbCatalog?.sides[side.serviceId || side.id]?.timeOfDay?.[definition?.map] || {};
1014
+ const themeFamily = definition && Object.keys(themeVariants).find(name => Object.values(themeVariants[name]).includes(definition.theme));
1015
+ const appearance = definition ? {theme:wbThemeLabel(themeFamily || definition.theme,metadata), themeId:themeFamily || definition.theme,
1016
+ timeOfDay:themeFamily ? (themeVariants[themeFamily][wbTimeOfDay] === definition.theme ? wbTimeOfDay : Object.keys(themeVariants[themeFamily]).find(moment => themeVariants[themeFamily][moment] === definition.theme)) : undefined,
1017
+ concreteThemeId:definition.theme} : undefined;
772
1018
  const configuration = side.definition.captureConfig ? " --config " + quoteCliArgument(side.definition.captureConfig) : "";
773
1019
  const semanticOwner = provenance && sidecarLayerWithSemanticAttribution(provenance).semanticAttribution[0]?.semanticOwner;
774
1020
  const captureCommand = definition ? "tileflow capture" + configuration + " --map " + quoteCliArgument(definition.map) + " --theme " + quoteCliArgument(definition.theme) +
@@ -776,7 +1022,7 @@ var workbenchClient = String.raw`
776
1022
  " --width=" + definition.viewport.width + " --height=" + definition.viewport.height + " --dpr=" + definition.viewport.dpr + " --json" : undefined;
777
1023
  return {schemaVersion:1, source:"browser-observation", config:side.definition.captureConfig || "tileflow.config.ts",
778
1024
  status:side.artifactStatus, generation:side.artifactGeneration, inspectionEnabled,
779
- displayedGeneration:Number(side.frame.contentDocument?.documentElement.dataset.tileflowArtifactGeneration), definition,
1025
+ displayedGeneration:Number(side.frame.contentDocument?.documentElement.dataset.tileflowArtifactGeneration), definition, appearance,
780
1026
  captureSemantics:"Compiled map at the observed camera and viewport; temporary preview edits are excluded.",
781
1027
  review:{referenceId:null, before:null, after:null, liveMode:stage.dataset.mode, source:"map"},
782
1028
  commands:{inspect:"tileflow inspect" + configuration + (semanticOwner ? " --domain " + quoteCliArgument(semanticOwner) : " --limit 80") + " --json", capture:captureCommand,
@@ -893,9 +1139,8 @@ var controlsStyles = `
893
1139
  .control-module-header input:checked { background:var(--accent); }
894
1140
  .control-module-header input:checked::before { transform:translateX(12px); }
895
1141
  .control-module-header input:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
896
- .control-module summary { cursor:pointer; padding:0 12px 10px; font-size:11px; color:var(--muted); }
897
1142
  .control-module fieldset { border:0; padding:0 12px 12px; margin:0; }
898
- .control-module fieldset:disabled { opacity:.45; }
1143
+ .control-module fieldset[hidden] { display:none; }
899
1144
  .control-field { display:flex; align-items:center; justify-content:space-between; flex-direction:row; gap:12px; font-size:12px; margin:9px 0; }
900
1145
  .control-field select,.control-field input[type=number] { width:132px; min-width:0; padding:5px 7px; font:inherit; }
901
1146
  .control-field input[type=checkbox] { accent-color:var(--accent); }
@@ -910,19 +1155,21 @@ var controlsPanel = `
910
1155
  <aside class="map-controls" id="map-controls" aria-label="Scene settings" tabindex="-1" hidden>
911
1156
  <div class="controls-heading"><h2>Styles</h2><button id="controls-reset">Reset</button></div>
912
1157
  <div class="controls-grid">
913
- <div class="controls-selection workbench-only" id="controls-selection" hidden>
1158
+ <div class="controls-selection workbench-only dt-card" id="controls-selection" hidden>
914
1159
  <div class="controls-section-title">Appearance</div>
915
1160
  <div class="control-field" id="wb-time-of-day-field" hidden><span>Time of day</span><div class="controls-segments" id="wb-time-of-day" role="radiogroup" aria-label="Time of day"></div></div>
916
- <div class="control-field dt-palette-field" id="wb-theme-field"><span>Theme</span><select id="wb-theme" aria-label="Palette" disabled hidden><option value="">Waiting for map\u2026</option></select><div id="wb-palettes" class="dt-palettes" role="radiogroup" aria-label="Theme palette"></div></div>
1161
+ <div class="control-field dt-palette-field" id="wb-theme-field"><span>Theme</span><select id="wb-theme" aria-label="Theme" disabled hidden><option value="">Waiting for map\u2026</option></select><div id="wb-palettes" class="dt-palettes" role="radiogroup" aria-label="Theme"></div></div>
917
1162
  </div>
918
- <fieldset class="controls-runtime" id="controls-runtime">
1163
+ <fieldset class="controls-runtime dt-card" id="controls-runtime">
919
1164
  <div class="controls-section-title">Preview rendering</div>
920
1165
  <label class="control-field">3D view<input id="controls-3d" type="checkbox" role="switch"></label>
921
1166
  <label class="control-field">Building animation<select id="controls-animation" hidden><option value="0">Off</option><option value="800">Grow</option><option value="fade">Fade</option></select><span class="controls-segments" id="controls-animation-segments" role="radiogroup" aria-label="Building animation"></span></label>
922
1167
  </fieldset>
923
1168
  </div>
924
- <div class="controls-section-title">Map modules</div>
925
- <fieldset id="controls-modules"></fieldset>
1169
+ <section class="dt-card controls-module-card">
1170
+ <div class="controls-section-title">Map modules</div>
1171
+ <fieldset id="controls-modules"></fieldset>
1172
+ </section>
926
1173
  <p id="controls-status" role="status" hidden></p>
927
1174
  </aside>
928
1175
  `;
@@ -945,10 +1192,6 @@ var controlsClient = String.raw`
945
1192
  scheduleMapControls(true);
946
1193
  });
947
1194
  for (const name of ["3d", "animation"]) ctl(name).addEventListener("change", () => { syncAnimationSegments(); scheduleMapControls(); });
948
- ctl("3d").addEventListener("change", () => {
949
- const map = states[activeSideId].map;
950
- if (map) map.easeTo({pitch:ctl("3d").checked ? Math.min(60,map.getMaxPitch()) : 0, duration:matchMedia("(prefers-reduced-motion: reduce)").matches ? 0 : 350}, {tileflowDevtools:true});
951
- });
952
1195
  for (const [value,label] of [["0","Off"],["800","Grow"],["fade","Fade"]]) {
953
1196
  const button=document.createElement("button"); button.type="button";button.value=value;button.textContent=label;button.setAttribute("role","radio");
954
1197
  button.addEventListener("click",()=>{ctl("animation").value=value;ctl("animation").dispatchEvent(new Event("change"));});ctl("animation-segments").append(button);
@@ -1049,7 +1292,7 @@ var controlsClient = String.raw`
1049
1292
  const query = livePreviewUrl(side).searchParams;
1050
1293
  controlsDraft = JSON.parse(query.get("controls") || "{}");
1051
1294
  side.appliedSceneStyle ||= JSON.stringify([identity.map, controlsIdentity(side).theme, controlsDraft]);
1052
- ctl("3d").checked = query.get("buildings3d") === "on";
1295
+ ctl("3d").checked = query.get("buildings3d") !== "off";
1053
1296
  ctl("animation").value = query.get("animation") === "fade" ? "fade" : Number(query.get("animation")) > 0 ? "800" : "0"; syncAnimationSegments();
1054
1297
  renderMapControls();
1055
1298
  controlsUndo.length = controlsRedo.length = 0;
@@ -1078,7 +1321,7 @@ var controlsClient = String.raw`
1078
1321
  if (!Object.keys(patch).length) delete controlsDraft[module];
1079
1322
  scheduleMapControls();
1080
1323
  }
1081
- function renderMapControls(expanded = [...ctl("modules").querySelectorAll("details[open]")].map((item) => item.dataset.module)) {
1324
+ function renderMapControls() {
1082
1325
  ctl("modules").replaceChildren();
1083
1326
  controlsBindings = [];
1084
1327
  const names = {poi:"Points of interest", land:"Land", water:"Water", nautical:"Nautical", roads:"Roads", buildings:"Buildings", boundaries:"Boundaries", labels:"Labels", aeroways:"Airports", transit:"Transit", vegetation:"Vegetation", addresses:"Addresses", landforms:"Landforms"};
@@ -1094,17 +1337,19 @@ var controlsClient = String.raw`
1094
1337
  toggle.setAttribute("role", "switch");
1095
1338
  toggle.setAttribute("aria-label", "Enable " + (names[module.id] || module.id));
1096
1339
  label.append(toggle); row.append(label); card.append(row);
1097
- const fieldset = document.createElement("fieldset"); fieldset.disabled = !toggle.checked;
1340
+ const fieldset = document.createElement("fieldset");
1341
+ const syncModuleEnabled = () => {
1342
+ fieldset.disabled = !toggle.checked;
1343
+ fieldset.hidden = !toggle.checked;
1344
+ };
1345
+ syncModuleEnabled();
1098
1346
  controlsBindings.push(() => {
1099
1347
  if (document.activeElement !== toggle) toggle.checked = controlsDraft[module.id]?.enabled ?? module.enabled;
1100
- fieldset.disabled = !toggle.checked;
1348
+ syncModuleEnabled();
1101
1349
  });
1102
- toggle.addEventListener("change", () => { changeControl(module.id, "enabled", toggle.checked, module.enabled); fieldset.disabled = !toggle.checked; });
1350
+ toggle.addEventListener("change", () => { changeControl(module.id, "enabled", toggle.checked, module.enabled); syncModuleEnabled(); });
1103
1351
  if (module.fields.length) {
1104
- const details = document.createElement("details");
1105
- details.dataset.module = module.id; details.open = expanded.includes(module.id);
1106
- const summary = document.createElement("summary"); summary.textContent = "Appearance & behavior";
1107
- details.append(summary, fieldset); card.append(details);
1352
+ card.append(fieldset);
1108
1353
  for (const field of module.fields) {
1109
1354
  const line = document.createElement("label"); line.className = "control-field";
1110
1355
  const title = document.createElement("span"); title.textContent = field.label;
@@ -1149,7 +1394,7 @@ var controlsClient = String.raw`
1149
1394
  controlsNotice("Enter valid field values to update the preview.", true); return;
1150
1395
  }
1151
1396
  const draft = reset ? {} : structuredClone(controlsDraft);
1152
- const next = {map, theme, controls:draft, buildings3d:!reset && ctl("3d").checked, animation:reset ? 0 : ctl("animation").value === "fade" ? "fade" : Number(ctl("animation").value)};
1397
+ const next = {map, theme, controls:draft, buildings3d:reset || ctl("3d").checked, animation:reset ? 0 : ctl("animation").value === "fade" ? "fade" : Number(ctl("animation").value)};
1153
1398
  const styleKey = JSON.stringify([map, theme, draft]);
1154
1399
  const isCurrent = () => revision === controlsRevision && controlsKey === key && side.id === activeSideId && side.bridgeConnected && epoch === side.loadEpoch && source === side.frame.src;
1155
1400
  const before = controlsHistoryCurrent && {...controlsHistoryCurrent, style:side.map.getStyle()};
@@ -1978,7 +2223,7 @@ function renderTileflowComparisonHtml(options) {
1978
2223
  if (message.type === bridgeInspectionType && Array.isArray(message.features)) {
1979
2224
  selectSide(side.id);
1980
2225
  selectedInspection = {side, coordinate: message.coordinate, features: message.features.slice(0, 16), featureIndex: 0};
1981
- renderInspection();
2226
+ renderInspection(true);
1982
2227
  return;
1983
2228
  }
1984
2229
  if (message.type === bridgeRuntimeErrorType) {
@@ -2152,7 +2397,8 @@ function renderTileflowComparisonHtml(options) {
2152
2397
  return configured.href;
2153
2398
  }
2154
2399
 
2155
- function renderInspection() {
2400
+ // Metadata refreshes update the inspection without navigating away from the active tab.
2401
+ function renderInspection(reveal = false) {
2156
2402
  if (!selectedInspection) return;
2157
2403
  const side = selectedInspection.side;
2158
2404
  const feature = selectedInspection.features[selectedInspection.featureIndex];
@@ -2165,7 +2411,7 @@ function renderTileflowComparisonHtml(options) {
2165
2411
  curveOutput.className = "empty";
2166
2412
  curveOutput.textContent = "Paint and layout values appear here.";
2167
2413
  sidecarOutput.textContent = "No layer selected.";
2168
- globalThis.__tileflowDevtoolsUI?.selectionChanged();
2414
+ if (reveal) globalThis.__tileflowDevtoolsUI?.selectionChanged();
2169
2415
  return;
2170
2416
  }
2171
2417
  inspectionOutput.className = "";
@@ -2187,7 +2433,7 @@ function renderTileflowComparisonHtml(options) {
2187
2433
  picker.value = String(selectedInspection.featureIndex);
2188
2434
  picker.addEventListener("change", () => {
2189
2435
  selectedInspection.featureIndex = boundedInteger(Number(picker.value), 0, selectedInspection.features.length - 1, 0);
2190
- renderInspection();
2436
+ renderInspection(true);
2191
2437
  });
2192
2438
  pickerLabel.append(picker);
2193
2439
  const summary = document.createElement("pre");
@@ -2212,7 +2458,7 @@ function renderTileflowComparisonHtml(options) {
2212
2458
  ? boundedJson(sidecarLayerWithSemanticAttribution(sidecarLayer))
2213
2459
  : "No compiler sidecar entry for this layer.";
2214
2460
  if (side.sidecar === undefined && !side.sidecarPromise) void loadSidecar(side);
2215
- globalThis.__tileflowDevtoolsUI?.selectionChanged();
2461
+ if (reveal) globalThis.__tileflowDevtoolsUI?.selectionChanged();
2216
2462
  }
2217
2463
 
2218
2464
  function populateCurveProperties(layer) {
@@ -2702,7 +2948,7 @@ function renderTileflowComparisonHtml(options) {
2702
2948
  for (const side of Object.values(states)) { side.highlightFeature?.(-1); side.hoverFeature?.(-1); }
2703
2949
  },
2704
2950
  loadSidecar: (side) => loadSidecar(side),
2705
- selectFeature: (index) => { if (selectedInspection && selectedInspection.features[index]) { selectedInspection.featureIndex = index; renderInspection(); } },
2951
+ selectFeature: (index) => { if (selectedInspection && selectedInspection.features[index]) { selectedInspection.featureIndex = index; renderInspection(true); } },
2706
2952
  inspect: (enabled) => setInspectionEnabled(enabled), inspecting: () => inspectionEnabled,
2707
2953
  controls: () => loadMapControls(),
2708
2954
  sprites: () => loadSprites(states[activeSideId])