@filipgutica/ui 1.11.2 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/site.js CHANGED
@@ -1,30 +1,30 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-DCS_wyYq.js";
2
- import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, mergeModels as h, nextTick as g, normalizeClass as _, normalizeStyle as v, onBeforeUnmount as y, onMounted as b, onUnmounted as x, openBlock as S, ref as C, renderList as w, renderSlot as T, shallowRef as E, toDisplayString as D, unref as O, useId as k, useModel as ee, useSlots as A, useTemplateRef as te, watch as j, withCtx as M } from "vue";
3
- import { tryOnMounted as N, usePreferredDark as P, useStorage as F } from "@vueuse/core";
2
+ import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, mergeModels as h, nextTick as g, normalizeClass as _, normalizeStyle as v, onBeforeUnmount as y, onMounted as b, onUnmounted as x, openBlock as S, ref as C, renderList as w, renderSlot as T, shallowRef as E, toDisplayString as D, unref as O, useId as k, useModel as A, useSlots as j, useTemplateRef as M, watch as N, withCtx as P } from "vue";
3
+ import { tryOnMounted as F, usePreferredDark as I, useStorage as L } from "@vueuse/core";
4
4
  //#region src/site/appearance.ts
5
- var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "dark", ne = `(function () {
5
+ var R = "tool-site-theme", z = (e) => e === "system" || e === "light" || e === "dark", ee = `(function () {
6
6
  var root = document.documentElement, choice;
7
- try { choice = localStorage.getItem('${I}'); } catch (error) {}
7
+ try { choice = localStorage.getItem('${R}'); } catch (error) {}
8
8
  var dark = choice === 'dark';
9
9
  if (choice !== 'light' && choice !== 'dark') {
10
10
  try { dark = matchMedia('(prefers-color-scheme: dark)').matches; } catch (error) {}
11
11
  }
12
12
  root.classList.toggle('dark', dark);
13
13
  if (choice === 'light' || choice === 'dark') root.dataset.theme = choice;
14
- })();`, R = ({ root: e, choice: t, appearance: n }) => {
14
+ })();`, B = ({ root: e, choice: t, appearance: n }) => {
15
15
  e.classList.toggle("dark", n === "dark"), t === "system" ? delete e.dataset.theme : e.dataset.theme = t;
16
- }, z = ({ applyToRoot: e = !0 } = {}) => {
17
- let t = F(I, "system", void 0, {
16
+ }, V = ({ applyToRoot: e = !0 } = {}) => {
17
+ let t = L(R, "system", void 0, {
18
18
  initOnMounted: !0,
19
19
  writeDefaults: !1,
20
20
  onError: () => {},
21
21
  serializer: {
22
- read: (e) => L(e) ? e : "system",
22
+ read: (e) => z(e) ? e : "system",
23
23
  write: (e) => e
24
24
  }
25
- }), n = P(), r = s(() => t.value), i = s(() => t.value === "system" ? n.value ? "dark" : "light" : t.value);
26
- return e && N(() => {
27
- j([r, i], () => R({
25
+ }), n = I(), r = s(() => t.value), i = s(() => t.value === "system" ? n.value ? "dark" : "light" : t.value);
26
+ return e && F(() => {
27
+ N([r, i], () => B({
28
28
  root: document.documentElement,
29
29
  choice: r.value,
30
30
  appearance: i.value
@@ -33,10 +33,10 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
33
33
  choice: r,
34
34
  appearance: i,
35
35
  chooseAppearance: (e) => {
36
- L(e) && (t.value = e);
36
+ z(e) && (t.value = e);
37
37
  }
38
38
  };
39
- }, B = [
39
+ }, H = [
40
40
  {
41
41
  id: "annoterm",
42
42
  label: "annoterm",
@@ -73,7 +73,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
73
73
  href: "https://filipgutica.github.io/ui/",
74
74
  repository: "https://github.com/filipgutica/ui"
75
75
  }
76
- ], re = { class: "fg-site-header" }, ie = { class: "fg-site-header__inner" }, V = ["aria-label"], H = {
76
+ ], te = { class: "fg-site-header" }, ne = { class: "fg-site-header__inner" }, re = ["aria-label"], ie = {
77
77
  class: "fg-site-projects__menu fg-site-nav",
78
78
  "aria-label": "Projects"
79
79
  }, U = ["href", "aria-current"], W = { class: "fg-site-header__end" }, G = {
@@ -121,7 +121,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
121
121
  value: "dark",
122
122
  label: "Dark"
123
123
  }
124
- ], n = s(() => B.find(({ id: t }) => t === e.project)?.label ?? e.project), r = A().default ? void 0 : z(), i = C(!1), a = C(), c = C(), f = () => {
124
+ ], n = s(() => H.find(({ id: t }) => t === e.project)?.label ?? e.project), r = j().default ? void 0 : V(), i = C(!1), a = C(), c = C(), f = () => {
125
125
  a.value && (a.value.open = !1);
126
126
  }, p = (e) => {
127
127
  e.key !== "Escape" || !a.value?.open || (f(), c.value?.focus());
@@ -132,7 +132,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
132
132
  };
133
133
  return b(() => {
134
134
  i.value = !0, document.addEventListener("pointerdown", h);
135
- }), y(() => document.removeEventListener("pointerdown", h)), (s, f) => (S(), u("header", re, [d("div", ie, [d("details", {
135
+ }), y(() => document.removeEventListener("pointerdown", h)), (s, f) => (S(), u("header", te, [d("div", ne, [d("details", {
136
136
  ref_key: "menu",
137
137
  ref: a,
138
138
  class: "fg-site-projects",
@@ -152,7 +152,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
152
152
  stroke: "currentColor",
153
153
  "stroke-width": "1.5",
154
154
  "aria-hidden": "true"
155
- }, [d("path", { d: "m4 6 4 4 4-4" })], -1)], 8, V), d("nav", H, [(S(!0), u(o, null, w(O(B), (t) => (S(), u("a", {
155
+ }, [d("path", { d: "m4 6 4 4 4-4" })], -1)], 8, re), d("nav", ie, [(S(!0), u(o, null, w(O(H), (t) => (S(), u("a", {
156
156
  key: t.id,
157
157
  href: t.href,
158
158
  "aria-current": t.id === e.project ? "page" : void 0
@@ -226,35 +226,38 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
226
226
  groups: {}
227
227
  },
228
228
  setup(e) {
229
- let t = k(), n = C(), o = C(!1), s = C(!1), l = C(!1), m = a({ targetIds: e.groups.flatMap((e) => e.items).flatMap(({ href: e }) => e.startsWith("#") && e.length > 1 ? [e.slice(1)] : []) }), h, _ = null, v = () => n.value?.querySelector("button.fg-site-rail__toggle"), y = () => {
229
+ let t = k(), n = C(), o = C(!1), l = C(!1), m = C(!1), h = a({ targetIds: e.groups.flatMap((e) => e.items).flatMap(({ href: e }) => e.startsWith("#") && e.length > 1 ? [e.slice(1)] : []) }), _ = s(() => e.groups.flatMap((e) => e.items).find((e) => e.current)?.label), v = s(() => e.groups.flatMap((e) => e.items).find((e) => e.href === `#${h.value}`)?.label), y = s(() => {
230
+ let t = _.value ?? v.value;
231
+ return t ? `${e.label}: ${t}` : e.label;
232
+ }), w, T = null, E = () => n.value?.querySelector("button.fg-site-rail__toggle"), A = () => {
230
233
  g(() => n.value?.querySelector(".fg-site-nav a")?.focus({ preventScroll: !0 }));
231
- }, w = () => {
232
- let e = h?.matches && !s.value && n.value?.contains(document.activeElement), t = h?.matches === !1 && s.value && !l.value && v() === document.activeElement;
233
- s.value = h?.matches === !0, s.value || (l.value = !1), e ? g(() => v()?.focus({ preventScroll: !0 })) : t && y();
234
- }, T = (e, t) => {
235
- !l.value || t.button !== 0 || t.metaKey || t.ctrlKey || t.altKey || t.shiftKey || (_ = e.startsWith("#") ? document.getElementById(e.slice(1)) : null, l.value = !1);
236
- }, E = (e) => {
237
- _ ? (e.preventDefault(), _.tabIndex = -1, _.focus({ preventScroll: !0 }), _ = null) : s.value || (e.preventDefault(), y());
234
+ }, j = () => {
235
+ let e = w?.matches && !l.value && n.value?.contains(document.activeElement), t = w?.matches === !1 && l.value && !m.value && E() === document.activeElement;
236
+ l.value = w?.matches === !0, l.value || (m.value = !1), e ? g(() => E()?.focus({ preventScroll: !0 })) : t && A();
237
+ }, M = (e, t) => {
238
+ !m.value || t.button !== 0 || t.metaKey || t.ctrlKey || t.altKey || t.shiftKey || (T = e.startsWith("#") ? document.getElementById(e.slice(1)) : null, m.value = !1);
239
+ }, N = (e) => {
240
+ T ? (e.preventDefault(), T.tabIndex = -1, T.focus({ preventScroll: !0 }), T = null) : l.value || (e.preventDefault(), A());
238
241
  };
239
242
  return b(() => {
240
- h = matchMedia(he), w(), o.value = !0, h.addEventListener("change", w);
241
- }), x(() => h?.removeEventListener("change", w)), (a, h) => (S(), u("div", {
243
+ w = matchMedia(he), j(), o.value = !0, w.addEventListener("change", j);
244
+ }), x(() => w?.removeEventListener("change", j)), (a, s) => (S(), u("div", {
242
245
  ref_key: "root",
243
246
  ref: n,
244
247
  class: "fg-site-rail",
245
248
  "data-enhanced": o.value
246
- }, [!o.value || !s.value ? (S(), u("details", {
249
+ }, [!o.value || !l.value ? (S(), u("details", {
247
250
  key: 0,
248
251
  class: "fg-site-rail__menu",
249
- open: o.value && !s.value
252
+ open: o.value && !l.value
250
253
  }, [d("summary", {
251
254
  class: "fg-site-rail__summary",
252
255
  "aria-controls": O(t)
253
- }, D(e.label), 9, me), p(X, {
256
+ }, D(y.value), 9, me), p(X, {
254
257
  "content-id": O(t),
255
258
  label: e.label,
256
259
  groups: e.groups,
257
- "active-id": O(m)
260
+ "active-id": O(h)
258
261
  }, null, 8, [
259
262
  "content-id",
260
263
  "label",
@@ -262,25 +265,25 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
262
265
  "active-id"
263
266
  ])], 8, pe)) : (S(), c(i, {
264
267
  key: 1,
265
- open: l.value,
266
- "onUpdate:open": h[0] ||= (e) => l.value = e,
268
+ open: m.value,
269
+ "onUpdate:open": s[0] ||= (e) => m.value = e,
267
270
  title: e.label,
268
- onCloseAutoFocus: E
271
+ onCloseAutoFocus: N
269
272
  }, {
270
- trigger: M(() => [p(r, {
273
+ trigger: P(() => [p(r, {
271
274
  variant: "ghost",
272
275
  size: "lg",
273
276
  class: "fg-site-rail__toggle"
274
277
  }, {
275
- default: M(() => [f(D(e.label), 1)]),
278
+ default: P(() => [f(D(y.value), 1)]),
276
279
  _: 1
277
280
  })]),
278
- default: M(() => [p(X, {
281
+ default: P(() => [p(X, {
279
282
  "content-id": O(t),
280
283
  label: e.label,
281
284
  groups: e.groups,
282
- "active-id": O(m),
283
- onNavigate: T
285
+ "active-id": O(h),
286
+ onNavigate: M
284
287
  }, null, 8, [
285
288
  "content-id",
286
289
  "label",
@@ -313,7 +316,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
313
316
  let o = Math.min(1, i.clientWidth / a.offsetWidth);
314
317
  o >= Z && (i.scrollLeft = 0), n.value = o >= Z ? o : 1, r.value = o >= Z ? Math.ceil(a.offsetHeight * n.value) + i.offsetHeight - i.clientHeight : void 0;
315
318
  };
316
- return j(() => [e.fit, e.html], o, { flush: "post" }), b(() => {
319
+ return N(() => [e.fit, e.html], o, { flush: "post" }), b(() => {
317
320
  typeof ResizeObserver < "u" && (a = new ResizeObserver(o), t.value && a.observe(t.value)), o();
318
321
  }), x(() => a?.disconnect()), (a, o) => (S(), u("div", {
319
322
  ref_key: "container",
@@ -345,38 +348,38 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
345
348
  }),
346
349
  emits: ["update:modelValue"],
347
350
  setup(e) {
348
- let i = ee(e, "modelValue"), a = C(!1), m = s(() => e.items.map(({ id: e, label: t }) => ({
351
+ let i = A(e, "modelValue"), a = C(!1), m = s(() => e.items.map(({ id: e, label: t }) => ({
349
352
  value: e,
350
353
  label: t
351
- }))), h = s(() => i.value ?? e.items[0]?.id ?? ""), _ = s(() => e.items.find(({ id: e }) => e === h.value)), v = C(!1), y = E(), O = 0, k = 0, A = te("fullSizeButton"), j = (e) => {
354
+ }))), h = s(() => i.value ?? e.items[0]?.id ?? ""), _ = s(() => e.items.find(({ id: e }) => e === h.value)), v = C(!1), y = E(), O = 0, k = 0, j = M("fullSizeButton"), N = (e) => {
352
355
  y.value = e, v.value = !0;
353
- }, N = (e) => {
354
- A.value?.isConnected && (e.preventDefault(), A.value.focus({ preventScroll: !0 }));
355
- }, P = () => {
356
+ }, F = (e) => {
357
+ j.value?.isConnected && (e.preventDefault(), j.value.focus({ preventScroll: !0 }));
358
+ }, I = () => {
356
359
  try {
357
360
  return document.getElementById(decodeURIComponent(location.hash.slice(1)));
358
361
  } catch {
359
362
  return null;
360
363
  }
361
- }, F = async () => {
364
+ }, L = async () => {
362
365
  await g(), cancelAnimationFrame(O), cancelAnimationFrame(k), O = requestAnimationFrame(() => {
363
- k = requestAnimationFrame(() => P()?.scrollIntoView({
366
+ k = requestAnimationFrame(() => I()?.scrollIntoView({
364
367
  behavior: "instant",
365
368
  block: "start"
366
369
  }));
367
370
  });
368
- }, I = () => {
369
- let t = P();
371
+ }, R = () => {
372
+ let t = I();
370
373
  if (!t) return !1;
371
374
  let n = e.items.find(({ id: n }) => document.getElementById(`${e.idPrefix}${n}`)?.contains(t));
372
375
  return !n || h.value === n.id ? !1 : (i.value = n.id, !0);
373
- }, L = () => {
374
- I() && F();
376
+ }, z = () => {
377
+ R() && L();
375
378
  };
376
379
  return b(() => {
377
- a.value = !0, I(), location.hash && F(), window.addEventListener("hashchange", L), window.addEventListener("popstate", L);
380
+ a.value = !0, R(), location.hash && L(), window.addEventListener("hashchange", z), window.addEventListener("popstate", z);
378
381
  }), x(() => {
379
- cancelAnimationFrame(O), cancelAnimationFrame(k), window.removeEventListener("hashchange", L), window.removeEventListener("popstate", L);
382
+ cancelAnimationFrame(O), cancelAnimationFrame(k), window.removeEventListener("hashchange", z), window.removeEventListener("popstate", z);
380
383
  }), (s, g) => (S(), u("div", {
381
384
  class: "fg-capture",
382
385
  "data-enhanced": a.value
@@ -384,12 +387,12 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
384
387
  a.value && _.value ? (S(), u("button", {
385
388
  key: 0,
386
389
  ref_key: "fullSizeButton",
387
- ref: A,
390
+ ref: j,
388
391
  type: "button",
389
392
  class: "fg-capture__full",
390
393
  "aria-label": `Expand ${_.value.label} capture at full size`,
391
394
  "aria-haspopup": "dialog",
392
- onClick: g[0] ||= (e) => j(_.value)
395
+ onClick: g[0] ||= (e) => N(_.value)
393
396
  }, [...g[4] ||= [d("svg", {
394
397
  viewBox: "0 0 24 24",
395
398
  fill: "none",
@@ -403,7 +406,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
403
406
  label: e.label,
404
407
  "onUpdate:modelValue": g[1] ||= (e) => i.value = e
405
408
  }, {
406
- panel: M(({ value: t }) => [(S(!0), u(o, null, w(e.items, (n) => (S(), u(o, { key: n.id }, [n.id === t ? (S(), u("figure", {
409
+ panel: P(({ value: t }) => [(S(!0), u(o, null, w(e.items, (n) => (S(), u(o, { key: n.id }, [n.id === t ? (S(), u("figure", {
407
410
  key: 0,
408
411
  id: `${e.idPrefix}${n.id}`,
409
412
  class: "fg-capture__figure"
@@ -422,7 +425,7 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
422
425
  tabindex: "-1",
423
426
  "aria-hidden": "true",
424
427
  title: `Open ${n.label} capture at full size`,
425
- onClick: (e) => j(n)
428
+ onClick: (e) => N(n)
426
429
  }, null, 8, Se)) : l("", !0)]), n.command || s.$slots.caption ? (S(), u("figcaption", Ce, [n.command ? (S(), u("code", we, D(n.command), 1)) : l("", !0), T(s.$slots, "caption", { item: n })])) : l("", !0)], 8, be)) : l("", !0)], 64))), 128))]),
427
430
  _: 3
428
431
  }, 8, [
@@ -436,17 +439,17 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
436
439
  title: `${y.value?.label ?? ""} capture`,
437
440
  description: "Scroll to read the full capture.",
438
441
  class: "fg-capture-viewer",
439
- onCloseAutoFocus: N
442
+ onCloseAutoFocus: F
440
443
  }, {
441
- footer: M(() => [p(r, {
444
+ footer: P(() => [p(r, {
442
445
  variant: "secondary",
443
446
  size: "lg",
444
447
  onClick: g[2] ||= (e) => v.value = !1
445
448
  }, {
446
- default: M(() => [...g[5] ||= [f(" Close capture ", -1)]]),
449
+ default: P(() => [...g[5] ||= [f(" Close capture ", -1)]]),
447
450
  _: 1
448
451
  })]),
449
- default: M(() => [y.value ? (S(), c(Q, {
452
+ default: P(() => [y.value ? (S(), c(Q, {
450
453
  key: 0,
451
454
  html: y.value.html,
452
455
  label: `${y.value.label} capture at full size`,
@@ -522,4 +525,4 @@ var I = "tool-site-theme", L = (e) => e === "system" || e === "light" || e === "
522
525
  }
523
526
  });
524
527
  //#endregion
525
- export { I as SITE_APPEARANCE_KEY, B as SITE_PROJECTS, Te as UiCapture, Ie as UiCommandList, oe as UiSiteHeader, ge as UiSiteNav, R as applySiteAppearance, ne as siteThemeBootScript, z as useSiteAppearance };
528
+ export { R as SITE_APPEARANCE_KEY, H as SITE_PROJECTS, Te as UiCapture, Ie as UiCommandList, oe as UiSiteHeader, ge as UiSiteNav, B as applySiteAppearance, ee as siteThemeBootScript, V as useSiteAppearance };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filipgutica/ui",
3
- "version": "1.11.2",
3
+ "version": "1.13.0",
4
4
  "description": "A compact Vue design system with Tailwind CSS and VS Code theme support",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -14,7 +14,9 @@
14
14
  "src/site.css",
15
15
  "src/themes/*.css",
16
16
  "README.md",
17
- "LICENSE"
17
+ "LICENSE",
18
+ "src/fonts.css",
19
+ "src/fonts/*"
18
20
  ],
19
21
  "exports": {
20
22
  ".": {
@@ -36,7 +38,9 @@
36
38
  "./theme.css": "./src/theme.css",
37
39
  "./components.css": "./src/components.css",
38
40
  "./site.css": "./src/site.css",
39
- "./themes/graphite-indigo.css": "./src/themes/graphite-indigo.css"
41
+ "./themes/graphite-indigo.css": "./src/themes/graphite-indigo.css",
42
+ "./fonts.css": "./src/fonts.css",
43
+ "./fonts/*": "./src/fonts/*"
40
44
  },
41
45
  "scripts": {
42
46
  "build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
@@ -5,7 +5,7 @@
5
5
  /* Package-owned typography keeps controls consistent across consuming apps. */
6
6
  .fg-button, .fg-input, .fg-select, .fg-checkbox, .fg-field,
7
7
  .fg-radio-card, .fg-badge, .fg-alert, .fg-surface, .fg-card,
8
- .fg-dialog__content, .fg-code-block, .fg-toggle-button {
8
+ .fg-dialog__content, .fg-code-block, .fg-toggle-button, .fg-switch {
9
9
  font-family: var(--font-ui);
10
10
  font-size: var(--text-md);
11
11
  font-weight: var(--weight-regular);
@@ -16,23 +16,50 @@
16
16
  min-width: 0;
17
17
  max-width: 100%;
18
18
  overflow: hidden;
19
- border: 1px solid color-mix(in srgb, var(--color-code-text) 22%, var(--color-code));
20
- border-radius: var(--radius-control);
19
+ border: 1px solid var(--color-border-subtle);
20
+ border-radius: var(--radius-panel);
21
21
  background: var(--color-code);
22
22
  color: var(--color-code-text);
23
23
  }
24
+ /* Terminal commands always use the dark palette, independent of the page theme. */
25
+ .fg-code-block[data-command="true"] {
26
+ --color-code-text: var(--color-terminal-text);
27
+ --color-muted: var(--color-terminal-caption-text);
28
+ --color-focus: var(--color-project-dark);
29
+ --color-syntax-comment: var(--color-terminal-caption-text);
30
+ --color-syntax-keyword: var(--color-terminal-text);
31
+ --color-syntax-string: var(--color-terminal-text);
32
+ --color-syntax-number: var(--color-terminal-text);
33
+ --color-syntax-function: var(--color-terminal-text);
34
+ --color-syntax-type: var(--color-terminal-text);
35
+ --color-syntax-variable: var(--color-terminal-text);
36
+ --color-syntax-operator: var(--color-terminal-text);
37
+ --color-syntax-punctuation: var(--color-terminal-text);
38
+ --color-syntax-tag: var(--color-terminal-text);
39
+ --color-syntax-attribute: var(--color-terminal-text);
40
+ border-color: var(--color-terminal-border);
41
+ background: var(--color-terminal);
42
+ }
43
+ .fg-code-block[data-command="true"] .fg-code-block__header { background: transparent; border-color: var(--color-terminal-border); }
44
+ .fg-code-block[data-command="true"] .fg-code-block__line::before {
45
+ content: '$ ' / '';
46
+ flex: none;
47
+ white-space: pre;
48
+ color: var(--color-project-dark);
49
+ user-select: none;
50
+ }
24
51
  .fg-code-block__header {
25
52
  display: flex;
26
53
  align-items: center;
27
54
  gap: var(--space-3);
28
55
  min-height: 2.5rem;
29
56
  padding: 0.35rem var(--space-3);
30
- border-bottom: 1px solid color-mix(in srgb, var(--color-code-text) 16%, transparent);
31
- background: color-mix(in srgb, var(--color-code-text) 5%, var(--color-code));
57
+ border-bottom: 1px solid var(--color-border-subtle);
58
+ background: var(--color-surface-raised);
32
59
  font-size: var(--text-xs);
33
60
  }
34
61
  .fg-code-block__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
35
- .fg-code-block__language { opacity: 0.7; }
62
+ .fg-code-block__language { color: var(--color-muted); }
36
63
  .fg-code-block__actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; flex-shrink: 0; }
37
64
  .fg-code-block__copy {
38
65
  display: inline-flex;
@@ -55,11 +82,11 @@
55
82
  .fg-code-block__copy:focus-visible, .fg-code-block__pre:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
56
83
  .fg-figure__plate:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
57
84
  .fg-code-block__pre { margin: 0; padding: var(--space-4); overflow: auto; max-height: 32rem; tab-size: 2; }
58
- .fg-code-block__pre, .fg-code-block__pre code { font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.65; }
85
+ .fg-code-block__pre, .fg-code-block__pre code { font-family: var(--font-mono); font-size: var(--text-code); line-height: 1.65; }
59
86
  .fg-code-block__pre code { display: block; color: inherit; }
60
87
  .fg-code-block__line { display: flex; min-height: 1.65em; }
61
88
  .fg-code-block__text { white-space: pre; }
62
- .fg-code-block__number { min-width: 2.5em; padding-right: 1em; flex-shrink: 0; text-align: right; opacity: 0.5; user-select: none; }
89
+ .fg-code-block__number { min-width: 2.5em; padding-right: 1em; flex-shrink: 0; text-align: right; color: var(--color-muted); user-select: none; }
63
90
  .fg-code-block[data-wrap="true"] .fg-code-block__text { min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
64
91
  .fg-code-block__status:empty { display: none; }
65
92
  .fg-code-block__status:not(:empty) { display: block; padding: var(--space-2) var(--space-3); font-size: var(--text-xs); }
@@ -144,6 +171,7 @@
144
171
  .fg-input:disabled,
145
172
  .fg-select:disabled,
146
173
  .fg-checkbox[data-disabled="true"],
174
+ .fg-switch[data-disabled="true"],
147
175
  .fg-toggle-button:disabled {
148
176
  cursor: not-allowed;
149
177
  opacity: 0.58;
@@ -390,15 +418,16 @@
390
418
  margin-top: 0.1rem;
391
419
  place-items: center;
392
420
  border: 1px solid var(--color-input-border);
393
- border-radius: 0.3rem;
421
+ border-radius: var(--radius-control);
394
422
  color: var(--color-button-text);
395
423
  background: var(--color-input-bg);
396
424
  box-shadow: var(--shadow-control);
397
425
  }
398
426
 
399
427
  .fg-checkbox__control[data-state="checked"] {
400
- border-color: var(--color-button-bg);
401
- background: var(--color-button-bg);
428
+ border-color: var(--color-accent);
429
+ color: var(--color-accent-text);
430
+ background: var(--color-accent);
402
431
  }
403
432
 
404
433
  .fg-checkbox__indicator {
@@ -519,7 +548,7 @@
519
548
  align-items: center;
520
549
  width: fit-content;
521
550
  border: 1px solid var(--color-border-subtle);
522
- border-radius: var(--radius-pill);
551
+ border-radius: var(--radius-inline);
523
552
  padding: 0.18rem 0.48rem;
524
553
  color: var(--color-muted);
525
554
  background: var(--color-surface-muted);
@@ -528,11 +557,11 @@
528
557
  line-height: 1.25;
529
558
  }
530
559
 
531
- .fg-badge[data-tone="info"] { color: var(--color-status-text, var(--color-info)); background: var(--color-info-surface); }
532
- .fg-badge[data-tone="success"] { color: var(--color-status-text, var(--color-success)); background: var(--color-success-surface); }
533
- .fg-badge[data-tone="warning"] { color: var(--color-status-text, var(--color-warning)); background: var(--color-warning-surface); }
560
+ .fg-badge[data-tone="info"] { border-color: var(--color-info); color: var(--color-status-text, var(--color-info)); background: var(--color-info-surface); }
561
+ .fg-badge[data-tone="success"] { border-color: var(--color-success); color: var(--color-status-text, var(--color-success)); background: var(--color-success-surface); }
562
+ .fg-badge[data-tone="warning"] { border-color: var(--color-warning); color: var(--color-status-text, var(--color-warning)); background: var(--color-warning-surface); }
534
563
  .fg-badge[data-tone="danger"],
535
- .fg-badge[data-tone="error"] { color: var(--color-status-text, var(--color-error)); background: var(--color-error-surface); }
564
+ .fg-badge[data-tone="error"] { border-color: var(--color-error); color: var(--color-status-text, var(--color-error)); background: var(--color-error-surface); }
536
565
 
537
566
  .fg-alert {
538
567
  display: flex;
@@ -545,9 +574,9 @@
545
574
  background: var(--color-surface);
546
575
  }
547
576
 
548
- .fg-alert[data-tone="info"] { border-color: color-mix(in srgb, var(--color-info) 35%, var(--color-border-subtle)); background: var(--color-info-surface); }
549
- .fg-alert[data-tone="success"] { border-color: color-mix(in srgb, var(--color-success) 35%, var(--color-border-subtle)); background: var(--color-success-surface); }
550
- .fg-alert[data-tone="warning"] { border-color: color-mix(in srgb, var(--color-warning) 35%, var(--color-border-subtle)); background: var(--color-warning-surface); }
577
+ .fg-alert[data-tone="info"] { border-color: var(--color-info); background: var(--color-info-surface); }
578
+ .fg-alert[data-tone="success"] { border-color: var(--color-success); background: var(--color-success-surface); }
579
+ .fg-alert[data-tone="warning"] { border-color: var(--color-warning); background: var(--color-warning-surface); }
551
580
  .fg-alert[data-tone="danger"],
552
581
  .fg-alert[data-tone="error"] {
553
582
  border-color: var(--color-error);
@@ -629,7 +658,7 @@
629
658
  .fg-figure__caption {
630
659
  max-width: var(--measure);
631
660
  color: var(--color-muted);
632
- font-family: var(--font-ui);
661
+ font-family: var(--font-mono);
633
662
  font-size: var(--text-sm);
634
663
  line-height: var(--leading);
635
664
  }
@@ -657,7 +686,7 @@
657
686
  width: 0.5rem;
658
687
  height: 0.5rem;
659
688
  border: 1px solid var(--color-border);
660
- border-radius: var(--radius-pill);
689
+ border-radius: var(--radius-inline);
661
690
  }
662
691
 
663
692
  .fg-score__pip[data-filled="true"] {
@@ -689,40 +718,76 @@
689
718
  .fg-toggle-button:hover:not(:disabled, [aria-pressed="true"]) { border-color: var(--color-border); }
690
719
  .fg-toggle-button[aria-pressed="true"] { border-color: var(--color-accent); }
691
720
 
692
- /* The thumb's position, not only its color, shows the state. */
693
- .fg-toggle-button__switch {
721
+ .fg-switch { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
722
+ .fg-switch__control {
723
+ display: inline-flex;
724
+ align-items: center;
725
+ justify-content: center;
726
+ flex: none;
727
+ min-width: var(--control-sm);
728
+ min-height: var(--control-md);
729
+ padding: 0;
730
+ border: 0;
731
+ background: transparent;
732
+ cursor: pointer;
733
+ }
734
+ .fg-switch[data-size="sm"] { font-size: var(--text-sm); }
735
+ .fg-switch[data-size="sm"] .fg-switch__control { min-height: var(--control-sm); }
736
+ .fg-switch[data-size="lg"] { font-size: var(--text-lg); }
737
+ .fg-switch[data-size="lg"] .fg-switch__control { min-height: var(--control-lg); }
738
+ /* The visible track scales with size; the thumb travels the track width minus its height. */
739
+ .fg-switch { --fg-switch-width: 2.25rem; --fg-switch-height: 1.25rem; }
740
+ .fg-switch[data-size="sm"] { --fg-switch-width: 1.75rem; --fg-switch-height: 1rem; }
741
+ .fg-switch[data-size="lg"] { --fg-switch-width: 2.75rem; --fg-switch-height: 1.5rem; }
742
+ .fg-switch__text { display: grid; min-width: 0; overflow-wrap: anywhere; }
743
+ .fg-switch__text label { cursor: pointer; }
744
+ .fg-switch[data-disabled="true"] :is(button, label) { cursor: not-allowed; }
745
+ .fg-switch__description { color: var(--color-muted); font-size: var(--text-sm); }
746
+
747
+ /* Both toggle controls share the track; thumb position also shows the state. */
748
+ .fg-toggle-button__switch,
749
+ .fg-switch__track {
694
750
  position: relative;
695
751
  flex: none;
696
752
  width: 1.75rem;
697
753
  height: 1rem;
698
754
  border: 1px solid var(--color-border);
699
- border-radius: var(--radius-pill);
755
+ border-radius: var(--radius-inline);
700
756
  background: var(--color-surface-muted);
701
757
  transition: background-color var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
702
758
  }
703
759
 
704
- .fg-toggle-button__switch::after {
760
+ .fg-toggle-button__switch::after,
761
+ .fg-switch__track::after {
705
762
  position: absolute;
706
763
  top: 0.125rem;
707
764
  left: 0.125rem;
708
765
  width: 0.625rem;
709
766
  height: 0.625rem;
710
- border-radius: var(--radius-pill);
767
+ border-radius: var(--radius-inline);
711
768
  background: var(--color-border);
712
769
  content: "";
713
770
  transition: transform var(--duration) var(--ease-out), background-color var(--duration) var(--ease-out);
714
771
  }
715
772
 
716
- .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch {
773
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch,
774
+ .fg-switch__control[aria-checked="true"] .fg-switch__track {
717
775
  border-color: var(--color-accent);
718
776
  background: var(--color-accent);
719
777
  }
720
778
 
721
- .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch::after {
722
- background: var(--color-button-text);
779
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch::after,
780
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after {
781
+ background: var(--color-accent-text);
723
782
  transform: translateX(0.75rem);
724
783
  }
725
784
 
785
+ .fg-switch__track { box-sizing: border-box; width: var(--fg-switch-width); height: var(--fg-switch-height); }
786
+ .fg-switch__track::after { width: calc(var(--fg-switch-height) - 0.375rem); height: calc(var(--fg-switch-height) - 0.375rem); }
787
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after {
788
+ transform: translateX(calc(var(--fg-switch-width) - var(--fg-switch-height)));
789
+ }
790
+
726
791
  .fg-toggle-button__text { display: grid; min-width: 0; }
727
792
 
728
793
  .fg-toggle-button__description {
@@ -735,7 +800,7 @@
735
800
  height: 0.55rem;
736
801
  overflow: hidden;
737
802
  border: 1px solid var(--color-border-subtle);
738
- border-radius: var(--radius-pill);
803
+ border-radius: var(--radius-inline);
739
804
  background: var(--color-surface-muted);
740
805
  }
741
806
 
@@ -765,7 +830,7 @@
765
830
  height: 0.375rem;
766
831
  flex: 1;
767
832
  overflow: hidden;
768
- border-radius: var(--radius-pill);
833
+ border-radius: var(--radius-inline);
769
834
  background: var(--color-surface-muted);
770
835
  }
771
836
 
@@ -796,7 +861,7 @@
796
861
  inset: 0;
797
862
  z-index: 50;
798
863
  background: var(--color-overlay);
799
- backdrop-filter: blur(2px);
864
+
800
865
  }
801
866
 
802
867
  .fg-dialog__content {
@@ -874,11 +939,15 @@
874
939
  .fg-slider__thumb:focus-visible,
875
940
  .fg-dialog__close:focus-visible,
876
941
  .fg-dialog__content:focus-visible,
877
- .fg-toggle-button:focus-visible {
942
+ .fg-toggle-button:focus-visible,
943
+ .fg-switch__control:focus-visible .fg-switch__track {
878
944
  outline: 2px solid var(--color-focus);
879
945
  outline-offset: 2px;
880
946
  }
881
947
 
948
+ /* The control is a larger transparent hit area, so the ring follows the visible track instead. */
949
+ .fg-switch__control:focus-visible { outline: none; }
950
+
882
951
  :root.high-contrast .fg-button,
883
952
  :root.high-contrast .fg-input,
884
953
  :root.high-contrast .fg-select,
@@ -906,6 +975,13 @@
906
975
  }
907
976
  }
908
977
 
978
+ @media (forced-colors: active) {
979
+ .fg-switch__track { border-color: ButtonText; background: Canvas; }
980
+ .fg-switch__track::after { background: ButtonText; }
981
+ .fg-switch__control[aria-checked="true"] .fg-switch__track { border-color: Highlight; background: Highlight; forced-color-adjust: none; }
982
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after { background: HighlightText; }
983
+ }
984
+
909
985
  @media (prefers-reduced-motion: reduce) {
910
986
  .fg-button,
911
987
  .fg-input,
@@ -915,7 +991,9 @@
915
991
  .fg-dialog__close,
916
992
  .fg-progress__indicator,
917
993
  .fg-toggle-button__switch,
918
- .fg-toggle-button__switch::after { transition: none; }
994
+ .fg-toggle-button__switch::after,
995
+ .fg-switch__track,
996
+ .fg-switch__track::after { transition: none; }
919
997
 
920
998
  .fg-button[aria-busy="true"]::before { animation-duration: 1.4s; }
921
999
  }