@kitlangton/knobs 0.4.0-next.3 → 0.4.0-next.4

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/ui.js CHANGED
@@ -607,7 +607,12 @@ var compareCss = `
607
607
  /* Glass: what's behind shows through, blurred, on the knobs tokens. */
608
608
  .knobs-cmp-label,.knobs-cmp-zoom{background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);
609
609
  box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim),0 2px 10px rgba(0,0,0,calc(.18 * var(--_k-shadow-k,1)))}
610
- .knobs-cmp-label{position:absolute;left:0;top:0;padding:1px 7px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;color:var(--_k-fg-2);white-space:nowrap;pointer-events:none;will-change:transform;transition:color calc(var(--_k-hover-out) * 1ms)}
610
+ /* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
611
+ .knobs-cmp-label{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;font-weight:var(--_k-weight-label);
612
+ white-space:nowrap;pointer-events:none;will-change:transform}
613
+ .knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
614
+ .knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
615
+ .knobs-cmp-mark svg{display:block;width:12px;height:12px}
611
616
  /* The wipe: a hairline down the line with a raised grip at the pointer's height; a wider strip
612
617
  takes the hand and the keys (a slider). It fades with the mode; wiping, line and grip brighten. */
613
618
  .knobs-cmp-handle{cursor:ew-resize;position:absolute;left:-12px;top:0;width:24px;height:0;opacity:0;pointer-events:none;outline:none;will-change:transform;transition:opacity .18s cubic-bezier(.4,0,1,1)}
@@ -1331,6 +1336,22 @@ var init_schema = __esm(() => {
1331
1336
  source: css("var(--k-warn)"),
1332
1337
  doc: "Modified lines."
1333
1338
  },
1339
+ {
1340
+ name: "before",
1341
+ tier: "semantic",
1342
+ type: "color",
1343
+ group: "Data",
1344
+ source: css("var(--k-fg-3)"),
1345
+ doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
1346
+ },
1347
+ {
1348
+ name: "after",
1349
+ tier: "semantic",
1350
+ type: "color",
1351
+ group: "Data",
1352
+ source: css("var(--k-fg)"),
1353
+ doc: "After in a comparison, and only After."
1354
+ },
1334
1355
  {
1335
1356
  name: "series-1",
1336
1357
  tier: "semantic",
@@ -1421,6 +1442,150 @@ var init_schema = __esm(() => {
1421
1442
  source: value("288px"),
1422
1443
  doc: "Panel width."
1423
1444
  },
1445
+ {
1446
+ name: "space-inside",
1447
+ tier: "semantic",
1448
+ type: "length",
1449
+ group: "Space",
1450
+ source: css("var(--k-unit)"),
1451
+ doc: "Parts of one thing: an icon and its label, a meta line and its title."
1452
+ },
1453
+ {
1454
+ name: "space-sibling",
1455
+ tier: "semantic",
1456
+ type: "length",
1457
+ group: "Space",
1458
+ source: css("calc(var(--k-unit) * 2)"),
1459
+ doc: "Siblings in a group: buttons in a row, a list item's lines."
1460
+ },
1461
+ {
1462
+ name: "space-title",
1463
+ tier: "semantic",
1464
+ type: "length",
1465
+ group: "Space",
1466
+ source: css("calc(var(--k-unit) * 3)"),
1467
+ doc: "A heading and what it heads."
1468
+ },
1469
+ {
1470
+ name: "space-group",
1471
+ tier: "semantic",
1472
+ type: "length",
1473
+ group: "Space",
1474
+ source: css("calc(var(--k-unit) * 12)"),
1475
+ doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
1476
+ },
1477
+ {
1478
+ name: "space-section",
1479
+ tier: "semantic",
1480
+ type: "length",
1481
+ group: "Space",
1482
+ source: css("calc(var(--k-unit) * 24)"),
1483
+ doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
1484
+ },
1485
+ {
1486
+ name: "space-column",
1487
+ tier: "semantic",
1488
+ type: "length",
1489
+ group: "Space",
1490
+ source: css("calc(var(--k-unit) * 6)"),
1491
+ doc: "Columns: a contents rail and the page, media side by side."
1492
+ },
1493
+ {
1494
+ name: "pad-page",
1495
+ tier: "semantic",
1496
+ type: "length",
1497
+ group: "Space",
1498
+ source: css("calc(var(--k-unit) * 6)"),
1499
+ doc: "A page's edge; 16px under 640px wide."
1500
+ },
1501
+ {
1502
+ name: "pad-card",
1503
+ tier: "semantic",
1504
+ type: "length",
1505
+ group: "Space",
1506
+ source: css("calc(var(--k-unit) * 3)"),
1507
+ doc: "Inside a card or popover."
1508
+ },
1509
+ {
1510
+ name: "type-heading",
1511
+ tier: "semantic",
1512
+ type: "length",
1513
+ group: "Type",
1514
+ source: value("20px"),
1515
+ doc: "Section headings (a PR's title, under its kicker), weight 500."
1516
+ },
1517
+ {
1518
+ name: "leading-heading",
1519
+ tier: "semantic",
1520
+ type: "length",
1521
+ group: "Type",
1522
+ source: value("28px"),
1523
+ doc: "Line height for type-heading."
1524
+ },
1525
+ {
1526
+ name: "type-title",
1527
+ tier: "semantic",
1528
+ type: "length",
1529
+ group: "Type",
1530
+ source: value("16px"),
1531
+ doc: "A page's title, weight 500."
1532
+ },
1533
+ {
1534
+ name: "leading-title",
1535
+ tier: "semantic",
1536
+ type: "length",
1537
+ group: "Type",
1538
+ source: value("24px"),
1539
+ doc: "Line height for type-title."
1540
+ },
1541
+ {
1542
+ name: "type-body",
1543
+ tier: "semantic",
1544
+ type: "length",
1545
+ group: "Type",
1546
+ source: value("13px"),
1547
+ doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
1548
+ },
1549
+ {
1550
+ name: "leading-body",
1551
+ tier: "semantic",
1552
+ type: "length",
1553
+ group: "Type",
1554
+ source: value("20px"),
1555
+ doc: "Line height for type-body."
1556
+ },
1557
+ {
1558
+ name: "type-label",
1559
+ tier: "semantic",
1560
+ type: "length",
1561
+ group: "Type",
1562
+ source: value("12px"),
1563
+ doc: "Labels over media, weight 500; mono inside body text."
1564
+ },
1565
+ {
1566
+ name: "leading-label",
1567
+ tier: "semantic",
1568
+ type: "length",
1569
+ group: "Type",
1570
+ source: value("16px"),
1571
+ doc: "Line height for type-label."
1572
+ },
1573
+ {
1574
+ name: "type-small",
1575
+ tier: "semantic",
1576
+ type: "length",
1577
+ group: "Type",
1578
+ source: value("11px"),
1579
+ doc: "Meta, controls, keys, timestamps; mono inside labels."
1580
+ },
1581
+ {
1582
+ name: "leading-small",
1583
+ tier: "semantic",
1584
+ type: "length",
1585
+ group: "Type",
1586
+ source: value("16px"),
1587
+ doc: "Line height for type-small."
1588
+ },
1424
1589
  {
1425
1590
  name: "font-size",
1426
1591
  tier: "semantic",
@@ -2385,16 +2550,18 @@ function injectTokens(doc) {
2385
2550
  style.textContent = rootCss;
2386
2551
  doc.head.append(style);
2387
2552
  }
2388
- var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
2553
+ var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
2389
2554
  var init_root = __esm(() => {
2390
2555
  init_knobs();
2391
2556
  init_css();
2392
2557
  init_glide();
2393
2558
  init_motion();
2394
2559
  extras = `:where(.${ROOT_CLASS}){--_k-shadow-k:calc(var(--k-shadow-strength,calc(.48 - .32 * var(--_k-light,0))) / .48);--_k-glass-tone:var(--k-glass-tone,calc(.5 + .58 * var(--_k-light,0)));--_k-fill-base:var(--k-fill-base,var(--_k-fill-selected));--_k-fill-hover-mix:var(--k-fill-hover-mix,var(--k-fill-rest-mix,20%));--_k-reveal-ease:var(--k-ease,cubic-bezier(.2,.8,.2,1))}`;
2560
+ narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
2395
2561
  spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
2396
2562
  rootCss = `${tokensCss(knobs)}
2397
2563
  ${extras}
2564
+ ${narrow}
2398
2565
  ${spring}
2399
2566
  ${DRIVERS}
2400
2567
  ${motionCss}`;
@@ -2684,6 +2851,12 @@ var css2 = `
2684
2851
  --_ku-pane-bg and --_ku-pane-ring so this reaches them. */
2685
2852
  :where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui:not(.knobs-surface),.knobs-ui[data-nested]{--_ku-gap:var(--k-ui-gap,0px);--_ku-pane-bg:transparent;--_ku-pane-ring:none;
2686
2853
  --_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
2854
+ /* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
2855
+ ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
2856
+ card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
2857
+ :is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
2858
+ :is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-tl-track,.knobs-ui[data-nested] .knobs-tl-track{background:transparent;border-radius:0;box-shadow:inset 0 -1px 0 var(--_k-border-subtle)}
2859
+ :where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
2687
2860
  /* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
2688
2861
  .knobs-ui{box-sizing:border-box}
2689
2862
  :where(.knobs-split>*,.knobs-pane-clip,.knobs-pane-inner,.knobs-pane-body,.knobs-pane-head,.knobs-pane-head *,.knobs-pane-rail,.knobs-pane-rail *,.knobs-tree,.knobs-tree *,.knobs-tree-ghost){box-sizing:border-box}
@@ -7930,6 +8103,17 @@ function compare(container, options) {
7930
8103
  const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
7931
8104
  labels[0].dataset.side = "before";
7932
8105
  labels[1].dataset.side = "after";
8106
+ const setLabel = (index, text) => {
8107
+ const l = labels[index];
8108
+ if (!l.firstElementChild) {
8109
+ const mark = el("span", "knobs-cmp-mark");
8110
+ mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
8111
+ l.append(mark, el("span", "knobs-cmp-name"));
8112
+ }
8113
+ const name = l.lastElementChild;
8114
+ if (name.textContent !== text)
8115
+ name.textContent = text;
8116
+ };
7933
8117
  const handle = el("div", "knobs-cmp-handle");
7934
8118
  handle.setAttribute("role", "slider");
7935
8119
  handle.setAttribute("aria-label", "Wipe");
@@ -8991,7 +9175,7 @@ function compare(container, options) {
8991
9175
  old.preview.replaceWith(s.preview);
8992
9176
  sides[index] = s;
8993
9177
  note.textContent = "";
8994
- labels[index].textContent = labelOf(index);
9178
+ setLabel(index, labelOf(index));
8995
9179
  if (near)
8996
9180
  loadSide(s);
8997
9181
  readColors();
@@ -9002,8 +9186,8 @@ function compare(container, options) {
9002
9186
  stage.insertBefore(sides[1].preview, labels[0]);
9003
9187
  stage.insertBefore(sides[0].el, labels[0]);
9004
9188
  stage.insertBefore(sides[0].preview, labels[0]);
9005
- labels[0].textContent = labelOf(0);
9006
- labels[1].textContent = labelOf(1);
9189
+ setLabel(0, labelOf(0));
9190
+ setLabel(1, labelOf(1));
9007
9191
  loupeBtn.setAttribute("aria-pressed", String(loupeOn));
9008
9192
  loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
9009
9193
  const modePill = modeList.length > 1 ? selectionPill(modes, {
@@ -9143,11 +9327,11 @@ function compare(container, options) {
9143
9327
  if (before)
9144
9328
  replace(0, before);
9145
9329
  else if (next.before)
9146
- labels[0].textContent = next.before.label ?? "Before";
9330
+ setLabel(0, next.before.label ?? "Before");
9147
9331
  if (after)
9148
9332
  replace(1, after);
9149
9333
  else if (next.after)
9150
- labels[1].textContent = next.after.label ?? "After";
9334
+ setLabel(1, next.after.label ?? "After");
9151
9335
  if (before || after)
9152
9336
  strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
9153
9337
  if (next.before || next.after)
@@ -19378,406 +19562,20 @@ function optionPicker(container, options) {
19378
19562
  // src/ui/walkthrough.ts
19379
19563
  init_motion();
19380
19564
  init_page_hints();
19565
+ init_icons();
19381
19566
  init_look();
19567
+ init_selection_pill();
19382
19568
 
19383
- // src/ui/walkthrough-media.ts
19384
- init_compare_model();
19385
- init_glide();
19386
- init_look();
19387
-
19388
- // src/ui/walkthrough-css.ts
19569
+ // src/ui/walkthrough-blocks.ts
19389
19570
  init_motion();
19390
- var snappy3 = springCss(SPRINGS.snappy);
19391
- var calm = springCss(SPRINGS.calm);
19392
- var walkthroughCss = `
19393
- :where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
19394
- .knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;
19395
- --kw-text:var(--k-walkthrough-text,14px);--kw-measure:var(--k-walkthrough-measure,68ch);--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));
19396
- --kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-pad:16px;--kw-ink:var(--k-walkthrough-ink,#ff375f);
19397
- container:knobs-wt / inline-size;display:block;width:100%;color:var(--_k-fg);font:var(--_k-weight) var(--kw-text)/1.5 var(--_k-font);text-align:left;
19398
- letter-spacing:normal;-webkit-font-smoothing:antialiased}
19399
- .knobs-walkthrough [hidden]{display:none!important}
19400
- .knobs-walkthrough :is(h1,h2,h3,p){margin:0;font:inherit;letter-spacing:inherit}
19401
- .knobs-walkthrough a{color:inherit;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-underline-offset:2px;transition:text-decoration-color .15s}
19402
- .knobs-walkthrough a:hover{text-decoration-color:currentColor}
19403
- .knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
19404
- :where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-step,button.knobs-wt-stitle,.knobs-wt-chapter){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
19405
- background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
19406
-
19407
- /* ——— layout: the rail beside the column; one column where it's narrow ——— */
19408
- .knobs-wt-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
19409
- .knobs-wt-main{display:flex;flex-direction:column;gap:56px;min-width:0;max-width:1120px;padding-bottom:40vh}
19410
- @container knobs-wt (max-width:880px){.knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:0}.knobs-wt-main{gap:44px}}
19411
-
19412
- /* ——— the page's head ——— */
19413
- .knobs-wt-head{display:flex;flex-direction:column;gap:10px}
19414
- .knobs-wt-title{font-size:calc(var(--kw-text) + 10px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.2;letter-spacing:-.01em!important}
19415
- .knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2)}
19416
- .knobs-wt-meta{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2px)}
19417
- .knobs-wt-meta>span{display:inline-flex;gap:6px;white-space:nowrap}
19418
- .knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono);font-size:calc(1em - .5px)}
19419
-
19420
- /* ——— a section: a PR or topic ——— */
19421
- .knobs-wt-section{display:flex;flex-direction:column;gap:14px;min-width:0}
19422
- .knobs-wt-shead{display:flex;flex-direction:column;gap:6px;scroll-margin-top:16px}
19423
- .knobs-wt-kicker{display:flex;align-items:center;gap:10px;font-size:calc(var(--kw-text) - 2px);color:var(--_k-fg-3)}
19424
- .knobs-wt-kicker a{font-family:var(--_k-mono);color:var(--_k-fg-2);text-decoration:none}
19425
- .knobs-wt-kicker a:hover{color:var(--_k-fg)}
19426
- .knobs-wt-stitle{font-size:calc(var(--kw-text) + 4px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.3}
19427
- .knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2)}
19428
- .knobs-wt-chip{display:inline-flex;align-items:center;gap:6px;height:20px;padding:0 8px;border-radius:999px;font-size:calc(var(--kw-text) - 3px);font-weight:var(--_k-weight-label);white-space:nowrap;
19429
- --kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
19430
- .knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
19431
- :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
19432
- :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
19433
- :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
19434
- :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
19435
- :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
19436
-
19437
- /* ——— a step: one card ——— */
19438
- .knobs-wt-step{position:relative;display:flex;flex-direction:column;gap:12px;padding:var(--kw-pad);border-radius:var(--_k-radius-panel);background:var(--kw-card);box-shadow:var(--kw-card-ring);
19439
- scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
19440
- .knobs-walkthrough[data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
19441
- .knobs-wt-step-head{display:flex;align-items:baseline;gap:10px;min-width:0}
19442
- .knobs-wt-num{flex:none;font:var(--_k-weight) calc(var(--kw-text) - 2px)/1 var(--_k-mono);color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
19443
- .knobs-wt-stepTitle{flex:1;min-width:0;font-weight:var(--_k-weight-title)!important}
19444
- .knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);margin-top:-6px!important}
19445
- .knobs-wt-question{font-weight:var(--_k-weight-label)!important}
19446
- /* The step Kit is on: its number lights, and its choices show their keys. */
19447
- .knobs-wt-step[data-current] .knobs-wt-num{color:var(--_k-fg)}
19448
- .knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:12px;min-width:0}
19449
- @container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
19450
-
19451
- /* ——— the feed: the agent's updates and answers, newest first, compact ——— */
19452
- .knobs-wt-feed{margin-top:-24px}
19453
- .knobs-wt-feed-list{list-style:none;margin:0;padding:0;max-height:260px;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column}
19454
- .knobs-wt-feed-list::-webkit-scrollbar{display:none}
19455
- .knobs-wt-fi{display:grid;grid-template-columns:64px 56px minmax(0,1fr) auto;gap:10px;align-items:baseline;padding:6px 0;font-size:calc(var(--kw-text) - 1px)}
19456
- .knobs-wt-fi+.knobs-wt-fi{box-shadow:inset 0 1px 0 var(--_k-border)}
19457
- .knobs-wt-fi-when{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums;white-space:nowrap}
19458
- .knobs-wt-fi-kind{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 2.5px);font-weight:var(--_k-weight-label)}
19459
- .knobs-wt-fi[data-kind="qa"] .knobs-wt-fi-kind{color:var(--kw-info)}
19460
- .knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
19461
- .knobs-wt-fi-q{color:var(--_k-fg-2)}
19462
- .knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
19463
- :where(.knobs-ui) :is(.knobs-wt-fi-step,.knobs-wt-steplink){all:revert;box-sizing:border-box;font:var(--_k-weight) calc(var(--k-walkthrough-text,14px) - 2.5px)/1 var(--_k-mono);color:var(--_k-fg-2);background:transparent;border:0;
19464
- padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
19465
- .knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
19466
-
19467
- /* ——— a step's sent notes ——— */
19468
- .knobs-wt-notes{display:flex;flex-direction:column}
19469
- .knobs-wt-notes:empty{display:none}
19470
- .knobs-wt-n{display:flex;align-items:flex-start;gap:10px;padding:6px 0;overflow:hidden;
19471
- transition:height var(--kw-snappy-ms) var(--kw-snappy),opacity var(--kw-snappy-ms) var(--kw-snappy),filter var(--kw-snappy-ms) var(--kw-snappy)}
19472
- .knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
19473
- .knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
19474
- .knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border)}
19475
- .knobs-wt-n-meta{flex:none;min-width:44px;padding-top:2px;color:var(--_k-fg-3);font:var(--_k-weight) calc(var(--kw-text) - 2.5px)/1.4 var(--_k-mono);font-variant-numeric:tabular-nums}
19476
- .knobs-wt-n-meta[data-seek]{cursor:pointer}
19477
- .knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
19478
- .knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;font-size:calc(var(--kw-text) - 1px)}
19479
- .knobs-wt-n-voice{height:30px;max-width:320px}
19480
- .knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:6px;background:var(--_k-fill)}
19481
- .knobs-wt-n-ink path{fill:none;stroke:var(--kw-ink);stroke-width:2px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
19482
-
19483
- /* ——— the note bar, docked at the bottom of the column ——— */
19484
- .knobs-wt-dock{position:sticky;bottom:12px;z-index:40;margin-top:-24px}
19485
- .knobs-wt-notebar{display:flex;flex-direction:column;gap:2px;padding:6px 6px 6px 14px;border-radius:calc(var(--_k-radius-panel) + 2px);background:var(--_k-bg);
19486
- box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
19487
- .knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap;overflow:hidden;
19488
- -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
19489
- .knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
19490
- :where(.knobs-ui) :is(.knobs-wt-input,.knobs-wt-tool,.knobs-wt-x,.knobs-wt-back){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;
19491
- border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
19492
- .knobs-ui .knobs-wt-input{flex:1;min-width:0;height:32px;max-height:140px;padding:6px 0;resize:none;color:var(--_k-fg);caret-color:var(--_k-accent);line-height:20px;font-size:var(--kw-text)}
19493
- .knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
19494
- .knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
19495
- .knobs-wt-attach:empty{display:none}
19496
- .knobs-wt-chip-a{display:inline-flex;align-items:center;gap:2px;height:24px;padding:0 2px 0 9px;border-radius:999px;background:var(--_k-fill-selected);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap}
19497
- .knobs-ui .knobs-wt-x{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;color:var(--_k-fg-3);cursor:pointer;transition:background .15s,color .15s}
19498
- .knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
19499
- .knobs-wt-x svg{width:10px;height:10px}
19500
- .knobs-ui .knobs-wt-tool{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:32px;height:32px;padding:0 8px;border-radius:calc(var(--_k-radius) + 2px);
19501
- color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
19502
- .knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
19503
- .knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
19504
- .knobs-wt-tool svg{width:15px;height:15px}
19505
- .knobs-wt-rec{font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums}
19506
- .knobs-wt-rec:empty{display:none}
19507
- .knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
19508
- .knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
19509
- /* Back: in place over the bar for a few seconds after a note moves the page on. */
19510
- .knobs-ui .knobs-wt-back{position:absolute;left:8px;bottom:calc(100% + 8px);height:28px;padding:0 12px;border-radius:999px;background:var(--_k-bg);color:var(--_k-fg);
19511
- box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font-size:calc(var(--kw-text) - 1.5px);font-weight:var(--_k-weight-label);cursor:pointer;
19512
- opacity:0;scale:.96;filter:blur(3px);pointer-events:none;transition:opacity .11s cubic-bezier(.4,0,1,1),scale .11s cubic-bezier(.4,0,1,1),filter .11s cubic-bezier(.4,0,1,1)}
19513
- .knobs-ui .knobs-wt-back[data-on]{opacity:1;scale:1;filter:none;pointer-events:auto;transition:opacity .15s cubic-bezier(.2,.8,.2,1),scale .15s cubic-bezier(.2,.8,.2,1),filter .15s cubic-bezier(.2,.8,.2,1)}
19514
- .knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
19515
-
19516
- /* ——— ink over a step's media ——— */
19517
- .knobs-wt-media,.knobs-wt-options{position:relative}
19518
- .knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
19519
- .knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
19520
- .knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
19521
-
19522
- /* ——— full-window: the step over the page, its media filling it; its place held in the page ——— */
19523
- .knobs-wt-scrim{position:fixed;inset:0;z-index:30;background:color-mix(in srgb,var(--_k-bg-page) 82%,transparent);opacity:0;pointer-events:none}
19524
- .knobs-wt-scrim[data-on]{pointer-events:auto}
19525
- .knobs-wt-hold-card{flex:none}
19526
- .knobs-wt-step[data-full]{position:fixed;z-index:35;margin:0;overflow:hidden;overscroll-behavior:contain;padding-bottom:84px;box-shadow:var(--kw-card-ring),var(--_k-shadow-overlay);background:var(--_k-bg)}
19527
- .knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
19528
- .knobs-wt-step[data-full] .knobs-wt-notes{display:none}
19529
- .knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
19530
- .knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
19531
- .knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
19532
- .knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
19533
- .knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
19534
-
19535
- /* ——— a taste test: the options side by side, Kit's pick lit and the rest stepping back ——— */
19536
- .knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:10px}
19537
- @container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
19538
- .knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:8px;min-width:0;padding:8px;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_ku-wash);
19539
- transition:background var(--kw-snappy-ms) var(--kw-snappy)}
19540
- .knobs-wt-option[data-picked]{background:color-mix(in srgb,var(--_k-accent) 12%,var(--_ku-wash))}
19541
- .knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
19542
- .knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
19543
- .knobs-ui .knobs-wt-pick{display:flex;align-items:center;gap:8px;width:100%;min-height:28px;padding:0 4px;border-radius:calc(var(--_k-radius) - 2px);cursor:pointer;color:var(--_k-fg-2);text-align:left}
19544
- .knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg)}
19545
- .knobs-wt-letter{flex:none;font:var(--_k-weight-title) calc(var(--kw-text) - 1px)/1 var(--_k-font);color:var(--_k-fg)}
19546
- .knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
19547
- .knobs-wt-suggested{flex:none;font-size:calc(var(--kw-text) - 3px);color:var(--_k-fg-3)}
19548
- .knobs-wt-check{flex:none;display:flex;width:18px;height:18px;align-items:center;justify-content:center;border-radius:50%;background:var(--_k-fill);color:transparent;
19549
- transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
19550
- .knobs-wt-check svg{width:12px;height:12px}
19551
- .knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
19552
- .knobs-wt-key{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;padding:0 3px;border-radius:4px;background:var(--_k-fill);color:var(--_k-fg-3);
19553
- font:var(--_k-weight-label) calc(var(--kw-text) - 4px)/1 var(--_k-font);font-variant-numeric:tabular-nums;opacity:.5;transition:opacity .15s}
19554
- .knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
19555
- .knobs-wt-ocap{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 1px);padding:0 4px}
19571
+ init_icons();
19572
+ init_look();
19573
+ init_selection_pill();
19556
19574
 
19557
- /* ——— the rail: progress, contents, export ——— */
19558
- .knobs-wt-rail{position:sticky;top:16px;display:flex;flex-direction:column;gap:14px;max-height:calc(100vh - 32px);min-height:0;font-size:calc(var(--kw-text) - 1.5px)}
19559
- .knobs-wt-progress{display:flex;flex-direction:column;gap:7px}
19560
- .knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2);font-variant-numeric:tabular-nums}
19561
- .knobs-wt-count b{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
19562
- .knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
19563
- .knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
19564
- .knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
19565
- /* The contents: no box, one text spine for sections and steps (the steps' dots hang in the
19566
- gutter left of it), and one pill behind the current step that springs between rows. */
19567
- .knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;margin:0 -8px;padding:0 0 8px}
19568
- .knobs-wt-toc::-webkit-scrollbar{display:none}
19569
- .knobs-wt-toc-section{display:block;padding:12px 8px 4px 26px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);font-weight:var(--_k-weight-label);white-space:nowrap;overflow:hidden;
19570
- -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
19571
- .knobs-wt-toc-section:first-of-type{padding-top:2px}
19572
- .knobs-wt-toc-mark{position:absolute;left:0;right:0;top:0;height:0;border-radius:calc(var(--_k-radius) - 1px);background:var(--_ku-wash-hi);pointer-events:none;opacity:0;will-change:transform}
19573
- .knobs-wt-toc-mark[data-on]{opacity:1}
19574
- .knobs-walkthrough[data-settled] .knobs-wt-toc-mark{transition:opacity .15s}
19575
- .knobs-ui .knobs-wt-toc-step{position:relative;display:flex;align-items:center;width:100%;text-align:left;height:26px;padding:0 8px 0 26px;color:var(--_k-fg-2);cursor:pointer;white-space:nowrap}
19576
- .knobs-ui .knobs-wt-toc-step:is(:hover,:focus-visible){color:var(--_k-fg)}
19577
- .knobs-wt-toc-step[aria-current="step"]{color:var(--_k-fg)}
19578
- .knobs-wt-toc-label{flex:1;min-width:0;overflow:hidden;-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
19579
- /* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
19580
- .knobs-wt-toc-glyph{--kw-tone:var(--_k-fg-3);position:absolute;left:11px;top:50%;width:7px;height:7px;margin-top:-3.5px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--kw-tone);
19581
- transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
19582
- .knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
19583
- .knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
19584
- .knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
19585
- .knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
19586
- .knobs-ui .knobs-wt-btn{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
19587
- transition:background .15s,color .15s}
19588
- .knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
19589
- .knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
19590
- .knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
19591
- .knobs-wt-keys{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);line-height:1.6}
19592
- .knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
19593
- /* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
19594
- @container knobs-wt (max-width:880px){
19595
- .knobs-wt-rail{z-index:4;flex-direction:row;align-items:center;gap:12px;max-height:none;margin:0 calc(var(--kw-pad) * -1) 20px;padding:8px var(--kw-pad);top:0;background:var(--_k-bg-page)}
19596
- .knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
19597
- .knobs-wt-step,.knobs-wt-shead{scroll-margin-top:60px}
19598
- }
19599
-
19600
- /* ——— media slots ——— */
19601
- .knobs-ui.knobs-wt-slot{position:relative;min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);font:var(--_k-weight) var(--k-walkthrough-text,14px)/1.5 var(--_k-font);
19602
- --kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
19603
- .knobs-wt-slot-label{display:block;margin:0 0 6px 2px;font:var(--_k-weight-label) calc(var(--k-walkthrough-text,14px) - 3px)/1.3 var(--_k-font);color:var(--_k-fg-2);letter-spacing:.04em;text-transform:uppercase}
19604
- /* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
19605
- sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
19606
- (92 px), and the frame strip with its gap (158 px). */
19607
- .knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
19608
- .knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
19609
- .knobs-wt-fit[data-strip]{--kw-chrome:158px}
19610
- .knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
19611
- .knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
19612
- .knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
19613
- .knobs-wt-frame[data-natural]{aspect-ratio:auto}
19614
- .knobs-wt-frame[data-natural]>img{position:static;height:auto}
19615
- .knobs-wt-code{margin:0;padding:12px 14px;max-height:420px;overflow:auto;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);color:var(--_k-fg);
19616
- font:calc(var(--k-walkthrough-text,14px) - 2px)/1.55 var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
19617
- .knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
19618
- .knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
19619
- .knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
19620
- .knobs-wt-out{color:var(--_k-fg-2)}
19621
- .knobs-wt-metric{display:flex;flex-direction:column;gap:8px;padding:12px 14px;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
19622
- .knobs-wt-mlabel{color:var(--_k-fg-2);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
19623
- .knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
19624
- .knobs-wt-mfrom{color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) + 2px)}
19625
- .knobs-wt-mto{font-size:calc(var(--k-walkthrough-text,14px) + 12px);font-weight:var(--_k-weight-title);line-height:1}
19626
- .knobs-wt-mof{color:var(--_k-fg-3)}
19627
- .knobs-wt-mdelta{--kw-tone:var(--_k-fg-2);padding:1px 7px;border-radius:999px;font-size:calc(var(--k-walkthrough-text,14px) - 3px);font-weight:var(--_k-weight-label);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
19628
- .knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
19629
- .knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
19630
- .knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
19631
- .knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
19632
- .knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
19633
- .knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
19634
- .knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:10px;padding:10px 14px;border-radius:calc(var(--_k-radius-panel) - 4px);background:color-mix(in srgb,var(--kw-tone) 11%,transparent);color:var(--_k-fg)}
19635
- .knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:.62em;border-radius:50%;background:var(--kw-tone)}
19636
- .knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
19637
- .knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
19638
- .knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
19639
- .knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
19640
- .knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
19641
- .knobs-wt-failed{display:flex;align-items:center;justify-content:center;min-height:80px;color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
19642
-
19643
- /* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
19644
- hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
19645
- :where(.knobs-wt-history,.knobs-wt-stack,.knobs-wt-table,.knobs-wt-chapters){--kw-t:var(--k-walkthrough-text,14px);--kw-line:calc(var(--kw-t) + 6px);--kw-rail:var(--_k-border-strong)}
19646
- :where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
19647
- :where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
19648
- :where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
19649
- :where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
19650
- :where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
19651
- .knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
19652
- .knobs-ui .knobs-wt-tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-2);font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);
19653
- text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
19654
- .knobs-ui a.knobs-wt-tag:is(:hover,:focus-visible){background:var(--_k-fill-selected);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
19655
-
19656
- /* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
19657
- dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
19658
- .knobs-wt-history{--kw-hy:calc(5px + var(--kw-line) / 2);display:flex;flex-direction:column;gap:18px;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
19659
- .knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
19660
- .knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
19661
- .knobs-ui .knobs-wt-hheading{margin:0;font:var(--_k-weight-label) calc(var(--kw-t) - 3px)/1.3 var(--_k-font);letter-spacing:.04em;text-transform:uppercase;color:var(--_k-fg-2)}
19662
- .knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
19663
- .knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
19664
- .knobs-wt-hev{display:grid;grid-template-columns:var(--kw-hw,11ch) 14px minmax(0,1fr);grid-template-areas:"when spine main";column-gap:10px;align-items:baseline;padding:5px 0}
19665
- .knobs-wt-hwhen{grid-area:when;display:flex;flex-direction:column;min-width:0;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
19666
- .knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
19667
- .knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
19668
- .knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
19669
- .knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
19670
- .knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
19671
- .knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
19672
- .knobs-wt-hdot{position:absolute;left:3.5px;top:calc(var(--kw-hy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--kw-tone,var(--_k-fg-3))}
19673
- .knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
19674
- .knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
19675
- .knobs-wt-hev[data-provenance="inferred"] .knobs-wt-hdot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--kw-tone,var(--_k-fg-3))}
19676
- .knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
19677
- .knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
19678
- .knobs-wt-prov{padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-3);font:var(--_k-weight) calc(var(--kw-t) - 3.5px)/18px var(--_k-mono);white-space:nowrap}
19679
- .knobs-wt-hev[data-provenance="inferred"] .knobs-wt-prov{background:transparent;color:var(--_k-warn);outline:1px dashed color-mix(in oklch,var(--_k-warn) 50%,transparent);outline-offset:-1px}
19680
- .knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
19681
- @container knobs-wt-slot (max-width:520px){
19682
- .knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
19683
- .knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
19684
- }
19685
-
19686
- /* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
19687
- git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
19688
- .knobs-wt-stack{--kw-spt:7px;--kw-spb:7px;--kw-sy:calc(var(--kw-spt) + var(--kw-line) / 2);display:flex;flex-direction:column;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
19689
- .knobs-wt-srow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;column-gap:10px;align-items:start;margin:0 -8px;padding:var(--kw-spt) 8px var(--kw-spb);
19690
- border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
19691
- .knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
19692
- .knobs-wt-srow[data-go]{cursor:pointer}
19693
- .knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
19694
- .knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
19695
- .knobs-wt-lane{position:relative;flex:none;width:16px}
19696
- .knobs-wt-lane:is([data-rail="pass"],[data-rail="tee"],[data-down])::before{content:"";position:absolute;left:7.5px;top:0;bottom:0;width:1px;background:var(--kw-rail)}
19697
- .knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
19698
- .knobs-wt-lane:is([data-rail="tee"],[data-rail="end"])::after{content:"";position:absolute;left:7.5px;top:0;width:13px;height:calc(var(--kw-sy) + .5px);border:solid var(--kw-rail);border-width:0 0 1px 1px;border-bottom-left-radius:6px}
19699
- .knobs-wt-lane[data-rail="node"]::after{content:"";position:absolute;left:4.5px;top:calc(var(--kw-sy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--_k-fg-3)}
19700
- .knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
19701
- .knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
19702
- .knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
19703
- .knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
19704
- .knobs-wt-sord{font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3);white-space:nowrap}
19705
- .knobs-ui .knobs-wt-spr{font:var(--_k-weight-label) calc(var(--kw-t) - 1.5px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2);text-decoration:none;white-space:nowrap}
19706
- .knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
19707
- .knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
19708
- .knobs-ui button.knobs-wt-stitle{cursor:pointer;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
19709
- .knobs-ui :is(.knobs-wt-srow[data-go]:hover button.knobs-wt-stitle,button.knobs-wt-stitle:focus-visible){text-decoration-color:color-mix(in oklch,currentColor 45%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
19710
- .knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
19711
- .knobs-wt-smeta{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 12px;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
19712
- .knobs-wt-delta{display:inline-flex;gap:6px}
19713
- .knobs-wt-add{color:var(--_k-diff-add)}
19714
- .knobs-wt-del{color:var(--_k-diff-del)}
19715
- .knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
19716
- .knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
19717
- .knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
19718
- @container knobs-wt-slot (max-width:520px){
19719
- .knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
19720
- .knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
19721
- .knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
19722
- }
19723
-
19724
- /* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
19725
- (the top one under the head), and thin bars show on hover. */
19726
- @property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
19727
- @property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
19728
- @keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
19729
- @keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
19730
- .knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
19731
- transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
19732
- .knobs-wt-table:is(:hover,:focus-visible){scrollbar-color:color-mix(in oklch,var(--_k-fg) 28%,transparent) transparent;transition-duration:calc(var(--_k-hover-in) * 1ms)}
19733
- .knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
19734
- @supports (animation-timeline:scroll()){
19735
- .knobs-wt-table{animation:knobs-fade-a linear both,knobs-fade-b linear both,kw-fade-l linear both,kw-fade-r linear both;animation-duration:auto;
19736
- animation-timeline:scroll(self block),scroll(self block),scroll(self inline),scroll(self inline);animation-range:0 24px,calc(100% - 24px) 100%,0 8px,calc(100% - 8px) 100%;
19737
- --kw-table-mask-y:linear-gradient(to bottom,#000 var(--kw-thead,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--kw-thead,0px),#000 calc(var(--kw-thead,0px) + 20px),#000 calc(100% - 20px),rgb(0 0 0/var(--knobs-fade-b)));
19738
- --kw-table-mask-x:linear-gradient(to right,rgb(0 0 0/var(--kw-fade-l)),#000 24px,#000 calc(100% - 24px),rgb(0 0 0/var(--kw-fade-r)));
19739
- -webkit-mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);-webkit-mask-composite:source-in;mask-composite:intersect}
19740
- }
19741
- .knobs-wt-table table{width:100%;margin:0;border-collapse:separate;border-spacing:0;font-size:calc(var(--kw-t) - 1.5px);line-height:1.45;font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
19742
- .knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px)}
19743
- .knobs-wt-table th{position:sticky;top:0;padding:0 12px 7px;text-align:left;vertical-align:bottom;font-weight:var(--_k-weight-label);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg-3);white-space:nowrap;
19744
- background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
19745
- .knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
19746
- .knobs-wt-table tr:last-child td{box-shadow:none}
19747
- .knobs-wt-table :is(th,td):first-child{padding-left:0}
19748
- .knobs-wt-table :is(th,td):last-child{padding-right:0}
19749
- .knobs-wt-table td:first-child{color:var(--_k-fg)}
19750
- .knobs-wt-table [data-align="right"]{text-align:right}
19751
- .knobs-wt-table [data-align="center"]{text-align:center}
19752
- .knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg);white-space:nowrap}
19753
- .knobs-wt-table td[data-long]{min-width:24ch}
19754
- .knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
19755
- .knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
19756
- .knobs-wt-ctone{color:var(--kw-tone)}
19757
-
19758
- /* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
19759
- .knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
19760
- .knobs-wt-chapter-mark{position:absolute;left:0;top:0;width:0;border-radius:calc(var(--_k-radius) + 2px);background:var(--_k-fill-selected);opacity:0;pointer-events:none;will-change:transform;
19761
- transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
19762
- .knobs-wt-chapter-mark[data-on]{opacity:1}
19763
- .knobs-ui .knobs-wt-chapter{position:relative;display:inline-flex;align-items:baseline;gap:6px;height:26px;padding:0 10px 0 8px;border-radius:calc(var(--_k-radius) + 2px);color:var(--_k-fg-2);
19764
- font-size:calc(var(--kw-t) - 2px);line-height:26px;white-space:nowrap;cursor:pointer;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
19765
- .knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
19766
- .knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
19767
- .knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
19768
- .knobs-wt-chapter-time{font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
19769
- .knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
19770
- @media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
19771
- `;
19772
-
19773
- // src/ui/walkthrough-blocks.ts
19774
- init_motion();
19775
- init_look();
19776
-
19777
- // src/ui/walkthrough-model.ts
19778
- var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
19779
- function slug(text) {
19780
- return text.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/^(.{0,48})-.*$/, (m, head) => m.length > 48 && head ? head : m).slice(0, 48) || "item";
19575
+ // src/ui/walkthrough-model.ts
19576
+ var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
19577
+ function slug(text) {
19578
+ return text.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/^(.{0,48})-.*$/, (m, head) => m.length > 48 && head ? head : m).slice(0, 48) || "item";
19781
19579
  }
19782
19580
  function uniqueIds() {
19783
19581
  const seen = new Map;
@@ -19979,7 +19777,15 @@ function fillTable(m) {
19979
19777
  out[k] = fillCell(v);
19980
19778
  return out;
19981
19779
  });
19982
- return { kind: "table", columns, rows, ...m.caption ? { caption: m.caption } : {} };
19780
+ const primary = columns.find((c) => c.key === m.primary)?.key ?? columns[0]?.key ?? "";
19781
+ return {
19782
+ kind: "table",
19783
+ columns,
19784
+ rows,
19785
+ ...m.caption ? { caption: m.caption } : {},
19786
+ stack: m.stack ?? "auto",
19787
+ primary
19788
+ };
19983
19789
  }
19984
19790
  function fillChapters(chapters) {
19985
19791
  const id = uniqueIds();
@@ -20052,6 +19858,8 @@ function normalizeWalkthrough(doc) {
20052
19858
  ...step.caption ? { caption: step.caption } : {},
20053
19859
  ...step.question ? { question: step.question } : {},
20054
19860
  media: list.map((m) => fillMedia(m, doc.base)),
19861
+ columns: Math.max(1, Math.min(3, Math.round(step.columns ?? 1))),
19862
+ ...step.more?.trim() && list.length > 1 ? { more: step.more.trim() } : {},
20055
19863
  options,
20056
19864
  ask
20057
19865
  };
@@ -20063,6 +19871,7 @@ function normalizeWalkthrough(doc) {
20063
19871
  id,
20064
19872
  title: s.title,
20065
19873
  ...link ? { link } : {},
19874
+ ...typeof s.kicker === "string" && s.kicker.trim() ? { kicker: s.kicker.trim() } : {},
20066
19875
  ...s.status ? { status: s.status } : {},
20067
19876
  ...s.summary ? { summary: s.summary } : {},
20068
19877
  steps: own
@@ -20073,14 +19882,25 @@ function normalizeWalkthrough(doc) {
20073
19882
  value
20074
19883
  }));
20075
19884
  const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
19885
+ const extra = (x) => ({
19886
+ ...x.status?.trim() ? { status: x.status.trim() } : {},
19887
+ trail: (x.trail ?? []).filter((t) => typeof t === "string" && t.trim())
19888
+ });
20076
19889
  const feed = sortFeed([
20077
- ...(doc.updates ?? []).map((u) => ({ kind: "update", at: parseAt(u.at), text: u.text, step: stepRef(u.step) })),
19890
+ ...(doc.updates ?? []).map((u) => ({
19891
+ kind: "update",
19892
+ at: parseAt(u.at),
19893
+ text: u.text,
19894
+ step: stepRef(u.step),
19895
+ ...extra(u)
19896
+ })),
20078
19897
  ...(doc.qa ?? []).map((x) => ({
20079
19898
  kind: "qa",
20080
19899
  at: parseAt(x.at),
20081
19900
  text: x.a,
20082
19901
  q: x.q,
20083
- step: stepRef(x.step)
19902
+ step: stepRef(x.step),
19903
+ ...extra(x)
20084
19904
  }))
20085
19905
  ]);
20086
19906
  return {
@@ -20093,10 +19913,32 @@ function normalizeWalkthrough(doc) {
20093
19913
  id: slug(v),
20094
19914
  label: label(v)
20095
19915
  })),
20096
- sections,
19916
+ sections: withKickers(sections, doc.sections, doc.kickers),
20097
19917
  steps
20098
19918
  };
20099
19919
  }
19920
+ var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
19921
+ function withKickers(sections, source, kickers = "pr") {
19922
+ if (kickers === false)
19923
+ return [...sections];
19924
+ const noun = typeof kickers === "object" ? kickers.noun.trim() : "PR";
19925
+ const counted = typeof kickers === "object" ? sections : sections.filter((s) => s.link && isPullRequest(s.link.href));
19926
+ return sections.map((s, i) => {
19927
+ const own = source[i]?.kicker;
19928
+ if (own !== undefined || s.kicker)
19929
+ return s;
19930
+ const at = counted.indexOf(s);
19931
+ return at < 0 ? s : { ...s, kicker: `${noun} ${at + 1} of ${counted.length}`.trim() };
19932
+ });
19933
+ }
19934
+ function tableStacks(stack, room, natural) {
19935
+ if (stack !== "auto")
19936
+ return stack === "always";
19937
+ return room > 0 && natural > room + 1;
19938
+ }
19939
+ function noteBarReserve(bar, inset, gap) {
19940
+ return Math.max(0, Math.ceil(bar)) + inset + gap;
19941
+ }
20100
19942
  function parseAt(at) {
20101
19943
  if (!at)
20102
19944
  return null;
@@ -20381,6 +20223,9 @@ function feedbackMarkdown(fb, verdicts) {
20381
20223
  `;
20382
20224
  }
20383
20225
  var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
20226
+ function plainMarkdown(text) {
20227
+ return text.replace(/\[([^\]\n]+)\]\([^)\s]+\)/g, "$1").replace(/`([^`\n]+)`/g, "$1").replace(/\*\*([^*\n]+)\*\*/g, "$1").replace(/(^|[^*\w])\*([^*\n]+)\*(?!\w)/g, "$1$2").replace(/\s+/g, " ").trim();
20228
+ }
20384
20229
  function inlineMarkdown(text) {
20385
20230
  const codes = [];
20386
20231
  let s = text.replace(/`([^`\n]+)`/g, (_, c) => {
@@ -20401,6 +20246,10 @@ function inlineMarkdown(text) {
20401
20246
  }
20402
20247
 
20403
20248
  // src/ui/walkthrough-blocks.ts
20249
+ var GLYPH = {
20250
+ go: icon("caretRight", { small: true }),
20251
+ caret: icon("caretRight", { small: true })
20252
+ };
20404
20253
  var el = (doc, tag, cls) => {
20405
20254
  const n = doc.createElement(tag);
20406
20255
  if (cls)
@@ -20430,9 +20279,10 @@ function stepButton(doc, ref, steps) {
20430
20279
  const s = ref && steps?.find(ref);
20431
20280
  if (!s || !steps)
20432
20281
  return null;
20433
- const b = text(doc, "button", "knobs-wt-steplink", s.number);
20282
+ const b = el(doc, "button", "knobs-wt-steplink");
20283
+ b.innerHTML = GLYPH.go;
20434
20284
  b.type = "button";
20435
- b.title = `Go to ${s.number} ${s.title}`;
20285
+ b.title = `Go to “${s.title}”`;
20436
20286
  b.setAttribute("aria-label", b.title);
20437
20287
  b.addEventListener("click", (e) => {
20438
20288
  e.stopPropagation();
@@ -20557,7 +20407,7 @@ function mountStack(host, m, steps) {
20557
20407
  if (target && steps) {
20558
20408
  const title = text(doc, "button", "knobs-wt-stitle", it.title);
20559
20409
  title.type = "button";
20560
- title.title = `Go to ${target.number} ${target.title}`;
20410
+ title.title = `Go to “${target.title}”`;
20561
20411
  title.addEventListener("click", (e) => {
20562
20412
  e.stopPropagation();
20563
20413
  steps.go(target.key);
@@ -20612,9 +20462,38 @@ function delta(doc, d) {
20612
20462
  s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
20613
20463
  return s;
20614
20464
  }
20465
+ function cellContent(doc, into, cell, steps) {
20466
+ let content;
20467
+ if (cell.badge) {
20468
+ content = link(doc, "knobs-wt-chip", cell.text, cell.href);
20469
+ content.dataset.tone = cell.badge;
20470
+ } else {
20471
+ const inner = cell.code ? text(doc, "code", "", cell.text) : null;
20472
+ if (cell.href) {
20473
+ content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
20474
+ if (inner)
20475
+ content.append(inner);
20476
+ } else
20477
+ content = inner ?? text(doc, "span", "", cell.text);
20478
+ if (cell.tone) {
20479
+ content.classList.add("knobs-wt-ctone");
20480
+ content.dataset.tone = cell.tone;
20481
+ }
20482
+ }
20483
+ into.append(content);
20484
+ const go = stepButton(doc, cell.step, steps);
20485
+ if (go)
20486
+ into.append(go);
20487
+ }
20488
+ var cellAttrs = (td, c) => {
20489
+ td.dataset.align = c.align;
20490
+ if (c.mono)
20491
+ td.dataset.mono = "";
20492
+ };
20615
20493
  function mountTable(host, m, steps) {
20616
20494
  const doc = host.ownerDocument;
20617
20495
  const win = doc.defaultView;
20496
+ const box = el(doc, "div", "knobs-wt-tablebox");
20618
20497
  const scroller = el(doc, "div", "knobs-wt-table");
20619
20498
  const table = el(doc, "table");
20620
20499
  if (m.caption)
@@ -20633,34 +20512,12 @@ function mountTable(host, m, steps) {
20633
20512
  const tr = el(doc, "tr");
20634
20513
  for (const c of m.columns) {
20635
20514
  const td = el(doc, "td");
20636
- td.dataset.align = c.align;
20637
- if (c.mono)
20638
- td.dataset.mono = "";
20515
+ cellAttrs(td, c);
20639
20516
  const cell = r[c.key];
20640
20517
  if (cell) {
20641
20518
  if (cell.text.length > 40 && !c.mono && !cell.code)
20642
20519
  td.dataset.long = "";
20643
- let content;
20644
- if (cell.badge) {
20645
- content = link(doc, "knobs-wt-chip", cell.text, cell.href);
20646
- content.dataset.tone = cell.badge;
20647
- } else {
20648
- const inner = cell.code ? text(doc, "code", "", cell.text) : null;
20649
- if (cell.href) {
20650
- content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
20651
- if (inner)
20652
- content.append(inner);
20653
- } else
20654
- content = inner ?? text(doc, "span", "", cell.text);
20655
- if (cell.tone) {
20656
- content.classList.add("knobs-wt-ctone");
20657
- content.dataset.tone = cell.tone;
20658
- }
20659
- }
20660
- td.append(content);
20661
- const go = stepButton(doc, cell.step, steps);
20662
- if (go)
20663
- td.append(go);
20520
+ cellContent(doc, td, cell, steps);
20664
20521
  }
20665
20522
  tr.append(td);
20666
20523
  }
@@ -20668,10 +20525,73 @@ function mountTable(host, m, steps) {
20668
20525
  }
20669
20526
  table.append(head, body);
20670
20527
  scroller.append(table);
20671
- host.append(scroller);
20528
+ const stack = el(doc, "div", "knobs-wt-tstack");
20529
+ stack.setAttribute("role", "list");
20530
+ if (m.caption)
20531
+ stack.setAttribute("aria-label", m.caption);
20532
+ const primary = m.columns.find((c) => c.key === m.primary) ?? m.columns[0];
20533
+ for (const r of m.rows) {
20534
+ const item = el(doc, "div", "knobs-wt-trow");
20535
+ item.setAttribute("role", "listitem");
20536
+ const title = el(doc, "div", "knobs-wt-ttitle");
20537
+ if (primary) {
20538
+ cellAttrs(title, primary);
20539
+ const cell = r[primary.key];
20540
+ if (cell)
20541
+ cellContent(doc, title, cell, steps);
20542
+ }
20543
+ const line = el(doc, "div", "knobs-wt-tline");
20544
+ line.append(title);
20545
+ const badges = el(doc, "div", "knobs-wt-tbadges");
20546
+ for (const c of m.columns) {
20547
+ const cell = r[c.key];
20548
+ if (c !== primary && cell?.badge)
20549
+ cellContent(doc, badges, cell, steps);
20550
+ }
20551
+ if (badges.childNodes.length)
20552
+ line.append(badges);
20553
+ item.append(line);
20554
+ const terms = el(doc, "dl", "knobs-wt-tterms");
20555
+ for (const c of m.columns) {
20556
+ if (c === primary)
20557
+ continue;
20558
+ const cell = r[c.key];
20559
+ if (!cell || cell.text === "" || cell.badge)
20560
+ continue;
20561
+ const dd = el(doc, "dd");
20562
+ cellAttrs(dd, c);
20563
+ dd.removeAttribute("data-align");
20564
+ cellContent(doc, dd, cell, steps);
20565
+ terms.append(text(doc, "dt", "", c.label), dd);
20566
+ }
20567
+ if (terms.childNodes.length)
20568
+ item.append(terms);
20569
+ stack.append(item);
20570
+ }
20571
+ if (m.caption)
20572
+ stack.append(text(doc, "p", "knobs-wt-tcaption", m.caption));
20573
+ box.append(scroller, stack);
20574
+ host.append(box);
20575
+ let natural = 0;
20576
+ const measureNatural = () => {
20577
+ if (!box.isConnected)
20578
+ return 0;
20579
+ const was = box.dataset.stacked;
20580
+ delete box.dataset.stacked;
20581
+ box.dataset.measure = "";
20582
+ const w = table.getBoundingClientRect().width;
20583
+ delete box.dataset.measure;
20584
+ if (was !== undefined)
20585
+ box.dataset.stacked = was;
20586
+ return w;
20587
+ };
20672
20588
  const measure = () => {
20589
+ if (!natural)
20590
+ natural = measureNatural();
20591
+ const stacked = tableStacks(m.stack, box.clientWidth, natural);
20592
+ box.toggleAttribute("data-stacked", stacked);
20673
20593
  scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
20674
- const scrolls = scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1;
20594
+ const scrolls = !stacked && (scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1);
20675
20595
  if (scrolls) {
20676
20596
  scroller.tabIndex = 0;
20677
20597
  scroller.setAttribute("role", "region");
@@ -20682,106 +20602,636 @@ function mountTable(host, m, steps) {
20682
20602
  scroller.removeAttribute("aria-label");
20683
20603
  }
20684
20604
  };
20605
+ if (m.stack === "always")
20606
+ box.dataset.stacked = "";
20685
20607
  const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
20686
- ro?.observe(scroller);
20608
+ ro?.observe(box);
20687
20609
  measure();
20610
+ doc.fonts?.ready.then(() => {
20611
+ if (!box.isConnected)
20612
+ return;
20613
+ natural = 0;
20614
+ measure();
20615
+ });
20688
20616
  return {
20689
20617
  dispose: () => {
20690
20618
  ro?.disconnect();
20691
- scroller.remove();
20619
+ box.remove();
20692
20620
  },
20693
20621
  context: () => ({ kind: "table" })
20694
20622
  };
20695
20623
  }
20696
- var grid2 = (v) => Math.round(v * 64) / 64;
20697
20624
  function chapterPills(host, chapters, io) {
20698
20625
  const doc = host.ownerDocument;
20699
- const win = doc.defaultView;
20700
- const bar = el(doc, "div", "knobs-wt-chapters");
20701
- bar.setAttribute("role", "group");
20702
- bar.setAttribute("aria-label", "Chapters");
20703
- const mark = el(doc, "span", "knobs-wt-chapter-mark");
20704
- mark.setAttribute("aria-hidden", "true");
20705
- bar.append(mark);
20706
- const pills = chapters.map((c) => {
20626
+ const list = el(doc, "div", "knobs-wt-chapters");
20627
+ list.setAttribute("role", "group");
20628
+ list.setAttribute("aria-label", "Chapters");
20629
+ let at = -2;
20630
+ const rows = chapters.map((c, i) => {
20707
20631
  const b = el(doc, "button", "knobs-wt-chapter");
20708
20632
  b.type = "button";
20709
- b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
20633
+ b.append(text(doc, "span", "knobs-wt-chapter-n", String(i + 1)));
20710
20634
  b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
20635
+ b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
20711
20636
  b.addEventListener("click", () => {
20712
20637
  io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
20713
20638
  io.seek(c.start);
20714
- sync();
20639
+ select(i);
20715
20640
  });
20716
- bar.append(b);
20641
+ list.append(b);
20717
20642
  return b;
20718
20643
  });
20719
- host.append(bar);
20720
- const x = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
20721
- const y = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
20722
- const w = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
20723
- const draw = () => {
20724
- const left = grid2(x.x);
20725
- mark.style.transform = `translate(${left}px,${grid2(y.x)}px)`;
20726
- mark.style.width = `${grid2(x.x + w.x) - left}px`;
20727
- };
20728
- const loop = frameLoop(win, (dt) => {
20729
- x.step(dt);
20730
- y.step(dt);
20731
- w.step(dt);
20732
- draw();
20733
- return !x.resting || !y.resting || !w.resting;
20644
+ host.append(list);
20645
+ const pill = selectionPill(list, {
20646
+ selected: () => rows[at] ?? null,
20647
+ rows: () => rows
20734
20648
  });
20735
- let at = -2;
20736
- let shown = false;
20737
- const place = (snap) => {
20738
- const p = pills[at];
20739
- if (!p) {
20740
- mark.removeAttribute("data-on");
20741
- pills.forEach((b) => b.removeAttribute("aria-current"));
20742
- shown = false;
20743
- return;
20744
- }
20745
- pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
20746
- const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
20747
- if (snap || !shown || reducedMotion(win)) {
20748
- x.snap(to[0]);
20749
- y.snap(to[1]);
20750
- w.snap(to[2]);
20751
- draw();
20752
- } else {
20753
- x.set(to[0]);
20754
- y.set(to[1]);
20755
- w.set(to[2]);
20756
- loop.wake();
20757
- }
20758
- mark.style.height = `${p.offsetHeight}px`;
20759
- mark.dataset.on = "";
20760
- shown = true;
20761
- };
20762
- const sync = () => {
20763
- const next = chapterAt(chapters, io.now());
20764
- if (next === at)
20649
+ const select = (i) => {
20650
+ if (i === at)
20765
20651
  return;
20766
- at = next;
20767
- place(false);
20652
+ at = i;
20653
+ rows.forEach((b, k) => k === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
20654
+ pill.update();
20768
20655
  };
20656
+ const sync = () => select(chapterAt(chapters, io.now()));
20769
20657
  sync();
20770
- const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
20771
- ro?.observe(bar);
20772
20658
  return {
20773
20659
  sync,
20774
20660
  get current() {
20775
20661
  return chapters[at] ?? null;
20776
20662
  },
20663
+ dispose() {
20664
+ pill.dispose();
20665
+ list.remove();
20666
+ }
20667
+ };
20668
+ }
20669
+ function disclosure(host, options) {
20670
+ const doc = host.ownerDocument;
20671
+ const win = doc.defaultView;
20672
+ let open = options.open === true;
20673
+ const root = el(doc, "div", "knobs-wt-disc");
20674
+ const toggle = el(doc, "button", "knobs-wt-disc-toggle");
20675
+ toggle.type = "button";
20676
+ toggle.innerHTML = GLYPH.caret;
20677
+ toggle.append(text(doc, "span", "", options.label));
20678
+ if (options.count !== undefined)
20679
+ toggle.append(text(doc, "span", "knobs-wt-disc-count", String(options.count)));
20680
+ const viewport = el(doc, "div", "knobs-wt-disc-body");
20681
+ const content = el(doc, "div", "knobs-wt-disc-content");
20682
+ content.append(options.content);
20683
+ viewport.append(content);
20684
+ root.append(toggle, viewport);
20685
+ host.append(root);
20686
+ const STATE = springMotion(SPRINGS.default);
20687
+ const h = new Spring(0, STATE.omega, STATE.zeta, 0.25);
20688
+ let full = 0;
20689
+ const paint = (moving) => {
20690
+ const k = full > 0 ? Math.max(0, Math.min(1, h.x / full)) : open ? 1 : 0;
20691
+ viewport.style.height = !moving && open ? "" : `${Math.max(0, h.x).toFixed(2)}px`;
20692
+ viewport.toggleAttribute("data-moving", moving);
20693
+ content.style.opacity = (open ? Math.min(1, k * 1.25) : Math.max(0, k * 1.5 - 0.5)).toFixed(3);
20694
+ };
20695
+ const loop = frameLoop(win, (dt) => {
20696
+ h.step(dt);
20697
+ const moving = !h.resting;
20698
+ paint(moving);
20699
+ return moving;
20700
+ });
20701
+ const sync = () => {
20702
+ root.toggleAttribute("data-open", open);
20703
+ toggle.setAttribute("aria-expanded", String(open));
20704
+ viewport.inert = !open;
20705
+ };
20706
+ sync();
20707
+ h.snap(0);
20708
+ paint(false);
20709
+ if (open) {
20710
+ viewport.style.height = "";
20711
+ content.style.opacity = "1";
20712
+ }
20713
+ const api = {
20714
+ element: root,
20715
+ get open() {
20716
+ return open;
20717
+ },
20718
+ toggle(next = !open) {
20719
+ if (next === open)
20720
+ return;
20721
+ open = next;
20722
+ sync();
20723
+ full = content.offsetHeight;
20724
+ if (reducedMotion(win)) {
20725
+ loop.stop();
20726
+ h.snap(open ? full : 0);
20727
+ viewport.style.height = open ? "" : "0px";
20728
+ content.style.opacity = open ? "1" : "0";
20729
+ return;
20730
+ }
20731
+ if (h.resting)
20732
+ h.snap(open ? 0 : full);
20733
+ h.set(open ? full : 0);
20734
+ paint(true);
20735
+ loop.wake();
20736
+ },
20777
20737
  dispose() {
20778
20738
  loop.stop();
20779
- ro?.disconnect();
20780
- bar.remove();
20739
+ root.remove();
20781
20740
  }
20782
20741
  };
20742
+ toggle.addEventListener("click", () => api.toggle());
20743
+ return api;
20783
20744
  }
20784
20745
 
20746
+ // src/ui/walkthrough-media.ts
20747
+ init_compare_model();
20748
+ init_glide();
20749
+ init_icons();
20750
+ init_look();
20751
+
20752
+ // src/ui/walkthrough-css.ts
20753
+ init_motion();
20754
+ var snappy3 = springCss(SPRINGS.snappy);
20755
+ var calm = springCss(SPRINGS.calm);
20756
+ var state = springCss(SPRINGS.default);
20757
+ var quick = springCss(FADE);
20758
+ var fade2 = "-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)";
20759
+ var walkthroughCss = `
20760
+ :where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
20761
+ .knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;--kw-state:${state.easing};--kw-state-ms:${state.duration}ms;--kw-quick:${quick.easing};--kw-quick-ms:${quick.duration}ms;
20762
+ --kw-measure:var(--k-walkthrough-measure,68ch);--kw-width:var(--k-walkthrough-width,680px);--kw-rail-w:220px;--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));
20763
+ --kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-under:var(--_k-bg-page);--kw-ink:var(--k-walkthrough-ink,#ff375f);--kw-strong:var(--_k-weight-label);
20764
+ container:knobs-wt / inline-size;display:block;width:100%;color:var(--_k-fg);font:var(--_k-weight) var(--_k-type-body)/var(--_k-leading-body) var(--_k-font);font-variant-numeric:tabular-nums;text-align:left;
20765
+ letter-spacing:normal;-webkit-font-smoothing:antialiased}
20766
+ .knobs-walkthrough [hidden]{display:none!important}
20767
+ /* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
20768
+ :where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
20769
+ .knobs-walkthrough a{color:inherit;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-underline-offset:2px;transition:text-decoration-color .15s}
20770
+ .knobs-walkthrough a:hover{text-decoration-color:currentColor}
20771
+ .knobs-walkthrough code,.knobs-wt-slot code{font:var(--_k-type-label) var(--_k-mono);padding:1px 5px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
20772
+ :where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-row,button.knobs-wt-stitle,.knobs-wt-chapter,.knobs-wt-disc-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
20773
+ background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
20774
+
20775
+ /* ——— layout: a readable column, centred, with a slim contents rail beside it (right by default);
20776
+ one column where it's narrow ——— */
20777
+ .knobs-wt-layout{display:grid;grid-template-columns:minmax(0,var(--kw-width)) var(--kw-rail-w);justify-content:center;gap:var(--_k-space-column);align-items:start}
20778
+ .knobs-walkthrough[data-rail="right"] .knobs-wt-main{grid-column:1;grid-row:1}
20779
+ .knobs-walkthrough[data-rail="right"] .knobs-wt-rail{grid-column:2;grid-row:1}
20780
+ .knobs-walkthrough[data-rail="left"] .knobs-wt-layout{grid-template-columns:var(--kw-rail-w) minmax(0,var(--kw-width))}
20781
+ .knobs-walkthrough[data-rail="none"] .knobs-wt-layout{grid-template-columns:minmax(0,var(--kw-width))}
20782
+ .knobs-wt-main{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0;padding-bottom:12px}
20783
+ /* The intro, the updates and each section: a section's room apart, the hairline in the middle. */
20784
+ .knobs-wt-flow{display:flex;flex-direction:column;gap:calc(var(--_k-space-section) / 2);min-width:0}
20785
+ .knobs-wt-flow>*+*{padding-top:calc(var(--_k-space-section) / 2);box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
20786
+ @container knobs-wt (max-width:940px){.knobs-walkthrough .knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:var(--_k-space-title)}
20787
+ .knobs-walkthrough[data-rail] .knobs-wt-layout>*{grid-column:auto;grid-row:auto}}
20788
+
20789
+ /* ——— one line of facts: small, faint, joined by ·, its trailing edge fading ——— */
20790
+ .knobs-wt-metaline{display:flex;align-items:baseline;gap:var(--_k-space-inside);min-width:0;overflow:hidden;white-space:nowrap;font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3);${fade2}}
20791
+ .knobs-wt-metaline>*{flex:none}
20792
+ .knobs-wt-metaline>*+*::before{content:"·";margin-right:var(--_k-space-inside);color:var(--_k-fg-3)}
20793
+ .knobs-walkthrough .knobs-wt-metaline a{display:inline-flex;align-items:baseline;color:inherit;text-decoration:none;transition:color calc(var(--_k-hover-out) * 1ms)}
20794
+ .knobs-walkthrough .knobs-wt-metaline a:hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
20795
+ .knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
20796
+ .knobs-wt-kicker-lead{color:var(--_k-fg);font-weight:var(--kw-strong)}
20797
+ .knobs-wt-metaline [data-status="on"]{color:var(--_k-fg)}
20798
+ .knobs-wt-metaline [data-status="warn"]{color:var(--_k-warn)}
20799
+
20800
+ /* ——— the page's head ——— */
20801
+ .knobs-wt-head{display:flex;flex-direction:column;gap:var(--_k-space-title)}
20802
+ .knobs-wt-title{font-size:var(--_k-type-title)!important;line-height:var(--_k-leading-title);font-weight:var(--kw-strong)!important;text-wrap:balance}
20803
+ .knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
20804
+ .knobs-wt-meta{display:flex;flex-wrap:wrap;gap:var(--_k-space-inside) var(--_k-space-title);color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
20805
+ .knobs-wt-meta>span{display:inline-flex;gap:var(--_k-space-inside);white-space:nowrap}
20806
+ .knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono)}
20807
+
20808
+ /* ——— a section: a PR or topic. Its kicker leads the meta line; its title outranks the page's ——— */
20809
+ .knobs-wt-section{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
20810
+ .knobs-wt-sintro{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0}
20811
+ .knobs-wt-shead{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0;scroll-margin-top:16px}
20812
+ .knobs-wt-heading{font-size:var(--_k-type-heading)!important;line-height:var(--_k-leading-heading);font-weight:var(--kw-strong)!important;letter-spacing:-.01em!important;text-wrap:balance}
20813
+ .knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
20814
+ .knobs-wt-chip{display:inline-flex;align-items:center;gap:6px;height:20px;padding:0 8px;border-radius:var(--_k-round);font-size:var(--_k-type-small);font-weight:var(--kw-strong);white-space:nowrap;
20815
+ --kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
20816
+ .knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
20817
+ :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
20818
+ :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
20819
+ :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
20820
+ :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
20821
+ :is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
20822
+
20823
+ /* ——— a step: on the page by default, a group's room between steps with a hairline in the middle;
20824
+ or (cards) one card each, the one surface its pieces sit on ——— */
20825
+ .knobs-walkthrough:not([data-cards]) .knobs-wt-step:not([data-full]){padding:0;border-radius:0;background:transparent;box-shadow:none}
20826
+ .knobs-walkthrough:not([data-cards]) .knobs-wt-step+.knobs-wt-step::before{content:"";position:absolute;left:0;right:0;top:calc(var(--_k-space-group) / -2);height:1px;background:var(--_k-border-subtle);pointer-events:none}
20827
+ .knobs-wt-step{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-title);padding:var(--_k-pad-card);border-radius:var(--_k-radius-panel);background:var(--kw-card);box-shadow:var(--kw-card-ring);
20828
+ scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
20829
+ .knobs-walkthrough[data-cards]{--kw-under:var(--kw-card)}
20830
+ .knobs-walkthrough[data-cards][data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
20831
+ .knobs-wt-step-head{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
20832
+ .knobs-wt-stepTitle{min-width:0;font-weight:var(--kw-strong)!important;text-wrap:balance}
20833
+ .knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
20834
+ .knobs-wt-question{font-weight:var(--kw-strong)!important;max-width:var(--kw-measure)}
20835
+ .knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:var(--_k-space-group) var(--_k-space-column);min-width:0}
20836
+ @container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
20837
+
20838
+ /* ——— the feed: updates and answers, newest first. Tight inside an item (4 / 8 / 4), a group's
20839
+ room between items with the hairline in the middle; no boxes ——— */
20840
+ .knobs-wt-feed{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0;scroll-margin-top:16px}
20841
+ .knobs-wt-feed-head{display:flex;align-items:baseline;gap:var(--_k-space-sibling)}
20842
+ .knobs-wt-feed-title{font-weight:var(--kw-strong)!important}
20843
+ .knobs-wt-feed-count{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}
20844
+ .knobs-wt-feed-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
20845
+ .knobs-wt-fi{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
20846
+ .knobs-wt-fi+.knobs-wt-fi::before{content:"";position:absolute;left:0;right:0;top:calc(var(--_k-space-group) / -2);height:1px;background:var(--_k-border-subtle)}
20847
+ .knobs-wt-fi-q,.knobs-wt-fi-a{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
20848
+ .knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
20849
+ .knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
20850
+ .knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
20851
+ :where(.knobs-ui) .knobs-wt-fi-step{all:revert;box-sizing:border-box;font:inherit;color:inherit;background:transparent;border:0;margin:0;padding:0;cursor:pointer;outline:none;
20852
+ transition:color calc(var(--_k-hover-out) * 1ms)}
20853
+ .knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
20854
+ :where(.knobs-ui) .knobs-wt-steplink{all:revert;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0 0 0 2px;padding:0;vertical-align:-5px;border:0;
20855
+ border-radius:calc(var(--_k-radius) / 2);background:transparent;color:var(--_k-fg-3);cursor:pointer;outline:none;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
20856
+ .knobs-ui .knobs-wt-steplink:is(:hover,:focus-visible){background:var(--_k-fill);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
20857
+ .knobs-wt-steplink svg{width:12px;height:12px}
20858
+
20859
+ /* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
20860
+ script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
20861
+ .knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
20862
+ .knobs-ui .knobs-wt-disc-toggle{display:inline-flex;align-items:center;gap:var(--_k-space-inside);width:max-content;height:20px;color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);cursor:pointer;
20863
+ border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
20864
+ .knobs-ui .knobs-wt-disc-toggle:is(:hover,:focus-visible),.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle{color:var(--_k-fg-2);transition-duration:calc(var(--_k-hover-in) * 1ms)}
20865
+ .knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
20866
+ .knobs-wt-disc-toggle svg{flex:none;width:12px;height:12px;transition:rotate var(--kw-state-ms) var(--kw-state)}
20867
+ .knobs-wt-disc[data-open]>.knobs-wt-disc-toggle svg{rotate:90deg}
20868
+ .knobs-wt-disc-count{color:var(--_k-fg-3)}
20869
+ .knobs-wt-disc-body{overflow:hidden}
20870
+ .knobs-wt-disc[data-open]>.knobs-wt-disc-body:not([data-moving]){overflow:visible}
20871
+ .knobs-wt-disc-body[data-moving]{-webkit-mask-image:linear-gradient(#000 calc(100% - 16px),transparent);mask-image:linear-gradient(#000 calc(100% - 16px),transparent)}
20872
+ .knobs-wt-disc-content{padding-top:var(--_k-space-inside)}
20873
+ /* A trail sits on the toggle's label edge: faint lines, the time trailing. */
20874
+ .knobs-wt-trail{display:flex;flex-direction:column;list-style:none;padding:0 0 0 calc(12px + var(--_k-space-inside));font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3);min-width:0}
20875
+ .knobs-wt-trail li{display:flex;align-items:baseline;gap:var(--_k-space-sibling);min-width:0;white-space:nowrap}
20876
+ .knobs-wt-trail-text{flex:0 1 auto;min-width:0;overflow:hidden;${fade2}}
20877
+ .knobs-wt-trail-at{flex:none}
20878
+
20879
+ /* ——— a step's sent notes ——— */
20880
+ .knobs-wt-notes{display:flex;flex-direction:column}
20881
+ .knobs-wt-notes:empty{display:none}
20882
+ .knobs-wt-n{display:flex;align-items:flex-start;gap:var(--_k-space-sibling);padding:6px 0;overflow:hidden;
20883
+ transition:height var(--kw-snappy-ms) var(--kw-snappy),opacity var(--kw-snappy-ms) var(--kw-snappy),filter var(--kw-snappy-ms) var(--kw-snappy)}
20884
+ .knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
20885
+ .knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
20886
+ .knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
20887
+ .knobs-wt-n-meta{flex:none;min-width:44px;color:var(--_k-fg-3);font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-body) var(--_k-mono)}
20888
+ .knobs-wt-n-meta[data-seek]{cursor:pointer}
20889
+ .knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
20890
+ .knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
20891
+ .knobs-wt-n-voice{height:30px;max-width:320px}
20892
+ .knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
20893
+ .knobs-wt-n-ink path{fill:none;stroke:var(--kw-ink);stroke-width:2px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
20894
+
20895
+ /* ——— the note bar, docked at the bottom of the column. It holds its own place at the page's end
20896
+ (so the last step stays clear of it), and script keeps its height as the scroller's
20897
+ scroll-padding-bottom ——— */
20898
+ .knobs-wt-dock{position:sticky;bottom:12px;z-index:40;display:grid;pointer-events:none}
20899
+ .knobs-wt-dock>*{pointer-events:auto}
20900
+ .knobs-wt-dock>:is(.knobs-wt-notebar,.knobs-wt-launch){grid-area:1/1}
20901
+ .knobs-wt-dock[data-mode="docked"]>.knobs-wt-launch{display:none}
20902
+ /* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
20903
+ from the launcher's corner; the exit is the shorter. */
20904
+ :where(.knobs-ui) .knobs-wt-launch{all:revert;box-sizing:border-box;justify-self:end;align-self:end;display:inline-flex;align-items:center;gap:6px;height:32px;margin:0;padding:0 10px 0 9px;border:0;border-radius:var(--_k-round);
20905
+ background:var(--_k-bg);color:var(--_k-fg-2);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);cursor:pointer;outline:none;transform-origin:100% 100%;
20906
+ transition:color calc(var(--_k-hover-out) * 1ms),opacity var(--kw-quick-ms) var(--kw-quick),scale var(--kw-quick-ms) var(--kw-quick),filter var(--kw-quick-ms) var(--kw-quick)}
20907
+ .knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
20908
+ .knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
20909
+ .knobs-wt-launch svg{width:16px;height:16px}
20910
+ .knobs-wt-launch kbd{font:inherit;font-weight:var(--_k-weight);color:var(--_k-fg-3)}
20911
+ .knobs-wt-dock[data-mode="collapsed"] .knobs-wt-notebar{transform-origin:100% 100%;transition:opacity var(--kw-quick-ms) var(--kw-quick),scale var(--kw-quick-ms) var(--kw-quick),filter var(--kw-quick-ms) var(--kw-quick)}
20912
+ .knobs-wt-dock[data-mode="collapsed"]:not([data-open])>.knobs-wt-notebar,.knobs-wt-dock[data-mode="collapsed"][data-open]>.knobs-wt-launch{opacity:0;scale:.98;filter:blur(3px);pointer-events:none;
20913
+ transition-duration:calc(var(--kw-quick-ms) * .8)}
20914
+ .knobs-wt-notebar{display:flex;flex-direction:column;gap:2px;padding:6px 6px 6px 14px;border-radius:calc(var(--_k-radius-panel) + 2px);background:var(--_k-bg);
20915
+ box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
20916
+ .knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);white-space:nowrap;overflow:hidden;${fade2}}
20917
+ .knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
20918
+ :where(.knobs-ui) :is(.knobs-wt-input,.knobs-wt-tool,.knobs-wt-x,.knobs-wt-back){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;
20919
+ border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
20920
+ .knobs-ui .knobs-wt-input{flex:1;min-width:0;height:32px;max-height:140px;padding:6px 0;resize:none;color:var(--_k-fg);caret-color:var(--_k-accent);line-height:var(--_k-leading-body);font-size:var(--_k-type-body)}
20921
+ .knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
20922
+ .knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
20923
+ .knobs-wt-attach:empty{display:none}
20924
+ .knobs-wt-chip-a{display:inline-flex;align-items:center;gap:2px;height:24px;padding:0 2px 0 9px;border-radius:var(--_k-round);background:var(--_k-fill-selected);font-size:var(--_k-type-small);white-space:nowrap}
20925
+ .knobs-ui .knobs-wt-x{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;color:var(--_k-fg-3);cursor:pointer;transition:background .15s,color .15s}
20926
+ .knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
20927
+ .knobs-wt-x svg{width:12px;height:12px}
20928
+ .knobs-ui .knobs-wt-tool{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:32px;height:32px;padding:0 8px;border-radius:calc(var(--_k-radius) + 2px);
20929
+ color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
20930
+ .knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
20931
+ .knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
20932
+ .knobs-wt-tool svg{width:16px;height:16px}
20933
+ .knobs-wt-rec{font-size:var(--_k-type-small)}
20934
+ .knobs-wt-rec:empty{display:none}
20935
+ .knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
20936
+ .knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
20937
+ /* Back: in place over the bar for a few seconds after a note moves the page on. */
20938
+ .knobs-ui .knobs-wt-back{position:absolute;left:8px;bottom:calc(100% + 8px);display:inline-flex;align-items:center;gap:var(--_k-space-inside);max-width:min(360px,calc(100% - 16px));height:28px;padding:0 12px 0 9px;
20939
+ border-radius:var(--_k-round);background:var(--_k-bg);color:var(--_k-fg);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font-size:var(--_k-type-small);font-weight:var(--kw-strong);cursor:pointer;
20940
+ opacity:0;scale:.96;filter:blur(3px);pointer-events:none;transition:opacity .11s cubic-bezier(.4,0,1,1),scale .11s cubic-bezier(.4,0,1,1),filter .11s cubic-bezier(.4,0,1,1)}
20941
+ .knobs-ui .knobs-wt-back[data-on]{opacity:1;scale:1;filter:none;pointer-events:auto;transition:opacity .15s cubic-bezier(.2,.8,.2,1),scale .15s cubic-bezier(.2,.8,.2,1),filter .15s cubic-bezier(.2,.8,.2,1)}
20942
+ .knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
20943
+ .knobs-wt-back svg{flex:none;width:12px;height:12px}
20944
+ .knobs-wt-back-label{min-width:0;overflow:hidden;white-space:nowrap;${fade2}}
20945
+
20946
+ /* ——— ink over a step's media ——— */
20947
+ .knobs-wt-media,.knobs-wt-options{position:relative}
20948
+ .knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
20949
+ .knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
20950
+ .knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
20951
+
20952
+ /* ——— full-window: the step over the page above the note bar, its media filling it; its place held
20953
+ in the page. The one raised surface ——— */
20954
+ .knobs-wt-scrim{position:fixed;inset:0;z-index:30;background:color-mix(in srgb,var(--_k-bg-page) 82%,transparent);opacity:0;pointer-events:none}
20955
+ .knobs-wt-scrim[data-on]{pointer-events:auto}
20956
+ .knobs-wt-hold-card{flex:none}
20957
+ .knobs-wt-step[data-full]{position:fixed;z-index:35;margin:0;overflow:hidden;overscroll-behavior:contain;padding:var(--_k-pad-card);border-radius:var(--_k-radius-panel);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);background:var(--_k-bg)}
20958
+ .knobs-wt-step[data-full]::before{content:none}
20959
+ .knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
20960
+ .knobs-wt-step[data-full] .knobs-wt-notes{display:none}
20961
+ .knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
20962
+ .knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
20963
+ .knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
20964
+ .knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
20965
+ .knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
20966
+
20967
+ /* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
20968
+ the step's card, so no fill of their own ——— */
20969
+ .knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:var(--_k-space-group) var(--_k-space-column)}
20970
+ @container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
20971
+ .knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
20972
+ .knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
20973
+ .knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
20974
+ .knobs-ui .knobs-wt-pick{display:flex;align-items:center;gap:8px;width:100%;min-height:28px;margin:0 -6px;width:calc(100% + 12px);padding:0 6px;border-radius:var(--_k-radius);cursor:pointer;color:var(--_k-fg-2);text-align:left;
20975
+ transition:background calc(var(--_k-hover-out) * 1ms)}
20976
+ .knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_k-fill);transition-duration:calc(var(--_k-hover-in) * 1ms)}
20977
+ .knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
20978
+ .knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--kw-strong);color:var(--_k-fg)}
20979
+ .knobs-wt-suggested{flex:none;font-size:var(--_k-type-small);color:var(--_k-fg-3)}
20980
+ .knobs-wt-check{flex:none;display:flex;width:18px;height:18px;align-items:center;justify-content:center;border-radius:50%;background:var(--_k-fill);color:transparent;
20981
+ transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
20982
+ .knobs-wt-check svg{width:12px;height:12px}
20983
+ .knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
20984
+ .knobs-wt-key{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;padding:0 3px;border-radius:4px;background:var(--_k-fill);color:var(--_k-fg-3);
20985
+ font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);opacity:.5;transition:opacity .15s}
20986
+ .knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
20987
+ .knobs-wt-ocap{color:var(--_k-fg-2);max-width:var(--kw-measure)}
20988
+
20989
+ /* ——— the rail: progress, contents, export ——— */
20990
+ .knobs-wt-rail{position:sticky;top:16px;display:flex;flex-direction:column;gap:var(--_k-space-title);max-height:calc(100vh - 32px);min-height:0;font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
20991
+ .knobs-wt-progress{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
20992
+ .knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2)}
20993
+ .knobs-wt-count b{color:var(--_k-fg);font-weight:var(--kw-strong)}
20994
+ .knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
20995
+ .knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
20996
+ .knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
20997
+ /* The contents: rows centred on one spine, title rows (32 high, the control radius) and the
20998
+ steps under them (20 high, half of it), bled out so their text sits on the rail's edge; the
20999
+ selection pill slides to the current step, and base rows never brighten for being current. */
21000
+ .knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column;gap:var(--_k-space-sibling);margin:0 calc(var(--_k-space-sibling) * -1);padding:0 0 8px}
21001
+ .knobs-wt-toc::-webkit-scrollbar{display:none}
21002
+ .knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
21003
+ .knobs-ui .knobs-wt-toc-row{position:relative;display:grid;grid-template-columns:var(--kw-toc-n,0px) minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;flex:none;width:100%;height:32px;
21004
+ padding:0 var(--_k-space-sibling);border-radius:var(--_k-radius);color:var(--_k-fg-2);font-size:var(--_k-type-body);line-height:var(--_k-leading-body);font-weight:var(--kw-strong);text-align:left;white-space:nowrap;cursor:pointer;
21005
+ transition:color calc(var(--_k-hover-out) * 1ms)}
21006
+ .knobs-ui .knobs-wt-toc-sub{height:20px;border-radius:calc(var(--_k-radius) / 2);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);font-weight:var(--_k-weight);color:var(--_k-fg-3)}
21007
+ .knobs-wt-toc[data-bare] .knobs-wt-toc-row{grid-template-columns:minmax(0,1fr) auto}
21008
+ .knobs-wt-toc[data-bare] .knobs-wt-toc-n{display:none}
21009
+ .knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
21010
+ .knobs-ui .knobs-wt-toc-sub:is(:hover,:focus-visible){color:var(--_k-fg-2)}
21011
+ .knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
21012
+ .knobs-wt-toc-n,.knobs-wt-toc-end{display:flex;align-items:center;font-size:var(--_k-type-small);line-height:var(--_k-leading-small);font-weight:var(--_k-weight);color:var(--_k-fg-3)}
21013
+ .knobs-wt-toc-row[data-active] .knobs-wt-toc-n{color:var(--_k-fg-2)}
21014
+ .knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
21015
+ .knobs-pick-copy .knobs-wt-toc-n,.knobs-pick-copy .knobs-wt-toc-end{color:var(--_k-fg-2)}
21016
+ /* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
21017
+ .knobs-wt-toc-glyph{--kw-tone:var(--_k-fg-3);display:block;width:6px;height:6px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--kw-tone);
21018
+ transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
21019
+ .knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
21020
+ .knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
21021
+ .knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
21022
+ .knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
21023
+ .knobs-ui .knobs-wt-btn{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
21024
+ transition:background .15s,color .15s}
21025
+ .knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
21026
+ .knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
21027
+ .knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
21028
+ .knobs-wt-keys{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
21029
+ .knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
21030
+ /* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
21031
+ @container knobs-wt (max-width:940px){
21032
+ .knobs-wt-rail{z-index:4;flex-direction:row;align-items:center;gap:var(--_k-space-title);max-height:none;margin:0 calc(var(--_k-pad-page) * -1);padding:8px var(--_k-pad-page);top:0;background:var(--_k-bg-page)}
21033
+ .knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
21034
+ .knobs-wt-step,.knobs-wt-shead,.knobs-wt-feed{scroll-margin-top:60px}
21035
+ }
21036
+
21037
+ /* ——— media slots. Only a picture's frame (a quiet fill while it loads or letterboxes) and a code
21038
+ block (a well) are bounded; a metric, a callout, a table, a stack and a history sit on the page,
21039
+ set apart by space, hairlines and their own colours. On a card (.knobs-surface) code drops its
21040
+ well for hairlines, so nothing draws a fill and a ring of its own there ——— */
21041
+ .knobs-ui.knobs-wt-slot{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);
21042
+ font:var(--_k-weight) var(--_k-type-body)/var(--_k-leading-body) var(--_k-font);font-variant-numeric:tabular-nums;--kw-measure:var(--k-walkthrough-measure,68ch);
21043
+ --kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
21044
+ .knobs-wt-slot-label{display:block;font:var(--_k-weight-label) var(--_k-type-label)/var(--_k-leading-label) var(--_k-font);color:var(--_k-fg-2)}
21045
+ .knobs-wt-body{min-width:0}
21046
+ /* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
21047
+ sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
21048
+ (92 px), and the frame strip with its gap (158 px). */
21049
+ .knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
21050
+ .knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
21051
+ .knobs-wt-fit[data-strip]{--kw-chrome:158px}
21052
+ .knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
21053
+ .knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
21054
+ .knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
21055
+ .knobs-wt-frame[data-natural]{aspect-ratio:auto;background:transparent}
21056
+ .knobs-wt-frame[data-natural]>img{position:static;height:auto}
21057
+ .knobs-wt-code{margin:0;padding:var(--_k-pad-card);max-height:420px;overflow:auto;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);color:var(--_k-fg);
21058
+ font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
21059
+ .knobs-surface .knobs-wt-code{padding-inline:0;border-radius:0;background:transparent;box-shadow:inset 0 1px 0 var(--_k-border-subtle),inset 0 -1px 0 var(--_k-border-subtle)}
21060
+ .knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
21061
+ .knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
21062
+ .knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
21063
+ .knobs-wt-out{color:var(--_k-fg-2)}
21064
+ .knobs-wt-metric{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
21065
+ .knobs-wt-mlabel{color:var(--_k-fg-2)}
21066
+ .knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--_k-space-sibling);font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
21067
+ .knobs-wt-mfrom{color:var(--_k-fg-3);font-size:var(--_k-type-title);line-height:var(--_k-leading-title)}
21068
+ .knobs-wt-mto{font-size:var(--_k-type-heading);line-height:var(--_k-leading-heading);font-weight:var(--_k-weight-label)}
21069
+ .knobs-wt-mof{color:var(--_k-fg-3)}
21070
+ .knobs-wt-mdelta{--kw-tone:var(--_k-fg-2);font-size:var(--_k-type-small);font-weight:var(--_k-weight-label);color:var(--kw-tone)}
21071
+ .knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
21072
+ .knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
21073
+ .knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
21074
+ .knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
21075
+ .knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
21076
+ .knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
21077
+ .knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg)}
21078
+ .knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:7px;border-radius:50%;background:var(--kw-tone)}
21079
+ .knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
21080
+ .knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
21081
+ .knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
21082
+ .knobs-wt-text{max-width:var(--kw-measure);color:var(--_k-fg-2)}
21083
+ .knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
21084
+ .knobs-wt-failed{display:flex;align-items:center;justify-content:center;min-height:80px;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
21085
+
21086
+ /* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
21087
+ hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
21088
+ :where(.knobs-wt-history,.knobs-wt-stack,.knobs-wt-tablebox,.knobs-wt-chapters){--kw-line:var(--_k-leading-body);--kw-rail:var(--_k-border-strong)}
21089
+ :where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
21090
+ :where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
21091
+ :where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
21092
+ :where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
21093
+ :where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
21094
+ .knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
21095
+ .knobs-ui .knobs-wt-tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-2);font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);
21096
+ text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
21097
+ .knobs-ui a.knobs-wt-tag:is(:hover,:focus-visible){background:var(--_k-fill-selected);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
21098
+
21099
+ /* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
21100
+ dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
21101
+ .knobs-wt-history{--kw-hy:calc(5px + var(--kw-line) / 2);display:flex;flex-direction:column;gap:18px;font-size:var(--_k-type-body);line-height:var(--kw-line);color:var(--_k-fg)}
21102
+ .knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
21103
+ .knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
21104
+ .knobs-ui .knobs-wt-hheading{margin:0;font:var(--_k-weight-label) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);letter-spacing:.04em;text-transform:uppercase;color:var(--_k-fg-2)}
21105
+ .knobs-wt-hsum{color:var(--_k-fg-3);font-size:var(--_k-type-small);font-variant-numeric:tabular-nums}
21106
+ .knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
21107
+ .knobs-wt-hev{display:grid;grid-template-columns:var(--kw-hw,11ch) 14px minmax(0,1fr);grid-template-areas:"when spine main";column-gap:10px;align-items:baseline;padding:5px 0}
21108
+ .knobs-wt-hwhen{grid-area:when;display:flex;flex-direction:column;min-width:0;font:var(--_k-weight) var(--_k-type-label)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
21109
+ .knobs-wt-hage{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
21110
+ .knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
21111
+ .knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
21112
+ .knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
21113
+ .knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
21114
+ .knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
21115
+ .knobs-wt-hdot{position:absolute;left:3.5px;top:calc(var(--kw-hy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--kw-tone,var(--_k-fg-3))}
21116
+ .knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
21117
+ .knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
21118
+ .knobs-wt-hev[data-provenance="inferred"] .knobs-wt-hdot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--kw-tone,var(--_k-fg-3))}
21119
+ .knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
21120
+ .knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
21121
+ .knobs-wt-prov{padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-3);font:var(--_k-weight) var(--_k-type-small)/18px var(--_k-mono);white-space:nowrap}
21122
+ .knobs-wt-hev[data-provenance="inferred"] .knobs-wt-prov{background:transparent;color:var(--_k-warn);outline:1px dashed color-mix(in oklch,var(--_k-warn) 50%,transparent);outline-offset:-1px}
21123
+ .knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
21124
+ @container knobs-wt-slot (max-width:520px){
21125
+ .knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
21126
+ .knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
21127
+ }
21128
+
21129
+ /* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
21130
+ git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
21131
+ .knobs-wt-stack{--kw-spt:7px;--kw-spb:7px;--kw-sy:calc(var(--kw-spt) + var(--kw-line) / 2);display:flex;flex-direction:column;font-size:var(--_k-type-body);line-height:var(--kw-line);color:var(--_k-fg)}
21132
+ .knobs-wt-srow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;column-gap:10px;align-items:start;margin:0 -8px;padding:var(--kw-spt) 8px var(--kw-spb);
21133
+ border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
21134
+ .knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
21135
+ .knobs-wt-srow[data-go]{cursor:pointer}
21136
+ .knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
21137
+ .knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
21138
+ .knobs-wt-lane{position:relative;flex:none;width:16px}
21139
+ .knobs-wt-lane:is([data-rail="pass"],[data-rail="tee"],[data-down])::before{content:"";position:absolute;left:7.5px;top:0;bottom:0;width:1px;background:var(--kw-rail)}
21140
+ .knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
21141
+ .knobs-wt-lane:is([data-rail="tee"],[data-rail="end"])::after{content:"";position:absolute;left:7.5px;top:0;width:13px;height:calc(var(--kw-sy) + .5px);border:solid var(--kw-rail);border-width:0 0 1px 1px;border-bottom-left-radius:6px}
21142
+ .knobs-wt-lane[data-rail="node"]::after{content:"";position:absolute;left:4.5px;top:calc(var(--kw-sy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--_k-fg-3)}
21143
+ .knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
21144
+ .knobs-wt-trunk{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
21145
+ .knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
21146
+ .knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
21147
+ .knobs-wt-sord{font:var(--_k-weight) var(--_k-type-label)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3);white-space:nowrap}
21148
+ .knobs-ui .knobs-wt-spr{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2);text-decoration:none;white-space:nowrap}
21149
+ .knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
21150
+ .knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
21151
+ .knobs-ui button.knobs-wt-stitle{cursor:pointer;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
21152
+ .knobs-ui :is(.knobs-wt-srow[data-go]:hover button.knobs-wt-stitle,button.knobs-wt-stitle:focus-visible){text-decoration-color:color-mix(in oklch,currentColor 45%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
21153
+ .knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
21154
+ .knobs-wt-smeta{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 12px;font:var(--_k-weight) var(--_k-type-small)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
21155
+ .knobs-wt-delta{display:inline-flex;gap:6px}
21156
+ .knobs-wt-add{color:var(--_k-diff-add)}
21157
+ .knobs-wt-del{color:var(--_k-diff-del)}
21158
+ .knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
21159
+ .knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
21160
+ .knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
21161
+ @container knobs-wt-slot (max-width:520px){
21162
+ .knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
21163
+ .knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
21164
+ .knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
21165
+ }
21166
+
21167
+ /* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
21168
+ (the top one under the head), and thin bars show on hover. */
21169
+ /* Too narrow for its columns, each row becomes a block: its primary cell titling the rest as term
21170
+ and value, the blocks parted by hairlines. Scrolling sideways is the last resort (stack: never). */
21171
+ .knobs-wt-tablebox{min-width:0}
21172
+ .knobs-wt-tablebox[data-measure] table{width:min-content}
21173
+ .knobs-wt-tstack{display:none;flex-direction:column;min-width:0}
21174
+ .knobs-wt-tablebox[data-stacked]>.knobs-wt-table{display:none}
21175
+ .knobs-wt-tablebox[data-stacked]>.knobs-wt-tstack{display:flex}
21176
+ .knobs-wt-trow{display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0;padding-block:var(--_k-space-title);box-shadow:inset 0 -1px 0 var(--_k-border-subtle)}
21177
+ .knobs-wt-trow:first-child{padding-top:0}
21178
+ .knobs-wt-trow:last-of-type{padding-bottom:0;box-shadow:none}
21179
+ .knobs-wt-tline{display:flex;align-items:baseline;justify-content:space-between;gap:var(--_k-space-title);min-width:0}
21180
+ .knobs-wt-tbadges{flex:none;display:flex;align-items:center;gap:var(--_k-space-inside)}
21181
+ .knobs-wt-ttitle{flex:1 1 auto;min-width:0;color:var(--_k-fg);font-weight:var(--_k-weight-label);overflow-wrap:anywhere}
21182
+ .knobs-wt-ttitle[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label)}
21183
+ .knobs-wt-tterms{display:grid;grid-template-columns:minmax(6ch,max-content) minmax(0,1fr);gap:var(--_k-space-inside) var(--_k-space-title);min-width:0}
21184
+ .knobs-wt-tterms dt{color:var(--_k-fg-3);font-size:var(--_k-type-small)}
21185
+ .knobs-wt-tterms dd{min-width:0;color:var(--_k-fg-2);overflow-wrap:anywhere}
21186
+ .knobs-wt-tterms dd[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg)}
21187
+ .knobs-wt-tcaption{padding-top:var(--_k-space-sibling);color:var(--_k-fg-3);font-size:var(--_k-type-small)}
21188
+ @property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
21189
+ @property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
21190
+ @keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
21191
+ @keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
21192
+ .knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
21193
+ transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
21194
+ .knobs-wt-table:is(:hover,:focus-visible){scrollbar-color:color-mix(in oklch,var(--_k-fg) 28%,transparent) transparent;transition-duration:calc(var(--_k-hover-in) * 1ms)}
21195
+ .knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
21196
+ @supports (animation-timeline:scroll()){
21197
+ .knobs-wt-table{animation:knobs-fade-a linear both,knobs-fade-b linear both,kw-fade-l linear both,kw-fade-r linear both;animation-duration:auto;
21198
+ animation-timeline:scroll(self block),scroll(self block),scroll(self inline),scroll(self inline);animation-range:0 24px,calc(100% - 24px) 100%,0 8px,calc(100% - 8px) 100%;
21199
+ --kw-table-mask-y:linear-gradient(to bottom,#000 var(--kw-thead,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--kw-thead,0px),#000 calc(var(--kw-thead,0px) + 20px),#000 calc(100% - 20px),rgb(0 0 0/var(--knobs-fade-b)));
21200
+ --kw-table-mask-x:linear-gradient(to right,rgb(0 0 0/var(--kw-fade-l)),#000 24px,#000 calc(100% - 24px),rgb(0 0 0/var(--kw-fade-r)));
21201
+ -webkit-mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);-webkit-mask-composite:source-in;mask-composite:intersect}
21202
+ }
21203
+ .knobs-wt-table table{width:100%;margin:0;border-collapse:separate;border-spacing:0;font-size:var(--_k-type-body);line-height:var(--_k-leading-body);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
21204
+ .knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
21205
+ .knobs-wt-table th{position:sticky;top:0;padding:0 12px 7px;text-align:left;vertical-align:bottom;font-weight:var(--_k-weight-label);font-size:var(--_k-type-small);color:var(--_k-fg-3);white-space:nowrap;
21206
+ background:var(--kw-under,var(--_k-pane-bg));box-shadow:inset 0 -1px 0 var(--_k-border)}
21207
+ .knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
21208
+ .knobs-wt-table tr:last-child td{box-shadow:none}
21209
+ .knobs-wt-table :is(th,td):first-child{padding-left:0}
21210
+ .knobs-wt-table :is(th,td):last-child{padding-right:0}
21211
+ .knobs-wt-table td:first-child{color:var(--_k-fg)}
21212
+ .knobs-wt-table [data-align="right"]{text-align:right}
21213
+ .knobs-wt-table [data-align="center"]{text-align:center}
21214
+ .knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg);white-space:nowrap}
21215
+ .knobs-wt-table td[data-long]{min-width:24ch}
21216
+ .knobs-ui :is(.knobs-wt-table,.knobs-wt-tstack) a.knobs-wt-chip{text-decoration:none}
21217
+ .knobs-wt-ctone{color:var(--kw-tone)}
21218
+
21219
+ /* Chapters: a readout list under a video or compare: number, label, start; the selection pill
21220
+ on the one playing, its rows bled out so their text sits on the media's edge. */
21221
+ .knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
21222
+ .knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
21223
+ .knobs-ui .knobs-wt-chapter{position:relative;display:grid;grid-template-columns:2ch minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;height:32px;padding:0 var(--_k-space-sibling);
21224
+ border-radius:var(--_k-radius);color:var(--_k-fg-2);text-align:left;white-space:nowrap;cursor:pointer;transition:color calc(var(--_k-hover-out) * 1ms)}
21225
+ .knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
21226
+ .knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
21227
+ .knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
21228
+ .knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
21229
+ .knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
21230
+ .knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
21231
+ @media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
21232
+ @media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
21233
+ `;
21234
+
20785
21235
  // src/ui/walkthrough-media.ts
20786
21236
  function injectWalkthroughStyles(doc) {
20787
21237
  if (doc.querySelector("style[data-knobs-ui-walkthrough]"))
@@ -21309,7 +21759,7 @@ function mediaSlot(container, options) {
21309
21759
  }
21310
21760
  };
21311
21761
  }
21312
- var CHECK3 = svg('<path d="m3.5 8.4 3 3 6-6.6"/>');
21762
+ var CHECK3 = icon("check", { small: true });
21313
21763
 
21314
21764
  // src/ui/walkthrough.ts
21315
21765
  var el2 = (doc, tag, cls) => {
@@ -21327,16 +21777,20 @@ var lookOf2 = (o) => ({
21327
21777
  ...o.preset ? { preset: o.preset } : {},
21328
21778
  ...o.theme ? { theme: o.theme } : {}
21329
21779
  });
21330
- var grid3 = (v) => Math.round(v * 64) / 64;
21780
+ var grid2 = (v) => Math.round(v * 64) / 64;
21331
21781
  var ICON = {
21332
- full: svg('<path d="M3 6.5V3h3.5M13 6.5V3H9.5M3 9.5V13h3.5M13 9.5V13H9.5"/>'),
21333
- exit: svg('<path d="M6.5 3v3.5H3M9.5 3v3.5H13M6.5 13V9.5H3M9.5 13V9.5H13"/>'),
21334
- pen: svg('<path d="M10.5 3.2 12.8 5.5 5.8 12.5 3 13l.5-2.8z"/><path d="M9.3 4.4l2.3 2.3"/>'),
21335
- mic: svg('<rect x="6" y="2.5" width="4" height="7" rx="2"/><path d="M3.8 8a4.2 4.2 0 0 0 8.4 0M8 12.2v1.8"/>'),
21782
+ full: icon("cornersOut"),
21783
+ exit: icon("cornersIn"),
21784
+ pen: icon("pencilSimple"),
21785
+ mic: icon("microphone"),
21336
21786
  stop: svg('<rect x="4.5" y="4.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none"/>'),
21337
- send: svg('<path d="M8 13V3.5M4 7.5 8 3.5l4 4"/>'),
21338
- close: svg('<path d="M4.5 4.5l7 7M11.5 4.5l-7 7"/>')
21787
+ send: icon("paperPlaneRight"),
21788
+ close: icon("x", { small: true }),
21789
+ back: icon("arrowLeft", { small: true }),
21790
+ out: icon("arrowUpRight", { small: true })
21339
21791
  };
21792
+ var DOCK_INSET = 12;
21793
+ var DOCK_GAP = 12;
21340
21794
  var CALM2 = springMotion(SPRINGS.calm);
21341
21795
  var SMOOTH = springMotion(SPRINGS.smooth);
21342
21796
  var BACK_MS = 4500;
@@ -21469,8 +21923,12 @@ function walkthrough(container, options) {
21469
21923
  let count = null;
21470
21924
  let fill = null;
21471
21925
  let tocEl = null;
21472
- let mark = null;
21926
+ let pill = null;
21927
+ let tocRows = [];
21928
+ let discs = [];
21473
21929
  let full = null;
21930
+ const noteMode = options.noteBar ?? "collapsed";
21931
+ let reserve = noteBarReserve(52, DOCK_INSET, DOCK_GAP);
21474
21932
  const viewOf = (key) => views.find((v) => v.step.key === key);
21475
21933
  const feedback = () => collectFeedback(page, state);
21476
21934
  const markdown = () => feedbackMarkdown(feedback(), page.verdicts);
@@ -21494,9 +21952,6 @@ function walkthrough(container, options) {
21494
21952
  else
21495
21953
  run();
21496
21954
  };
21497
- const pillY = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
21498
- const pillH = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
21499
- let pillPlaced = false;
21500
21955
  const scroll = {
21501
21956
  spring: new Spring(0, CALM2.omega, CALM2.zeta, 0.5),
21502
21957
  to: null,
@@ -21504,13 +21959,6 @@ function walkthrough(container, options) {
21504
21959
  };
21505
21960
  const motion = frameLoop(win, (dt) => {
21506
21961
  let more = false;
21507
- if (mark) {
21508
- pillY.step(dt);
21509
- pillH.step(dt);
21510
- mark.style.transform = `translateY(${grid3(pillY.x)}px)`;
21511
- mark.style.height = `${grid3(pillY.x + pillH.x) - grid3(pillY.x)}px`;
21512
- more ||= !pillY.resting || !pillH.resting;
21513
- }
21514
21962
  if (scroll.to && scroll.el) {
21515
21963
  scroll.spring.set(scrollTarget(scroll.to, scroll.el));
21516
21964
  scroll.spring.step(dt);
@@ -21574,21 +22022,12 @@ function walkthrough(container, options) {
21574
22022
  v.glyph.dataset.tone = v.step.ask === "none" ? "none" : verdict ? verdictTone(verdict, page.verdicts.findIndex((x) => x.id === verdict)) : done ? "accent" : "dim";
21575
22023
  };
21576
22024
  const placeMark = () => {
21577
- if (!mark || !tocEl)
22025
+ if (!pill || !tocEl)
21578
22026
  return;
22027
+ pill.update();
21579
22028
  const row = viewOf(current)?.toc;
21580
22029
  if (!row)
21581
- return void mark.removeAttribute("data-on");
21582
- mark.dataset.on = "";
21583
- if (!pillPlaced || reduced()) {
21584
- pillY.snap(row.offsetTop);
21585
- pillH.snap(row.offsetHeight);
21586
- pillPlaced = true;
21587
- } else {
21588
- pillY.set(row.offsetTop);
21589
- pillH.set(row.offsetHeight);
21590
- }
21591
- motion.wake();
22030
+ return;
21592
22031
  const top = row.offsetTop;
21593
22032
  const bottom = top + row.offsetHeight;
21594
22033
  if (top < tocEl.scrollTop + 8)
@@ -21605,6 +22044,9 @@ function walkthrough(container, options) {
21605
22044
  const v = viewOf(key);
21606
22045
  v?.card.setAttribute("data-current", "");
21607
22046
  v?.toc?.setAttribute("aria-current", "step");
22047
+ for (const r of tocRows)
22048
+ if (r.dataset.section)
22049
+ r.toggleAttribute("data-active", r.dataset.section === v?.step.section);
21608
22050
  if (key)
21609
22051
  record({ what: "step", step: key });
21610
22052
  placeMark();
@@ -21621,6 +22063,16 @@ function walkthrough(container, options) {
21621
22063
  else
21622
22064
  break;
21623
22065
  }
22066
+ const s = scrollerOf(root);
22067
+ if (s.scrollTop > 0 && s.scrollTop >= s.scrollHeight - s.clientHeight - 2) {
22068
+ const bottom = (s === doc.scrollingElement ? win.innerHeight : s.getBoundingClientRect().bottom) - reserve;
22069
+ for (let i = views.length - 1;i >= 0; i--) {
22070
+ if (views[i].card.getBoundingClientRect().top < bottom) {
22071
+ pick = views[i].step.key;
22072
+ break;
22073
+ }
22074
+ }
22075
+ }
21624
22076
  setCurrent(pick);
21625
22077
  };
21626
22078
  let scrollRaf = 0;
@@ -21663,15 +22115,20 @@ function walkthrough(container, options) {
21663
22115
  };
21664
22116
  const scrim = el2(doc, "div", "knobs-wt-scrim");
21665
22117
  scrim.addEventListener("click", () => setFull(false));
21666
- const fullRect = () => ({ x: 12, y: 12, w: win.innerWidth - 24, h: win.innerHeight - 24 });
22118
+ const fullRect = () => ({
22119
+ x: DOCK_INSET,
22120
+ y: DOCK_INSET,
22121
+ w: win.innerWidth - DOCK_INSET * 2,
22122
+ h: win.innerHeight - DOCK_INSET - reserve
22123
+ });
21667
22124
  const placeFull = (f) => {
21668
22125
  const a = f.hold.getBoundingClientRect();
21669
22126
  const b = fullRect();
21670
22127
  const k = reduced() ? Math.round(f.p.target) : f.p.x;
21671
- const left = grid3(a.left + (b.x - a.left) * k);
21672
- const top = grid3(a.top + (b.y - a.top) * k);
21673
- const right = grid3(a.right + (b.x + b.w - a.right) * k);
21674
- const bottom = grid3(a.bottom + (b.y + b.h - a.bottom) * k);
22128
+ const left = grid2(a.left + (b.x - a.left) * k);
22129
+ const top = grid2(a.top + (b.y - a.top) * k);
22130
+ const right = grid2(a.right + (b.x + b.w - a.right) * k);
22131
+ const bottom = grid2(a.bottom + (b.y + b.h - a.bottom) * k);
21675
22132
  const s = f.v.card.style;
21676
22133
  s.left = `${left}px`;
21677
22134
  s.top = `${top}px`;
@@ -21808,6 +22265,7 @@ function walkthrough(container, options) {
21808
22265
  ink.on = true;
21809
22266
  ink.layer.dataset.on = "";
21810
22267
  root.dataset.inking = "";
22268
+ bar.setOpen(true);
21811
22269
  bar.sync();
21812
22270
  };
21813
22271
  const voice = {
@@ -21847,6 +22305,7 @@ function walkthrough(container, options) {
21847
22305
  });
21848
22306
  voice.recorder = rec;
21849
22307
  voice.started = performance.now();
22308
+ bar.setOpen(true);
21850
22309
  rec.start();
21851
22310
  voice.timer = win.setInterval(() => bar.sync(), 250);
21852
22311
  bar.sync();
@@ -21873,7 +22332,10 @@ function walkthrough(container, options) {
21873
22332
  if (!v)
21874
22333
  return;
21875
22334
  backTo = key;
21876
- backPill.textContent = `← Back to ${v.step.number}`;
22335
+ backPill.innerHTML = ICON.back;
22336
+ const words = el2(doc, "span", "knobs-wt-back-label");
22337
+ words.textContent = `Back to ${plainMarkdown(v.step.title)}`;
22338
+ backPill.append(words);
21877
22339
  backPill.dataset.on = "";
21878
22340
  win.clearTimeout(backTimer);
21879
22341
  backTimer = win.setTimeout(hideBack, BACK_MS);
@@ -21905,7 +22367,41 @@ function walkthrough(container, options) {
21905
22367
  sendBtn.dataset.send = "";
21906
22368
  row.append(input, attach, fullBtn, penBtn, micBtn, sendBtn);
21907
22369
  box.append(on, row);
21908
- dock.append(backPill, box);
22370
+ const launch = el2(doc, "button", "knobs-wt-launch");
22371
+ launch.type = "button";
22372
+ launch.innerHTML = ICON.pen;
22373
+ launch.append("Note");
22374
+ const kbd = el2(doc, "kbd");
22375
+ kbd.textContent = "n";
22376
+ launch.append(kbd);
22377
+ launch.setAttribute("aria-label", "Write a note (n)");
22378
+ launch.addEventListener("click", () => setOpen(true, true));
22379
+ dock.dataset.mode = noteMode;
22380
+ dock.append(backPill, box, launch);
22381
+ let open = noteMode !== "collapsed";
22382
+ const setOpen = (on, focus = false) => {
22383
+ if (noteMode === "collapsed" && on !== open) {
22384
+ open = on;
22385
+ dock.toggleAttribute("data-open", on);
22386
+ box.inert = !on;
22387
+ launch.inert = on;
22388
+ syncReserve();
22389
+ }
22390
+ if (on && focus)
22391
+ input.focus({ preventScroll: true });
22392
+ };
22393
+ dock.toggleAttribute("data-open", open);
22394
+ box.inert = !open;
22395
+ launch.inert = open;
22396
+ const empty = () => !input.value.trim() && !voice.pending && !voice.recorder && !ink.on && !ink.paths.length;
22397
+ const onOutside = (e) => {
22398
+ if (open && noteMode === "collapsed" && !dock.contains(e.target) && empty())
22399
+ setOpen(false);
22400
+ };
22401
+ doc.addEventListener("pointerdown", onOutside, true);
22402
+ const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => syncReserve()) : null;
22403
+ ro?.observe(box);
22404
+ ro?.observe(launch);
21909
22405
  const fit = () => {
21910
22406
  input.style.height = "auto";
21911
22407
  input.style.height = `${Math.min(140, input.scrollHeight)}px`;
@@ -21921,6 +22417,8 @@ function walkthrough(container, options) {
21921
22417
  } else if (e.key === "Escape") {
21922
22418
  e.preventDefault();
21923
22419
  input.blur();
22420
+ if (empty())
22421
+ setOpen(false);
21924
22422
  viewOf(current)?.card.focus({ preventScroll: true });
21925
22423
  }
21926
22424
  });
@@ -21940,13 +22438,13 @@ function walkthrough(container, options) {
21940
22438
  const sync = () => {
21941
22439
  const v = viewOf(current);
21942
22440
  const ctx = describeMedia(mediaContext(v));
21943
- const where = v ? `${v.step.number} ${v.step.title}` : "General note";
22441
+ const where = v ? plainMarkdown(v.step.title) : "General note";
21944
22442
  const text = ctx ? `${where} · ${ctx}` : where;
21945
22443
  if (text !== lastOn) {
21946
22444
  on.textContent = text;
21947
22445
  lastOn = text;
21948
22446
  }
21949
- input.placeholder = v ? `Note on ${v.step.number}… (n)` : "A note on the whole page… (n)";
22447
+ input.placeholder = v ? "A note on this step… (n)" : "A note on the whole page… (n)";
21950
22448
  const attached = `${voice.pending?.url ?? ""}|${ink.paths.length}`;
21951
22449
  if (attached !== lastAttached) {
21952
22450
  lastAttached = attached;
@@ -21985,14 +22483,45 @@ function walkthrough(container, options) {
21985
22483
  };
21986
22484
  return {
21987
22485
  dock,
22486
+ box,
22487
+ launch,
21988
22488
  input,
21989
22489
  sync,
22490
+ get open() {
22491
+ return open;
22492
+ },
22493
+ setOpen,
22494
+ empty,
22495
+ unobserve: () => {
22496
+ ro?.disconnect();
22497
+ doc.removeEventListener("pointerdown", onOutside, true);
22498
+ },
21990
22499
  clear() {
21991
22500
  input.value = "";
21992
22501
  fit();
21993
22502
  }
21994
22503
  };
21995
22504
  })();
22505
+ let padded = null;
22506
+ function syncReserve() {
22507
+ if (disposed)
22508
+ return;
22509
+ const h = (bar.open ? bar.box : bar.launch).offsetHeight;
22510
+ if (noteMode === "hidden")
22511
+ reserve = 0;
22512
+ else if (h)
22513
+ reserve = noteBarReserve(h, DOCK_INSET, DOCK_GAP);
22514
+ root.style.setProperty("--kw-reserve", `${reserve}px`);
22515
+ const s = scrollerOf(root);
22516
+ if (padded?.el !== s) {
22517
+ if (padded)
22518
+ padded.el.style.scrollPaddingBottom = padded.was;
22519
+ padded = { el: s, was: s.style.scrollPaddingBottom };
22520
+ }
22521
+ s.style.scrollPaddingBottom = `${reserve}px`;
22522
+ if (full)
22523
+ placeFull(full);
22524
+ }
21996
22525
  const ticker = win.setInterval(() => !doc.hidden && bar.sync(), 500);
21997
22526
  const send = (text = bar.input.value) => {
21998
22527
  if (voice.recorder)
@@ -22028,6 +22557,10 @@ function walkthrough(container, options) {
22028
22557
  syncProgress();
22029
22558
  emit();
22030
22559
  bar.sync();
22560
+ if (noteMode === "collapsed") {
22561
+ bar.input.blur();
22562
+ bar.setOpen(false);
22563
+ }
22031
22564
  if (v && options.advance !== false) {
22032
22565
  const to = adjacentStep(views.map((x) => x.step.key), v.step.key, 1);
22033
22566
  if (to && to !== v.step.key) {
@@ -22035,7 +22568,8 @@ function walkthrough(container, options) {
22035
22568
  setFull(false);
22036
22569
  go(to);
22037
22570
  showBack(v.step.key);
22038
- bar.input.focus({ preventScroll: true });
22571
+ if (noteMode === "docked")
22572
+ bar.input.focus({ preventScroll: true });
22039
22573
  }
22040
22574
  }
22041
22575
  };
@@ -22122,22 +22656,105 @@ function walkthrough(container, options) {
22122
22656
  row.addEventListener("transitionend", done, { once: true });
22123
22657
  win.setTimeout(done, 600);
22124
22658
  };
22659
+ const metaLine = (cls) => el2(doc, "div", `knobs-wt-metaline ${cls}`);
22660
+ const metaText = (line, text, cls) => {
22661
+ const s = el2(doc, "span", cls);
22662
+ s.textContent = text;
22663
+ line.append(s);
22664
+ return s;
22665
+ };
22666
+ const metaLink = (line, text, href) => {
22667
+ const a = el2(doc, "a");
22668
+ a.href = href;
22669
+ a.target = "_blank";
22670
+ a.rel = "noreferrer";
22671
+ a.textContent = text;
22672
+ a.insertAdjacentHTML("beforeend", ICON.out);
22673
+ line.append(a);
22674
+ return a;
22675
+ };
22676
+ const feedItem = (f, now) => {
22677
+ const li = el2(doc, "li", "knobs-wt-fi");
22678
+ li.dataset.kind = f.kind;
22679
+ const q = el2(doc, "div", "knobs-wt-fi-q");
22680
+ const meta = metaLine("knobs-wt-fi-meta");
22681
+ if (f.at !== null) {
22682
+ const when = metaText(meta, ago(f.at, now));
22683
+ when.title = new Date(f.at).toLocaleString();
22684
+ } else
22685
+ metaText(meta, f.kind === "qa" ? "Answer" : "Update");
22686
+ const step = f.step ? page.steps.find((s) => s.key === f.step) : undefined;
22687
+ if (step) {
22688
+ const section = page.sections.find((s) => s.id === step.section);
22689
+ const b = el2(doc, "button", "knobs-wt-fi-step");
22690
+ b.type = "button";
22691
+ b.textContent = section?.link?.label ?? plainMarkdown(step.title);
22692
+ b.title = `Go to “${plainMarkdown(step.title)}”`;
22693
+ b.addEventListener("click", () => go(step.key));
22694
+ meta.append(b);
22695
+ }
22696
+ if (f.status) {
22697
+ const id = f.status.toLowerCase();
22698
+ const shipped = /^(ship|shipped|merged|done)$/.test(id);
22699
+ const changes = /^(changes?|changes queued)$/.test(id);
22700
+ const s = metaText(meta, shipped ? "Shipped" : changes ? "Changes queued" : f.status);
22701
+ s.dataset.status = shipped ? "on" : changes ? "warn" : "";
22702
+ }
22703
+ q.append(meta);
22704
+ if (f.q)
22705
+ q.append(prose2(doc, "p", "knobs-wt-fi-ask", f.q));
22706
+ else
22707
+ q.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
22708
+ li.append(q);
22709
+ if (f.q || f.trail.length) {
22710
+ const a = el2(doc, "div", "knobs-wt-fi-a");
22711
+ if (f.q)
22712
+ a.append(prose2(doc, "div", "knobs-wt-fi-answer", f.text));
22713
+ if (f.trail.length) {
22714
+ const list = el2(doc, "ol", "knobs-wt-trail");
22715
+ for (const line of f.trail) {
22716
+ const i = line.indexOf(" · ");
22717
+ const row = el2(doc, "li");
22718
+ const words = el2(doc, "span", "knobs-wt-trail-text");
22719
+ words.textContent = i < 0 ? line : line.slice(i + 3);
22720
+ row.append(words);
22721
+ if (i >= 0) {
22722
+ const at = el2(doc, "span", "knobs-wt-trail-at");
22723
+ at.textContent = line.slice(0, i);
22724
+ row.append(at);
22725
+ }
22726
+ list.append(row);
22727
+ }
22728
+ discs.push(disclosure(a, { label: "Context", count: f.trail.length, content: list }));
22729
+ }
22730
+ li.append(a);
22731
+ }
22732
+ return li;
22733
+ };
22125
22734
  const build = () => {
22126
22735
  for (const v of views) {
22127
22736
  v.slots.forEach((s) => s.dispose());
22128
22737
  v.taste?.dispose();
22129
22738
  }
22739
+ for (const d of discs)
22740
+ d.dispose();
22741
+ discs = [];
22742
+ pill?.dispose();
22743
+ pill = null;
22744
+ tocRows = [];
22130
22745
  if (full) {
22131
22746
  full.p.snap(0);
22132
22747
  closeFull();
22133
22748
  }
22134
22749
  clearInk();
22135
22750
  views = [];
22136
- pillPlaced = false;
22137
22751
  root.textContent = "";
22138
22752
  root.removeAttribute("data-settled");
22753
+ root.dataset.rail = options.rail === false ? "none" : options.rail === "left" ? "left" : "right";
22754
+ root.toggleAttribute("data-cards", options.cards === true);
22139
22755
  const layout = el2(doc, "div", "knobs-wt-layout");
22140
22756
  const main = el2(doc, "div", "knobs-wt-main");
22757
+ const flow = el2(doc, "div", "knobs-wt-flow");
22141
22758
  const head = el2(doc, "header", "knobs-wt-head");
22142
22759
  const h1 = el2(doc, "h1", "knobs-wt-title");
22143
22760
  h1.textContent = page.title;
@@ -22164,42 +22781,27 @@ function walkthrough(container, options) {
22164
22781
  }
22165
22782
  head.append(meta);
22166
22783
  }
22167
- main.append(head);
22784
+ flow.append(head);
22785
+ let feedEl = null;
22168
22786
  if (page.feed.length) {
22169
- const feed = el2(doc, "section", "knobs-wt-feed");
22170
- feed.setAttribute("aria-label", "Latest");
22171
- const list = el2(doc, "ol", "knobs-wt-feed-list knobs-scroll-fade");
22787
+ feedEl = el2(doc, "section", "knobs-wt-feed");
22788
+ feedEl.id = "wt-latest";
22789
+ feedEl.setAttribute("aria-label", "Updates and answers");
22790
+ const fh = el2(doc, "header", "knobs-wt-feed-head");
22791
+ const h = el2(doc, "h2", "knobs-wt-feed-title");
22792
+ h.textContent = page.feed.some((f) => f.kind === "qa") ? "Updates & Q&A" : "Updates";
22793
+ const n = el2(doc, "span", "knobs-wt-feed-count");
22794
+ n.textContent = String(page.feed.length);
22795
+ fh.append(h, n);
22796
+ const list = el2(doc, "ol", "knobs-wt-feed-list");
22172
22797
  const now = Date.now();
22173
- for (const f of page.feed) {
22174
- const li = el2(doc, "li", "knobs-wt-fi");
22175
- li.dataset.kind = f.kind;
22176
- const when = el2(doc, "span", "knobs-wt-fi-when");
22177
- when.textContent = f.at === null ? "" : ago(f.at, now);
22178
- if (f.at !== null)
22179
- when.title = new Date(f.at).toLocaleString();
22180
- const kind = el2(doc, "span", "knobs-wt-fi-kind");
22181
- kind.textContent = f.kind === "qa" ? "Answer" : "Update";
22182
- const body = el2(doc, "div", "knobs-wt-fi-body");
22183
- if (f.q)
22184
- body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
22185
- body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
22186
- li.append(when, kind, body);
22187
- if (f.step) {
22188
- const target = f.step;
22189
- const link = el2(doc, "button", "knobs-wt-fi-step");
22190
- link.type = "button";
22191
- link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
22192
- link.title = "Go to the step";
22193
- link.addEventListener("click", () => go(target));
22194
- li.append(link);
22195
- }
22196
- list.append(li);
22197
- }
22198
- feed.append(list);
22199
- main.append(feed);
22798
+ for (const f of page.feed)
22799
+ list.append(feedItem(f, now));
22800
+ feedEl.append(fh, list);
22801
+ flow.append(feedEl);
22200
22802
  }
22201
22803
  let rail = null;
22202
- count = fill = tocEl = mark = null;
22804
+ count = fill = tocEl = null;
22203
22805
  if (options.rail !== false) {
22204
22806
  rail = el2(doc, "aside", "knobs-wt-rail");
22205
22807
  rail.setAttribute("aria-label", "Progress");
@@ -22211,8 +22813,17 @@ function walkthrough(container, options) {
22211
22813
  progress.append(count, meter);
22212
22814
  tocEl = el2(doc, "nav", "knobs-wt-toc");
22213
22815
  tocEl.setAttribute("aria-label", "Contents");
22214
- mark = el2(doc, "div", "knobs-wt-toc-mark");
22215
- tocEl.append(mark);
22816
+ const ns = page.sections.map((s) => s.kicker && s.link ? s.link.label : "");
22817
+ const nw = Math.max(0, ...ns.map((n) => n.length));
22818
+ tocEl.style.setProperty("--kw-toc-n", nw ? `${nw + 0.5}ch` : "0px");
22819
+ if (!nw)
22820
+ tocEl.dataset.bare = "";
22821
+ if (feedEl) {
22822
+ const group = el2(doc, "div", "knobs-wt-toc-group");
22823
+ const target = feedEl;
22824
+ group.append(tocRow("Latest", "", String(page.feed.length), false, () => target.scrollIntoView({ block: "start", behavior: reduced() ? "auto" : "smooth" })));
22825
+ tocEl.append(group);
22826
+ }
22216
22827
  rail.append(progress, tocEl, actions(true));
22217
22828
  if (options.keys !== false) {
22218
22829
  const keys = el2(doc, "div", "knobs-wt-keys");
@@ -22224,45 +22835,44 @@ function walkthrough(container, options) {
22224
22835
  const sec = el2(doc, "section", "knobs-wt-section");
22225
22836
  sec.id = `wt-${section.id}`;
22226
22837
  const sh = el2(doc, "header", "knobs-wt-shead");
22227
- if (section.link || section.status) {
22228
- const kicker = el2(doc, "div", "knobs-wt-kicker");
22229
- if (section.link) {
22230
- const a = el2(doc, "a");
22231
- a.href = section.link.href;
22232
- a.target = "_blank";
22233
- a.rel = "noreferrer";
22234
- a.textContent = `${section.link.label} ↗`;
22235
- kicker.append(a);
22236
- }
22838
+ if (section.kicker || section.link || section.status) {
22839
+ const meta = metaLine("knobs-wt-kicker");
22840
+ if (section.kicker)
22841
+ metaText(meta, section.kicker, "knobs-wt-kicker-lead");
22842
+ if (section.link)
22843
+ metaLink(meta, section.link.label, section.link.href);
22237
22844
  if (section.status) {
22238
22845
  const s = statusLook(section.status);
22239
- const chip = el2(doc, "span", "knobs-wt-chip");
22240
- chip.dataset.tone = s.tone;
22241
- chip.textContent = s.label;
22242
- kicker.append(chip);
22846
+ metaText(meta, s.label, "knobs-wt-status").dataset.tone = s.tone;
22243
22847
  }
22244
- sh.append(kicker);
22848
+ sh.append(meta);
22245
22849
  }
22246
- const h2 = el2(doc, "h2", "knobs-wt-stitle");
22247
- h2.textContent = section.title;
22850
+ const h2 = el2(doc, "h2", "knobs-wt-heading");
22851
+ h2.innerHTML = inlineMarkdown(section.title);
22248
22852
  sh.append(h2);
22853
+ const intro = el2(doc, "div", "knobs-wt-sintro");
22854
+ intro.append(sh);
22249
22855
  if (section.summary)
22250
- sh.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
22251
- sec.append(sh);
22856
+ intro.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
22857
+ sec.append(intro);
22858
+ let group = null;
22252
22859
  if (tocEl) {
22253
- const t = el2(doc, "div", "knobs-wt-toc-section");
22254
- t.textContent = section.link ? `${section.link.label} ${section.title}` : section.title;
22255
- t.title = section.title;
22256
- tocEl.append(t);
22860
+ group = el2(doc, "div", "knobs-wt-toc-group");
22861
+ const first = section.steps[0]?.key;
22862
+ const n = section.kicker && section.link ? section.link.label : "";
22863
+ group.append(tocRow(plainMarkdown(section.title), n, "", false, () => first ? go(first) : undefined, section.id));
22864
+ tocEl.append(group);
22257
22865
  }
22258
22866
  for (const step of section.steps) {
22259
- const v = stepView(step);
22867
+ const v = stepView(step, group);
22260
22868
  sec.append(v.card);
22261
22869
  views.push(v);
22262
22870
  }
22263
- main.append(sec);
22871
+ flow.append(sec);
22264
22872
  }
22265
- main.append(bar.dock);
22873
+ main.append(flow);
22874
+ if (noteMode !== "hidden")
22875
+ main.append(bar.dock);
22266
22876
  if (rail)
22267
22877
  layout.append(rail);
22268
22878
  layout.append(main);
@@ -22272,16 +22882,40 @@ function walkthrough(container, options) {
22272
22882
  for (const n of notesOn(state, v.step.key))
22273
22883
  renderNote(v, n);
22274
22884
  }
22885
+ if (tocEl)
22886
+ pill = selectionPill(tocEl, {
22887
+ selected: () => viewOf(current)?.toc ?? null,
22888
+ rows: () => tocRows
22889
+ });
22275
22890
  syncProgress();
22276
22891
  current = null;
22277
22892
  fromScroll();
22278
22893
  placeMark();
22279
22894
  bar.sync();
22895
+ syncReserve();
22280
22896
  win.requestAnimationFrame(() => win.requestAnimationFrame(() => {
22281
22897
  if (!disposed && !reduced())
22282
22898
  root.dataset.settled = "";
22283
22899
  }));
22284
22900
  };
22901
+ const tocRow = (label, n, end, sub, run, section) => {
22902
+ const b = el2(doc, "button", sub ? "knobs-wt-toc-row knobs-wt-toc-sub" : "knobs-wt-toc-row");
22903
+ b.type = "button";
22904
+ if (section)
22905
+ b.dataset.section = section;
22906
+ const ncol = el2(doc, "span", "knobs-wt-toc-n");
22907
+ ncol.textContent = n;
22908
+ const t = el2(doc, "span", "knobs-wt-toc-label");
22909
+ t.textContent = label;
22910
+ const e = el2(doc, "span", "knobs-wt-toc-end");
22911
+ e.textContent = end;
22912
+ b.title = label;
22913
+ b.append(ncol, t, e);
22914
+ b.addEventListener("mousedown", (ev) => ev.preventDefault());
22915
+ b.addEventListener("click", run);
22916
+ tocRows.push(b);
22917
+ return b;
22918
+ };
22285
22919
  const actions = (rail) => {
22286
22920
  const row = el2(doc, "div", "knobs-wt-actions");
22287
22921
  const btn = (text, run, primary = false) => {
@@ -22322,30 +22956,38 @@ function walkthrough(container, options) {
22322
22956
  toast("Couldn't reach the clipboard", { tone: "warn", look, doc });
22323
22957
  }
22324
22958
  };
22325
- const stepView = (step) => {
22326
- const card = el2(doc, "article", "knobs-wt-step knobs-surface");
22959
+ const stepView = (step, group) => {
22960
+ const card = el2(doc, "article", options.cards ? "knobs-wt-step knobs-surface" : "knobs-wt-step");
22327
22961
  card.id = `wt-${step.key.replace("/", "--")}`;
22328
22962
  card.tabIndex = -1;
22329
22963
  card.dataset.key = step.key;
22330
- card.setAttribute("aria-label", `${step.number} ${step.title}`);
22964
+ card.setAttribute("aria-label", plainMarkdown(step.title));
22331
22965
  const head = el2(doc, "header", "knobs-wt-step-head");
22332
- const num = el2(doc, "span", "knobs-wt-num");
22333
- num.textContent = step.number;
22334
22966
  const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
22335
- h3.textContent = step.title;
22336
- head.append(num, h3);
22337
- card.append(head);
22967
+ h3.innerHTML = inlineMarkdown(step.title);
22968
+ head.append(h3);
22338
22969
  if (step.caption)
22339
- card.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
22970
+ head.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
22971
+ card.append(head);
22340
22972
  const slots = [];
22341
22973
  const onEvent = (e) => record({ ...e, step: step.key });
22342
22974
  let media = null;
22343
22975
  if (step.media.length) {
22344
- media = el2(doc, "div", "knobs-wt-media");
22345
- media.style.setProperty("--kw-n", String(Math.min(step.media.length, 3)));
22346
- for (const m of step.media)
22347
- slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
22976
+ const grid = (list) => {
22977
+ const g = el2(doc, "div", "knobs-wt-media");
22978
+ g.style.setProperty("--kw-n", String(Math.min(list.length, step.columns)));
22979
+ for (const m of list)
22980
+ slots.push(mediaSlot(g, { ...look, media: m, onEvent, steps: stepLinks }));
22981
+ return g;
22982
+ };
22983
+ const [first, ...rest] = step.media;
22984
+ media = grid(step.more ? [first] : step.media);
22348
22985
  card.append(media);
22986
+ if (step.more && rest.length) {
22987
+ const holder = el2(doc, "div", "knobs-wt-more");
22988
+ discs.push(disclosure(holder, { label: step.more, count: rest.length, content: grid(rest) }));
22989
+ card.append(holder);
22990
+ }
22349
22991
  }
22350
22992
  let taste = null;
22351
22993
  if (step.question)
@@ -22370,16 +23012,11 @@ function walkthrough(container, options) {
22370
23012
  });
22371
23013
  let toc = null;
22372
23014
  let glyph = null;
22373
- if (tocEl) {
22374
- toc = el2(doc, "button", "knobs-wt-toc-step");
22375
- toc.type = "button";
23015
+ if (group) {
23016
+ toc = tocRow(plainMarkdown(step.title), "", "", true, () => go(step.key));
22376
23017
  glyph = el2(doc, "span", "knobs-wt-toc-glyph");
22377
- const label = el2(doc, "span", "knobs-wt-toc-label");
22378
- label.textContent = step.title;
22379
- toc.title = `${step.number} ${step.title}`;
22380
- toc.append(glyph, label);
22381
- toc.addEventListener("click", () => go(step.key));
22382
- tocEl.append(toc);
23018
+ toc.querySelector(".knobs-wt-toc-end").append(glyph);
23019
+ group.append(toc);
22383
23020
  }
22384
23021
  return { step, card, media, notes, toc, glyph, taste, slots };
22385
23022
  };
@@ -22438,15 +23075,21 @@ function walkthrough(container, options) {
22438
23075
  setFull(false);
22439
23076
  return go(next);
22440
23077
  }
23078
+ if ((key === "Home" || key === "End") && views.length) {
23079
+ claim();
23080
+ if (full)
23081
+ setFull(false);
23082
+ return go(views[key === "Home" ? 0 : views.length - 1].step.key);
23083
+ }
22441
23084
  if (key === "ArrowLeft" || key === "ArrowRight") {
22442
23085
  const d = (key === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 2 : 0.5);
22443
23086
  if (seekBy(d))
22444
23087
  claim();
22445
23088
  return;
22446
23089
  }
22447
- if (key === "n") {
23090
+ if (key === "n" && noteMode !== "hidden") {
22448
23091
  claim();
22449
- bar.input.focus({ preventScroll: true });
23092
+ bar.setOpen(true, true);
22450
23093
  return;
22451
23094
  }
22452
23095
  const v = viewOf(current);
@@ -22525,6 +23168,12 @@ function walkthrough(container, options) {
22525
23168
  win.removeEventListener(type, stopScroll);
22526
23169
  doc.removeEventListener("keydown", onKey);
22527
23170
  unregisterHints();
23171
+ bar.unobserve();
23172
+ pill?.dispose();
23173
+ for (const d of discs)
23174
+ d.dispose();
23175
+ if (padded)
23176
+ padded.el.style.scrollPaddingBottom = padded.was;
22528
23177
  for (const v of views) {
22529
23178
  v.slots.forEach((s) => s.dispose());
22530
23179
  v.taste?.dispose();