mevebu 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/mevebu/app/mevebu.js +260 -208
  2. package/mevebu/app/tailwind.css +1658 -2079
  3. package/mevebu/app/tailwind.src.css +161 -1127
  4. package/mevebu/index.html +2 -2
  5. package/mevebu/libs/js/core.js +245 -96
  6. package/mevebu/libs/js/tools/abstract-checklist.js +5 -7
  7. package/mevebu/libs/js/tools/add-subtract-days.js +9 -11
  8. package/mevebu/libs/js/tools/age-calculator.js +7 -8
  9. package/mevebu/libs/js/tools/api-request-builder.js +3 -4
  10. package/mevebu/libs/js/tools/area-converter.js +7 -9
  11. package/mevebu/libs/js/tools/aspect-ratio.js +8 -9
  12. package/mevebu/libs/js/tools/average-calculator.js +4 -5
  13. package/mevebu/libs/js/tools/base64.js +2 -3
  14. package/mevebu/libs/js/tools/binary-calculator.js +6 -7
  15. package/mevebu/libs/js/tools/border-radius.js +7 -9
  16. package/mevebu/libs/js/tools/box-shadow.js +6 -7
  17. package/mevebu/libs/js/tools/break-even.js +4 -5
  18. package/mevebu/libs/js/tools/business-days.js +7 -8
  19. package/mevebu/libs/js/tools/canonical-tag.js +5 -6
  20. package/mevebu/libs/js/tools/caption-counter.js +5 -7
  21. package/mevebu/libs/js/tools/case-converter.js +10 -11
  22. package/mevebu/libs/js/tools/case-inspector.js +14 -16
  23. package/mevebu/libs/js/tools/cash-denomination.js +7 -8
  24. package/mevebu/libs/js/tools/cash-flow.js +7 -8
  25. package/mevebu/libs/js/tools/cert-expiry.js +5 -7
  26. package/mevebu/libs/js/tools/changelog-generator.js +4 -6
  27. package/mevebu/libs/js/tools/character-counter.js +10 -13
  28. package/mevebu/libs/js/tools/checklist.js +6 -7
  29. package/mevebu/libs/js/tools/citation-number-check.js +10 -13
  30. package/mevebu/libs/js/tools/coin-flip.js +9 -11
  31. package/mevebu/libs/js/tools/color-converter.js +6 -7
  32. package/mevebu/libs/js/tools/color-palette.js +6 -8
  33. package/mevebu/libs/js/tools/color-picker.js +4 -5
  34. package/mevebu/libs/js/tools/content-calendar.js +3 -4
  35. package/mevebu/libs/js/tools/contrast-checker.js +5 -6
  36. package/mevebu/libs/js/tools/cron-builder.js +4 -6
  37. package/mevebu/libs/js/tools/css-clamp.js +5 -6
  38. package/mevebu/libs/js/tools/css-formatter.js +4 -7
  39. package/mevebu/libs/js/tools/css-grid.js +6 -7
  40. package/mevebu/libs/js/tools/css-minifier.js +5 -8
  41. package/mevebu/libs/js/tools/csv-to-json.js +2 -3
  42. package/mevebu/libs/js/tools/csv-viewer.js +9 -11
  43. package/mevebu/libs/js/tools/currency-format.js +5 -7
  44. package/mevebu/libs/js/tools/daily-planner.js +9 -10
  45. package/mevebu/libs/js/tools/data-masker.js +6 -8
  46. package/mevebu/libs/js/tools/data-storage.js +7 -9
  47. package/mevebu/libs/js/tools/data-validator.js +9 -11
  48. package/mevebu/libs/js/tools/date-difference.js +6 -7
  49. package/mevebu/libs/js/tools/date-format.js +11 -13
  50. package/mevebu/libs/js/tools/delimiter-converter.js +3 -5
  51. package/mevebu/libs/js/tools/discount-calculator.js +4 -5
  52. package/mevebu/libs/js/tools/doi-resolver.js +4 -5
  53. package/mevebu/libs/js/tools/env-formatter.js +3 -6
  54. package/mevebu/libs/js/tools/equation-formatter.js +5 -9
  55. package/mevebu/libs/js/tools/expense-split.js +6 -7
  56. package/mevebu/libs/js/tools/fake-data.js +8 -13
  57. package/mevebu/libs/js/tools/find-replace.js +3 -5
  58. package/mevebu/libs/js/tools/flashcard-creator.js +9 -10
  59. package/mevebu/libs/js/tools/font-pairing.js +6 -8
  60. package/mevebu/libs/js/tools/fraction-calculator.js +10 -13
  61. package/mevebu/libs/js/tools/git-command-builder.js +11 -22
  62. package/mevebu/libs/js/tools/gpa-calculator.js +8 -10
  63. package/mevebu/libs/js/tools/grade-calculator.js +7 -8
  64. package/mevebu/libs/js/tools/gradient-generator.js +10 -12
  65. package/mevebu/libs/js/tools/habit-tracker.js +8 -9
  66. package/mevebu/libs/js/tools/hash-generator.js +3 -5
  67. package/mevebu/libs/js/tools/hashtag-formatter.js +6 -8
  68. package/mevebu/libs/js/tools/hmac-generator.js +3 -5
  69. package/mevebu/libs/js/tools/hpp-calculator.js +4 -5
  70. package/mevebu/libs/js/tools/html-entity.js +2 -3
  71. package/mevebu/libs/js/tools/html-formatter.js +3 -6
  72. package/mevebu/libs/js/tools/http-status.js +5 -7
  73. package/mevebu/libs/js/tools/inventory-quantity.js +7 -8
  74. package/mevebu/libs/js/tools/json-formatter.js +3 -6
  75. package/mevebu/libs/js/tools/json-minifier.js +5 -8
  76. package/mevebu/libs/js/tools/json-to-csv.js +3 -5
  77. package/mevebu/libs/js/tools/json-to-typescript.js +2 -5
  78. package/mevebu/libs/js/tools/json-validator.js +2 -3
  79. package/mevebu/libs/js/tools/jwt-decoder.js +6 -7
  80. package/mevebu/libs/js/tools/jwt-expiry.js +5 -6
  81. package/mevebu/libs/js/tools/jwt-generator.js +4 -6
  82. package/mevebu/libs/js/tools/length-converter.js +7 -9
  83. package/mevebu/libs/js/tools/license-reference.js +10 -13
  84. package/mevebu/libs/js/tools/line-counter.js +5 -7
  85. package/mevebu/libs/js/tools/list-difference.js +5 -7
  86. package/mevebu/libs/js/tools/list-merger.js +4 -5
  87. package/mevebu/libs/js/tools/locale-number.js +5 -8
  88. package/mevebu/libs/js/tools/markdown-preview.js +5 -8
  89. package/mevebu/libs/js/tools/markdown-table.js +5 -7
  90. package/mevebu/libs/js/tools/markup-calculator.js +4 -5
  91. package/mevebu/libs/js/tools/meeting-agenda.js +8 -9
  92. package/mevebu/libs/js/tools/meta-preview.js +12 -13
  93. package/mevebu/libs/js/tools/meta-tags.js +6 -7
  94. package/mevebu/libs/js/tools/mime-types.js +5 -7
  95. package/mevebu/libs/js/tools/name-picker.js +2 -3
  96. package/mevebu/libs/js/tools/number-base-converter.js +9 -12
  97. package/mevebu/libs/js/tools/password-generator.js +9 -12
  98. package/mevebu/libs/js/tools/password-strength.js +21 -25
  99. package/mevebu/libs/js/tools/percent-to-fraction.js +6 -7
  100. package/mevebu/libs/js/tools/percentage-calculator.js +6 -9
  101. package/mevebu/libs/js/tools/percentage-change.js +4 -5
  102. package/mevebu/libs/js/tools/permutation-combination.js +9 -12
  103. package/mevebu/libs/js/tools/prefix-suffix.js +2 -3
  104. package/mevebu/libs/js/tools/priority-matrix.js +6 -10
  105. package/mevebu/libs/js/tools/profit-margin.js +4 -5
  106. package/mevebu/libs/js/tools/qr-generator.js +3 -4
  107. package/mevebu/libs/js/tools/qr-scanner.js +11 -12
  108. package/mevebu/libs/js/tools/quadratic-solver.js +7 -8
  109. package/mevebu/libs/js/tools/query-builder.js +2 -3
  110. package/mevebu/libs/js/tools/quiz-formatter.js +4 -6
  111. package/mevebu/libs/js/tools/ratio-calculator.js +7 -8
  112. package/mevebu/libs/js/tools/readability.js +12 -15
  113. package/mevebu/libs/js/tools/reading-time.js +5 -7
  114. package/mevebu/libs/js/tools/reference-completeness.js +6 -8
  115. package/mevebu/libs/js/tools/regex-tester.js +7 -10
  116. package/mevebu/libs/js/tools/remove-duplicate-lines.js +2 -3
  117. package/mevebu/libs/js/tools/remove-extra-spaces.js +3 -5
  118. package/mevebu/libs/js/tools/robots-txt.js +3 -4
  119. package/mevebu/libs/js/tools/roman-numeral-converter.js +6 -8
  120. package/mevebu/libs/js/tools/sales-commission.js +8 -9
  121. package/mevebu/libs/js/tools/scientific-calculator.js +10 -14
  122. package/mevebu/libs/js/tools/scientific-notation.js +8 -9
  123. package/mevebu/libs/js/tools/script-planner.js +8 -10
  124. package/mevebu/libs/js/tools/selling-price.js +4 -5
  125. package/mevebu/libs/js/tools/semver-helper.js +3 -5
  126. package/mevebu/libs/js/tools/sentence-length.js +9 -10
  127. package/mevebu/libs/js/tools/sequence-analyzer.js +7 -8
  128. package/mevebu/libs/js/tools/sitemap-xml.js +4 -7
  129. package/mevebu/libs/js/tools/slug-converter.js +3 -5
  130. package/mevebu/libs/js/tools/slug-preview.js +6 -7
  131. package/mevebu/libs/js/tools/sort-lines.js +3 -5
  132. package/mevebu/libs/js/tools/speed-converter.js +7 -9
  133. package/mevebu/libs/js/tools/spin-wheel.js +19 -17
  134. package/mevebu/libs/js/tools/sql-formatter.js +5 -9
  135. package/mevebu/libs/js/tools/sql-minifier.js +5 -8
  136. package/mevebu/libs/js/tools/standard-deviation.js +6 -9
  137. package/mevebu/libs/js/tools/stopwatch.js +4 -6
  138. package/mevebu/libs/js/tools/study-schedule.js +8 -9
  139. package/mevebu/libs/js/tools/subtitle-formatter.js +10 -11
  140. package/mevebu/libs/js/tools/table-to-markdown.js +8 -12
  141. package/mevebu/libs/js/tools/tax-calculator.js +4 -5
  142. package/mevebu/libs/js/tools/temperature-converter.js +8 -11
  143. package/mevebu/libs/js/tools/text-diff.js +11 -7
  144. package/mevebu/libs/js/tools/text-direction.js +3 -5
  145. package/mevebu/libs/js/tools/text-reverser.js +3 -5
  146. package/mevebu/libs/js/tools/time-duration.js +8 -9
  147. package/mevebu/libs/js/tools/timestamp-converter.js +4 -6
  148. package/mevebu/libs/js/tools/timezone-converter.js +9 -13
  149. package/mevebu/libs/js/tools/title-length.js +6 -7
  150. package/mevebu/libs/js/tools/unicode-inspector.js +4 -5
  151. package/mevebu/libs/js/tools/url-inspector.js +8 -9
  152. package/mevebu/libs/js/tools/url-parser.js +12 -13
  153. package/mevebu/libs/js/tools/utf8-bytes.js +6 -9
  154. package/mevebu/libs/js/tools/uuid-generator.js +5 -9
  155. package/mevebu/libs/js/tools/version-compare.js +3 -4
  156. package/mevebu/libs/js/tools/video-duration.js +5 -7
  157. package/mevebu/libs/js/tools/volume-converter.js +7 -9
  158. package/mevebu/libs/js/tools/weekly-planner.js +8 -10
  159. package/mevebu/libs/js/tools/weight-converter.js +7 -9
  160. package/mevebu/libs/js/tools/weighted-average.js +4 -5
  161. package/mevebu/libs/js/tools/word-counter.js +10 -13
  162. package/mevebu/libs/js/tools/word-limit.js +4 -5
  163. package/mevebu/libs/js/tools/yaml-formatter.js +6 -7
  164. package/package.json +1 -1
@@ -6,7 +6,7 @@ const ALGORITHMS = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"];
6
6
  export function mount(slot) {
7
7
  const source = textArea({ value: "mevebu", rows: 5, "aria-label": "Text to hash", placeholder: "Type or paste text" });
8
8
  const result = output();
9
- const digest = el("p", { class: "mvb-note" });
9
+ const digest = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
10
10
  const error = notice("error");
11
11
 
12
12
  let algorithm = "SHA-256";
@@ -17,8 +17,7 @@ export function mount(slot) {
17
17
  onChange: (value) => {
18
18
  algorithm = value;
19
19
  run();
20
- },
21
- });
20
+ }});
22
21
 
23
22
  async function run() {
24
23
  error.write("");
@@ -45,8 +44,7 @@ export function mount(slot) {
45
44
  stack(panel("Algorithm", chips), panel("Text", source)),
46
45
  stack(panel("Hash", result), digest, error)
47
46
  ),
48
- foot: actions(copy),
49
- });
47
+ foot: actions(copy)});
50
48
  slot.append(card.node);
51
49
  run();
52
50
 
@@ -4,8 +4,8 @@ import { el, bench, stack, panel, textArea, chipRow, output, copyButton, actions
4
4
  const clean = (raw) => raw.replace(/#/g, "").replace(/[^\p{L}\p{N}_]/gu, "");
5
5
 
6
6
  function tile(label) {
7
- const value = el("span", { class: "mvb-stat__v" }, "0");
8
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
7
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
8
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
9
9
  node.set = (text) => { value.textContent = text; };
10
10
  return node;
11
11
  }
@@ -14,22 +14,21 @@ export function mount(slot) {
14
14
  const source = textArea({ rows: 8, "aria-label": "Tags", placeholder: "One tag per line or space separated" });
15
15
  const tagsTile = tile("Tags");
16
16
  const removedTile = tile("Duplicates removed");
17
- const stats = el("div", { class: "mvb-stats" }, tagsTile, removedTile);
17
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, tagsTile, removedTile);
18
18
  const out = output({ rows: 8 });
19
19
 
20
20
  let mode = "list";
21
21
  const modeChips = chipRow(
22
22
  [
23
23
  { value: "line", label: "One line" },
24
- { value: "list", label: "One per line" },
25
- ],
24
+ { value: "list", label: "One per line" }],
26
25
  { value: "list", label: "Layout", onChange: (next) => { mode = next; run(); } }
27
26
  );
28
27
 
29
28
  let result = "";
30
29
 
31
30
  function run() {
32
- const tokens = source.value.split(/[\s,]+/).map(clean).filter(Boolean);
31
+ const tokens = source.value.split(/[\s]+/).map(clean).filter(Boolean);
33
32
  const seen = new Set();
34
33
  const tags = [];
35
34
  for (const token of tokens) {
@@ -51,8 +50,7 @@ export function mount(slot) {
51
50
  stack(panel("Tags", source), panel("Layout", modeChips)),
52
51
  stack(stats, panel("Result", out))
53
52
  ),
54
- foot: actions(copyButton(() => result, "Copy tags", "fill")),
55
- });
53
+ foot: actions(copyButton(() => result, "Copy tags", "fill"))});
56
54
  slot.append(card.node);
57
55
  run();
58
56
 
@@ -5,8 +5,7 @@ const ALGORITHMS = [
5
5
  { value: "SHA-256", label: "SHA-256" },
6
6
  { value: "SHA-384", label: "SHA-384" },
7
7
  { value: "SHA-512", label: "SHA-512" },
8
- { value: "SHA-1", label: "SHA-1" },
9
- ];
8
+ { value: "SHA-1", label: "SHA-1" }];
10
9
 
11
10
  const encoder = new TextEncoder();
12
11
  const toHex = (bytes) => [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
@@ -46,13 +45,12 @@ export function mount(slot) {
46
45
  body: bench(
47
46
  stack(
48
47
  panel("Message", message),
49
- panel("Secret key", el("div", { class: "mvb-secret" }, secret, showButton)),
48
+ panel("Secret key", el("div", { class: "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2" }, secret, showButton)),
50
49
  panel("Hash", hashField)
51
50
  ),
52
51
  stack(panel("Signature", result), error)
53
52
  ),
54
- foot: actions(copyButton(() => result.textContent, "Copy signature", "fill")),
55
- });
53
+ foot: actions(copyButton(() => result.textContent, "Copy signature", "fill"))});
56
54
  slot.append(card.node);
57
55
  run();
58
56
 
@@ -6,8 +6,8 @@ function fmt(n) {
6
6
  }
7
7
 
8
8
  function tile(label) {
9
- const value = el("span", { class: "mvb-stat__v" }, "-");
10
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
9
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
10
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
11
11
  node.set = (text) => { value.textContent = text; };
12
12
  return node;
13
13
  }
@@ -19,7 +19,7 @@ export function mount(slot) {
19
19
  const units = numberInput({ value: "1", min: "1", "aria-label": "Units made" });
20
20
  const total = tile("Total cost");
21
21
  const perUnit = tile("Cost per unit");
22
- const stats = el("div", { class: "mvb-stats" }, total, perUnit);
22
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, total, perUnit);
23
23
  const error = notice("error");
24
24
  let text = "";
25
25
 
@@ -59,8 +59,7 @@ export function mount(slot) {
59
59
  ),
60
60
  stack(stats)
61
61
  ),
62
- foot: actions(copyButton(() => text, "Copy result", "fill")),
63
- });
62
+ foot: actions(copyButton(() => text, "Copy result", "fill"))});
64
63
  slot.append(card.node);
65
64
  run();
66
65
 
@@ -13,7 +13,7 @@ function decode(text) {
13
13
 
14
14
  export function mount(slot) {
15
15
  const source = textArea({ rows: 6, value: "<a href=\"/x\">Tom & Jerry</a>", "aria-label": "Input" });
16
- const result = textArea({ rows: 6, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Result" });
16
+ const result = textArea({ rows: 6, readonly: true, "aria-label": "Result" });
17
17
  const error = notice("error");
18
18
  let mode = "encode";
19
19
 
@@ -38,8 +38,7 @@ export function mount(slot) {
38
38
  stack(panel("Direction", chips), panel("Input", source), error),
39
39
  stack(panel("Result", result))
40
40
  ),
41
- foot: actions(copyButton(() => result.value, "Copy result", "fill")),
42
- });
41
+ foot: actions(copyButton(() => result.value, "Copy result", "fill"))});
43
42
  slot.append(card.node);
44
43
  run();
45
44
 
@@ -8,11 +8,9 @@ const tagName = (token) => (token.match(/^<\s*\/?\s*([a-zA-Z0-9:-]+)/) || [])[1]
8
8
  export function mount(slot) {
9
9
  const source = textArea({
10
10
  rows: 12,
11
- class: "mvb-in mvb-in--area mvb-in--mono",
12
11
  "aria-label": "HTML",
13
- value: "<div class=\"card\"><h1>Title</h1><p>Text <strong>bold</strong></p><br></div>",
14
- });
15
- const result = textArea({ rows: 12, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Formatted HTML" });
12
+ value: "<div class=\"card\"><h1>Title</h1><p>Text <strong>bold</strong></p><br></div>"});
13
+ const result = textArea({ rows: 12, readonly: true, "aria-label": "Formatted HTML" });
16
14
  const warn = notice("warn");
17
15
  let size = "2";
18
16
 
@@ -61,8 +59,7 @@ export function mount(slot) {
61
59
  stack(panel("Indent", chips), panel("HTML", source), warn),
62
60
  stack(panel("Formatted", result))
63
61
  ),
64
- foot: actions(copyButton(() => result.value, "Copy markup", "fill")),
65
- });
62
+ foot: actions(copyButton(() => result.value, "Copy markup", "fill"))});
66
63
  slot.append(card.node);
67
64
  run();
68
65
 
@@ -6,14 +6,13 @@ const CODES = [
6
6
  [200, "OK"], [201, "Created"], [202, "Accepted"], [203, "Non-Authoritative Information"], [204, "No Content"], [205, "Reset Content"], [206, "Partial Content"],
7
7
  [300, "Multiple Choices"], [301, "Moved Permanently"], [302, "Found"], [303, "See Other"], [304, "Not Modified"], [307, "Temporary Redirect"], [308, "Permanent Redirect"],
8
8
  [400, "Bad Request"], [401, "Unauthorized"], [402, "Payment Required"], [403, "Forbidden"], [404, "Not Found"], [405, "Method Not Allowed"], [406, "Not Acceptable"], [408, "Request Timeout"], [409, "Conflict"], [410, "Gone"], [411, "Length Required"], [412, "Precondition Failed"], [413, "Payload Too Large"], [414, "URI Too Long"], [415, "Unsupported Media Type"], [416, "Range Not Satisfiable"], [418, "I'm a teapot"], [422, "Unprocessable Entity"], [425, "Too Early"], [426, "Upgrade Required"], [428, "Precondition Required"], [429, "Too Many Requests"], [431, "Request Header Fields Too Large"], [451, "Unavailable For Legal Reasons"],
9
- [500, "Internal Server Error"], [501, "Not Implemented"], [502, "Bad Gateway"], [503, "Service Unavailable"], [504, "Gateway Timeout"], [505, "HTTP Version Not Supported"], [507, "Insufficient Storage"], [508, "Loop Detected"], [511, "Network Authentication Required"],
10
- ];
9
+ [500, "Internal Server Error"], [501, "Not Implemented"], [502, "Bad Gateway"], [503, "Service Unavailable"], [504, "Gateway Timeout"], [505, "HTTP Version Not Supported"], [507, "Insufficient Storage"], [508, "Loop Detected"], [511, "Network Authentication Required"]];
11
10
 
12
11
  const statusClass = (code) => `${Math.floor(code / 100)}xx`;
13
12
 
14
13
  export function mount(slot) {
15
14
  const filter = textInput({ type: "search", placeholder: "Code or reason", "aria-label": "Filter" });
16
- const scroll = el("div", { class: "mvb-scroll" });
15
+ const scroll = el("div", { class: "max-h-80 overflow-auto" });
17
16
  let group = "all";
18
17
  let visible = CODES;
19
18
 
@@ -30,12 +29,12 @@ export function mount(slot) {
30
29
  return String(code).includes(query) || message.toLowerCase().includes(query);
31
30
  });
32
31
  if (!visible.length) {
33
- scroll.replaceChildren(el("p", { class: "mvb-note" }, "No code matches."));
32
+ scroll.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "No code matches."));
34
33
  return;
35
34
  }
36
35
  scroll.replaceChildren(el(
37
36
  "table",
38
- { class: "mvb-ttable" },
37
+ { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
39
38
  el("thead", {}, el("tr", {}, el("th", {}, "Code"), el("th", {}, "Message"), el("th", {}, "Class"))),
40
39
  el("tbody", {}, ...visible.map(([code, message]) => el("tr", {},
41
40
  el("td", {}, String(code)),
@@ -52,8 +51,7 @@ export function mount(slot) {
52
51
  stack(panel("Filter", filter), panel("Class", chips)),
53
52
  stack(panel("Status codes", scroll))
54
53
  ),
55
- foot: actions(copyButton(() => visible.map(([code, message]) => `${code} ${message}`).join("\n"), "Copy list", "fill")),
56
- });
54
+ foot: actions(copyButton(() => visible.map(([code, message]) => `${code} ${message}`).join("\n"), "Copy list", "fill"))});
57
55
  slot.append(card.node);
58
56
  run();
59
57
 
@@ -16,16 +16,16 @@ export function mount(slot) {
16
16
  const opening = numberInput({ value: "0", min: "0", "aria-label": "Opening stock" });
17
17
  const stockIn = numberInput({ value: "0", min: "0", "aria-label": "Stock in" });
18
18
  const stockOut = numberInput({ value: "0", min: "0", "aria-label": "Stock out" });
19
- const listWrap = el("div", { class: "mvb-scroll" });
20
- const stats = el("div", { class: "mvb-stats" });
19
+ const listWrap = el("div", { class: "max-h-80 overflow-auto" });
20
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
21
21
  const warn = notice("warn");
22
22
 
23
23
  const addButton = button("Add", { icon: "plus", kind: "fill" });
24
24
 
25
25
  const save = () => writePin(PIN, list);
26
- const tile = (key, value) => el("div", { class: "mvb-stat" },
27
- el("span", { class: "mvb-stat__v" }, String(value)),
28
- el("span", { class: "mvb-stat__k" }, key));
26
+ const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
27
+ el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
28
+ el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
29
29
 
30
30
  const closing = (item) => item.opening + item.in - item.out;
31
31
 
@@ -43,7 +43,7 @@ export function mount(slot) {
43
43
  if (!list.length) {
44
44
  listWrap.replaceChildren(blank("package", "No items yet."));
45
45
  } else {
46
- listWrap.replaceChildren(el("table", { class: "mvb-ttable" },
46
+ listWrap.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
47
47
  el("thead", {}, el("tr", {},
48
48
  el("th", {}, "Item"), el("th", {}, "Opening"), el("th", {}, "In"),
49
49
  el("th", {}, "Out"), el("th", {}, "Closing"), el("th", {}, ""))),
@@ -92,8 +92,7 @@ export function mount(slot) {
92
92
  foot: actions(
93
93
  copyButton(() => list.map((item) => `${item.name}: opening ${fmt(item.opening)}, in ${fmt(item.in)}, out ${fmt(item.out)}, closing ${fmt(closing(item))}`).join("\n"), "Copy stock"),
94
94
  addButton
95
- ),
96
- });
95
+ )});
97
96
  slot.append(card.node);
98
97
  render();
99
98
 
@@ -4,12 +4,10 @@ import { bench, stack, panel, textArea, notice, chipRow, copyButton, actions, to
4
4
  export function mount(slot) {
5
5
  const source = textArea({
6
6
  rows: 12,
7
- class: "mvb-in mvb-in--area mvb-in--mono",
8
7
  "aria-label": "JSON",
9
8
  placeholder: "Paste JSON",
10
- value: '{"hello":"world","count":3,"items":[1,2,3]}',
11
- });
12
- const result = textArea({ rows: 12, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Result" });
9
+ value: '{"hello":"world","count":3,"items":[1,2,3]}'});
10
+ const result = textArea({ rows: 12, readonly: true, "aria-label": "Result" });
13
11
  const error = notice("error");
14
12
  let indent = "2";
15
13
 
@@ -40,8 +38,7 @@ export function mount(slot) {
40
38
  stack(panel("Indent", chips), panel("JSON", source), error),
41
39
  stack(panel("Result", result))
42
40
  ),
43
- foot: actions(copyButton(() => result.value, "Copy result", "fill")),
44
- });
41
+ foot: actions(copyButton(() => result.value, "Copy result", "fill"))});
45
42
  slot.append(card.node);
46
43
  run();
47
44
 
@@ -4,18 +4,16 @@ import { el, bench, stack, panel, textArea, notice, copyButton, actions, toolcar
4
4
  const bytes = (text) => new TextEncoder().encode(text).length;
5
5
 
6
6
  const tile = (key, value) =>
7
- el("div", { class: "mvb-stat" }, el("span", { class: "mvb-stat__v" }, value), el("span", { class: "mvb-stat__k" }, key));
7
+ el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, value), el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
8
8
 
9
9
  export function mount(slot) {
10
10
  const source = textArea({
11
11
  rows: 12,
12
- class: "mvb-in mvb-in--area mvb-in--mono",
13
12
  "aria-label": "JSON",
14
13
  placeholder: "Paste JSON",
15
- value: '{\n "hello": "world",\n "count": 3\n}',
16
- });
17
- const result = textArea({ rows: 12, readonly: true, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Minified JSON" });
18
- const stats = el("div", { class: "mvb-stats" });
14
+ value: '{\n "hello": "world",\n "count": 3\n}'});
15
+ const result = textArea({ rows: 12, readonly: true, "aria-label": "Minified JSON" });
16
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
19
17
  const error = notice("error");
20
18
 
21
19
  function run() {
@@ -47,8 +45,7 @@ export function mount(slot) {
47
45
  stack(panel("JSON", source), error),
48
46
  stack(panel("Minified", result), stats)
49
47
  ),
50
- foot: actions(copyButton(() => result.value, "Copy result", "fill")),
51
- });
48
+ foot: actions(copyButton(() => result.value, "Copy result", "fill"))});
52
49
  slot.append(card.node);
53
50
  run();
54
51
 
@@ -10,7 +10,7 @@ function stringifyCSV(rows, delimiter) {
10
10
  }
11
11
 
12
12
  export function mount(slot) {
13
- const source = textArea({ rows: 12, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "JSON", placeholder: '[{"name":"Ada","role":"engineer"}]' });
13
+ const source = textArea({ rows: 12, "aria-label": "JSON", placeholder: '[{"name":"Ada","role":"engineer"}]' });
14
14
  const result = output({ rows: 12 });
15
15
  const error = notice("error");
16
16
  let current = "";
@@ -45,8 +45,7 @@ export function mount(slot) {
45
45
  ...records.map((record) => header.map((key) => {
46
46
  const value = record[key];
47
47
  return value && typeof value === "object" ? JSON.stringify(value) : value;
48
- })),
49
- ];
48
+ }))];
50
49
  current = stringifyCSV(rows, ",");
51
50
  result.write(current);
52
51
  }
@@ -61,8 +60,7 @@ export function mount(slot) {
61
60
  foot: actions(
62
61
  downloadButton(() => current, "data.csv", "Download CSV", "text/csv"),
63
62
  copyButton(() => current, "Copy CSV", "fill")
64
- ),
65
- });
63
+ )});
66
64
  slot.append(card.node);
67
65
  run();
68
66
 
@@ -55,11 +55,9 @@ function generate(data, rootName) {
55
55
  export function mount(slot) {
56
56
  const source = textArea({
57
57
  rows: 12,
58
- class: "mvb-in mvb-in--area mvb-in--mono",
59
58
  "aria-label": "JSON",
60
59
  placeholder: "Paste a JSON object or array",
61
- value: '{\n "id": 1,\n "name": "Ada",\n "tags": ["dev"],\n "address": { "city": "London" }\n}',
62
- });
60
+ value: '{\n "id": 1,\n "name": "Ada",\n "tags": ["dev"],\n "address": { "city": "London" }\n}'});
63
61
  const nameInput = textInput({ value: "Root", "aria-label": "Root type name" });
64
62
  const result = output({ rows: 16 });
65
63
  const error = notice("error");
@@ -91,8 +89,7 @@ export function mount(slot) {
91
89
  stack(panel("Root type name", nameInput), panel("JSON", source), error),
92
90
  stack(panel("TypeScript", result))
93
91
  ),
94
- foot: actions(copyButton(() => result.textContent, "Copy types", "fill")),
95
- });
92
+ foot: actions(copyButton(() => result.textContent, "Copy types", "fill"))});
96
93
  slot.append(card.node);
97
94
  run();
98
95
 
@@ -12,7 +12,7 @@ function describe(data) {
12
12
  }
13
13
 
14
14
  export function mount(slot) {
15
- const source = textArea({ rows: 12, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "JSON", placeholder: "Paste JSON" });
15
+ const source = textArea({ rows: 12, "aria-label": "JSON", placeholder: "Paste JSON" });
16
16
  const report = output({ rows: 4 });
17
17
  const error = notice("error");
18
18
 
@@ -38,8 +38,7 @@ export function mount(slot) {
38
38
  stack(panel("JSON", source), error),
39
39
  stack(panel("Result", report))
40
40
  ),
41
- foot: actions(copyButton(() => report.textContent, "Copy result", "fill")),
42
- });
41
+ foot: actions(copyButton(() => report.textContent, "Copy result", "fill"))});
43
42
  slot.append(card.node);
44
43
  run();
45
44
 
@@ -12,10 +12,10 @@ function decodeSegment(segment) {
12
12
  }
13
13
 
14
14
  export function mount(slot) {
15
- const source = textArea({ rows: 4, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Token", placeholder: "Paste a JWT" });
15
+ const source = textArea({ rows: 4, "aria-label": "Token", placeholder: "Paste a JWT" });
16
16
  const headerOut = output({ rows: 4 });
17
17
  const payloadOut = output({ rows: 8 });
18
- const claims = el("div", { class: "mvb-kv" });
18
+ const claims = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" });
19
19
  const error = notice("error");
20
20
 
21
21
  function render() {
@@ -49,9 +49,9 @@ export function mount(slot) {
49
49
  const value = Number(payload[key]);
50
50
  const when = Number.isFinite(value) ? new Date(value * 1000).toLocaleString() : String(payload[key]);
51
51
  claims.append(
52
- el("div", { class: "mvb-kv__row" },
53
- el("span", { class: "mvb-kv__k" }, label),
54
- el("span", { class: "mvb-kv__v" }, when))
52
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" },
53
+ el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, label),
54
+ el("span", { class: "wrap-anywhere font-mono text-2xs" }, when))
55
55
  );
56
56
  }
57
57
  }
@@ -63,8 +63,7 @@ export function mount(slot) {
63
63
  stack(panel("Token", source), error),
64
64
  stack(panel("Header", headerOut), panel("Payload", payloadOut), claims)
65
65
  ),
66
- foot: actions(copyButton(() => payloadOut.textContent, "Copy payload", "fill")),
67
- });
66
+ foot: actions(copyButton(() => payloadOut.textContent, "Copy payload", "fill"))});
68
67
  slot.append(card.node);
69
68
  render();
70
69
 
@@ -21,11 +21,11 @@ function relative(seconds) {
21
21
  }
22
22
 
23
23
  const kvRow = (key, value) =>
24
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
24
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
25
25
 
26
26
  export function mount(slot) {
27
- const source = textArea({ rows: 4, class: "mvb-in mvb-in--area mvb-in--mono", "aria-label": "Token", placeholder: "Paste a JWT" });
28
- const claims = el("div", { class: "mvb-kv" });
27
+ const source = textArea({ rows: 4, "aria-label": "Token", placeholder: "Paste a JWT" });
28
+ const claims = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" });
29
29
  const status = notice("note");
30
30
  const error = notice("error");
31
31
  let summary = "";
@@ -82,12 +82,11 @@ export function mount(slot) {
82
82
  stack(
83
83
  panel("Token", source),
84
84
  error,
85
- el("p", { class: "mvb-note" }, "Only the payload is read in this tab. The signature is not checked, so a valid look is not proof the token is genuine.")
85
+ el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Only the payload is read in this tab. The signature is not checked, so a valid look is not proof the token is genuine.")
86
86
  ),
87
87
  stack(panel("Time claims", claims), status)
88
88
  ),
89
- foot: actions(copyButton(() => summary, "Copy claims", "fill")),
90
- });
89
+ foot: actions(copyButton(() => summary, "Copy claims", "fill"))});
91
90
  slot.append(card.node);
92
91
  run();
93
92
 
@@ -21,12 +21,11 @@ export function mount(slot) {
21
21
  const headerField = textArea({ rows: 3, value: '{\n "alg": "HS256",\n "typ": "JWT"\n}' });
22
22
  const payloadField = textArea({
23
23
  rows: 7,
24
- value: `{\n "sub": "1234567890",\n "name": "Ada",\n "admin": true,\n "iat": ${now}\n}`,
25
- });
24
+ value: `{\n "sub": "1234567890",\n "name": "Ada",\n "admin": true,\n "iat": ${now}\n}`});
26
25
  const secretField = textInput({ type: "password", value: "your-256-bit-secret", autocomplete: "new-password" });
27
26
  const showButton = el(
28
27
  "button",
29
- { class: "mvb-icobtn", type: "button", "aria-label": "Show secret", "aria-pressed": "false" },
28
+ { class: "inline-flex size-[var(--ctl)] cursor-pointer items-center justify-center rounded-r1 border border-transparent bg-transparent text-ink-2 transition-colors duration-150 hover:bg-deck-2 hover:text-ink focus-visible:border-jade", type: "button", "aria-label": "Show secret", "aria-pressed": "false" },
30
29
  icon("eye")
31
30
  );
32
31
  const error = notice("error");
@@ -94,13 +93,12 @@ export function mount(slot) {
94
93
  stack(
95
94
  panel("Header", headerField),
96
95
  panel("Payload", payloadField),
97
- panel("Secret", el("div", { class: "mvb-secret" }, secretField, showButton)),
96
+ panel("Secret", el("div", { class: "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2" }, secretField, showButton)),
98
97
  error
99
98
  ),
100
99
  stack(panel("Token", tokenOut), timePanel)
101
100
  ),
102
- foot: actions(copyBtn),
103
- });
101
+ foot: actions(copyBtn)});
104
102
  slot.append(card.node);
105
103
  sign();
106
104
 
@@ -9,8 +9,7 @@ const UNITS = [
9
9
  { value: "in", label: "Inch", factor: 0.0254 },
10
10
  { value: "ft", label: "Foot", factor: 0.3048 },
11
11
  { value: "yd", label: "Yard", factor: 0.9144 },
12
- { value: "mi", label: "Mile", factor: 1609.344 },
13
- ];
12
+ { value: "mi", label: "Mile", factor: 1609.344 }];
14
13
 
15
14
  const byId = Object.fromEntries(UNITS.map((unit) => [unit.value, unit]));
16
15
  const options = UNITS.map(({ value, label }) => ({ value, label }));
@@ -27,11 +26,11 @@ export function mount(slot) {
27
26
  const value = numberInput({ value: "1", step: "any", "aria-label": "Value" });
28
27
  const from = selectInput(options, { value: "m", "aria-label": "From unit" });
29
28
  const to = selectInput(options, { value: "ft", "aria-label": "To unit" });
30
- const result = el("span", { class: "mvb-stat__v" }, "-");
31
- const stats = el("div", { class: "mvb-stats" }, el("div", { class: "mvb-stat" }, el("span", { class: "mvb-stat__k" }, "Result"), result));
32
- const factor = el("p", { class: "mvb-note" });
29
+ const result = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
30
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, el("span", { class: "text-2xs font-semibold text-ink-3" }, "Result"), result));
31
+ const factor = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
33
32
  const error = notice("error");
34
- const scroll = el("div", { class: "mvb-scroll" });
33
+ const scroll = el("div", { class: "max-h-80 overflow-auto" });
35
34
  let text = "";
36
35
 
37
36
  function run() {
@@ -51,7 +50,7 @@ export function mount(slot) {
51
50
  const out = (n * a.factor) / b.factor;
52
51
  result.textContent = `${fmt(out)} ${b.value}`;
53
52
  factor.textContent = `1 ${a.value} = ${fmt(a.factor / b.factor)} ${b.value}`;
54
- scroll.replaceChildren(el("table", { class: "mvb-ttable" },
53
+ scroll.replaceChildren(el("table", { class: "w-full border-collapse font-mono text-sm [&_th]:wrap-anywhere [&_td]:wrap-anywhere [&_th]:border-b [&_td]:border-b [&_th]:border-orbit [&_td]:border-orbit [&_th]:px-2.5 [&_td]:px-2.5 [&_th]:py-2 [&_td]:py-2 [&_th]:text-start [&_td]:text-start [&_th]:font-sans [&_th]:text-2xs [&_th]:font-semibold [&_th]:text-ink-2 [&_tbody>tr:last-child>th]:border-b-0 [&_tbody>tr:last-child>td]:border-b-0" },
55
54
  el("thead", {}, el("tr", {}, el("th", {}, "Unit"), el("th", {}, "Value"))),
56
55
  el("tbody", {}, ...UNITS.map((unit) => el("tr", {},
57
56
  el("td", {}, unit.label),
@@ -75,8 +74,7 @@ export function mount(slot) {
75
74
  stack(panel("Value", value), panel("From", from), panel("To", to), error),
76
75
  stack(panel("Result", stats), factor, panel("All units", scroll))
77
76
  ),
78
- foot: actions(swap, copyButton(() => text, "Copy result", "fill")),
79
- });
77
+ foot: actions(swap, copyButton(() => text, "Copy result", "fill"))});
80
78
  slot.append(card.node);
81
79
  run();
82
80
 
@@ -7,19 +7,18 @@ const LICENSES = [
7
7
  { value: "GPL-3.0", label: "GPL-3.0", can: "Use, modify and distribute.", must: "Release derivative works under the same license and share the source.", cannot: "Add restrictions beyond the license." },
8
8
  { value: "BSD-3-Clause", label: "BSD-3-Clause", can: "Use, modify and distribute, including commercially.", must: "Keep the copyright notice and disclaimer.", cannot: "Use contributor names to endorse derivatives." },
9
9
  { value: "MPL-2.0", label: "MPL-2.0", can: "Use, modify and distribute.", must: "Share changes to MPL-licensed files under MPL.", cannot: "Hold contributors liable." },
10
- { value: "Unlicense", label: "Unlicense", can: "Use, modify and distribute with no conditions.", must: "Nothing.", cannot: "Hold the author liable." },
11
- ];
10
+ { value: "Unlicense", label: "Unlicense", can: "Use, modify and distribute with no conditions.", must: "Nothing.", cannot: "Hold the author liable." }];
12
11
 
13
12
  const kvRow = (key, value) =>
14
- el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), el("span", { class: "mvb-kv__v" }, value));
13
+ el("div", { class: "grid gap-3 bg-deck px-3 py-[9px] [grid-template-columns:minmax(90px,34%)_minmax(0,1fr)]" }, el("span", { class: "wrap-anywhere text-2xs font-semibold text-ink-2" }, key), el("span", { class: "wrap-anywhere font-mono text-2xs" }, value));
15
14
 
16
15
  export function mount(slot) {
17
- const name = el("span", { class: "mvb-stat__v" }, LICENSES[0].label);
18
- const stats = el("div", { class: "mvb-stats" }, el("div", { class: "mvb-stat" }, el("span", { class: "mvb-stat__k" }, "License"), name));
19
- const can = el("span", { class: "mvb-kv__v" });
20
- const must = el("span", { class: "mvb-kv__v" });
21
- const cannot = el("span", { class: "mvb-kv__v" });
22
- const kv = el("div", { class: "mvb-kv" }, kvRow("Can", can), kvRow("Must", must), kvRow("Cannot", cannot));
16
+ const name = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, LICENSES[0].label);
17
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, el("span", { class: "text-2xs font-semibold text-ink-3" }, "License"), name));
18
+ const can = el("span", { class: "wrap-anywhere font-mono text-2xs" });
19
+ const must = el("span", { class: "wrap-anywhere font-mono text-2xs" });
20
+ const cannot = el("span", { class: "wrap-anywhere font-mono text-2xs" });
21
+ const kv = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, kvRow("Can", can), kvRow("Must", must), kvRow("Cannot", cannot));
23
22
  const disclaimer = notice("note");
24
23
  disclaimer.write("Short summary, not legal advice.");
25
24
  let current = LICENSES[0];
@@ -31,8 +30,7 @@ export function mount(slot) {
31
30
  onChange: (value) => {
32
31
  current = LICENSES.find((entry) => entry.value === value);
33
32
  run();
34
- },
35
- });
33
+ }});
36
34
 
37
35
  function run() {
38
36
  name.textContent = current.label;
@@ -47,8 +45,7 @@ export function mount(slot) {
47
45
  stack(panel("License", chips), disclaimer),
48
46
  stack(panel("Summary", stats), panel("Terms", kv))
49
47
  ),
50
- foot: actions(copyButton(() => text, "Copy summary", "fill")),
51
- });
48
+ foot: actions(copyButton(() => text, "Copy summary", "fill"))});
52
49
  slot.append(card.node);
53
50
  run();
54
51
 
@@ -2,8 +2,8 @@
2
2
  import { el, bench, stack, panel, textArea, button, copyButton, actions, toolcard } from "../core.js";
3
3
 
4
4
  function tile(label) {
5
- const value = el("span", { class: "mvb-stat__v" }, "0");
6
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
5
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
6
+ const node = el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" }, value, el("span", { class: "text-2xs font-semibold text-ink-3" }, label));
7
7
  node.set = (text) => { value.textContent = text; };
8
8
  return node;
9
9
  }
@@ -14,7 +14,7 @@ export function mount(slot) {
14
14
  const totalTile = tile("Total lines");
15
15
  const filledTile = tile("Filled");
16
16
  const blankTile = tile("Blank");
17
- const stats = el("div", { class: "mvb-stats" }, totalTile, filledTile, blankTile);
17
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, totalTile, filledTile, blankTile);
18
18
 
19
19
  let counts = { total: 0, filled: 0, blank: 0 };
20
20
 
@@ -22,8 +22,7 @@ export function mount(slot) {
22
22
  return [
23
23
  `${counts.total} total lines`,
24
24
  `${counts.filled} filled`,
25
- `${counts.blank} blank`,
26
- ].join("\n");
25
+ `${counts.blank} blank`].join("\n");
27
26
  }
28
27
 
29
28
  function run() {
@@ -44,8 +43,7 @@ export function mount(slot) {
44
43
  stack(panel("Text", source)),
45
44
  stack(stats)
46
45
  ),
47
- foot: actions(clearButton, copyButton(summary, "Copy summary", "fill")),
48
- });
46
+ foot: actions(clearButton, copyButton(summary, "Copy summary", "fill"))});
49
47
  slot.append(card.node);
50
48
  run();
51
49