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
@@ -12,14 +12,14 @@ export function mount(slot) {
12
12
  const saved = readPin(PIN, {});
13
13
  const counts = new Map();
14
14
 
15
- const listWrap = el("div", { class: "mvb-scroll" });
16
- const stats = el("div", { class: "mvb-stats" });
15
+ const listWrap = el("div", { class: "max-h-80 overflow-auto" });
16
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
17
17
  const note = notice("note");
18
18
  note.write("Values are generic. Match them to your currency.");
19
19
 
20
- const tile = (key, value) => el("div", { class: "mvb-stat" },
21
- el("span", { class: "mvb-stat__v" }, String(value)),
22
- el("span", { class: "mvb-stat__k" }, key));
20
+ const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
21
+ el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
22
+ el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
23
23
 
24
24
  const readCount = (value) => {
25
25
  const input = counts.get(value);
@@ -40,7 +40,7 @@ export function mount(slot) {
40
40
  el("th", {}, fmt(value)),
41
41
  el("td", {}, fmt(readCount(value))),
42
42
  el("td", {}, fmt(value * readCount(value)))));
43
- listWrap.replaceChildren(el("table", { class: "mvb-ttable" },
43
+ 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" },
44
44
  el("thead", {}, el("tr", {}, el("th", {}, "Value"), el("th", {}, "Count"), el("th", {}, "Subtotal"))),
45
45
  el("tbody", {}, ...rows)));
46
46
  const pieces = DENOMINATIONS.reduce((sum, value) => sum + readCount(value), 0);
@@ -63,8 +63,7 @@ export function mount(slot) {
63
63
  () => DENOMINATIONS.map((value) => `${fmt(value)} x ${readCount(value)} = ${fmt(value * readCount(value))}`).join("\n"),
64
64
  "Copy count",
65
65
  "fill"
66
- )),
67
- });
66
+ ))});
68
67
  slot.append(card.node);
69
68
  render();
70
69
 
@@ -20,15 +20,15 @@ export function mount(slot) {
20
20
  [{ value: "in", label: "In" }, { value: "out", label: "Out" }],
21
21
  { value: "in", label: "Direction", onChange: (next) => { type = next; } }
22
22
  );
23
- const listWrap = el("div", { class: "mvb-scroll" });
24
- const stats = el("div", { class: "mvb-stats" });
23
+ const listWrap = el("div", { class: "max-h-80 overflow-auto" });
24
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
25
25
 
26
26
  const addButton = button("Add", { icon: "plus", kind: "fill" });
27
27
 
28
28
  const save = () => writePin(PIN, { opening: Number(opening.value) || 0, entries });
29
- const tile = (key, value) => el("div", { class: "mvb-stat" },
30
- el("span", { class: "mvb-stat__v" }, String(value)),
31
- el("span", { class: "mvb-stat__k" }, key));
29
+ const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
30
+ el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
31
+ el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
32
32
 
33
33
  function totals() {
34
34
  let balance = Number(opening.value) || 0;
@@ -69,7 +69,7 @@ export function mount(slot) {
69
69
  el("td", {}, fmt(balance)),
70
70
  el("td", {}, removeButton(entry)));
71
71
  });
72
- listWrap.replaceChildren(el("table", { class: "mvb-ttable" },
72
+ 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" },
73
73
  el("thead", {}, el("tr", {}, el("th", {}, "Label"), el("th", {}, "In"), el("th", {}, "Out"), el("th", {}, "Balance"), el("th", {}, ""))),
74
74
  el("tbody", {}, ...rows)));
75
75
  }
@@ -113,8 +113,7 @@ export function mount(slot) {
113
113
  copyButton(() => totals().lines.join("\n"), "Copy summary"),
114
114
  downloadButton(() => csv(), "cash-flow.csv", "Save CSV", "text/csv"),
115
115
  addButton
116
- ),
117
- });
116
+ )});
118
117
  slot.append(card.node);
119
118
  render();
120
119
 
@@ -5,8 +5,8 @@ const DAY = 86400000;
5
5
  const pad = (value) => String(value).padStart(2, "0");
6
6
 
7
7
  function tile(label) {
8
- const value = el("span", { class: "mvb-stat__v" }, "-");
9
- const node = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, label));
8
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "-");
9
+ 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));
10
10
  node.set = (text) => { value.textContent = text; };
11
11
  return node;
12
12
  }
@@ -16,14 +16,13 @@ export function mount(slot) {
16
16
  const dateField = textInput({
17
17
  type: "date",
18
18
  value: `${soon.getFullYear()}-${pad(soon.getMonth() + 1)}-${pad(soon.getDate())}`,
19
- "aria-label": "Expiry date",
20
- });
19
+ "aria-label": "Expiry date"});
21
20
  const warnField = numberInput({ min: "1", max: "365", value: "30", "aria-label": "Warn threshold in days" });
22
21
 
23
22
  const daysTile = tile("Days left");
24
23
  const weeksTile = tile("Weeks left");
25
24
  const statusTile = tile("Status");
26
- const stats = el("div", { class: "mvb-stats" }, daysTile, weeksTile, statusTile);
25
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, daysTile, weeksTile, statusTile);
27
26
  const status = notice("note");
28
27
  const error = notice("error");
29
28
  let summary = "";
@@ -70,8 +69,7 @@ export function mount(slot) {
70
69
  ),
71
70
  stack(stats, status)
72
71
  ),
73
- foot: actions(copyButton(() => summary, "Copy summary", "fill")),
74
- });
72
+ foot: actions(copyButton(() => summary, "Copy summary", "fill"))});
75
73
  slot.append(card.node);
76
74
  run();
77
75
 
@@ -5,12 +5,11 @@ const GROUPS = [
5
5
  { key: "added", label: "Added" },
6
6
  { key: "changed", label: "Changed" },
7
7
  { key: "fixed", label: "Fixed" },
8
- { key: "removed", label: "Removed" },
9
- ];
8
+ { key: "removed", label: "Removed" }];
10
9
 
11
10
  export function mount(slot) {
12
- const version = textInput({ value: "1.0.0", class: "mvb-in mvb-in--mono", "aria-label": "Version" });
13
- const date = el("input", { class: "mvb-in", type: "date", value: new Date().toISOString().slice(0, 10), "aria-label": "Date" });
11
+ const version = textInput({ value: "1.0.0", mono: true, "aria-label": "Version" });
12
+ const date = el("input", { class: "min-w-0 rounded-r1 border border-orbit bg-deck text-ink transition-[border-color,box-shadow] duration-150 placeholder:text-ink-3 hover:border-orbit-hard focus:border-jade focus:outline-none focus:ring-3 focus:ring-jade-soft w-full min-h-[var(--ctl)] px-3 py-2.5 text-base", type: "date", value: new Date().toISOString().slice(0, 10), "aria-label": "Date" });
14
13
  const fields = GROUPS.map((group) => ({ ...group, area: textArea({ rows: 3, "aria-label": group.label }) }));
15
14
  const out = output({ rows: 16 });
16
15
  let text = "";
@@ -37,8 +36,7 @@ export function mount(slot) {
37
36
  stack(panel("Version", version), panel("Date", date), ...fields.map((group) => panel(group.label, group.area))),
38
37
  stack(panel("Changelog", out))
39
38
  ),
40
- foot: actions(copyButton(() => text, "Copy Markdown", "fill")),
41
- });
39
+ foot: actions(copyButton(() => text, "Copy Markdown", "fill"))});
42
40
  slot.append(card.node);
43
41
  run();
44
42
 
@@ -6,8 +6,8 @@ const chars = (text) => [...text].length;
6
6
  const withoutSpaces = (text) => [...text.replace(/\s/g, "")].length;
7
7
 
8
8
  function tile(label) {
9
- const value = el("span", { class: "mvb-stat__v" }, "0");
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" }, "0");
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,11 +19,11 @@ export function mount(slot) {
19
19
  const totalTile = tile("Characters");
20
20
  const noSpaceTile = tile("Without spaces");
21
21
  const wordsTile = tile("Words");
22
- const stats = el("div", { class: "mvb-stats" }, totalTile, noSpaceTile, wordsTile);
22
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, totalTile, noSpaceTile, wordsTile);
23
23
 
24
- const meter = el("div", { class: "mvb-meter", role: "img", "aria-label": "Character limit" }, el("div", { class: "mvb-meter__fill" }));
24
+ const meter = el("div", { class: "h-2 overflow-hidden rounded-full bg-deck-2", role: "img", "aria-label": "Character limit" }, el("div", { class: "h-full w-0 rounded-full bg-orbit-hard transition-[width,background-color] duration-150 data-[level=weak]:bg-danger data-[level=ok]:bg-star data-[level=strong]:bg-jade" }));
25
25
  const limitNote = notice("note");
26
- const fill = meter.querySelector(".mvb-meter__fill");
26
+ const fill = meter.firstElementChild;
27
27
 
28
28
  let counts = { total: 0, noSpace: 0, words: 0 };
29
29
 
@@ -31,8 +31,7 @@ export function mount(slot) {
31
31
  return [
32
32
  `${counts.total} characters`,
33
33
  `${counts.noSpace} without spaces`,
34
- `${counts.words} words`,
35
- ].join("\n");
34
+ `${counts.words} words`].join("\n");
36
35
  }
37
36
 
38
37
  function run() {
@@ -40,8 +39,7 @@ export function mount(slot) {
40
39
  counts = {
41
40
  total: chars(text),
42
41
  noSpace: withoutSpaces(text),
43
- words: text.trim() ? text.trim().split(/\s+/).length : 0,
44
- };
42
+ words: text.trim() ? text.trim().split(/\s+/).length : 0};
45
43
  totalTile.set(String(counts.total));
46
44
  noSpaceTile.set(String(counts.noSpace));
47
45
  wordsTile.set(String(counts.words));
@@ -50,11 +48,11 @@ export function mount(slot) {
50
48
  if (limit > 0) {
51
49
  const ratio = counts.total / limit;
52
50
  fill.style.width = `${Math.min(100, ratio * 100)}%`;
53
- fill.className = `mvb-meter__fill ${ratio > 1 ? "mvb-weak" : ratio > 0.8 ? "mvb-ok" : "mvb-strong"}`;
51
+ fill.dataset.level = ratio > 1 ? "weak" : ratio > 0.8 ? "ok" : "strong";
54
52
  limitNote.write(ratio > 1 ? `${counts.total - limit} over the limit.` : `${limit - counts.total} characters left.`);
55
53
  } else {
56
54
  fill.style.width = "0%";
57
- fill.className = "mvb-meter__fill";
55
+ delete fill.dataset.level;
58
56
  limitNote.write("");
59
57
  }
60
58
  }
@@ -69,8 +67,7 @@ export function mount(slot) {
69
67
  stack(panel("Text", source), panel("Character limit", limitField)),
70
68
  stack(stats, meter, limitNote)
71
69
  ),
72
- foot: actions(clearButton, copyButton(summary, "Copy summary", "fill")),
73
- });
70
+ foot: actions(clearButton, copyButton(summary, "Copy summary", "fill"))});
74
71
  slot.append(card.node);
75
72
  run();
76
73
 
@@ -9,16 +9,16 @@ export function mount(slot) {
9
9
  let list = Array.isArray(saved) ? saved : [];
10
10
 
11
11
  const entry = textInput({ placeholder: "New item", "aria-label": "New item" });
12
- const listWrap = el("div", { class: "mvb-scroll" });
13
- const stats = el("div", { class: "mvb-stats" });
12
+ const listWrap = el("div", { class: "max-h-80 overflow-auto" });
13
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" });
14
14
 
15
15
  const addButton = button("Add", { icon: "plus", kind: "fill" });
16
16
  const clearDone = button("Clear finished", { icon: "trash" });
17
17
  const copyList = copyButton(() => listText(), "Copy list");
18
18
 
19
- const tile = (key, value) => el("div", { class: "mvb-stat" },
20
- el("span", { class: "mvb-stat__v" }, String(value)),
21
- el("span", { class: "mvb-stat__k" }, key));
19
+ const tile = (key, value) => el("div", { class: "grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3" },
20
+ el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, String(value)),
21
+ el("span", { class: "text-2xs font-semibold text-ink-3" }, key));
22
22
 
23
23
  const save = () => writePin(PIN, list);
24
24
 
@@ -75,8 +75,7 @@ export function mount(slot) {
75
75
  stack(panel("New item", entry)),
76
76
  stack(stats, panel("Items", listWrap))
77
77
  ),
78
- foot: actions(copyList, clearDone, addButton),
79
- });
78
+ foot: actions(copyList, clearDone, addButton)});
80
79
  slot.append(card.node);
81
80
  renderList();
82
81
 
@@ -2,8 +2,8 @@
2
2
  import { el, bench, stack, panel, textArea, notice, 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
  }
@@ -47,8 +47,8 @@ export function mount(slot) {
47
47
  const refsTile = tile("References");
48
48
  const missingTile = tile("Missing");
49
49
  const unusedTile = tile("Unused");
50
- const stats = el("div", { class: "mvb-stats" }, citedTile, refsTile, missingTile, unusedTile);
51
- const tableWrap = el("div", { class: "mvb-scroll" });
50
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, citedTile, refsTile, missingTile, unusedTile);
51
+ const tableWrap = el("div", { class: "max-h-80 overflow-auto" });
52
52
  const note = notice("note");
53
53
  note.write("A number match does not prove the reference is correct.");
54
54
  let report = "";
@@ -66,14 +66,13 @@ export function mount(slot) {
66
66
 
67
67
  const rows = [
68
68
  ...missing.map((n) => [n, "Cited, no reference"]),
69
- ...unused.map((n) => [n, "Reference, not cited"]),
70
- ];
69
+ ...unused.map((n) => [n, "Reference, not cited"])];
71
70
  if (!body.value.trim() && !list.value.trim()) {
72
- tableWrap.replaceChildren(el("p", { class: "mvb-note" }, "Paste the text and the reference list."));
71
+ tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Paste the text and the reference list."));
73
72
  } else if (!rows.length) {
74
- tableWrap.replaceChildren(el("p", { class: "mvb-note" }, "Every number matches."));
73
+ tableWrap.replaceChildren(el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" }, "Every number matches."));
75
74
  } else {
76
- tableWrap.replaceChildren(el("table", { class: "mvb-ttable" },
75
+ tableWrap.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" },
77
76
  el("thead", {}, el("tr", {}, el("th", {}, "Number"), el("th", {}, "Problem"))),
78
77
  el("tbody", {}, ...rows.map((row) => el("tr", {},
79
78
  el("th", {}, String(row[0])),
@@ -84,8 +83,7 @@ export function mount(slot) {
84
83
 
85
84
  report = [
86
85
  ...missing.map((n) => `${n}: cited, no reference`),
87
- ...unused.map((n) => `${n}: reference, not cited`),
88
- ].join("\n");
86
+ ...unused.map((n) => `${n}: reference, not cited`)].join("\n");
89
87
  }
90
88
 
91
89
  body.addEventListener("input", run);
@@ -96,8 +94,7 @@ export function mount(slot) {
96
94
  stack(panel("Text with citations", body), panel("Reference list", list), note),
97
95
  stack(stats, panel("Problems", tableWrap))
98
96
  ),
99
- foot: actions(copyButton(() => report, "Copy problems", "fill")),
100
- });
97
+ foot: actions(copyButton(() => report, "Copy problems", "fill"))});
101
98
  slot.append(card.node);
102
99
  run();
103
100
 
@@ -7,8 +7,8 @@ const TOSS_MS = 400;
7
7
 
8
8
  /** A tally tile. The value is the node the tool writes to. */
9
9
  function tile(key) {
10
- const value = el("span", { class: "mvb-stat__v" }, "0");
11
- const row = el("div", { class: "mvb-stat" }, value, el("span", { class: "mvb-stat__k" }, key));
10
+ const value = el("span", { class: "wrap-anywhere text-xl font-bold tracking-[-0.02em] tabular-nums" }, "0");
11
+ const row = 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" }, key));
12
12
  return { row, value };
13
13
  }
14
14
 
@@ -19,12 +19,12 @@ export function mount(slot) {
19
19
  let tails = Number(saved.tails) || 0;
20
20
  let timer = 0;
21
21
 
22
- const coin = el("div", { class: "mvb-coin", role: "img", "aria-label": "Coin, not flipped yet" }, "?");
23
- const verdict = el("p", { class: "mvb-flip__result min-h-7", "aria-live": "polite" });
22
+ const coin = el("div", { class: "grid size-32 select-none place-items-center rounded-full bg-jade text-display font-bold text-on-jade data-[toss]:animate-toss", role: "img", "aria-label": "Coin, not flipped yet" }, "?");
23
+ const verdict = el("p", { class: "text-lg font-bold tracking-[-0.01em] min-h-7", "aria-live": "polite" });
24
24
  const headsTile = tile("Heads");
25
25
  const tailsTile = tile("Tails");
26
26
  const totalTile = tile("Total");
27
- const stats = el("div", { class: "mvb-stats" }, headsTile.row, tailsTile.row, totalTile.row);
27
+ const stats = el("div", { class: "grid gap-2.5 [grid-template-columns:repeat(auto-fit,minmax(120px,1fr))]" }, headsTile.row, tailsTile.row, totalTile.row);
28
28
 
29
29
  function render(decision) {
30
30
  verdict.textContent = decision;
@@ -40,9 +40,9 @@ export function mount(slot) {
40
40
 
41
41
  flipButton.addEventListener("click", () => {
42
42
  clearTimeout(timer);
43
- coin.classList.remove("mvb-toss");
43
+ delete coin.dataset.toss;
44
44
  void coin.offsetWidth;
45
- coin.classList.add("mvb-toss");
45
+ coin.dataset.toss = "";
46
46
  timer = setTimeout(() => {
47
47
  const isHeads = randomInt(2) === 0;
48
48
  if (isHeads) heads++;
@@ -65,16 +65,14 @@ export function mount(slot) {
65
65
  stack(panel("Coin", coin)),
66
66
  stack(panel("Result", verdict), stats)
67
67
  ),
68
- foot: actions(resetButton, flipButton),
69
- });
68
+ foot: actions(resetButton, flipButton)});
70
69
  slot.append(card.node);
71
70
  render("");
72
71
 
73
72
  return {
74
73
  unmount() {
75
74
  clearTimeout(timer);
76
- },
77
- };
75
+ }};
78
76
  }
79
77
 
80
78
  export default { mount };
@@ -70,12 +70,12 @@ function luminance({ r, g, b }) {
70
70
  }
71
71
 
72
72
  export function mount(slot) {
73
- const anyField = textInput({ value: "#F5B942", class: "mvb-in mvb-in--mono", "aria-label": "Any color" });
73
+ const anyField = textInput({ value: "#F5B942", mono: true, "aria-label": "Any color" });
74
74
  const picker = colorInput({ value: "#f5b942", "aria-label": "Pick a color" });
75
- const swatch = el("div", { class: "mvb-swatch" });
75
+ const swatch = el("div", { class: "h-14 rounded-r1 border border-orbit-hard bg-deck-2" });
76
76
 
77
77
  const readonly = (label) => {
78
- const field = textInput({ readonly: true, class: "mvb-in mvb-in--mono", "aria-label": `${label}, press to copy` });
78
+ const field = textInput({ readonly: true, mono: true, "aria-label": `${label}, press to copy` });
79
79
  const wrap = panel(label, field);
80
80
  wrap.style.cursor = "pointer";
81
81
  wrap.addEventListener("click", async () => {
@@ -91,7 +91,7 @@ export function mount(slot) {
91
91
  const cssField = readonly("CSS variable");
92
92
 
93
93
  const error = notice("error");
94
- const reading = el("p", { class: "mvb-note" });
94
+ const reading = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
95
95
 
96
96
  // `from` names the control the value came from. The text field is never
97
97
  // rewritten while it is being typed into: "#abc" is valid shorthand one
@@ -136,14 +136,13 @@ export function mount(slot) {
136
136
  const card = toolcard({
137
137
  body: bench(
138
138
  stack(
139
- panel("Color", el("div", { class: "mvb-row" }, picker, anyField)),
139
+ panel("Color", el("div", { class: "flex min-w-0 flex-wrap items-center gap-2" }, picker, anyField)),
140
140
  error,
141
141
  panel(null, swatch),
142
142
  reading
143
143
  ),
144
144
  stack(hexField, rgbField, hslField, cssField)
145
- ),
146
- });
145
+ )});
147
146
  slot.append(card.node);
148
147
  read("#F5B942", "init");
149
148
 
@@ -59,7 +59,7 @@ function palette(hex, scheme) {
59
59
 
60
60
  export function mount(slot) {
61
61
  const picker = colorInput({ value: "#f5b942", "aria-label": "Base color" });
62
- const swatches = el("div", { class: "mvb-swatches" });
62
+ const swatches = el("div", { class: "grid gap-2 [grid-template-columns:repeat(auto-fit,minmax(96px,1fr))]" });
63
63
  let colors = [];
64
64
  let scheme = "analogous";
65
65
 
@@ -67,8 +67,7 @@ export function mount(slot) {
67
67
  [
68
68
  { value: "analogous", label: "Analogous" },
69
69
  { value: "complementary", label: "Complementary" },
70
- { value: "monochrome", label: "Monochrome" },
71
- ],
70
+ { value: "monochrome", label: "Monochrome" }],
72
71
  { value: scheme, label: "Scheme", onChange: (value) => { scheme = value; paint(); } }
73
72
  );
74
73
 
@@ -82,9 +81,9 @@ export function mount(slot) {
82
81
  ...colors.map((hex) =>
83
82
  el(
84
83
  "button",
85
- { class: "mvb-swatchcard", type: "button", onclick: () => copyOne(hex) },
86
- el("span", { class: "mvb-swatchcard__chip", style: `background:${hex}` }),
87
- el("span", { class: "mvb-swatchcard__code" }, hex)
84
+ { class: "grid cursor-pointer gap-1.5 rounded-r1 border border-orbit bg-deck p-2 text-start transition-colors duration-150 hover:border-jade", type: "button", onclick: () => copyOne(hex) },
85
+ el("span", { class: "h-[52px] rounded-lg border border-orbit-hard", style: `background:${hex}` }),
86
+ el("span", { class: "font-mono text-2xs text-ink-2" }, hex)
88
87
  )
89
88
  )
90
89
  );
@@ -99,8 +98,7 @@ export function mount(slot) {
99
98
  ),
100
99
  foot: actions(
101
100
  copyButton(() => colors.map((hex, i) => `--color-${i + 1}: ${hex};`).join("\n"), "Copy CSS variables", "fill")
102
- ),
103
- });
101
+ )});
104
102
  slot.append(card.node);
105
103
  paint();
106
104
 
@@ -32,13 +32,13 @@ function toHsl({ r, g, b }) {
32
32
 
33
33
  export function mount(slot) {
34
34
  const picker = colorInput({ value: "#f5b942", "aria-label": "Pick a color" });
35
- const hexInput = textInput({ value: "#F5B942", class: "mvb-in mvb-in--mono", "aria-label": "Hex value" });
36
- const swatch = el("div", { class: "mvb-swatch" });
35
+ const hexInput = textInput({ value: "#F5B942", mono: true, "aria-label": "Hex value" });
36
+ const swatch = el("div", { class: "h-14 rounded-r1 border border-orbit-hard bg-deck-2" });
37
37
  const error = notice("error");
38
38
  let current = "#f5b942";
39
39
 
40
40
  const readonly = (label) => {
41
- const field = textInput({ readonly: true, class: "mvb-in mvb-in--mono", "aria-label": `${label}, press to copy` });
41
+ const field = textInput({ readonly: true, mono: true, "aria-label": `${label}, press to copy` });
42
42
  const wrap = panel(label, field);
43
43
  wrap.style.cursor = "pointer";
44
44
  wrap.addEventListener("click", async () => {
@@ -82,8 +82,7 @@ export function mount(slot) {
82
82
  foot: actions(
83
83
  copyButton(() => `--color: ${current};`, "Copy CSS"),
84
84
  copyButton(() => current, "Copy hex", "fill")
85
- ),
86
- });
85
+ )});
87
86
  slot.append(card.node);
88
87
  read("#F5B942", false);
89
88
 
@@ -19,7 +19,7 @@ export function mount(slot) {
19
19
  { value: "Idea", label: "Status", onChange: (next) => { status = next; } }
20
20
  );
21
21
 
22
- const listWrap = el("div", { class: "mvb-scroll" });
22
+ const listWrap = el("div", { class: "max-h-80 overflow-auto" });
23
23
  const addButton = button("Add", { icon: "plus", kind: "fill" });
24
24
 
25
25
  const save = () => writePin(PIN, { entries });
@@ -46,7 +46,7 @@ export function mount(slot) {
46
46
  el("td", {}, entry.platform || ""),
47
47
  el("td", {}, entry.status),
48
48
  el("td", {}, removeButton(entry))));
49
- listWrap.replaceChildren(el("table", { class: "mvb-ttable" },
49
+ 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" },
50
50
  el("thead", {}, el("tr", {},
51
51
  el("th", {}, "Date"), el("th", {}, "Topic"), el("th", {}, "Platform"), el("th", {}, "Status"), el("th", {}, ""))),
52
52
  el("tbody", {}, ...rows)));
@@ -100,8 +100,7 @@ export function mount(slot) {
100
100
  downloadButton(() => csv(), "content-calendar.csv", "Save CSV", "text/csv"),
101
101
  downloadButton(() => markdown(), "content-calendar.md", "Save Markdown", "text/markdown"),
102
102
  addButton
103
- ),
104
- });
103
+ )});
105
104
  slot.append(card.node);
106
105
  render();
107
106
 
@@ -31,19 +31,19 @@ export function mount(slot) {
31
31
  const bgPicker = colorInput({ value: "#ffffff", "aria-label": "Background color" });
32
32
 
33
33
  const kvRow = (key) => {
34
- const value = el("span", { class: "mvb-kv__v" }, "-");
35
- return { v: value, node: el("div", { class: "mvb-kv__row" }, el("span", { class: "mvb-kv__k" }, key), value) };
34
+ const value = el("span", { class: "wrap-anywhere font-mono text-2xs" }, "-");
35
+ return { v: value, node: 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), value) };
36
36
  };
37
37
  const ratioRow = kvRow("Contrast ratio");
38
38
  const normalAA = kvRow("Normal text AA");
39
39
  const normalAAA = kvRow("Normal text AAA");
40
40
  const largeAA = kvRow("Large text AA");
41
41
  const largeAAA = kvRow("Large text AAA");
42
- const list = el("div", { class: "mvb-kv" }, ratioRow.node, normalAA.node, normalAAA.node, largeAA.node, largeAAA.node);
42
+ const list = el("div", { class: "grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit" }, ratioRow.node, normalAA.node, normalAAA.node, largeAA.node, largeAAA.node);
43
43
 
44
44
  const sample = el(
45
45
  "div",
46
- { class: "mvb-preview__sample" },
46
+ { class: "w-full rounded-lg border border-orbit bg-deck px-[18px] py-4" },
47
47
  el("p", { style: "margin:0 0 8px;font-size:20px;font-weight:700" }, "Large text sample"),
48
48
  el("p", { style: "margin:0;font-size:15px" }, "Normal text sample for the contrast reading.")
49
49
  );
@@ -82,8 +82,7 @@ export function mount(slot) {
82
82
  stack(panel("Text color", textPicker), panel("Background color", bgPicker)),
83
83
  stack(sample, list)
84
84
  ),
85
- foot: actions(swap, copyButton(() => reading, "Copy result", "fill")),
86
- });
85
+ foot: actions(swap, copyButton(() => reading, "Copy result", "fill"))});
87
86
  slot.append(card.node);
88
87
  update();
89
88
 
@@ -38,8 +38,7 @@ const FIELDS = [
38
38
  ["hour", "Hour", "0-23", "*"],
39
39
  ["day", "Day of month", "1-31", "*"],
40
40
  ["month", "Month", "1-12", "*"],
41
- ["weekday", "Day of week", "0-6", "*"],
42
- ];
41
+ ["weekday", "Day of week", "0-6", "*"]];
43
42
 
44
43
  export function mount(slot) {
45
44
  const inputs = {};
@@ -49,8 +48,8 @@ export function mount(slot) {
49
48
  return panel(label, input, hint);
50
49
  });
51
50
 
52
- const expression = textInput({ readonly: true, class: "mvb-in mvb-in--mono", "aria-label": "Cron expression" });
53
- const reading = el("p", { class: "mvb-note" });
51
+ const expression = textInput({ readonly: true, mono: true, "aria-label": "Cron expression" });
52
+ const reading = el("p", { class: "border-s-[3px] border-transparent ps-2 text-sm text-ink-3" });
54
53
  const error = notice("error");
55
54
 
56
55
  function run() {
@@ -80,8 +79,7 @@ export function mount(slot) {
80
79
  stack(...controls, error),
81
80
  stack(panel("Expression", expression), panel("Reading", reading))
82
81
  ),
83
- foot: actions(reset, copyButton(() => expression.value, "Copy expression", "fill")),
84
- });
82
+ foot: actions(reset, copyButton(() => expression.value, "Copy expression", "fill"))});
85
83
  slot.append(card.node);
86
84
  run();
87
85
 
@@ -3,11 +3,11 @@ import { el, bench, stack, rangeInput, output, copyButton, actions, toolcard } f
3
3
 
4
4
  function slider(label, { min, max, step, value, unit }) {
5
5
  const input = rangeInput({ min, max, step, value, "aria-label": label });
6
- const val = el("span", { class: "mvb-slider__val" }, `${value}${unit}`);
6
+ const val = el("span", { class: "text-end font-mono text-2xs text-ink-2" }, `${value}${unit}`);
7
7
  const node = el(
8
8
  "div",
9
- { class: "mvb-slider" },
10
- el("span", { class: "mvb-slider__label" }, label),
9
+ { class: "grid items-center gap-2.5 [grid-template-columns:88px_minmax(0,1fr)_62px] max-[45rem]:[grid-template-columns:minmax(0,1fr)_62px]" },
10
+ el("span", { class: "text-2xs font-semibold text-ink-2 max-[45rem]:col-span-2" }, label),
11
11
  input,
12
12
  val
13
13
  );
@@ -24,7 +24,7 @@ export function mount(slot) {
24
24
 
25
25
  const sample = el(
26
26
  "div",
27
- { class: "mvb-preview__sample" },
27
+ { class: "w-full rounded-lg border border-orbit bg-deck px-[18px] py-4" },
28
28
  el("p", { style: "margin:0" }, "The quick brown fox jumps over the lazy dog.")
29
29
  );
30
30
  const code = output();
@@ -55,8 +55,7 @@ export function mount(slot) {
55
55
  stack(min, preferred, max),
56
56
  stack(sample, code)
57
57
  ),
58
- foot: actions(copyButton(() => `font-size: ${clampValue()};`, "Copy CSS", "fill")),
59
- });
58
+ foot: actions(copyButton(() => `font-size: ${clampValue()};`, "Copy CSS", "fill"))});
60
59
  slot.append(card.node);
61
60
  update();
62
61