@kitlangton/knobs 0.4.0-next.1 → 0.4.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +164 -12
  2. package/dist/dev/{chunk-1qzffbpa.js → chunk-5pb7ymrd.js} +150 -46
  3. package/dist/dev/{chunk-ayb292zj.js → chunk-a7cjgy8x.js} +2 -2
  4. package/dist/dev/{chunk-8mabjeyk.js → chunk-dyq4m24m.js} +162 -1
  5. package/dist/dev/index.js +3 -3
  6. package/dist/panel.js +312 -46
  7. package/dist/review-react.js +18580 -0
  8. package/dist/review-solid.js +18482 -0
  9. package/dist/review.js +18488 -0
  10. package/dist/themes.js +281 -23
  11. package/dist/types/review/font.d.ts +13 -0
  12. package/dist/types/review/foundations.d.ts +175 -0
  13. package/dist/types/review/index.d.ts +13 -0
  14. package/dist/types/review/react.d.ts +1 -0
  15. package/dist/types/review/solid.d.ts +1 -0
  16. package/dist/types/themes/index.d.ts +7 -2
  17. package/dist/types/themes/review.d.ts +8 -0
  18. package/dist/types/tokens/schema.d.ts +180 -0
  19. package/dist/types/ui/compare-css.d.ts +1 -1
  20. package/dist/types/ui/compare-gpu.d.ts +6 -6
  21. package/dist/types/ui/compare-model.d.ts +85 -2
  22. package/dist/types/ui/compare.d.ts +18 -4
  23. package/dist/types/ui/diff.d.ts +4 -5
  24. package/dist/types/ui/history-css.d.ts +1 -0
  25. package/dist/types/ui/history-model.d.ts +249 -0
  26. package/dist/types/ui/history.d.ts +38 -0
  27. package/dist/types/ui/icons.d.ts +40 -0
  28. package/dist/types/ui/index.d.ts +8 -4
  29. package/dist/types/ui/player-css.d.ts +1 -0
  30. package/dist/types/ui/player.d.ts +51 -0
  31. package/dist/types/ui/review-look.d.ts +6 -0
  32. package/dist/types/ui/review-options.d.ts +28 -0
  33. package/dist/types/ui/selection-pill-css.d.ts +1 -0
  34. package/dist/types/ui/selection-pill.d.ts +106 -0
  35. package/dist/types/ui/timeline-model.d.ts +27 -0
  36. package/dist/types/ui/timeline.d.ts +16 -1
  37. package/dist/types/ui/tree.d.ts +3 -2
  38. package/dist/types/ui/walkthrough-annotations.d.ts +42 -0
  39. package/dist/types/ui/walkthrough-blocks.d.ts +87 -0
  40. package/dist/types/ui/walkthrough-media.d.ts +30 -1
  41. package/dist/types/ui/walkthrough-model.d.ts +469 -5
  42. package/dist/types/ui/walkthrough.d.ts +27 -5
  43. package/dist/ui-react.js +5124 -1031
  44. package/dist/ui-solid.js +5136 -1043
  45. package/dist/ui.js +6411 -2269
  46. package/package.json +13 -1
@@ -409,6 +409,24 @@ export declare const TOKENS: readonly [{
409
409
  readonly css: "var(--k-warn)";
410
410
  };
411
411
  readonly doc: "Modified lines.";
412
+ }, {
413
+ readonly name: "before";
414
+ readonly tier: "semantic";
415
+ readonly type: "color";
416
+ readonly group: "Data";
417
+ readonly source: {
418
+ readonly css: "var(--k-fg-3)";
419
+ };
420
+ readonly doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour.";
421
+ }, {
422
+ readonly name: "after";
423
+ readonly tier: "semantic";
424
+ readonly type: "color";
425
+ readonly group: "Data";
426
+ readonly source: {
427
+ readonly css: "var(--k-fg)";
428
+ };
429
+ readonly doc: "After in a comparison, and only After.";
412
430
  }, {
413
431
  readonly name: "series-1";
414
432
  readonly tier: "semantic";
@@ -510,6 +528,168 @@ export declare const TOKENS: readonly [{
510
528
  readonly value: "288px";
511
529
  };
512
530
  readonly doc: "Panel width.";
531
+ }, {
532
+ readonly name: "space-inside";
533
+ readonly tier: "semantic";
534
+ readonly type: "length";
535
+ readonly group: "Space";
536
+ readonly source: {
537
+ readonly css: "var(--k-unit)";
538
+ };
539
+ readonly doc: "Parts of one thing: an icon and its label, a meta line and its title.";
540
+ }, {
541
+ readonly name: "space-sibling";
542
+ readonly tier: "semantic";
543
+ readonly type: "length";
544
+ readonly group: "Space";
545
+ readonly source: {
546
+ readonly css: "calc(var(--k-unit) * 2)";
547
+ };
548
+ readonly doc: "Siblings in a group: buttons in a row, a list item's lines.";
549
+ }, {
550
+ readonly name: "space-title";
551
+ readonly tier: "semantic";
552
+ readonly type: "length";
553
+ readonly group: "Space";
554
+ readonly source: {
555
+ readonly css: "calc(var(--k-unit) * 3)";
556
+ };
557
+ readonly doc: "A heading and what it heads.";
558
+ }, {
559
+ readonly name: "space-group";
560
+ readonly tier: "semantic";
561
+ readonly type: "length";
562
+ readonly group: "Space";
563
+ readonly source: {
564
+ readonly css: "calc(var(--k-unit) * 12)";
565
+ };
566
+ readonly doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle).";
567
+ }, {
568
+ readonly name: "space-section";
569
+ readonly tier: "semantic";
570
+ readonly type: "length";
571
+ readonly group: "Space";
572
+ readonly source: {
573
+ readonly css: "calc(var(--k-unit) * 24)";
574
+ };
575
+ readonly doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle.";
576
+ }, {
577
+ readonly name: "space-column";
578
+ readonly tier: "semantic";
579
+ readonly type: "length";
580
+ readonly group: "Space";
581
+ readonly source: {
582
+ readonly css: "calc(var(--k-unit) * 6)";
583
+ };
584
+ readonly doc: "Columns: a contents rail and the page, media side by side.";
585
+ }, {
586
+ readonly name: "pad-page";
587
+ readonly tier: "semantic";
588
+ readonly type: "length";
589
+ readonly group: "Space";
590
+ readonly source: {
591
+ readonly css: "calc(var(--k-unit) * 6)";
592
+ };
593
+ readonly doc: "A page's edge; 16px under 640px wide.";
594
+ }, {
595
+ readonly name: "pad-card";
596
+ readonly tier: "semantic";
597
+ readonly type: "length";
598
+ readonly group: "Space";
599
+ readonly source: {
600
+ readonly css: "calc(var(--k-unit) * 3)";
601
+ };
602
+ readonly doc: "Inside a card or popover.";
603
+ }, {
604
+ readonly name: "type-heading";
605
+ readonly tier: "semantic";
606
+ readonly type: "length";
607
+ readonly group: "Type";
608
+ readonly source: {
609
+ readonly value: "20px";
610
+ };
611
+ readonly doc: "A page's title, weight 500.";
612
+ }, {
613
+ readonly name: "leading-heading";
614
+ readonly tier: "semantic";
615
+ readonly type: "length";
616
+ readonly group: "Type";
617
+ readonly source: {
618
+ readonly value: "28px";
619
+ };
620
+ readonly doc: "Line height for type-heading.";
621
+ }, {
622
+ readonly name: "type-title";
623
+ readonly tier: "semantic";
624
+ readonly type: "length";
625
+ readonly group: "Type";
626
+ readonly source: {
627
+ readonly value: "16px";
628
+ };
629
+ readonly doc: "Section titles (under their kicker), weight 500.";
630
+ }, {
631
+ readonly name: "leading-title";
632
+ readonly tier: "semantic";
633
+ readonly type: "length";
634
+ readonly group: "Type";
635
+ readonly source: {
636
+ readonly value: "24px";
637
+ };
638
+ readonly doc: "Line height for type-title.";
639
+ }, {
640
+ readonly name: "type-body";
641
+ readonly tier: "semantic";
642
+ readonly type: "length";
643
+ readonly group: "Type";
644
+ readonly source: {
645
+ readonly value: "13px";
646
+ };
647
+ readonly doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis.";
648
+ }, {
649
+ readonly name: "leading-body";
650
+ readonly tier: "semantic";
651
+ readonly type: "length";
652
+ readonly group: "Type";
653
+ readonly source: {
654
+ readonly value: "20px";
655
+ };
656
+ readonly doc: "Line height for type-body.";
657
+ }, {
658
+ readonly name: "type-label";
659
+ readonly tier: "semantic";
660
+ readonly type: "length";
661
+ readonly group: "Type";
662
+ readonly source: {
663
+ readonly value: "12px";
664
+ };
665
+ readonly doc: "Mono inside body text: code and paths.";
666
+ }, {
667
+ readonly name: "leading-label";
668
+ readonly tier: "semantic";
669
+ readonly type: "length";
670
+ readonly group: "Type";
671
+ readonly source: {
672
+ readonly value: "16px";
673
+ };
674
+ readonly doc: "Line height for type-label.";
675
+ }, {
676
+ readonly name: "type-small";
677
+ readonly tier: "semantic";
678
+ readonly type: "length";
679
+ readonly group: "Type";
680
+ readonly source: {
681
+ readonly value: "11px";
682
+ };
683
+ readonly doc: "Meta, controls, keys, timestamps; mono inside labels.";
684
+ }, {
685
+ readonly name: "leading-small";
686
+ readonly tier: "semantic";
687
+ readonly type: "length";
688
+ readonly group: "Type";
689
+ readonly source: {
690
+ readonly value: "16px";
691
+ };
692
+ readonly doc: "Line height for type-small.";
513
693
  }, {
514
694
  readonly name: "font-size";
515
695
  readonly tier: "semantic";
@@ -1 +1 @@
1
- export declare const compareCss = "\n:where(.knobs-compare,.knobs-compare *,.knobs-cmp-strip,.knobs-cmp-strip *){box-sizing:border-box}\n.knobs-ui.knobs-compare{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));--_ku-cmp-line:var(--_k-compare-divider);\n --_ku-cmp-stage:var(--_k-compare-stage);\n display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}\n.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:2px;height:24px;padding:0 2px}\n.knobs-cmp-modes{display:flex;align-items:center;gap:2px}\n.knobs-ui .knobs-cmp-mode,.knobs-ui .knobs-cmp-toggle{height:22px;padding:0 7px;border-radius:max(0px,calc(var(--_k-radius) - 2px));color:var(--_k-fg-3);cursor:pointer;white-space:nowrap;\n transition:color .15s,background .15s}\n.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible),.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}\n.knobs-ui .knobs-cmp-mode[aria-checked=\"true\"],.knobs-ui .knobs-cmp-toggle[aria-pressed=\"true\"]{color:var(--_k-fg);font-weight:var(--_k-weight-label)}\n.knobs-cmp-fill{flex:1}\n.knobs-cmp-toggle[hidden]{display:none}\n/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked\n data-nested, the stage drops its fill and the sides sit on that card. */\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-compare,.knobs-ui.knobs-compare[data-nested]{--_ku-cmp-stage:var(--k-compare-stage,transparent)}\n/* In a page's flow (a container with no height), it takes the height its sides need. */\n.knobs-ui.knobs-compare[data-auto]{height:auto}\n.knobs-compare[data-auto] .knobs-cmp-stage{flex:none;min-height:0}\n.knobs-cmp-stage{position:relative;flex:1;min-height:96px;overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_ku-cmp-stage);touch-action:pan-y;outline:none}\n.knobs-compare[data-frame=\"flat\"] .knobs-cmp-stage{border-radius:0}\n.knobs-compare[data-mode=\"wipe\"] .knobs-cmp-stage{cursor:ew-resize}\n/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */\n.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}\n.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}\n.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:ew-resize!important}\n.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}\n.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}\n.knobs-compare[data-renderer=\"gpu\"] .knobs-cmp-media{opacity:0}\n/* Glass: what's behind shows through, blurred, on the knobs tokens. */\n.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);\n 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)))}\n.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 .15s}\n.knobs-cmp-label[data-lit]{color:var(--_k-fg)}\n.knobs-cmp-label[data-dim]{color:var(--_k-fg-3)}\n/* The wipe: a hairline down the line with a grip at its middle; a wider strip takes the hand and\n the keys (a slider). It fades with the mode. */\n.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)}\n.knobs-cmp-handle[data-on]{opacity:1;pointer-events:auto;transition:opacity .22s cubic-bezier(.2,.8,.2,1)}\n.knobs-cmp-handle::before{content:\"\";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:var(--_ku-cmp-line);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}\n.knobs-cmp-handle::after{content:\"\";position:absolute;top:50%;left:9px;width:6px;height:28px;margin-top:-14px;border-radius:3px;background:var(--_ku-cmp-line);\n box-shadow:0 1px 3px rgba(0,0,0,.35),0 0 0 .5px rgba(0,0,0,.2);transition:scale .18s var(--_ku-ease),box-shadow .15s}\n.knobs-compare[data-dragging] .knobs-cmp-handle::after{scale:1.12}\n.knobs-cmp-handle:focus-visible::after,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus::after{box-shadow:0 1px 3px rgba(0,0,0,.35),0 0 0 3px color-mix(in srgb,var(--_k-accent) 40%,transparent)}\n/* The split's hairline, down the middle side by side. */\n.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}\n/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */\n.knobs-cmp-zoom{position:absolute;right:8px;bottom:8px;display:flex;align-items:center;gap:4px;height:26px;padding:0 3px 0 10px;border-radius:999px;\n color:var(--_k-fg);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;\n opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}\n.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}\n:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;\n height:20px;padding:0 8px;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}\n:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}\n.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}\n.knobs-cmp-note:empty{display:none}\n.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}\n.knobs-cmp-timeline-host{flex:none;height:56px;min-height:0}\n/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */\n.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}\n.knobs-cmp-strip>canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}\n";
1
+ export declare const compareCss = "\n:where(.knobs-compare,.knobs-compare *,.knobs-cmp-strip,.knobs-cmp-strip *){box-sizing:border-box}\n.knobs-ui.knobs-compare{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));--_ku-cmp-line:var(--_k-compare-divider);\n --_ku-cmp-stage:var(--_k-compare-stage);\n display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;\n font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}\n.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}\n/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being\n picked: the pill's bright copy is. */\n.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}\n.knobs-cmp-modes[hidden]{display:none}\n/* Hover is a quiet fill under the arrow cursor (no hand, no brightening), there at once. */\n.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:default;white-space:nowrap;\n transition:background calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-mode:not([aria-checked=\"true\"]):is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n/* Toggles: icon buttons, the accent's wash when on. */\n.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:default;\n transition:background calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-ui .knobs-cmp-toggle[aria-pressed=\"true\"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}\n.knobs-cmp-toggle svg{display:block}\n.knobs-cmp-fill{flex:1}\n.knobs-cmp-toggle[hidden]{display:none}\n/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked\n data-nested, the stage drops its fill and the sides sit on that card. */\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-compare,.knobs-ui.knobs-compare[data-nested]{--_ku-cmp-stage:var(--k-compare-stage,transparent)}\n/* In a page's flow (a container with no height), it takes the height its sides need. */\n.knobs-ui.knobs-compare[data-auto]{height:auto}\n.knobs-compare[data-auto] .knobs-cmp-stage{flex:none;min-height:0}\n.knobs-cmp-stage{position:relative;flex:1;min-height:96px;overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_ku-cmp-stage);touch-action:pan-y;outline:none}\n.knobs-compare[data-frame=\"flat\"] .knobs-cmp-stage{border-radius:0}\n.knobs-compare[data-mode=\"wipe\"] .knobs-cmp-stage{cursor:ew-resize}\n/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */\n/* Zoomed, it pans: a move cursor, never a hand. */\n.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:move;touch-action:none}\n.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:move!important}\n/* Wiping, the grip stands in for the cursor. */\n.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}\n.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}\n.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}\n.knobs-compare[data-renderer=\"gpu\"] .knobs-cmp-media{opacity:0}\n/* The media comes in with its first frames: a fade and a 4px blur on the default spring. */\n.knobs-cmp-canvas,.knobs-compare[data-renderer=\"dom\"] .knobs-cmp-media{transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}\n.knobs-compare:not([data-ready]) :is(.knobs-cmp-canvas,.knobs-cmp-media){opacity:0;filter:blur(4px)}\n/* Over the pictures: a quiet scrim, dark in either appearance, blurred, with no ring. */\n.knobs-cmp-label,.knobs-cmp-zoom,.knobs-cmp-grip{background:var(--_ku-media-scrim);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}\n/* \u2717 Before \u00B7 \u2713 After: Before quieter, After in full. Neutral: no colour of its own. */\n.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-weight:var(--_k-weight-label);\n white-space:nowrap;pointer-events:none;will-change:transform}\n.knobs-cmp-label[data-side=\"before\"]{color:var(--_ku-on-media-2)}\n.knobs-cmp-label[data-side=\"after\"]{color:var(--_ku-on-media)}\n/* Fusing, the mark folds away and the label is its name. */\n.knobs-cmp-mark{flex:none;display:flex;justify-content:flex-end;overflow:hidden}\n.knobs-cmp-mark svg{display:block;flex:none;width:12px;height:12px}\n/* The fuse's seam: a blurred strip over where the sides meet, soft at both sides. */\n.knobs-cmp-seam{position:absolute;left:0;top:0;width:8px;height:0;opacity:0;pointer-events:none;will-change:transform,opacity;\n -webkit-mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent);mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent)}\n/* The wipe: a hairline down the line with a raised grip in its middle (at the pointer's height\n while dragged); a wider strip takes the hand and the keys (a slider). It fades in with the\n fuse; wiping, line and grip brighten. */\n.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,opacity}\n.knobs-cmp-handle[data-on]{pointer-events:auto}\n.knobs-cmp-handle::before{content:\"\";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:color-mix(in srgb,var(--_ku-cmp-line) 72%,transparent);box-shadow:0 0 6px var(--_ku-media-scrim)}\n.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}\n.knobs-cmp-grip{position:absolute;top:0;left:4px;width:16px;height:28px;border-radius:min(8px,calc(var(--_k-radius) * 999));will-change:transform}\n.knobs-cmp-grip::before,.knobs-cmp-grip::after{content:\"\";position:absolute;top:10px;width:1px;height:8px;background:var(--_ku-on-media-2);transition:background calc(var(--_k-hover-out) * 1ms)}\n.knobs-cmp-grip::before{left:6px}\n.knobs-cmp-grip::after{left:9px}\n.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_ku-on-media)}\n.knobs-cmp-handle:focus-visible .knobs-cmp-grip,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus .knobs-cmp-grip{box-shadow:0 0 0 2px var(--_k-accent)}\n/* The split's hairline, down the middle side by side. */\n.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}\n/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */\n.knobs-cmp-zoom{position:absolute;right:8px;bottom:8px;display:flex;align-items:center;gap:4px;height:26px;padding:0 3px 0 10px;border-radius:999px;\n color:var(--_ku-on-media);font-variant-numeric:tabular-nums;font-feature-settings:var(--_kr-data,\"tnum\");white-space:nowrap;\n opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}\n.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}\n:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;\n display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_ku-on-media-2);cursor:default;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}\n:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_ku-on-media) 16%,transparent);color:var(--_ku-on-media);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);pointer-events:none}\n.knobs-cmp-note:empty{display:none}\n.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}\n.knobs-cmp-timeline-host{flex:none;min-height:0}\n/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */\n.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;\n font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);color:var(--_k-fg)}\n.knobs-cmp-strip>canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}\n";
@@ -3,7 +3,6 @@ export declare const MODE_INDEX: {
3
3
  readonly side: 0;
4
4
  readonly wipe: 1;
5
5
  readonly difference: 2;
6
- readonly flicker: 3;
7
6
  };
8
7
  export interface CompareDraw {
9
8
  /** Device px: where each side's picture lands (zoomed, it's larger than its clip). */
@@ -12,20 +11,21 @@ export interface CompareDraw {
12
11
  /** Device px: the part of the stage each side may draw in. */
13
12
  readonly beforeClip: Rect;
14
13
  readonly afterClip: Rect;
14
+ /** Device px: the clips' corner radii, Before's left and right, then After's. */
15
+ readonly radii: readonly [number, number, number, number];
15
16
  readonly width: number;
16
17
  readonly height: number;
17
18
  readonly dpr: number;
18
- /** The wipe's line (device px) and its soft edge (device px). */
19
+ /**
20
+ * Where Before is cut (device px: the split side by side, the wipe's line fused) and its soft
21
+ * edge either side (device px). Side and Wipe composite the same way; only the cut moves.
22
+ */
19
23
  readonly wipeX: number;
20
24
  readonly soft: number;
21
25
  readonly from: number;
22
26
  readonly to: number;
23
27
  /** 0 shows `from`, 1 shows `to`. */
24
28
  readonly mix: number;
25
- /** Before in After's place (X held). */
26
- readonly flick: boolean;
27
- /** Flicker mode's phase: Before showing. */
28
- readonly phase: boolean;
29
29
  readonly threshold: number;
30
30
  readonly gain: number;
31
31
  readonly accent: readonly [number, number, number];
@@ -1,5 +1,18 @@
1
1
  import type { TimeView } from "./timeline-model.js";
2
- export type CompareMode = "side" | "wipe" | "difference" | "flicker";
2
+ /** Side by side, a wipe, or (opt in) a difference. */
3
+ export type CompareMode = "side" | "wipe" | "difference";
4
+ /**
5
+ * The modes a viewer offers (`["side", "wipe"]` unless given; `difference` only when asked for),
6
+ * in their order, and the mode it starts in (the first offered when the asked one isn't).
7
+ */
8
+ export declare function compareModes(modes?: readonly CompareMode[], mode?: CompareMode): {
9
+ readonly modes: readonly CompareMode[];
10
+ readonly mode: CompareMode;
11
+ };
12
+ /** The mode a key picks among those offered: a digit by position, or S, W, D. */
13
+ export declare function modeForKey(key: string, modes: readonly CompareMode[]): CompareMode | null;
14
+ /** A mode's letter key (S, W, D). */
15
+ export declare const modeKey: (mode: CompareMode) => string;
3
16
  export type MediaKind = "video" | "image";
4
17
  /** A source's kind: as given, else by its extension (a video's, or an image). */
5
18
  export declare function mediaKind(src: string, kind?: MediaKind): MediaKind;
@@ -76,7 +89,10 @@ export interface CompareLayout {
76
89
  readonly after: Rect;
77
90
  readonly split: number;
78
91
  };
79
- /** Overlaid (wipe, difference, flicker): both in the same place. */
92
+ /**
93
+ * Overlaid (wipe, difference): both in the same place, one side's size, centred on the split,
94
+ * so fusing never resizes anything.
95
+ */
80
96
  readonly overlay: {
81
97
  readonly before: Rect;
82
98
  readonly after: Rect;
@@ -84,6 +100,57 @@ export interface CompareLayout {
84
100
  }
85
101
  /** Where the two sides sit inside `box`, side by side and overlaid. */
86
102
  export declare function compareLayout(box: Rect, before: Size, after: Size): CompareLayout;
103
+ /**
104
+ * Kit Motion's blend blur, in px: the feather Before's cut swells to mid-fuse, the blur of the
105
+ * strip over the seam at its peak (mid-fuse too), and the overlap the seam fades in over.
106
+ */
107
+ export declare const FUSE: {
108
+ readonly feather: 32;
109
+ readonly blur: 8;
110
+ readonly seamFade: 48;
111
+ };
112
+ export interface FuseFrame {
113
+ /** Where Before is cut: the split side by side, the wipe's line fused. */
114
+ readonly cut: number;
115
+ /** The cut's soft edge, px either side of it. */
116
+ readonly feather: number;
117
+ /** The seam's (and the wipe handle's) opacity, 0–1. */
118
+ readonly seam: number;
119
+ /** The seam's blur (px): none apart or fused, `FUSE.blur` mid-fuse. */
120
+ readonly blur: number;
121
+ }
122
+ /**
123
+ * Kit Motion's Comparison fuse, one frame of it: side by side (`k` 0) the panes glide together
124
+ * into one (`k` 1). Before is cut only where the inner edges overlap, with a feather that swells
125
+ * mid-transition, and a blurred strip over the seam blends the two, strongest mid-transition
126
+ * (the blend blur); it fades in as they overlap. `before` and `after` are where the sides are
127
+ * drawn this frame.
128
+ */
129
+ export declare function fuseFrame(L: CompareLayout, before: Rect, after: Rect, k: number, wipe: number): FuseFrame;
130
+ /**
131
+ * A label folded `fold` (0 open, 1 folded to its name): its mark's width, opacity and blur (px,
132
+ * up to `blur` as it goes, kit-motion's in-place exit).
133
+ */
134
+ /**
135
+ * Each side's corner radii, `left` and `right` (px), so the frame is rounded at every frame of the
136
+ * fuse: a side's outer corners always take the frame's radius `r`; its inner ones (at the split)
137
+ * are square apart and grow to `r` as the sides fuse into one picture.
138
+ */
139
+ export declare const fuseCorners: (r: number, k: number) => {
140
+ before: {
141
+ left: number;
142
+ right: number;
143
+ };
144
+ after: {
145
+ left: number;
146
+ right: number;
147
+ };
148
+ };
149
+ export declare const labelFold: (fold: number, mark: number, blur?: number) => {
150
+ width: number;
151
+ opacity: number;
152
+ blur: number;
153
+ };
87
154
  /** The height a split screen of `w` needs so neither side has margins: half its width, in shape. */
88
155
  export declare const splitHeight: (w: number, media: Size) => number;
89
156
  /**
@@ -134,6 +201,22 @@ export declare function wipeGrab(x: number, rect: Rect, wipe: number, slop?: num
134
201
  onLine: boolean;
135
202
  offset: number;
136
203
  };
204
+ /**
205
+ * Wiping, Before and After ride either side of the seam at `x`, `gap` from it, each fading out as
206
+ * its side runs out of room (`left`/`right`: the wipe's edges; `wb`/`wa`: the labels' widths).
207
+ */
208
+ export declare function seamLabels(x: number, left: number, right: number, wb: number, wa: number, gap?: number): {
209
+ before: {
210
+ x: number;
211
+ opacity: number;
212
+ };
213
+ after: {
214
+ x: number;
215
+ opacity: number;
216
+ };
217
+ };
218
+ /** Where the wipe's grip sits for a pointer at `y`: its top, kept `margin` inside the line. */
219
+ export declare function gripTop(y: number, rect: Rect, grip: number, margin?: number): number;
137
220
  /** The wipe moved by a key: 1% a press, 10% with Shift. */
138
221
  export declare const wipeKey: (wipe: number, dir: -1 | 1, big?: boolean) => number;
139
222
  export interface StripColumn {
@@ -29,8 +29,13 @@ export interface CompareSource {
29
29
  export interface CompareOptions extends UiLook {
30
30
  readonly before: CompareSource;
31
31
  readonly after: CompareSource;
32
- /** `"side"` (side by side) by default. */
32
+ /** The first of `modes` (`"side"`, side by side) by default. */
33
33
  readonly mode?: CompareMode;
34
+ /**
35
+ * The modes it offers, in the mode bar's order and on `1`–`3`: `["side", "wipe"]` by default.
36
+ * Add `"difference"` to offer a difference. One mode hides the bar.
37
+ */
38
+ readonly modes?: readonly CompareMode[];
34
39
  /** Where the wipe's line sits, 0 (all After) to 1 (all Before); 0.5. */
35
40
  readonly wipe?: number;
36
41
  /** Frames per second (the bound timeline's, else 30): steps, and where paused videos land. */
@@ -41,8 +46,9 @@ export interface CompareOptions extends UiLook {
41
46
  readonly threshold?: number;
42
47
  /**
43
48
  * The clock: an existing `timeline()` (its time drives both sides; while playing it follows
44
- * After), or `true` for one of its own under the viewer. Without one, `seek`, `play` and keys
45
- * still work.
49
+ * After), or `true` for one of its own under the viewer: a player's thin progress line (the
50
+ * `"line"` variant, as `player()` has), its markers chapter segments. Without one, `seek`,
51
+ * `play` and keys still work.
46
52
  */
47
53
  readonly timeline?: Timeline | boolean;
48
54
  /** The frame strip over the timeline (off; one timeline is made if there's none). */
@@ -68,6 +74,8 @@ export interface CompareOptions extends UiLook {
68
74
  export interface Compare {
69
75
  readonly element: HTMLElement;
70
76
  readonly mode: CompareMode;
77
+ /** The modes it offers. */
78
+ readonly modes: readonly CompareMode[];
71
79
  readonly wipe: number;
72
80
  readonly loupe: boolean;
73
81
  /** Seconds. */
@@ -85,7 +93,13 @@ export interface Compare {
85
93
  readonly loop: CompareLoop | null;
86
94
  /** New sources, mode, wipe, loupe, threshold or fps. A new mode glides in. */
87
95
  update(next: Partial<Pick<CompareOptions, "before" | "after" | "mode" | "wipe" | "loupe" | "threshold" | "fps">>): void;
88
- seek(time: number): void;
96
+ /**
97
+ * `glide`: a jump the hand didn't make (a chapter's click): the timeline's playhead catches up
98
+ * from where it is while the videos land at once.
99
+ */
100
+ seek(time: number, options?: {
101
+ readonly glide?: boolean;
102
+ }): void;
89
103
  /** Moves by `seconds`, the timeline's playhead gliding there (playing carries on). */
90
104
  seekBy(seconds: number): void;
91
105
  play(): void;
@@ -105,12 +105,11 @@ export declare function diffCounts(file: DiffFile, doc?: Document, options?: {
105
105
  /** A file's change as a letter (M, A, D, R), for a tree's `icon`. */
106
106
  export declare function diffStatus(file: DiffFile, doc?: Document): HTMLElement;
107
107
  /**
108
- * A code diff in a knobs card: a header with the file's path, its counts and Split | Unified
109
- * over the diff, drawn by `@pierre/diffs` (Shiki highlighting, word-level changes, hunks that
108
+ * A code diff on the void (no card, fill or ring: a hairline under its header and one under the
109
+ * code): a quiet header with the file's path, its counts and Split | Unified over the diff, drawn by `@pierre/diffs` (Shiki highlighting, word-level changes, hunks that
110
110
  * expand when the whole files are known). Takes a unified patch or before and after pairs.
111
111
  * Changing the file or the layout fades the new view in over the old, in place; each file
112
- * keeps its scroll. On another surface (a card, a split's pane, a walkthrough's step) it draws
113
- * no card of its own. Needs `@pierre/diffs` installed; it loads on first use.
112
+ * keeps its scroll. Needs `@pierre/diffs` installed; it loads on first use.
114
113
  */
115
114
  export declare function codeDiff(container: HTMLElement, options: CodeDiffOptions): CodeDiff;
116
115
  export interface DiffReviewOptions extends CodeDiffOptions {
@@ -147,7 +146,7 @@ export interface DiffReview {
147
146
  dispose(): void;
148
147
  }
149
148
  /**
150
- * A diff beside its file list, as a review, in one card: the list is a drawer at its left that
149
+ * A diff beside its file list, as a review, on the void as the diff is: the list is a drawer at its left that
151
150
  * springs open and shut (0 to 256px, .4 s, no bounce; the diff reflows as it moves) from a
152
151
  * button at the start of the diff's header, or ⌘B / Ctrl+B. In it, a field that narrows the list
153
152
  * by path, then the changed files as a compact tree (folders folded into paths), each with its
@@ -0,0 +1 @@
1
+ export declare const historyCss = "\n:where(.knobs-history,.knobs-history *){box-sizing:border-box}\n.knobs-ui.knobs-history{--hy-gutter:128px;--hy-lane:24px;--hy-bar:16px;--hy-axis:20px;--hy-bandrow:0px;--hy-c:var(--_k-fg-3);\n --hy-fade:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);\n position:relative;display:flex;flex-direction:column;width:100%;min-width:0;outline:none;color:var(--_k-fg);\n font:var(--_k-weight) var(--_k-type-body)/var(--_k-leading-body) var(--_k-font);font-variant-numeric:tabular-nums;font-feature-settings:var(--_kr-data,\"tnum\");\n text-align:left;letter-spacing:normal;-webkit-font-smoothing:antialiased;user-select:none;-webkit-user-select:none}\n.knobs-history[data-bands]{--hy-bandrow:var(--_k-leading-small)}\n.knobs-history[data-narrow]{--hy-gutter:0px}\n.knobs-history [hidden]{display:none!important}\n:where(.knobs-ui) :is(.knobs-hy-ev,.knobs-hy-span,.knobs-hy-jump,.knobs-hy-more){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;\n background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}\n.knobs-history [data-tone=\"good\"]{--hy-c:var(--_k-ok)}\n.knobs-history [data-tone=\"warn\"]{--hy-c:var(--_k-warn)}\n.knobs-history [data-tone=\"bad\"]{--hy-c:var(--_k-danger)}\n.knobs-history [data-tone=\"info\"]{--hy-c:var(--_k-info)}\n.knobs-history [data-tone=\"dim\"]{--hy-c:var(--_k-fg-3)}\n\n/* \u2014\u2014\u2014 the chart: lane labels beside the plot (above each lane where it's narrow) \u2014\u2014\u2014 */\n.knobs-hy-chart{position:relative;display:grid;grid-template-columns:var(--hy-gutter) minmax(0,1fr)}\n.knobs-hy-axis{position:relative;grid-column:2;grid-row:1;height:calc(var(--hy-bandrow) + var(--hy-axis))}\n:is(.knobs-hy-tick,.knobs-hy-now,.knobs-hy-blabel){position:absolute;white-space:nowrap;font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}\n.knobs-hy-tick{bottom:2px;padding-left:4px}\n.knobs-hy-now{bottom:2px;color:var(--_k-accent-fg);font-weight:var(--_k-weight-label)}\n.knobs-hy-blabel{top:0;padding-left:4px;overflow:hidden;color:var(--_k-fg-2)}\n.knobs-hy-label{grid-column:1;align-self:center;min-width:0;margin-right:var(--_k-space-title);overflow:hidden;white-space:nowrap;\n font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}\n.knobs-history[data-narrow] .knobs-hy-label{grid-column:2;align-self:end;margin:0}\n:is(.knobs-hy-label,.knobs-hy-blabel)[data-overflow]{-webkit-mask-image:var(--hy-fade);mask-image:var(--hy-fade)}\n.knobs-hy-track{position:relative;grid-column:2;height:var(--hy-lane)}\n.knobs-hy-layer{position:absolute;inset:0;grid-column:2;grid-row:1/-1;pointer-events:none}\n\n/* Bands and month lines behind the lanes; today, the selection and the pointer's line over them. */\n.knobs-hy-band{position:absolute;top:0;bottom:0;background:var(--_k-fill);box-shadow:inset 1px 0 0 var(--_k-border-subtle)}\n:is(.knobs-hy-grid,.knobs-hy-today,.knobs-hy-hover,.knobs-hy-sel){position:absolute;left:0;top:calc(var(--hy-bandrow) + var(--hy-axis));bottom:0;width:1px;margin-left:-.5px}\n.knobs-hy-grid{background:var(--_k-border-subtle)}\n.knobs-hy-today{top:calc(var(--hy-bandrow) + var(--hy-axis) - 4px);background:var(--_k-accent)}\n.knobs-hy-hover{background:color-mix(in oklch,var(--_k-fg) 32%,transparent);opacity:0;transition:opacity calc(var(--_k-hover-out) * 1ms)}\n.knobs-hy-hover[data-on]{opacity:1;transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-hy-sel{background:var(--_k-fg-2);opacity:0}\n.knobs-hy-sel[data-on]{opacity:.6}\n\n/* Spans: a soft bar in their state's tone, inferred ones hatched; the tag at the end. */\n.knobs-hy-span{position:absolute;top:calc((var(--hy-lane) - var(--hy-bar)) / 2);height:var(--hy-bar);border-radius:var(--_k-radius-sm);cursor:default;\n background:color-mix(in oklch,var(--hy-c) 24%,transparent);transition:background calc(var(--_k-hover-out) * 1ms),box-shadow calc(var(--_k-hover-out) * 1ms)}\n.knobs-hy-span[data-inferred]{background:repeating-linear-gradient(135deg,color-mix(in oklch,var(--hy-c) 34%,transparent) 0 2px,color-mix(in oklch,var(--hy-c) 9%,transparent) 2px 6px)}\n.knobs-hy-span[data-hover]{background-color:color-mix(in oklch,var(--hy-c) 34%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-hy-span[data-selected]{box-shadow:inset 0 0 0 1px var(--hy-c)}\n.knobs-hy-span[data-clip-start]{border-top-left-radius:0;border-bottom-left-radius:0;-webkit-mask-image:linear-gradient(to right,transparent,#000 16px);mask-image:linear-gradient(to right,transparent,#000 16px)}\n.knobs-hy-span[data-clip-end]{border-top-right-radius:0;border-bottom-right-radius:0;-webkit-mask-image:linear-gradient(to left,transparent,#000 16px);mask-image:linear-gradient(to left,transparent,#000 16px)}\n.knobs-hy-tag{position:absolute;top:0;right:6px;font-size:var(--_k-type-small);line-height:var(--hy-bar);white-space:nowrap;pointer-events:none;\n color:color-mix(in oklch,var(--hy-c) 55%,var(--_k-fg))}\n.knobs-hy-tag[data-place=\"after\"]{right:auto;left:calc(100% + 6px)}\n.knobs-hy-tag[data-place=\"none\"]{visibility:hidden}\n\n/* Event marks (their kind named in the tooltip): a dot for a commit, a diamond for a release, a cross for a deletion, a square for a\n channel's switch, a triangle for a finding; inferred ones hollow. */\n.knobs-hy-ev{position:absolute;top:0;width:16px;height:var(--hy-lane);margin-left:-8px;cursor:default;--hy-c:var(--_k-fg-2);--hy-s:9px}\n.knobs-hy-ev::before{content:\"\";position:absolute;left:50%;top:50%;width:var(--hy-s);height:var(--hy-s);margin:calc(var(--hy-s) / -2) 0 0 calc(var(--hy-s) / -2);\n border-radius:50%;background:var(--hy-c);transition:scale calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy)}\n.knobs-hy-ev[data-range]{width:calc(var(--hy-w) + 16px)}\n.knobs-hy-ev[data-range]::before{left:calc(8px - var(--hy-s) / 2);right:calc(8px - var(--hy-s) / 2);width:auto;margin-left:0;border-radius:var(--_k-round)}\n.knobs-hy-ev[data-type=\"release\"]{--hy-s:8px}\n.knobs-hy-ev[data-type=\"release\"]::before{border-radius:1.5px;rotate:45deg}\n.knobs-hy-ev[data-type=\"channel\"]{--hy-s:8px}\n.knobs-hy-ev[data-type=\"channel\"]::before{border-radius:2px}\n.knobs-hy-ev[data-type=\"audit\"]{--hy-s:10px}\n.knobs-hy-ev[data-type=\"audit\"]::before{border-radius:0;clip-path:polygon(50% 4%,100% 92%,0 92%)}\n.knobs-hy-ev[data-type=\"deletion\"]::before{border-radius:0;rotate:45deg;\n background:linear-gradient(var(--hy-c),var(--hy-c)) center/100% 1.75px no-repeat,linear-gradient(var(--hy-c),var(--hy-c)) center/1.75px 100% no-repeat}\n.knobs-hy-ev[data-inferred]:not([data-type=\"audit\"],[data-type=\"deletion\"])::before{background:transparent;box-shadow:inset 0 0 0 1.5px var(--hy-c)}\n.knobs-hy-ev[data-inferred]:is([data-type=\"audit\"],[data-type=\"deletion\"])::before{opacity:.5}\n/* Held-back marks (commits, by default) come up while the pointer is on their lane, and stay with\n \"Show commits\" or while selected. */\n.knobs-hy-ev[data-quiet]{opacity:0;transition:opacity calc(var(--_k-hover-out) * 1ms)}\n.knobs-hy-track:hover .knobs-hy-ev[data-quiet]{opacity:.6;transition-duration:calc(var(--_k-hover-in) * 1ms)}\n:is(.knobs-history[data-all] .knobs-hy-ev[data-quiet],.knobs-hy-ev[data-quiet]:is([data-selected],[data-hover])){opacity:1}\n.knobs-hy-ev[data-hover]::before{scale:1.25}\n.knobs-hy-ev[data-selected]::before{scale:1.3}\n.knobs-hy-ev[data-selected]::after{content:\"\";position:absolute;left:50%;top:50%;width:calc(var(--hy-s) + 9px);height:calc(var(--hy-s) + 9px);\n margin:calc((var(--hy-s) + 9px) / -2) 0 0 calc((var(--hy-s) + 9px) / -2);border-radius:50%;box-shadow:0 0 0 1.5px var(--hy-c)}\n.knobs-hy-ev[data-range][data-selected]::after{left:3px;right:3px;width:auto;margin-left:0;border-radius:var(--_k-round)}\n.knobs-history:focus-visible .knobs-hy-ev[data-selected]::after{box-shadow:0 0 0 2px var(--_k-focus)}\n.knobs-history:focus-visible .knobs-hy-span[data-selected]{box-shadow:inset 0 0 0 2px var(--_k-focus)}\n\n/* \u2014\u2014\u2014 under the chart: \"Show commits\", and a legend only when inferred and verified both appear \u2014\u2014\u2014 */\n.knobs-hy-foot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--_k-space-inside) var(--_k-space-title);margin-top:var(--_k-space-sibling);padding-left:var(--hy-gutter);\n font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}\n.knobs-hy-legend{display:flex;flex-wrap:wrap;gap:var(--_k-space-inside) var(--_k-space-title)}\n.knobs-ui .knobs-hy-more{height:20px;margin-left:-6px;padding:0 6px;border-radius:var(--_k-radius-sm);color:var(--_k-fg-3);cursor:default;\n transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-hy-more:is(:hover,:focus-visible){background:var(--_k-fill-hover);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-hy-key{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}\n.knobs-hy-swatch{flex:none;width:14px;height:8px;border-radius:2px;background:color-mix(in oklch,var(--hy-c) 34%,transparent)}\n.knobs-hy-swatch[data-inferred]{background:repeating-linear-gradient(135deg,color-mix(in oklch,var(--hy-c) 60%,transparent) 0 1.5px,transparent 1.5px 4px)}\n\n/* \u2014\u2014\u2014 the detail: one area under the chart, its height on a spring \u2014\u2014\u2014 */\n.knobs-hy-detail{position:relative;overflow:hidden;user-select:text;-webkit-user-select:text}\n.knobs-hy-detail[data-moving]{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 16px),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - 16px),transparent)}\n.knobs-hy-dc{padding:var(--_k-space-title) 0 0 var(--hy-gutter);transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy)}\n.knobs-hy-dc:is([data-enter],[data-leave]){opacity:0}\n.knobs-hy-dc[data-leave]{position:absolute;left:0;right:0;top:0;transition-duration:calc(var(--_k-motion-snappy-ms) * .8ms)}\n.knobs-hy-dmeta{display:flex;flex-wrap:wrap;gap:0 var(--_k-space-sibling);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}\n.knobs-hy-dmeta>[data-tone]{color:var(--hy-c)}\n.knobs-hy-dtitle{margin-top:var(--_k-space-inside);font-size:var(--_k-type-body);line-height:var(--_k-leading-body);font-weight:var(--_k-weight-label);color:var(--_k-fg);text-wrap:balance}\n.knobs-hy-dtext{margin:var(--_k-space-inside) 0 0;max-width:68ch;font-size:var(--_k-type-body);line-height:var(--_k-leading-body);color:var(--_k-fg-2);text-wrap:pretty}\n.knobs-hy-dtext code{font:var(--_k-type-label) var(--_k-mono);letter-spacing:0;padding:1px 5px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}\n.knobs-hy-dfoot{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:var(--_k-space-sibling)}\n.knobs-hy-dfoot:empty{display:none}\n.knobs-hy-evidence{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:var(--_k-radius-sm);background:var(--_k-fill);color:var(--_k-fg-2);\n font:var(--_k-type-small)/1 var(--_k-mono);text-decoration:none;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}\na.knobs-hy-evidence:hover{background:var(--_k-fill-hover);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-ui .knobs-hy-jump{display:inline-flex;align-items:center;gap:4px;height:20px;padding:0 5px 0 6px;border-radius:var(--_k-radius-sm);color:var(--_k-fg-2);cursor:default;\n font-size:var(--_k-type-small);transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-hy-jump:is(:hover,:focus-visible){background:var(--_k-fill-hover);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-hy-jump svg{width:12px;height:12px}\n\n/* \u2014\u2014\u2014 the pointer's tooltip: title, date, one line \u2014\u2014\u2014 */\n.knobs-hy-tip{position:absolute;left:0;top:0;max-width:280px;padding:6px 8px;border-radius:var(--_k-radius-md);background:var(--_k-bg-overlay);\n box-shadow:var(--_k-shadow-overlay),0 0 0 1px var(--_k-border);pointer-events:none;opacity:0;transition:opacity calc(var(--_k-hover-out) * 1ms)}\n.knobs-hy-tip[data-on]{opacity:1;transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-hy-tt{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);font-weight:var(--_k-weight-label);color:var(--_k-fg);text-wrap:balance}\n:is(.knobs-hy-td,.knobs-hy-tl){font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}\n.knobs-hy-tl{margin-top:2px;color:var(--_k-fg-2);text-wrap:pretty}\n.knobs-hy-tl:empty{display:none}\n\n@media(prefers-reduced-motion:reduce){\n .knobs-history :where(*,::before,::after){transition-property:opacity,background,color,box-shadow!important}\n .knobs-hy-dc{transition-duration:calc(var(--_k-hover-out) * 1ms)!important}\n}\n";