colorsbymax 0.2.3 → 0.3.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.
@@ -950,19 +950,38 @@ var lift = (hex, min, max = .78) => {
950
950
  const [h, s, l] = hslOf$2(hex);
951
951
  return hsl$1(h, s, Math.min(max, Math.max(min, l)));
952
952
  };
953
+ /**
954
+ * Lightens a colour, keeping its hue and saturation, until it reaches `ratio` against `bg`.
955
+ * Lightness alone doesn't guarantee that: a vivid blue or violet at 60% lightness still reads dark.
956
+ */
957
+ var readOn = (hex, bg, ratio) => {
958
+ const [h, s, l] = hslOf$2(hex);
959
+ let out = hex;
960
+ for (let x = l; contrastRatio(out, bg) < ratio && x < .96; x += .01) out = hsl$1(h, s, x);
961
+ return out;
962
+ };
963
+ var TEXT = 4.8;
964
+ var ICON = 3.3;
953
965
  /** @param {import('./tokens.js').ThemeTokens} t */
954
966
  function darkTokens(t) {
955
- const primary = lift(t.primary, .58, .7);
956
- const onPrimary = luminance(primary) > .18 ? tone(t.background, .08, .3) : "#ffffff";
967
+ const background = tone(t.background, .08, .3);
968
+ const secondary = tone(t.secondary, .2, .45);
969
+ const areaBg = deriveAppTokens({
970
+ ...t,
971
+ secondary
972
+ })["app-background"];
973
+ const lighterBg = luminance(areaBg) > luminance(background) ? areaBg : background;
974
+ const primary = readOn(lift(t.primary, .58, .7), lighterBg, TEXT);
975
+ const onPrimary = [background, "#ffffff"].sort((a, b) => contrastRatio(b, primary) - contrastRatio(a, primary))[0];
957
976
  const tokens = {
958
977
  ...t,
959
978
  primary,
960
979
  "on-primary": onPrimary,
961
980
  "primary-dark": tone(t["primary-dark"], .82, .7),
962
- "primary-alt": lift(t["primary-alt"], .6),
963
- background: tone(t.background, .08, .3),
981
+ "primary-alt": readOn(lift(t["primary-alt"], .6), lighterBg, ICON),
982
+ background,
964
983
  surface: tone(t.background, .12, .25),
965
- secondary: tone(t.secondary, .2, .45),
984
+ secondary,
966
985
  "on-secondary": tone(t["on-secondary"], .86, .6),
967
986
  accent: tone(t.accent, .17, .45),
968
987
  "on-accent": tone(t["on-accent"], .86, .6),
@@ -971,12 +990,12 @@ function darkTokens(t) {
971
990
  ink: tone(t.ink, .94, .15),
972
991
  "ink-secondary": tone(t["ink-secondary"], .76, .12),
973
992
  "ink-muted": tone(t["ink-muted"], .7, .12),
974
- success: lift(t.success, .6),
975
- warning: lift(t.warning, .6),
976
- danger: lift(t.danger, .66),
977
- info: lift(t.info, .66)
993
+ success: readOn(lift(t.success, .6), background, ICON),
994
+ warning: readOn(lift(t.warning, .6), background, ICON),
995
+ danger: readOn(lift(t.danger, .66), background, ICON),
996
+ info: readOn(lift(t.info, .66), background, ICON)
978
997
  };
979
- for (let n = 1; n <= 8; n++) tokens[`data-${n}`] = lift(t[`data-${n}`], .6);
998
+ for (let n = 1; n <= 8; n++) tokens[`data-${n}`] = readOn(lift(t[`data-${n}`], .6), background, n <= 2 ? TEXT : ICON);
980
999
  const full = {
981
1000
  ...tokens,
982
1001
  ...deriveAppTokens(tokens)
@@ -1403,14 +1422,16 @@ function createRecolourer() {
1403
1422
  const sheet = document.createElement("style");
1404
1423
  sheet.dataset.colorsbymax = "recolour";
1405
1424
  document.head.append(sheet);
1406
- const site = themeFromRoles(inferRoles(collectColors()).roles);
1425
+ const { roles } = inferRoles(collectColors());
1426
+ const site = themeFromRoles(roles);
1427
+ const plain = !roles.primary;
1407
1428
  const siteBgL = hslOf$1(site.background)[2];
1408
1429
  const siteInkL = hslOf$1(site.ink)[2];
1409
1430
  /** Each distinct painted value, keyed "prop|value", plus the background under text and icons. */
1410
1431
  const entries = /* @__PURE__ */ new Map();
1411
1432
  let theme = null;
1412
- const idFor = (prop, value, kind, backdrop = null, role = null) => {
1413
- const key = `${prop}|${value}|${backdrop ?? ""}|${role ?? ""}`;
1433
+ const idFor = (prop, value, kind, backdrop = null, role = null, accent = false) => {
1434
+ const key = `${prop}|${value}|${backdrop ?? ""}|${role ?? ""}|${accent ? "a" : ""}`;
1414
1435
  let entry = entries.get(key);
1415
1436
  if (!entry) {
1416
1437
  entry = {
@@ -1419,7 +1440,8 @@ function createRecolourer() {
1419
1440
  value,
1420
1441
  kind,
1421
1442
  backdrop,
1422
- role
1443
+ role,
1444
+ accent
1423
1445
  };
1424
1446
  entries.set(key, entry);
1425
1447
  if (theme) pendingRules += rule(entry);
@@ -1443,9 +1465,11 @@ function createRecolourer() {
1443
1465
  const cs = getComputedStyle(el);
1444
1466
  const ids = [];
1445
1467
  const role = el instanceof SVGElement || !hasOwnText(el) ? "icon" : "text";
1468
+ const ownFill = (parse(cs.backgroundColor)?.alpha ?? 0) >= .5;
1469
+ const accent = plain && !ownFill && (role === "icon" || el.localName === "a");
1446
1470
  const colour = (prop, css, kind) => {
1447
1471
  if (!parse(css)) return;
1448
- ids.push(FOREGROUND.has(prop) ? idFor(prop, css, kind, backdropOf(el), prop === "color" ? role : "icon") : idFor(prop, css, kind));
1472
+ ids.push(FOREGROUND.has(prop) ? idFor(prop, css, kind, backdropOf(el), prop === "color" ? role : "icon", accent) : idFor(prop, css, kind));
1449
1473
  };
1450
1474
  colour("background-color", cs.backgroundColor, "bg");
1451
1475
  colour("color", cs.color, "text");
@@ -1566,7 +1590,12 @@ function createRecolourer() {
1566
1590
  let value;
1567
1591
  if (entry.prop === "background-image") value = entry.value.replace(COLOR_IN_GRADIENT, (stop) => mapColour(stop, entry.kind));
1568
1592
  else if (entry.backdrop) {
1569
- const fg = mapHex(entry.value, entry.kind);
1593
+ const own = parse(entry.value);
1594
+ const brand = entry.accent && own && hslOf$1(own.hex)[1] < NEUTRAL_SATURATION;
1595
+ const fg = brand ? {
1596
+ hex: theme.primary,
1597
+ alpha: own.alpha
1598
+ } : mapHex(entry.value, entry.kind);
1570
1599
  const bg = mapHex(entry.backdrop, "bg");
1571
1600
  const original = {
1572
1601
  fg: parse(entry.value)?.hex,
@@ -1574,7 +1603,7 @@ function createRecolourer() {
1574
1603
  };
1575
1604
  if (fg && bg && original.fg && original.bg) {
1576
1605
  const aim = entry.role === "text" ? MIN_TEXT_CONTRAST : MIN_ICON_CONTRAST;
1577
- const target = Math.min(aim, contrastRatio(original.fg, original.bg));
1606
+ const target = brand ? aim : Math.min(aim, contrastRatio(original.fg, original.bg));
1578
1607
  const lighter = luminance(original.fg) > luminance(original.bg);
1579
1608
  value = format({
1580
1609
  ...fg,
@@ -1626,6 +1655,117 @@ function createRecolourer() {
1626
1655
  };
1627
1656
  }
1628
1657
  //#endregion
1658
+ //#region src/settings.js
1659
+ /**
1660
+ * @typedef {Object} PanelSettings
1661
+ * @property {'light' | 'dark' | 'system'} mode Which version of each theme to list; the panel matches it
1662
+ * @property {boolean} showPicks
1663
+ * @property {boolean} showLibrary
1664
+ * @property {boolean} showCustom "Custom palettes" section
1665
+ * @property {boolean} showOverrides "Override a single colour" section
1666
+ * @property {boolean} showImportExport
1667
+ * @property {boolean} draggable Whether the colour button can be dragged
1668
+ * @property {boolean} animateDot Whether the colour button's dot cycles through the theme's colours
1669
+ * @property {number | null} panelWidth Pixels; null is the standard width
1670
+ * @property {number | 'full' | null} panelHeight Pixels, 'full' for all the room there is, or null to fit the content
1671
+ * @property {boolean} libraryCollapsed Whether the library's category chips are folded away
1672
+ * @property {boolean} colourLogo Whether themes re-colour the site's logo too (off keeps its own colours)
1673
+ * @property {boolean} hideButton Hidden on this device from the finish screen (Alt+Shift+C brings it back)
1674
+ */
1675
+ /** @type {PanelSettings} */
1676
+ var DEFAULT_SETTINGS = {
1677
+ mode: "light",
1678
+ showPicks: true,
1679
+ showLibrary: true,
1680
+ showCustom: true,
1681
+ showOverrides: true,
1682
+ showImportExport: true,
1683
+ draggable: true,
1684
+ animateDot: true,
1685
+ panelWidth: null,
1686
+ panelHeight: null,
1687
+ libraryCollapsed: false,
1688
+ colourLogo: false,
1689
+ hideButton: false
1690
+ };
1691
+ /** Size presets offered in settings; dragging an edge gives a custom size instead. */
1692
+ var PANEL_PRESETS = [
1693
+ {
1694
+ id: "compact",
1695
+ label: "Compact",
1696
+ width: 340,
1697
+ height: null
1698
+ },
1699
+ {
1700
+ id: "standard",
1701
+ label: "Standard",
1702
+ width: null,
1703
+ height: null
1704
+ },
1705
+ {
1706
+ id: "large",
1707
+ label: "Large",
1708
+ width: 560,
1709
+ height: "full"
1710
+ }
1711
+ ];
1712
+ /**
1713
+ * @param {string} storageKey
1714
+ * @param {PanelSettings} [defaults] the site's starting settings (see the config's colourLogo)
1715
+ * @returns {PanelSettings}
1716
+ */
1717
+ function loadSettings(storageKey, defaults = DEFAULT_SETTINGS) {
1718
+ try {
1719
+ const saved = JSON.parse(window.localStorage.getItem(`${storageKey}:settings`) || "null");
1720
+ if (!saved || typeof saved !== "object") return defaults;
1721
+ const out = { ...defaults };
1722
+ for (const [key, fallback] of Object.entries(defaults)) if (typeof saved[key] === typeof fallback) out[key] = saved[key];
1723
+ if (![
1724
+ "light",
1725
+ "dark",
1726
+ "system"
1727
+ ].includes(out.mode)) out.mode = defaults.mode;
1728
+ const size = (v) => typeof v === "number" && v > 0 && v < 1e4;
1729
+ out.panelWidth = size(saved.panelWidth) ? saved.panelWidth : null;
1730
+ out.panelHeight = size(saved.panelHeight) || saved.panelHeight === "full" ? saved.panelHeight : null;
1731
+ return out;
1732
+ } catch {
1733
+ return defaults;
1734
+ }
1735
+ }
1736
+ function saveSettings(storageKey, settings) {
1737
+ try {
1738
+ window.localStorage.setItem(`${storageKey}:settings`, JSON.stringify(settings));
1739
+ } catch {}
1740
+ }
1741
+ /** True while the device prefers dark colours. */
1742
+ function usePrefersDark() {
1743
+ const query = "(prefers-color-scheme: dark)";
1744
+ const [dark, setDark] = useState(() => window.matchMedia(query).matches);
1745
+ useEffect(() => {
1746
+ const mq = window.matchMedia(query);
1747
+ const update = () => setDark(mq.matches);
1748
+ mq.addEventListener("change", update);
1749
+ return () => mq.removeEventListener("change", update);
1750
+ }, []);
1751
+ return dark;
1752
+ }
1753
+ /**
1754
+ * @typedef {Object} SettingsApi
1755
+ * @property {PanelSettings} settings
1756
+ * @property {(patch: Partial<PanelSettings>) => void} update
1757
+ * @property {() => void} reset
1758
+ * @property {'light' | 'dark'} mode `settings.mode` with "system" resolved
1759
+ * @property {(() => void) | null} resetButton Moves the colour button back to its corner; null when it's there
1760
+ */
1761
+ /** @type {import('react').Context<SettingsApi | null>} */
1762
+ var SettingsContext = createContext(null);
1763
+ function useSettings() {
1764
+ const ctx = useContext(SettingsContext);
1765
+ if (!ctx) throw new Error("useSettings must be used inside the colorsbymax switcher");
1766
+ return ctx;
1767
+ }
1768
+ //#endregion
1629
1769
  //#region src/storage.js
1630
1770
  var DEFAULT_STORAGE_KEY = "colorsbymax";
1631
1771
  var VERSION = 1;
@@ -1772,6 +1912,10 @@ var newId = () => `custom-${Date.now().toString(36)}-${Math.random().toString(36
1772
1912
  * Where each token is used on this site, shown in the editors
1773
1913
  * @property {boolean} [scrollbars] Colour the page's scrollbars from the theme (default true)
1774
1914
  * @property {() => Promise<any>} [pdf] Enables PDF uploads: pass `loadPdf` from 'colorsbymax/pdf'
1915
+ * @property {boolean} [colourLogo] Whether themes colour the site's logo for a first-time visitor
1916
+ * (default false: the logo keeps its own colours). Visitors can still change it in settings.
1917
+ * @property {boolean} [intro] Bring the colour button in with a short pop and burst of the theme's
1918
+ * colours, a moment after the page loads (default true). Reduced motion fades it in instead.
1775
1919
  * @property {boolean} [hidden] Hide the colour button and panel; the theme still applies. Use
1776
1920
  * `hidden: import.meta.env.PROD` to keep it out of production once the colours are chosen.
1777
1921
  * @property {'bottom-right' | 'bottom-left' | 'top-left' | 'top-right'} [position] Where the colour
@@ -1871,7 +2015,11 @@ function ThemeProvider({ config = {}, children }) {
1871
2015
  recolourer.current = null;
1872
2016
  };
1873
2017
  }, [recolourMode]);
1874
- const [logoColouring, setLogoColouring] = useState(false);
2018
+ const settingDefaults = useMemo(() => ({
2019
+ ...DEFAULT_SETTINGS,
2020
+ colourLogo: Boolean(initialConfig.colourLogo)
2021
+ }), [initialConfig]);
2022
+ const [logoColouring, setLogoColouring] = useState(() => loadSettings(storageKey, settingDefaults).colourLogo);
1875
2023
  useLayoutEffect(() => {
1876
2024
  recolourer.current?.setLogoColouring(logoColouring);
1877
2025
  }, [logoColouring, pageColours]);
@@ -1929,8 +2077,80 @@ function ThemeProvider({ config = {}, children }) {
1929
2077
  }
1930
2078
  }))(s);
1931
2079
  }), []);
2080
+ /** Selects a theme by id; pass the theme itself for library themes and dark twins. */
2081
+ const selectTheme = useCallback((id, theme) => setState((s) => ({
2082
+ ...s,
2083
+ activeId: id,
2084
+ snapshot: theme?.library || theme?.derived ? {
2085
+ id: theme.id,
2086
+ name: theme.name,
2087
+ tokens: theme.tokens
2088
+ } : s.snapshot
2089
+ })), []);
2090
+ const [modeSetting, setModeSetting] = useState(() => loadSettings(storageKey, settingDefaults).mode);
2091
+ const prefersDark = usePrefersDark();
2092
+ const mode = modeSetting === "system" ? prefersDark ? "dark" : "light" : modeSetting;
2093
+ const modeRef = useRef(mode);
2094
+ modeRef.current = mode;
2095
+ const setMode = useCallback((next) => {
2096
+ if (![
2097
+ "light",
2098
+ "dark",
2099
+ "system"
2100
+ ].includes(next)) return;
2101
+ setModeSetting(next);
2102
+ saveSettings(storageKey, {
2103
+ ...loadSettings(storageKey, settingDefaults),
2104
+ mode: next
2105
+ });
2106
+ }, [storageKey, settingDefaults]);
2107
+ useLayoutEffect(() => {
2108
+ if (base.custom) return;
2109
+ if (mode === "dark" && !isDarkTheme(base.tokens)) {
2110
+ const twin = toDark(base);
2111
+ selectTheme(twin.id, twin);
2112
+ } else if (mode === "light" && base.id.endsWith("~dark")) {
2113
+ const lightId = base.id.slice(0, -DARK_SUFFIX.length);
2114
+ const local = allThemes.find((t) => t.id === lightId);
2115
+ if (local) selectTheme(local.id, local);
2116
+ else loadLibrary().then((lib) => {
2117
+ const t = lib.themes.find((x) => x.id === lightId);
2118
+ if (t) selectTheme(t.id, t);
2119
+ }, () => {});
2120
+ }
2121
+ }, [
2122
+ mode,
2123
+ base,
2124
+ allThemes,
2125
+ selectTheme
2126
+ ]);
2127
+ useLayoutEffect(() => {
2128
+ const html = document.documentElement;
2129
+ html.dataset.colorsbymaxScheme = mode;
2130
+ html.style.colorScheme = mode;
2131
+ for (const el of document.querySelectorAll("[data-colorsbymax-mode]")) {
2132
+ const want = el.getAttribute("data-colorsbymax-mode");
2133
+ el.setAttribute("aria-pressed", String(want === "toggle" ? mode === "dark" : want === modeSetting));
2134
+ }
2135
+ }, [mode, modeSetting]);
2136
+ useEffect(() => {
2137
+ const onClick = (e) => {
2138
+ const el = e.target.closest?.("[data-colorsbymax-mode]");
2139
+ if (!el) return;
2140
+ const want = el.getAttribute("data-colorsbymax-mode");
2141
+ setMode(want === "toggle" ? modeRef.current === "dark" ? "light" : "dark" : want);
2142
+ };
2143
+ document.addEventListener("click", onClick);
2144
+ return () => document.removeEventListener("click", onClick);
2145
+ }, [setMode]);
1932
2146
  const api = {
1933
2147
  state,
2148
+ /** The switcher's starting settings for this site. */
2149
+ settingDefaults,
2150
+ /** The mode in effect ('light' or 'dark'), the visitor's setting ('system' follows the device), and a setter. */
2151
+ mode,
2152
+ modeSetting,
2153
+ setMode,
1934
2154
  storageKey,
1935
2155
  siteName,
1936
2156
  usage: initialConfig.usage ?? {},
@@ -1938,6 +2158,8 @@ function ThemeProvider({ config = {}, children }) {
1938
2158
  position: initialConfig.position ?? "bottom-right",
1939
2159
  /** True when the config hides the switcher (e.g. in production); the theme still applies. */
1940
2160
  hidden: Boolean(initialConfig.hidden),
2161
+ /** Whether the colour button makes an entrance when it first appears. */
2162
+ intro: initialConfig.intro !== false,
1941
2163
  /** True when colorsbymax is swapping the page's own colours (the site isn't wired to tokens). */
1942
2164
  recolouring: Boolean(pageColours),
1943
2165
  /** Turns re-colouring of the site's logo on or off (the switcher's "Colour the logo" setting). */
@@ -1950,16 +2172,7 @@ function ThemeProvider({ config = {}, children }) {
1950
2172
  active: base,
1951
2173
  tokens,
1952
2174
  issues,
1953
- /** Selects a theme by id; pass the theme itself for library themes and dark twins. */
1954
- selectTheme: (id, theme) => setState((s) => ({
1955
- ...s,
1956
- activeId: id,
1957
- snapshot: theme?.library || theme?.derived ? {
1958
- id: theme.id,
1959
- name: theme.name,
1960
- tokens: theme.tokens
1961
- } : s.snapshot
1962
- })),
2175
+ selectTheme,
1963
2176
  createCustom: (name) => {
1964
2177
  const id = newId();
1965
2178
  setState((s) => ({
@@ -2313,6 +2526,17 @@ var ClipboardPaste = icon("clipboard-paste", [
2313
2526
  "rx": "1"
2314
2527
  }]
2315
2528
  ]);
2529
+ var ToggleRight = icon("toggle-right", [["circle", {
2530
+ "cx": "15",
2531
+ "cy": "12",
2532
+ "r": "3"
2533
+ }], ["rect", {
2534
+ "width": "20",
2535
+ "height": "14",
2536
+ "x": "2",
2537
+ "y": "5",
2538
+ "rx": "7"
2539
+ }]]);
2316
2540
  /** Images are scaled down to at most this many pixels on their longest side before sampling. */
2317
2541
  var SAMPLE_SIZE = 200;
2318
2542
  /** PDF pages read, from the first. */
@@ -2533,112 +2757,118 @@ var cssSnippet = (tokens) => `:root {\n${TOKEN_KEYS.map((k) => ` --color-${k}:
2533
2757
  var keepPrompt = (name, tokens) => `Update my colorsbymax setup so the colours I chose become my site's default and the colour switcher is hidden in production. In the colorsbymax config (the autoMount({...}) call, or the config passed to <ThemeProvider>), set defaultTheme to { name: ${JSON.stringify(name)}, tokens: ${JSON.stringify(tokens)} } and set hidden: ${VITE_PROD} (use ${NODE_PROD} if this isn't a Vite project). If the site uses import 'colorsbymax/auto', replace it with import { autoMount } from 'colorsbymax/auto' and an autoMount({...}) call with that config. Don't change anything else.`;
2534
2758
  /** @param {boolean} recolouring true when colorsbymax was swapping the site's hard-coded colours */
2535
2759
  var removePrompt = (tokens, recolouring) => recolouring ? `Remove colorsbymax from this project but keep the colours it currently shows. The site's CSS uses hard-coded colours that colorsbymax was swapping at runtime, so update the site's own CSS to use this palette instead (primary is the main brand colour, background the page, ink the text): ${JSON.stringify(tokens)}. Then uninstall the colorsbymax package and delete its import (import 'colorsbymax/auto', autoMount, ThemeProvider or ThemeSwitcher) and any colorsbymax pre-paint script in index.html.` : `Remove colorsbymax from this project but keep my colours: add these CSS variables to my global stylesheet, replacing any existing --color-* values: ${cssSnippet(tokens)} Then uninstall the colorsbymax package and delete its usage (ThemeProvider, ThemeSwitcher, autoMount or import 'colorsbymax/auto') and any colorsbymax pre-paint script in index.html. Keep colorsbymax/tokens.css only if nothing else needs it.`;
2536
- //#endregion
2537
- //#region src/settings.js
2538
- /**
2539
- * @typedef {Object} PanelSettings
2540
- * @property {'light' | 'dark' | 'system'} mode Which version of each theme to list; the panel matches it
2541
- * @property {boolean} showPicks
2542
- * @property {boolean} showLibrary
2543
- * @property {boolean} showCustom "Custom palettes" section
2544
- * @property {boolean} showOverrides "Override a single colour" section
2545
- * @property {boolean} showImportExport
2546
- * @property {boolean} draggable Whether the colour button can be dragged
2547
- * @property {boolean} animateDot Whether the colour button's dot cycles through the theme's colours
2548
- * @property {number | null} panelWidth Pixels; null is the standard width
2549
- * @property {number | 'full' | null} panelHeight Pixels, 'full' for all the room there is, or null to fit the content
2550
- * @property {boolean} libraryCollapsed Whether the library's category chips are folded away
2551
- * @property {boolean} colourLogo Whether themes re-colour the site's logo too (off keeps its own colours)
2552
- * @property {boolean} hideButton Hidden on this device from the finish screen (Alt+Shift+C brings it back)
2553
- */
2554
- /** @type {PanelSettings} */
2555
- var DEFAULT_SETTINGS = {
2556
- mode: "light",
2557
- showPicks: true,
2558
- showLibrary: true,
2559
- showCustom: true,
2560
- showOverrides: true,
2561
- showImportExport: true,
2562
- draggable: true,
2563
- animateDot: true,
2564
- panelWidth: null,
2565
- panelHeight: null,
2566
- libraryCollapsed: false,
2567
- colourLogo: false,
2568
- hideButton: false
2569
- };
2570
- /** Size presets offered in settings; dragging an edge gives a custom size instead. */
2571
- var PANEL_PRESETS = [
2572
- {
2573
- id: "compact",
2574
- label: "Compact",
2575
- width: 340,
2576
- height: null
2577
- },
2578
- {
2579
- id: "standard",
2580
- label: "Standard",
2581
- width: null,
2582
- height: null
2583
- },
2584
- {
2585
- id: "large",
2586
- label: "Large",
2587
- width: 560,
2588
- height: "full"
2589
- }
2590
- ];
2591
- /** @returns {PanelSettings} */
2592
- function loadSettings(storageKey) {
2593
- try {
2594
- const saved = JSON.parse(window.localStorage.getItem(`${storageKey}:settings`) || "null");
2595
- if (!saved || typeof saved !== "object") return DEFAULT_SETTINGS;
2596
- const out = { ...DEFAULT_SETTINGS };
2597
- for (const [key, fallback] of Object.entries(DEFAULT_SETTINGS)) if (typeof saved[key] === typeof fallback) out[key] = saved[key];
2598
- if (![
2599
- "light",
2600
- "dark",
2601
- "system"
2602
- ].includes(out.mode)) out.mode = DEFAULT_SETTINGS.mode;
2603
- const size = (v) => typeof v === "number" && v > 0 && v < 1e4;
2604
- out.panelWidth = size(saved.panelWidth) ? saved.panelWidth : null;
2605
- out.panelHeight = size(saved.panelHeight) || saved.panelHeight === "full" ? saved.panelHeight : null;
2606
- return out;
2607
- } catch {
2608
- return DEFAULT_SETTINGS;
2609
- }
2760
+ /** The switch's markup: a sun in light mode, a moon in dark. */
2761
+ var TOGGLE_HTML = `<button type="button" class="cbm-mode-toggle" data-colorsbymax-mode="toggle" aria-label="Switch between light and dark mode">
2762
+ <svg class="cbm-mode-sun" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
2763
+ <svg class="cbm-mode-moon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>
2764
+ </button>`;
2765
+ /** Its styles. It takes the colour of the text around it, so it suits any top bar. */
2766
+ var TOGGLE_CSS = `.cbm-mode-toggle {
2767
+ display: inline-grid;
2768
+ place-items: center;
2769
+ width: 2.25rem;
2770
+ height: 2.25rem;
2771
+ border: 1px solid currentColor;
2772
+ border-radius: 9999px;
2773
+ background: transparent;
2774
+ color: inherit;
2775
+ opacity: 0.85;
2776
+ cursor: pointer;
2610
2777
  }
2611
- function saveSettings(storageKey, settings) {
2612
- try {
2613
- window.localStorage.setItem(`${storageKey}:settings`, JSON.stringify(settings));
2614
- } catch {}
2615
- }
2616
- /** True while the device prefers dark colours. */
2617
- function usePrefersDark() {
2618
- const query = "(prefers-color-scheme: dark)";
2619
- const [dark, setDark] = useState(() => window.matchMedia(query).matches);
2620
- useEffect(() => {
2621
- const mq = window.matchMedia(query);
2622
- const update = () => setDark(mq.matches);
2623
- mq.addEventListener("change", update);
2624
- return () => mq.removeEventListener("change", update);
2625
- }, []);
2626
- return dark;
2778
+ .cbm-mode-toggle:hover { opacity: 1; }
2779
+ .cbm-mode-toggle .cbm-mode-moon,
2780
+ html[data-colorsbymax-scheme="dark"] .cbm-mode-toggle .cbm-mode-sun { display: none; }
2781
+ html[data-colorsbymax-scheme="dark"] .cbm-mode-toggle .cbm-mode-moon { display: block; }`;
2782
+ /** The same switch as a React component. */
2783
+ var TOGGLE_REACT = `// ModeToggle.jsx: put <ModeToggle /> in your top bar. colorsbymax makes it work.
2784
+ export function ModeToggle() {
2785
+ return (
2786
+ <button type="button" className="cbm-mode-toggle" data-colorsbymax-mode="toggle" aria-label="Switch between light and dark mode">
2787
+ <svg className="cbm-mode-sun" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
2788
+ <circle cx="12" cy="12" r="4" />
2789
+ <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" />
2790
+ </svg>
2791
+ <svg className="cbm-mode-moon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
2792
+ <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
2793
+ </svg>
2794
+ </button>
2795
+ )
2796
+ }`;
2797
+ /** A prompt for Claude, Cursor or Copilot that adds the switch to the site's top bar. */
2798
+ var TOGGLE_PROMPT = `Add a light and dark mode switch to my site's top navigation bar, next to its other links or buttons. The site uses colorsbymax, which makes the switch work: any element with data-colorsbymax-mode="toggle" switches the whole site between light and dark and remembers the visitor's choice. Use this button (as a React component if the nav is React):
2799
+
2800
+ ${TOGGLE_HTML}
2801
+
2802
+ and add these styles to the global stylesheet, adjusting size and spacing to match the nav:
2803
+
2804
+ ${TOGGLE_CSS}
2805
+
2806
+ Don't change anything else.`;
2807
+ var PREVIEW = "data-colorsbymax-preview";
2808
+ /** Where a switch would go: the page's top bar, or null if it has none. */
2809
+ function topBar() {
2810
+ for (const selector of [
2811
+ "header nav",
2812
+ "nav",
2813
+ "[role=\"navigation\"]",
2814
+ "header",
2815
+ "[role=\"banner\"]"
2816
+ ]) for (const el of document.querySelectorAll(selector)) {
2817
+ if (el.closest("colorsbymax-root")) continue;
2818
+ const r = el.getBoundingClientRect();
2819
+ if (r.width > 200 && r.height > 12 && r.top < window.innerHeight / 2) return el;
2820
+ }
2821
+ return null;
2627
2822
  }
2823
+ /** Whether a preview switch is on the page. */
2824
+ var isPreviewing = () => Boolean(document.querySelector(`[${PREVIEW}]`));
2628
2825
  /**
2629
- * @typedef {Object} SettingsApi
2630
- * @property {PanelSettings} settings
2631
- * @property {(patch: Partial<PanelSettings>) => void} update
2632
- * @property {() => void} reset
2633
- * @property {'light' | 'dark'} mode `settings.mode` with "system" resolved
2634
- * @property {(() => void) | null} resetButton Moves the colour button back to its corner; null when it's there
2826
+ * Puts a switch in the page's top bar (or the top-left corner if it has none) until the next
2827
+ * reload. Returns where it went: 'nav' or 'corner'.
2635
2828
  */
2636
- /** @type {import('react').Context<SettingsApi | null>} */
2637
- var SettingsContext = createContext(null);
2638
- function useSettings() {
2639
- const ctx = useContext(SettingsContext);
2640
- if (!ctx) throw new Error("useSettings must be used inside the colorsbymax switcher");
2641
- return ctx;
2829
+ function previewToggle() {
2830
+ removePreview();
2831
+ const style = document.createElement("style");
2832
+ style.setAttribute(PREVIEW, "");
2833
+ style.textContent = TOGGLE_CSS;
2834
+ document.head.append(style);
2835
+ const holder = document.createElement("span");
2836
+ holder.innerHTML = TOGGLE_HTML;
2837
+ const button = holder.firstElementChild;
2838
+ button.setAttribute(PREVIEW, "");
2839
+ button.setAttribute("aria-pressed", String(document.documentElement.dataset.colorsbymaxScheme === "dark"));
2840
+ const bar = topBar();
2841
+ if (bar) {
2842
+ button.style.marginInline = "0.5rem";
2843
+ bar.append(button);
2844
+ } else {
2845
+ Object.assign(button.style, {
2846
+ position: "fixed",
2847
+ top: "16px",
2848
+ left: "16px",
2849
+ zIndex: "59",
2850
+ background: "Canvas"
2851
+ });
2852
+ document.body.append(button);
2853
+ }
2854
+ button.animate?.([
2855
+ {
2856
+ transform: "scale(0.4)",
2857
+ opacity: 0
2858
+ },
2859
+ { transform: "scale(1.15)" },
2860
+ {
2861
+ transform: "scale(1)",
2862
+ opacity: 1
2863
+ }
2864
+ ], {
2865
+ duration: 450,
2866
+ easing: "ease-out"
2867
+ });
2868
+ return bar ? "nav" : "corner";
2869
+ }
2870
+ function removePreview() {
2871
+ for (const el of document.querySelectorAll(`[${PREVIEW}]`)) el.remove();
2642
2872
  }
2643
2873
  //#endregion
2644
2874
  //#region src/ThemePanel.jsx
@@ -2689,7 +2919,7 @@ function useSavedToYours() {
2689
2919
  }
2690
2920
  function ThemePanel() {
2691
2921
  const theme = useTheme();
2692
- const { settings, mode, audit } = useSettings();
2922
+ const { settings, mode, audit, update } = useSettings();
2693
2923
  const overrideCount = Object.keys(theme.state.overrides).length;
2694
2924
  const [view, setView] = useState("main");
2695
2925
  const returnFocus = useRef(null);
@@ -2754,33 +2984,73 @@ function ThemePanel() {
2754
2984
  children: "by mrmaxdesigns"
2755
2985
  })] }), /* @__PURE__ */ jsxs("div", {
2756
2986
  className: "flex items-center gap-1",
2757
- children: [/* @__PURE__ */ jsxs("button", {
2758
- type: "button",
2759
- onClick: audit.toggle,
2760
- className: `${btn} px-2 ${audit.on ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
2761
- "aria-pressed": audit.on,
2762
- "data-tip": "Audit the page: point out what won’t look right with these colours",
2763
- children: [/* @__PURE__ */ jsx(ScanSearch, {
2764
- className: "w-4 h-4",
2765
- "aria-hidden": "true"
2766
- }), "Audit"]
2767
- }), /* @__PURE__ */ jsx("button", {
2768
- type: "button",
2769
- onClick: (e) => view === "settings" ? setView("main") : showView("settings", e.currentTarget),
2770
- className: `${btn} px-1.5 ${view === "settings" ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
2771
- "aria-label": "Panel settings",
2772
- "aria-pressed": view === "settings",
2773
- "data-tip": "Panel settings",
2774
- children: /* @__PURE__ */ jsx(Settings, {
2775
- className: "w-4 h-4",
2776
- "aria-hidden": "true"
2987
+ children: [
2988
+ /* @__PURE__ */ jsx("div", {
2989
+ role: "radiogroup",
2990
+ "aria-label": "Theme mode",
2991
+ className: "flex items-center rounded-lg border border-zinc-200 p-0.5",
2992
+ children: MODES.map(({ id, label, Icon }) => {
2993
+ const on = settings.mode === id;
2994
+ return /* @__PURE__ */ jsx("button", {
2995
+ type: "button",
2996
+ role: "radio",
2997
+ "aria-checked": on,
2998
+ "aria-label": label,
2999
+ "data-tip": id === "system" ? "Auto: follow this device" : label,
3000
+ onClick: () => update({ mode: id }),
3001
+ className: `grid h-7 w-7 place-items-center rounded-md cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 ${on ? "bg-zinc-900 text-white" : "text-zinc-600 hover:bg-zinc-100 hover:text-zinc-900"}`,
3002
+ children: /* @__PURE__ */ jsx(Icon, {
3003
+ className: "w-3.5 h-3.5",
3004
+ "aria-hidden": "true"
3005
+ })
3006
+ }, id);
3007
+ })
3008
+ }),
3009
+ /* @__PURE__ */ jsxs("button", {
3010
+ type: "button",
3011
+ onClick: (e) => view === "mode-toggle" ? setView("main") : showView("mode-toggle", e.currentTarget),
3012
+ className: `${btn} shrink-0 whitespace-nowrap px-1.5 @min-[500px]:px-2 ${view === "mode-toggle" ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
3013
+ "aria-pressed": view === "mode-toggle",
3014
+ "aria-label": "Add a light and dark switch to your site",
3015
+ "data-tip": "Add a light and dark switch to your site",
3016
+ children: [/* @__PURE__ */ jsx(ToggleRight, {
3017
+ className: "w-4 h-4",
3018
+ "aria-hidden": "true"
3019
+ }), /* @__PURE__ */ jsx("span", {
3020
+ className: "hidden @min-[500px]:inline",
3021
+ children: "Add to site"
3022
+ })]
3023
+ }),
3024
+ /* @__PURE__ */ jsxs("button", {
3025
+ type: "button",
3026
+ onClick: audit.toggle,
3027
+ className: `${btn} px-2 ${audit.on ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
3028
+ "aria-pressed": audit.on,
3029
+ "data-tip": "Audit the page: point out what won’t look right with these colours",
3030
+ children: [/* @__PURE__ */ jsx(ScanSearch, {
3031
+ className: "w-4 h-4",
3032
+ "aria-hidden": "true"
3033
+ }), "Audit"]
3034
+ }),
3035
+ /* @__PURE__ */ jsx("button", {
3036
+ type: "button",
3037
+ onClick: (e) => view === "settings" ? setView("main") : showView("settings", e.currentTarget),
3038
+ className: `${btn} px-1.5 ${view === "settings" ? "border-zinc-900 bg-zinc-100" : "border-transparent"}`,
3039
+ "aria-label": "Panel settings",
3040
+ "aria-pressed": view === "settings",
3041
+ "data-tip": "Panel settings",
3042
+ children: /* @__PURE__ */ jsx(Settings, {
3043
+ className: "w-4 h-4",
3044
+ "aria-hidden": "true"
3045
+ })
2777
3046
  })
2778
- })]
3047
+ ]
2779
3048
  })]
2780
3049
  }),
2781
3050
  view === "contrast" && /* @__PURE__ */ jsx(ContrastView, { onBack: () => setView("main") }),
2782
3051
  view === "settings" && /* @__PURE__ */ jsx(SettingsView, { onBack: () => setView("main") }),
2783
3052
  view === "finish" && /* @__PURE__ */ jsx(FinishView, { onBack: () => setView("main") }),
3053
+ view === "mode-toggle" && /* @__PURE__ */ jsx(ModeToggleView, { onBack: () => setView("main") }),
2784
3054
  /* @__PURE__ */ jsxs("div", {
2785
3055
  hidden: view !== "main",
2786
3056
  children: [/* @__PURE__ */ jsxs(ContrastNav.Provider, {
@@ -2895,6 +3165,137 @@ function Toast({ toast, onDismiss }) {
2895
3165
  ]
2896
3166
  });
2897
3167
  }
3168
+ /**
3169
+ * "Add to site": a light and dark switch for the site itself. Every theme has a dark version, so any
3170
+ * site can switch; this shows the switch, previews it in the page's top bar, and gives the code and
3171
+ * an AI-editor prompt to add it for good.
3172
+ */
3173
+ function ModeToggleView({ onBack }) {
3174
+ const { settings, update } = useSettings();
3175
+ const { toast } = usePanel();
3176
+ const headingRef = useRef(null);
3177
+ const [previewing, setPreviewing] = useState(isPreviewing);
3178
+ const [tab, setTab] = useState("html");
3179
+ useEffect(() => headingRef.current?.focus(), []);
3180
+ const preview = () => {
3181
+ const where = previewToggle();
3182
+ setPreviewing(true);
3183
+ toast(where === "nav" ? "The switch is in your top bar. Try it; it’s gone when you reload." : "No top bar found, so the switch is in the top-left corner. It’s gone when you reload.");
3184
+ };
3185
+ const stop = () => {
3186
+ removePreview();
3187
+ setPreviewing(false);
3188
+ };
3189
+ return /* @__PURE__ */ jsxs("div", {
3190
+ className: "px-4 py-3 space-y-4",
3191
+ children: [
3192
+ /* @__PURE__ */ jsxs("button", {
3193
+ type: "button",
3194
+ className: `${btn} border-transparent px-1.5`,
3195
+ onClick: onBack,
3196
+ children: [/* @__PURE__ */ jsx(ArrowLeft, {
3197
+ className: "w-3.5 h-3.5",
3198
+ "aria-hidden": "true"
3199
+ }), " Back"]
3200
+ }),
3201
+ /* @__PURE__ */ jsx("h3", {
3202
+ ref: headingRef,
3203
+ tabIndex: -1,
3204
+ className: "text-sm font-semibold focus:outline-none",
3205
+ children: "Add a light and dark switch to your site"
3206
+ }),
3207
+ /* @__PURE__ */ jsx("p", {
3208
+ className: "text-xs text-zinc-600",
3209
+ children: "Every theme has a dark version, so your whole site can switch, even if it never had a dark mode. Put a switch in your top bar and visitors can choose; colorsbymax does the rest and remembers their choice. It keeps working when the colour button is hidden."
3210
+ }),
3211
+ /* @__PURE__ */ jsxs("div", {
3212
+ className: "flex items-center justify-between gap-3 rounded-xl border border-zinc-200 bg-zinc-50 p-3",
3213
+ children: [/* @__PURE__ */ jsxs("div", {
3214
+ className: "text-xs text-zinc-700",
3215
+ children: [/* @__PURE__ */ jsx("p", {
3216
+ className: "font-semibold text-zinc-900",
3217
+ children: "Try it here first"
3218
+ }), /* @__PURE__ */ jsx("p", { children: previewing ? "The switch is on this page. It’s gone when you reload." : "Puts a working switch in this page’s top bar." })]
3219
+ }), previewing ? /* @__PURE__ */ jsx("button", {
3220
+ type: "button",
3221
+ className: btn,
3222
+ onClick: stop,
3223
+ children: "Remove"
3224
+ }) : /* @__PURE__ */ jsxs("button", {
3225
+ type: "button",
3226
+ className: btnPrimary,
3227
+ onClick: preview,
3228
+ children: [/* @__PURE__ */ jsx(ToggleRight, {
3229
+ className: "w-3.5 h-3.5",
3230
+ "aria-hidden": "true"
3231
+ }), " Preview it"]
3232
+ })]
3233
+ }),
3234
+ /* @__PURE__ */ jsx("div", {
3235
+ role: "radiogroup",
3236
+ "aria-label": "Mode",
3237
+ className: "grid grid-cols-3 gap-2",
3238
+ children: MODES.map(({ id, label, Icon }) => /* @__PURE__ */ jsxs("button", {
3239
+ type: "button",
3240
+ role: "radio",
3241
+ "aria-checked": settings.mode === id,
3242
+ onClick: () => update({ mode: id }),
3243
+ className: `flex h-8 items-center justify-center gap-1.5 rounded-lg border text-xs font-medium cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 ${settings.mode === id ? "border-zinc-900 bg-zinc-900 text-white" : "border-zinc-300 bg-white text-zinc-800 hover:bg-zinc-50"}`,
3244
+ children: [
3245
+ /* @__PURE__ */ jsx(Icon, {
3246
+ className: "w-3.5 h-3.5",
3247
+ "aria-hidden": "true"
3248
+ }),
3249
+ " ",
3250
+ label
3251
+ ]
3252
+ }, id))
3253
+ }),
3254
+ /* @__PURE__ */ jsxs("div", {
3255
+ className: "space-y-2",
3256
+ children: [
3257
+ /* @__PURE__ */ jsx("p", {
3258
+ className: "text-xs font-semibold text-zinc-900",
3259
+ children: "Add it for good"
3260
+ }),
3261
+ /* @__PURE__ */ jsx("div", {
3262
+ role: "tablist",
3263
+ "aria-label": "Code for",
3264
+ className: "flex gap-1",
3265
+ children: [["html", "HTML"], ["react", "React"]].map(([id, label]) => /* @__PURE__ */ jsx("button", {
3266
+ type: "button",
3267
+ role: "tab",
3268
+ "aria-selected": tab === id,
3269
+ onClick: () => setTab(id),
3270
+ className: `rounded-md px-2 py-1 text-[11px] font-semibold cursor-pointer ${tab === id ? "bg-zinc-900 text-white" : "text-zinc-600 hover:bg-zinc-100"}`,
3271
+ children: label
3272
+ }, id))
3273
+ }),
3274
+ /* @__PURE__ */ jsx(CopyBlock, {
3275
+ label: tab === "html" ? "In your top bar" : "ModeToggle.jsx",
3276
+ text: tab === "html" ? TOGGLE_HTML : TOGGLE_REACT
3277
+ }),
3278
+ /* @__PURE__ */ jsx(CopyBlock, {
3279
+ label: "In your global stylesheet",
3280
+ text: TOGGLE_CSS
3281
+ }),
3282
+ /* @__PURE__ */ jsx(CopyBlock, {
3283
+ label: "Or ask Claude, Cursor or Copilot",
3284
+ text: TOGGLE_PROMPT,
3285
+ copyLabel: "Copy prompt"
3286
+ })
3287
+ ]
3288
+ }),
3289
+ /* @__PURE__ */ jsxs("p", {
3290
+ className: "rounded-lg bg-zinc-100 p-2.5 text-[11px] text-zinc-700",
3291
+ children: [/* @__PURE__ */ jsx("strong", {
3292
+ className: "font-semibold text-zinc-900",
3293
+ children: "Already have a dark mode?"
3294
+ }), " You don’t need this. The theme you pick colours your site well in light and dark, with contrast checked in both."]
3295
+ })
3296
+ ]
3297
+ });
3298
+ }
2898
3299
  /** Shows code with a copy button. */
2899
3300
  function CopyBlock({ label, text, copyLabel = "Copy" }) {
2900
3301
  const { toast } = usePanel();
@@ -3569,6 +3970,8 @@ function PresetGrid() {
3569
3970
  const { toast, reveal } = usePanel();
3570
3971
  const wrapRef = useRef(null);
3571
3972
  const pendingScroll = useRef(false);
3973
+ const themesRef = useRef(null);
3974
+ const scrollToThemes = useRef(false);
3572
3975
  useEffect(() => {
3573
3976
  if (!reveal) return;
3574
3977
  setCategory(reveal.group);
@@ -3580,6 +3983,14 @@ function PresetGrid() {
3580
3983
  pendingScroll.current = true;
3581
3984
  }, [reveal]);
3582
3985
  useEffect(() => {
3986
+ if (scrollToThemes.current && themesRef.current) {
3987
+ scrollToThemes.current = false;
3988
+ const still = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
3989
+ themesRef.current.scrollIntoView({
3990
+ block: "start",
3991
+ behavior: still ? "auto" : "smooth"
3992
+ });
3993
+ }
3583
3994
  if (!pendingScroll.current) return;
3584
3995
  pendingScroll.current = false;
3585
3996
  const root = wrapRef.current;
@@ -3667,10 +4078,11 @@ function PresetGrid() {
3667
4078
  "yours"
3668
4079
  ].includes(category));
3669
4080
  const catInfo = library?.categories.find((c) => c.id === category);
3670
- const choose = (id) => {
4081
+ const choose = (id, { scroll = false } = {}) => {
3671
4082
  setCategory(id);
3672
4083
  setQuery("");
3673
4084
  setLimit(PAGE_SIZE);
4085
+ scrollToThemes.current = scroll;
3674
4086
  };
3675
4087
  const pick = (t) => selectTheme(t.id, t);
3676
4088
  const surprise = () => {
@@ -3802,7 +4214,7 @@ function PresetGrid() {
3802
4214
  type: "button",
3803
4215
  "aria-pressed": on,
3804
4216
  "data-tip": c.description,
3805
- onClick: () => choose(c.id),
4217
+ onClick: () => choose(c.id, { scroll: true }),
3806
4218
  className: `flex h-8 min-w-0 items-center gap-1 rounded-lg border px-2 text-xs font-medium cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-1 ${on ? "border-zinc-900 bg-zinc-900 text-white" : "border-zinc-300 bg-white text-zinc-800 hover:bg-zinc-50"}`,
3807
4219
  children: [
3808
4220
  on && /* @__PURE__ */ jsx(Check, {
@@ -3821,6 +4233,10 @@ function PresetGrid() {
3821
4233
  }, c.id);
3822
4234
  })
3823
4235
  })] }),
4236
+ /* @__PURE__ */ jsx("div", {
4237
+ ref: themesRef,
4238
+ className: "scroll-mt-3"
4239
+ }),
3824
4240
  !q && /* @__PURE__ */ jsx("p", {
3825
4241
  className: "text-xs text-zinc-600",
3826
4242
  children: (catInfo ?? chips.find((c) => c.id === category))?.description
@@ -5258,7 +5674,7 @@ function AuditBar({ anchorRect, open, hiddenCount, themeIssues, onRecheck, onClo
5258
5674
  }
5259
5675
  //#endregion
5260
5676
  //#region src/panel-css.generated.js
5261
- var panel_css_generated_default = "/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (display:block){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-900:oklch(39.1% .09 240.876);--color-zinc-50:oklch(98.5% 0 none);--color-zinc-100:oklch(96.7% .001 286.375);--color-zinc-200:oklch(92% .004 286.32);--color-zinc-300:oklch(87.1% .006 286.286);--color-zinc-400:oklch(70.5% .015 286.067);--color-zinc-500:oklch(55.2% .016 285.938);--color-zinc-600:oklch(44.2% .017 285.786);--color-zinc-700:oklch(37% .013 285.805);--color-zinc-800:oklch(27.4% .006 286.033);--color-zinc-900:oklch(21% .006 285.885);--color-white:#fff;--spacing:4px;--text-xs:12px;--text-xs--line-height:calc(1 / .75);--text-sm:14px;--text-sm--line-height:calc(1.25 / .875);--text-base:16px;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-snug:1.375;--radius-md:6px;--radius-lg:8px;--radius-xl:12px;--radius-2xl:16px;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}.theme-switcher{letter-spacing:normal;color:var(--color-zinc-900);font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:16px;line-height:1.5}}@layer components;@layer utilities{.\\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-x-3{inset-inline:calc(var(--spacing) * 3)}.inset-x-5{inset-inline:calc(var(--spacing) * 5)}.inset-y-5{inset-block:calc(var(--spacing) * 5)}.-top-2{top:calc(var(--spacing) * -2)}.-top-\\[6px\\]{top:-6px}.top-0{top:0}.top-1\\.5{top:calc(var(--spacing) * 1.5)}.top-1\\/2{top:50%}.top-5{top:calc(var(--spacing) * 5)}.top-\\[84px\\]{top:84px}.-right-0\\.5{right:calc(var(--spacing) * -.5)}.-right-2{right:calc(var(--spacing) * -2)}.right-1\\.5{right:calc(var(--spacing) * 1.5)}.right-5{right:calc(var(--spacing) * 5)}.right-6{right:calc(var(--spacing) * 6)}.right-full{right:100%}.-bottom-0\\.5{bottom:calc(var(--spacing) * -.5)}.-bottom-2{bottom:calc(var(--spacing) * -2)}.-bottom-\\[6px\\]{bottom:-6px}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-5{bottom:calc(var(--spacing) * 5)}.-left-2{left:calc(var(--spacing) * -2)}.left-5{left:calc(var(--spacing) * 5)}.left-full{left:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-\\[55\\]{z-index:55}.z-\\[56\\]{z-index:56}.z-\\[57\\]{z-index:57}.z-\\[60\\]{z-index:60}.z-\\[61\\]{z-index:61}.z-\\[62\\]{z-index:62}.z-\\[70\\]{z-index:70}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-px{margin-top:1px}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.mb-2\\.5{margin-bottom:calc(var(--spacing) * 2.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-2\\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-px{height:1px}.max-h-40{max-height:calc(var(--spacing) * 40)}.min-h-0{min-height:0}.w-2\\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-9{width:calc(var(--spacing) * 9)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-\\[5\\.5rem\\]{width:88px}.w-full{width:100%}.max-w-\\[240px\\]{max-width:240px}.max-w-\\[calc\\(100vw-80px\\)\\]{max-width:calc(100vw - 80px)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-ew-resize{cursor:ew-resize}.cursor-grabbing{cursor:grabbing}.cursor-nesw-resize{cursor:nesw-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-nwse-resize{cursor:nwse-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-0\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[inherit\\]{border-radius:inherit}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-400{border-color:var(--color-amber-400)}.border-red-600{border-color:var(--color-red-600)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.border-zinc-200{border-color:var(--color-zinc-200)}.border-zinc-300{border-color:var(--color-zinc-300)}.border-zinc-900{border-color:var(--color-zinc-900)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-100{background-color:var(--color-sky-100)}.bg-white{background-color:var(--color-white)}.bg-white\\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-white\\/90{background-color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.bg-zinc-50{background-color:var(--color-zinc-50)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-zinc-200{background-color:var(--color-zinc-200)}.bg-zinc-900{background-color:var(--color-zinc-900)}.object-contain{object-fit:contain}.p-0\\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:var(--spacing)}.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1\\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-1{padding-left:var(--spacing)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.align-super{vertical-align:super}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-amber-950{color:var(--color-amber-950)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-700{color:var(--color-red-700)}.text-sky-900{color:var(--color-sky-900)}.text-white{color:var(--color-white)}.text-zinc-300{color:var(--color-zinc-300)}.text-zinc-500{color:var(--color-zinc-500)}.text-zinc-600{color:var(--color-zinc-600)}.text-zinc-700{color:var(--color-zinc-700)}.text-zinc-800{color:var(--color-zinc-800)}.text-zinc-900{color:var(--color-zinc-900)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-zinc-900{accent-color:var(--color-zinc-900)}.opacity-25{opacity:.25}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-white{--tw-ring-color:var(--color-white)}.ring-zinc-900{--tw-ring-color:var(--color-zinc-900)}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-\\[color\\,background-color\\,box-shadow\\,scale\\]{transition-property:color,background-color,box-shadow,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\\:text-zinc-500::placeholder{color:var(--color-zinc-500)}@media (hover:hover){.hover\\:bg-amber-200:hover{background-color:var(--color-amber-200)}.hover\\:bg-white:hover{background-color:var(--color-white)}.hover\\:bg-zinc-50:hover{background-color:var(--color-zinc-50)}.hover\\:bg-zinc-100:hover{background-color:var(--color-zinc-100)}.hover\\:bg-zinc-200:hover{background-color:var(--color-zinc-200)}.hover\\:bg-zinc-400\\/30:hover{background-color:#9f9fa94d}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-zinc-400\\/30:hover{background-color:color-mix(in oklab, var(--color-zinc-400) 30%, transparent)}}.hover\\:bg-zinc-700:hover{background-color:var(--color-zinc-700)}.hover\\:text-amber-950:hover{color:var(--color-amber-950)}.hover\\:text-zinc-900:hover{color:var(--color-zinc-900)}.hover\\:opacity-100:hover{opacity:1}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-white:focus-visible{--tw-ring-color:var(--color-white)}.focus-visible\\:ring-zinc-900:focus-visible{--tw-ring-color:var(--color-zinc-900)}.focus-visible\\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-inset:focus-visible{--tw-ring-inset:inset}.disabled\\:opacity-50:disabled{opacity:.5}@media (prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}.motion-reduce\\:transition-none{transition-property:none}}@media (min-width:1200px){.min-\\[1200px\\]\\:top-\\[27px\\]{top:27px}.min-\\[1200px\\]\\:right-4{right:calc(var(--spacing) * 4)}}@media (min-width:640px){.sm\\:inline{display:inline}}@container (min-width:380px){.\\@min-\\[380px\\]\\:h-10{height:calc(var(--spacing) * 10)}.\\@min-\\[380px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.\\@min-\\[380px\\]\\:flex-row{flex-direction:row}.\\@min-\\[380px\\]\\:justify-start{justify-content:flex-start}.\\@min-\\[380px\\]\\:gap-1\\.5{gap:calc(var(--spacing) * 1.5)}}@container (min-width:440px){.\\@min-\\[440px\\]\\:inline{display:inline}.\\@min-\\[440px\\]\\:px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}}@container (min-width:520px){.\\@min-\\[520px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:host{all:initial}.cbm-dark{color-scheme:dark;--color-white:oklch(21% .006 285.885);--color-zinc-50:oklch(24.5% .006 286);--color-zinc-100:oklch(27.4% .006 286.033);--color-zinc-200:oklch(33% .01 285.9);--color-zinc-300:oklch(42% .015 285.8);--color-zinc-400:oklch(52% .016 285.9);--color-zinc-500:oklch(68% .015 286.067);--color-zinc-600:oklch(74% .012 286);--color-zinc-700:oklch(82% .008 286.2);--color-zinc-800:oklch(88% .006 286.3);--color-zinc-900:oklch(96.7% .001 286.375);--color-zinc-950:oklch(98.5% 0 0);--color-amber-50:oklch(27.9% .077 45.635);--color-amber-100:oklch(33% .09 46);--color-amber-200:oklch(41.4% .112 45.904);--color-amber-300:oklch(55.5% .163 48.998);--color-amber-700:oklch(87.9% .169 91.605);--color-amber-800:oklch(92.4% .12 95.746);--color-amber-900:oklch(96.2% .059 95.617);--color-amber-950:oklch(98.7% .022 95.277);--color-emerald-50:oklch(26.2% .051 172.552);--color-emerald-800:oklch(90.5% .093 164.15);--color-emerald-900:oklch(95% .052 163.051);--color-sky-50:oklch(29.3% .066 243.157);--color-sky-100:oklch(39.1% .09 240.876);--color-sky-900:oklch(95.1% .026 236.824);--color-red-600:oklch(70.4% .191 22.216);--color-red-700:oklch(80.8% .114 19.571)}.cbm-dark *{--tw-ring-offset-color:oklch(21% .006 285.885)}.theme-scroll{--cbm-thumb:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 55%, var(--color-white))}}.theme-scroll{--cbm-thumb-hover:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb-hover:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 80%, var(--color-white))}}.theme-scroll{scrollbar-width:thin;scrollbar-color:var(--cbm-thumb) transparent}.theme-scroll:hover{scrollbar-color:var(--cbm-thumb-hover) transparent}.theme-scroll::-webkit-scrollbar{width:6px}.theme-scroll::-webkit-scrollbar-track{background:0 0}.theme-scroll::-webkit-scrollbar-thumb{background:var(--cbm-thumb);border-radius:9999px}.theme-scroll:hover::-webkit-scrollbar-thumb{background:var(--cbm-thumb-hover)}.theme-panel{transform-origin:100% 0;animation:.16s ease-out theme-panel-in}@keyframes theme-panel-in{0%{opacity:0;transform:translateY(-6px)scale(.98)}}.theme-hint{animation:.12s ease-out theme-hint-in}.theme-toast{animation:.18s ease-out theme-toast-in}@keyframes theme-toast-in{0%{opacity:0;transform:translateY(8px)}}@keyframes theme-hint-in{0%{opacity:0}}@media (prefers-reduced-motion:reduce){.theme-panel,.theme-hint,.theme-toast{animation:none}}.theme-panel summary{list-style:none}.theme-panel summary::-webkit-details-marker{display:none}.theme-panel details[open]>summary .theme-chevron{transform:rotate(90deg)}@keyframes spin{to{transform:rotate(360deg)}}";
5677
+ var panel_css_generated_default = "/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (display:block){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-900:oklch(39.1% .09 240.876);--color-zinc-50:oklch(98.5% 0 none);--color-zinc-100:oklch(96.7% .001 286.375);--color-zinc-200:oklch(92% .004 286.32);--color-zinc-300:oklch(87.1% .006 286.286);--color-zinc-400:oklch(70.5% .015 286.067);--color-zinc-500:oklch(55.2% .016 285.938);--color-zinc-600:oklch(44.2% .017 285.786);--color-zinc-700:oklch(37% .013 285.805);--color-zinc-800:oklch(27.4% .006 286.033);--color-zinc-900:oklch(21% .006 285.885);--color-white:#fff;--spacing:4px;--text-xs:12px;--text-xs--line-height:calc(1 / .75);--text-sm:14px;--text-sm--line-height:calc(1.25 / .875);--text-base:16px;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-snug:1.375;--radius-md:6px;--radius-lg:8px;--radius-xl:12px;--radius-2xl:16px;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}.theme-switcher{letter-spacing:normal;color:var(--color-zinc-900);font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:16px;line-height:1.5}}@layer components;@layer utilities{.\\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-3{inset-inline:calc(var(--spacing) * 3)}.inset-x-5{inset-inline:calc(var(--spacing) * 5)}.inset-y-5{inset-block:calc(var(--spacing) * 5)}.-top-2{top:calc(var(--spacing) * -2)}.-top-\\[6px\\]{top:-6px}.top-0{top:0}.top-1\\.5{top:calc(var(--spacing) * 1.5)}.top-1\\/2{top:50%}.top-5{top:calc(var(--spacing) * 5)}.top-\\[84px\\]{top:84px}.-right-0\\.5{right:calc(var(--spacing) * -.5)}.-right-2{right:calc(var(--spacing) * -2)}.right-1\\.5{right:calc(var(--spacing) * 1.5)}.right-5{right:calc(var(--spacing) * 5)}.right-6{right:calc(var(--spacing) * 6)}.right-full{right:100%}.-bottom-0\\.5{bottom:calc(var(--spacing) * -.5)}.-bottom-2{bottom:calc(var(--spacing) * -2)}.-bottom-\\[6px\\]{bottom:-6px}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-5{bottom:calc(var(--spacing) * 5)}.-left-2{left:calc(var(--spacing) * -2)}.left-5{left:calc(var(--spacing) * 5)}.left-full{left:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-\\[55\\]{z-index:55}.z-\\[56\\]{z-index:56}.z-\\[57\\]{z-index:57}.z-\\[60\\]{z-index:60}.z-\\[61\\]{z-index:61}.z-\\[62\\]{z-index:62}.z-\\[70\\]{z-index:70}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-px{margin-top:1px}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.mb-2\\.5{margin-bottom:calc(var(--spacing) * 2.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-2\\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-px{height:1px}.max-h-40{max-height:calc(var(--spacing) * 40)}.min-h-0{min-height:0}.w-2\\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-9{width:calc(var(--spacing) * 9)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-\\[5\\.5rem\\]{width:88px}.w-full{width:100%}.max-w-\\[240px\\]{max-width:240px}.max-w-\\[calc\\(100vw-80px\\)\\]{max-width:calc(100vw - 80px)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-ew-resize{cursor:ew-resize}.cursor-grabbing{cursor:grabbing}.cursor-nesw-resize{cursor:nesw-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-nwse-resize{cursor:nwse-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.scroll-mt-3{scroll-margin-top:calc(var(--spacing) * 3)}.list-decimal{list-style-type:decimal}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-0\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[inherit\\]{border-radius:inherit}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-400{border-color:var(--color-amber-400)}.border-red-600{border-color:var(--color-red-600)}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.border-zinc-200{border-color:var(--color-zinc-200)}.border-zinc-300{border-color:var(--color-zinc-300)}.border-zinc-900{border-color:var(--color-zinc-900)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-100{background-color:var(--color-sky-100)}.bg-white{background-color:var(--color-white)}.bg-white\\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-white\\/90{background-color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.bg-zinc-50{background-color:var(--color-zinc-50)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-zinc-200{background-color:var(--color-zinc-200)}.bg-zinc-900{background-color:var(--color-zinc-900)}.object-contain{object-fit:contain}.p-0\\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:var(--spacing)}.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1\\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-1{padding-left:var(--spacing)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.align-super{vertical-align:super}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-amber-950{color:var(--color-amber-950)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-700{color:var(--color-red-700)}.text-sky-900{color:var(--color-sky-900)}.text-white{color:var(--color-white)}.text-zinc-300{color:var(--color-zinc-300)}.text-zinc-500{color:var(--color-zinc-500)}.text-zinc-600{color:var(--color-zinc-600)}.text-zinc-700{color:var(--color-zinc-700)}.text-zinc-800{color:var(--color-zinc-800)}.text-zinc-900{color:var(--color-zinc-900)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-zinc-900{accent-color:var(--color-zinc-900)}.opacity-25{opacity:.25}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-white{--tw-ring-color:var(--color-white)}.ring-zinc-900{--tw-ring-color:var(--color-zinc-900)}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-\\[color\\,background-color\\,box-shadow\\,scale\\]{transition-property:color,background-color,box-shadow,scale;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-700{--tw-duration:.7s;transition-duration:.7s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}.placeholder\\:text-zinc-500::placeholder{color:var(--color-zinc-500)}@media (hover:hover){.hover\\:bg-amber-200:hover{background-color:var(--color-amber-200)}.hover\\:bg-white:hover{background-color:var(--color-white)}.hover\\:bg-zinc-50:hover{background-color:var(--color-zinc-50)}.hover\\:bg-zinc-100:hover{background-color:var(--color-zinc-100)}.hover\\:bg-zinc-200:hover{background-color:var(--color-zinc-200)}.hover\\:bg-zinc-400\\/30:hover{background-color:#9f9fa94d}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-zinc-400\\/30:hover{background-color:color-mix(in oklab, var(--color-zinc-400) 30%, transparent)}}.hover\\:bg-zinc-700:hover{background-color:var(--color-zinc-700)}.hover\\:text-amber-950:hover{color:var(--color-amber-950)}.hover\\:text-zinc-900:hover{color:var(--color-zinc-900)}.hover\\:opacity-100:hover{opacity:1}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-white:focus-visible{--tw-ring-color:var(--color-white)}.focus-visible\\:ring-zinc-900:focus-visible{--tw-ring-color:var(--color-zinc-900)}.focus-visible\\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-inset:focus-visible{--tw-ring-inset:inset}.disabled\\:opacity-50:disabled{opacity:.5}@media (prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}.motion-reduce\\:transition-none{transition-property:none}}@media (min-width:1200px){.min-\\[1200px\\]\\:top-\\[27px\\]{top:27px}.min-\\[1200px\\]\\:right-4{right:calc(var(--spacing) * 4)}}@media (min-width:640px){.sm\\:inline{display:inline}}@container (min-width:380px){.\\@min-\\[380px\\]\\:h-10{height:calc(var(--spacing) * 10)}.\\@min-\\[380px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.\\@min-\\[380px\\]\\:flex-row{flex-direction:row}.\\@min-\\[380px\\]\\:justify-start{justify-content:flex-start}.\\@min-\\[380px\\]\\:gap-1\\.5{gap:calc(var(--spacing) * 1.5)}}@container (min-width:440px){.\\@min-\\[440px\\]\\:inline{display:inline}.\\@min-\\[440px\\]\\:px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}}@container (min-width:500px){.\\@min-\\[500px\\]\\:inline{display:inline}.\\@min-\\[500px\\]\\:px-2{padding-inline:calc(var(--spacing) * 2)}}@container (min-width:520px){.\\@min-\\[520px\\]\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:host{all:initial}.cbm-dark{color-scheme:dark;--color-white:oklch(21% .006 285.885);--color-zinc-50:oklch(24.5% .006 286);--color-zinc-100:oklch(27.4% .006 286.033);--color-zinc-200:oklch(33% .01 285.9);--color-zinc-300:oklch(42% .015 285.8);--color-zinc-400:oklch(52% .016 285.9);--color-zinc-500:oklch(68% .015 286.067);--color-zinc-600:oklch(74% .012 286);--color-zinc-700:oklch(82% .008 286.2);--color-zinc-800:oklch(88% .006 286.3);--color-zinc-900:oklch(96.7% .001 286.375);--color-zinc-950:oklch(98.5% 0 0);--color-amber-50:oklch(27.9% .077 45.635);--color-amber-100:oklch(33% .09 46);--color-amber-200:oklch(41.4% .112 45.904);--color-amber-300:oklch(55.5% .163 48.998);--color-amber-700:oklch(87.9% .169 91.605);--color-amber-800:oklch(92.4% .12 95.746);--color-amber-900:oklch(96.2% .059 95.617);--color-amber-950:oklch(98.7% .022 95.277);--color-emerald-50:oklch(26.2% .051 172.552);--color-emerald-800:oklch(90.5% .093 164.15);--color-emerald-900:oklch(95% .052 163.051);--color-sky-50:oklch(29.3% .066 243.157);--color-sky-100:oklch(39.1% .09 240.876);--color-sky-900:oklch(95.1% .026 236.824);--color-red-600:oklch(70.4% .191 22.216);--color-red-700:oklch(80.8% .114 19.571)}.cbm-dark *{--tw-ring-offset-color:oklch(21% .006 285.885)}.theme-scroll{--cbm-thumb:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 55%, var(--color-white))}}.theme-scroll{--cbm-thumb-hover:var(--color-primary,oklch(55.2% .016 285.938))}@supports (color:color-mix(in lab, red, red)){.theme-scroll{--cbm-thumb-hover:color-mix(in srgb, var(--color-primary,var(--color-zinc-500)) 80%, var(--color-white))}}.theme-scroll{scrollbar-width:thin;scrollbar-color:var(--cbm-thumb) transparent}.theme-scroll:hover{scrollbar-color:var(--cbm-thumb-hover) transparent}.theme-scroll::-webkit-scrollbar{width:6px}.theme-scroll::-webkit-scrollbar-track{background:0 0}.theme-scroll::-webkit-scrollbar-thumb{background:var(--cbm-thumb);border-radius:9999px}.theme-scroll:hover::-webkit-scrollbar-thumb{background:var(--cbm-thumb-hover)}.theme-panel{transform-origin:100% 0;animation:.16s ease-out theme-panel-in}@keyframes theme-panel-in{0%{opacity:0;transform:translateY(-6px)scale(.98)}}.theme-hint{animation:.12s ease-out theme-hint-in}.theme-toast{animation:.18s ease-out theme-toast-in}@keyframes theme-toast-in{0%{opacity:0;transform:translateY(8px)}}@keyframes theme-hint-in{0%{opacity:0}}.theme-arrive{animation:.62s cubic-bezier(.34,1.56,.64,1) both theme-arrive}@keyframes theme-arrive{0%{opacity:0;transform:scale(.2)rotate(-45deg)}60%{opacity:1;transform:scale(1.16)rotate(8deg)}to{transform:scale(1)rotate(0)}}.theme-burst-piece{line-height:0;animation:.95s cubic-bezier(.15,.75,.3,1) both theme-burst-piece;display:block;position:absolute;top:50%;left:50%}@keyframes theme-burst-piece{0%{opacity:0;transform:translate(-50%, -50%) rotate(var(--r)) scale(.3)}12%{opacity:1}65%{opacity:1}to{opacity:0;transform:translate(calc(-50% + var(--x)), calc(-50% + var(--y))) rotate(calc(var(--r) + 150deg)) scale(1)}}.theme-piece-dot{background:currentColor;border-radius:9999px;width:6px;height:6px}.theme-piece-dash{background:currentColor;border-radius:9999px;width:10px;height:3px}@media (prefers-reduced-motion:reduce){.theme-panel,.theme-hint,.theme-toast{animation:none}.theme-arrive{animation:.3s ease-out both theme-hint-in}.theme-burst{display:none}}.theme-panel summary{list-style:none}.theme-panel summary::-webkit-details-marker{display:none}.theme-panel details[open]>summary .theme-chevron{transform:rotate(90deg)}@keyframes spin{to{transform:rotate(360deg)}}";
5262
5678
  //#endregion
5263
5679
  //#region src/ThemeSwitcher.jsx
5264
5680
  var CORNERS = {
@@ -5277,6 +5693,8 @@ var MIN_PANEL_HEIGHT = 260;
5277
5693
  var DRAG_THRESHOLD = 5;
5278
5694
  var HINT_DELAY = 100;
5279
5695
  var DOT_INTERVAL = 1500;
5696
+ var INTRO_DELAY = 900;
5697
+ var BURST_TIME = 1100;
5280
5698
  var FOCUSABLE = "a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])";
5281
5699
  /** Tag of the element that hosts the switcher's shadow root. The site scan skips it. */
5282
5700
  var HOST_TAG = "colorsbymax-root";
@@ -5305,10 +5723,33 @@ function ThemeSwitcher() {
5305
5723
  return mount && createPortal(/* @__PURE__ */ jsx(Switcher, {}), mount);
5306
5724
  }
5307
5725
  function Switcher() {
5308
- const { issues, storageKey, tokens, active, themes, selectTheme, position: requested, setLogoColouring } = useTheme();
5726
+ const { issues, storageKey, tokens, position: requested, setLogoColouring, intro, mode, modeSetting, setMode, settingDefaults } = useTheme();
5309
5727
  const position = CORNERS[requested] ? requested : "bottom-right";
5310
5728
  const [open, setOpen] = useState(false);
5311
- const [settings, setSettings] = useState(() => loadSettings(storageKey));
5729
+ const [arrived, setArrived] = useState(!intro);
5730
+ const [entering, setEntering] = useState(false);
5731
+ const [burst, setBurst] = useState(0);
5732
+ const celebrate = () => setBurst((n) => n + 1);
5733
+ useEffect(() => {
5734
+ if (arrived) return;
5735
+ const timer = setTimeout(() => {
5736
+ setArrived(true);
5737
+ setEntering(true);
5738
+ celebrate();
5739
+ }, INTRO_DELAY);
5740
+ return () => clearTimeout(timer);
5741
+ }, []);
5742
+ const [bursting, setBursting] = useState(false);
5743
+ useEffect(() => {
5744
+ if (!burst) return;
5745
+ setBursting(true);
5746
+ const timer = setTimeout(() => {
5747
+ setBursting(false);
5748
+ setEntering(false);
5749
+ }, BURST_TIME);
5750
+ return () => clearTimeout(timer);
5751
+ }, [burst]);
5752
+ const [settings, setSettings] = useState(() => loadSettings(storageKey, settingDefaults));
5312
5753
  useEffect(() => setLogoColouring(settings.colourLogo), [settings.colourLogo, setLogoColouring]);
5313
5754
  const [auditOn, setAuditOn] = useState(false);
5314
5755
  const [findings, setFindings] = useState([]);
@@ -5345,8 +5786,6 @@ function Switcher() {
5345
5786
  window.addEventListener("keydown", onKey);
5346
5787
  return () => window.removeEventListener("keydown", onKey);
5347
5788
  }, []);
5348
- const prefersDark = usePrefersDark();
5349
- const mode = settings.mode === "system" ? prefersDark ? "dark" : "light" : settings.mode;
5350
5789
  const buttonRef = useRef(null);
5351
5790
  const panelRef = useRef(null);
5352
5791
  const layerRef = useRef(null);
@@ -5414,6 +5853,7 @@ function Switcher() {
5414
5853
  };
5415
5854
  useEffect(() => {
5416
5855
  const button = buttonRef.current;
5856
+ if (!button) return;
5417
5857
  const onEnter = (e) => {
5418
5858
  if (e.pointerType === "touch" || e.buttons || open || !settings.draggable) return;
5419
5859
  clearTimeout(hintTimer.current);
@@ -5430,7 +5870,12 @@ function Switcher() {
5430
5870
  button.removeEventListener("pointerenter", onEnter);
5431
5871
  button.removeEventListener("pointerleave", onLeave);
5432
5872
  };
5433
- }, [open, settings.draggable]);
5873
+ }, [
5874
+ open,
5875
+ settings.draggable,
5876
+ arrived,
5877
+ settings.hideButton
5878
+ ]);
5434
5879
  const close = useCallback(() => {
5435
5880
  setOpen(false);
5436
5881
  buttonRef.current?.focus();
@@ -5455,7 +5900,6 @@ function Switcher() {
5455
5900
  if (!d || d.id !== e.pointerId) return;
5456
5901
  if (!(e.buttons & 1)) return onDragEnd(e);
5457
5902
  if (!d.moved && Math.hypot(e.clientX - d.x, e.clientY - d.y) < DRAG_THRESHOLD) return;
5458
- if (!d.moved) setOpen(false);
5459
5903
  d.moved = true;
5460
5904
  d.point = clampToViewport({
5461
5905
  left: e.clientX - d.dx,
@@ -5479,11 +5923,17 @@ function Switcher() {
5479
5923
  saveButtonPosition(storageKey, null);
5480
5924
  };
5481
5925
  const storeSettings = (next) => {
5482
- saveSettings(storageKey, next);
5926
+ saveSettings(storageKey, {
5927
+ ...next,
5928
+ mode: loadSettings(storageKey, settingDefaults).mode
5929
+ });
5483
5930
  return next;
5484
5931
  };
5485
5932
  const settingsApi = {
5486
- settings,
5933
+ settings: {
5934
+ ...settings,
5935
+ mode: modeSetting
5936
+ },
5487
5937
  mode,
5488
5938
  audit: {
5489
5939
  on: auditOn,
@@ -5497,36 +5947,20 @@ function Switcher() {
5497
5947
  }
5498
5948
  }
5499
5949
  },
5500
- update: (patch) => setSettings((s) => storeSettings({
5501
- ...s,
5502
- ...patch
5503
- })),
5504
- reset: () => setSettings(storeSettings(DEFAULT_SETTINGS)),
5950
+ update: ({ mode: nextMode, ...patch }) => {
5951
+ if (nextMode) setMode(nextMode);
5952
+ if (Object.keys(patch).length) setSettings((s) => storeSettings({
5953
+ ...s,
5954
+ ...patch,
5955
+ mode: nextMode ?? modeSetting
5956
+ }));
5957
+ },
5958
+ reset: () => {
5959
+ setMode(settingDefaults.mode);
5960
+ setSettings(storeSettings(settingDefaults));
5961
+ },
5505
5962
  resetButton: saved ? resetPosition : null
5506
5963
  };
5507
- const lastMode = useRef(mode);
5508
- useEffect(() => {
5509
- if (lastMode.current === mode) return;
5510
- lastMode.current = mode;
5511
- if (active.custom) return;
5512
- if (mode === "dark" && !isDarkTheme(active.tokens)) {
5513
- const twin = toDark(active);
5514
- selectTheme(twin.id, twin);
5515
- } else if (mode === "light" && active.id.endsWith("~dark")) {
5516
- const lightId = active.id.slice(0, -DARK_SUFFIX.length);
5517
- const local = themes.find((t) => t.id === lightId);
5518
- if (local) selectTheme(local.id, local);
5519
- else loadLibrary().then((lib) => {
5520
- const t = lib.themes.find((x) => x.id === lightId);
5521
- if (t) selectTheme(t.id, t);
5522
- }, () => {});
5523
- }
5524
- }, [
5525
- mode,
5526
- active,
5527
- themes,
5528
- selectTheme
5529
- ]);
5530
5964
  useEffect(() => {
5531
5965
  if (!open) return;
5532
5966
  const panel = panelRef.current;
@@ -5567,7 +6001,7 @@ function Switcher() {
5567
6001
  document.removeEventListener("pointerdown", onPointerDown);
5568
6002
  };
5569
6003
  }, [open, close]);
5570
- if (settings.hideButton) return null;
6004
+ if (settings.hideButton || !arrived) return null;
5571
6005
  return /* @__PURE__ */ jsx(SettingsContext.Provider, {
5572
6006
  value: settingsApi,
5573
6007
  children: /* @__PURE__ */ jsxs("div", {
@@ -5587,6 +6021,7 @@ function Switcher() {
5587
6021
  return;
5588
6022
  }
5589
6023
  hideHint();
6024
+ celebrate();
5590
6025
  if (open) close();
5591
6026
  else setOpen(true);
5592
6027
  },
@@ -5596,7 +6031,7 @@ function Switcher() {
5596
6031
  onPointerCancel: onDragEnd,
5597
6032
  onLostPointerCapture: onDragEnd,
5598
6033
  style: placed ?? void 0,
5599
- className: `theme-switcher fixed z-[60] ${placed ? "" : CORNERS[position]} grid place-items-center w-9 h-9 rounded-full border border-zinc-200 bg-white/90 text-zinc-700 backdrop-blur hover:bg-white hover:text-zinc-900 transition-[color,background-color,box-shadow,scale] select-none ${settings.draggable ? "touch-none" : ""} focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-2 ${dragPoint ? "scale-110 shadow-xl cursor-grabbing" : "shadow-md cursor-pointer"}`,
6034
+ className: `theme-switcher fixed z-[60] ${placed ? "" : CORNERS[position]} grid place-items-center w-9 h-9 rounded-full border border-zinc-200 bg-white/90 text-zinc-700 backdrop-blur hover:bg-white hover:text-zinc-900 transition-[color,background-color,box-shadow,scale] select-none ${settings.draggable ? "touch-none" : ""} focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-2 ${dragPoint ? "scale-110 shadow-xl cursor-grabbing" : "shadow-md cursor-pointer"} ${entering ? "theme-arrive" : ""}`,
5600
6035
  children: [
5601
6036
  /* @__PURE__ */ jsx(Palette, {
5602
6037
  className: "w-4 h-4",
@@ -5606,6 +6041,7 @@ function Switcher() {
5606
6041
  tokens,
5607
6042
  animate: settings.animateDot
5608
6043
  }),
6044
+ bursting && /* @__PURE__ */ jsx(Burst, { tokens }, burst),
5609
6045
  hint && !open && !dragPoint && /* @__PURE__ */ jsx("span", {
5610
6046
  "aria-hidden": "true",
5611
6047
  className: `theme-hint pointer-events-none absolute top-1/2 -translate-y-1/2 whitespace-nowrap rounded-md bg-zinc-900 px-2 py-1 text-[11px] font-medium text-white shadow-lg ${hintOnLeft ? "right-full mr-2" : "left-full ml-2"}`,
@@ -5683,6 +6119,59 @@ function CyclingDot({ tokens, animate }) {
5683
6119
  style: { backgroundColor: still ? tokens.primary : colours[index % colours.length] }
5684
6120
  });
5685
6121
  }
6122
+ var BURST_KEYS = [
6123
+ "primary",
6124
+ "primary-alt",
6125
+ "data-1",
6126
+ "data-2",
6127
+ "data-3",
6128
+ "data-4",
6129
+ "warning",
6130
+ "data-5"
6131
+ ];
6132
+ var BURST_PIECES = Array.from({ length: 12 }, (_, i) => {
6133
+ const angle = (i * 30 + (i % 2 ? 9 : -6)) * (Math.PI / 180);
6134
+ const distance = 30 + i % 3 * 9;
6135
+ return {
6136
+ x: Math.round(Math.cos(angle) * distance),
6137
+ y: Math.round(Math.sin(angle) * distance),
6138
+ r: Math.round(angle * 180 / Math.PI),
6139
+ shape: [
6140
+ "squiggle",
6141
+ "dot",
6142
+ "dash"
6143
+ ][i % 3],
6144
+ delay: i % 4 * 25
6145
+ };
6146
+ });
6147
+ function Burst({ tokens }) {
6148
+ return /* @__PURE__ */ jsx("span", {
6149
+ "aria-hidden": "true",
6150
+ className: "theme-burst pointer-events-none absolute inset-0",
6151
+ children: BURST_PIECES.map((p, i) => /* @__PURE__ */ jsx("span", {
6152
+ className: `theme-burst-piece ${p.shape === "squiggle" ? "" : `theme-piece-${p.shape}`}`,
6153
+ style: {
6154
+ "--x": `${p.x}px`,
6155
+ "--y": `${p.y}px`,
6156
+ "--r": `${p.r}deg`,
6157
+ color: tokens[BURST_KEYS[i % BURST_KEYS.length]],
6158
+ animationDelay: `${p.delay}ms`
6159
+ },
6160
+ children: p.shape === "squiggle" && /* @__PURE__ */ jsx("svg", {
6161
+ width: "16",
6162
+ height: "10",
6163
+ viewBox: "0 0 16 10",
6164
+ fill: "none",
6165
+ children: /* @__PURE__ */ jsx("path", {
6166
+ d: "M1 5c1.6-3.6 3.4-3.6 4.6 0s3 3.6 4.6 0 3-3.6 4.4 0",
6167
+ stroke: "currentColor",
6168
+ strokeWidth: "2.2",
6169
+ strokeLinecap: "round"
6170
+ })
6171
+ })
6172
+ }, i))
6173
+ });
6174
+ }
5686
6175
  function usePrefersReducedMotion() {
5687
6176
  const query = "(prefers-reduced-motion: reduce)";
5688
6177
  const [reduce, setReduce] = useState(() => window.matchMedia(query).matches);
@@ -5924,4 +6413,4 @@ function ResizeHandles({ free, onStart, onMove, onEnd, onReset, active }) {
5924
6413
  }, Object.keys(edges).join("-")));
5925
6414
  }
5926
6415
  //#endregion
5927
- export { PAIRINGS as A, TOKEN_KEYS as C, MIN_CONTRAST_NON_TEXT as D, MIN_CONTRAST_LARGE_TEXT as E, contrastRatio as F, normalizeHex as I, checkTheme as M, fixAll as N, MIN_CONTRAST_TEXT as O, suggestFix as P, TOKEN_GROUPS as S, deriveAppTokens as T, darkTokens as _, rolesFromPalette as a, BASE_TOKENS as b, applyTokens as c, prePaintScript as d, collectColors as f, themeFromRoles as g, suggestThemes as h, dominantColours as i, checkRamp as j, MIN_RAMP_STEP_DELTA_E as k, useTheme as l, inferRoles as m, DEFAULT_SETTINGS as n, themeFromPalette as o, detectSiteName as p, coloursFromFile as r, ThemeProvider as s, ThemeSwitcher as t, DEFAULT_STORAGE_KEY as u, isDarkTheme as v, completeTokens as w, PRESETS as x, toDark as y };
6416
+ export { PAIRINGS as A, TOKEN_KEYS as C, MIN_CONTRAST_NON_TEXT as D, MIN_CONTRAST_LARGE_TEXT as E, contrastRatio as F, normalizeHex as I, checkTheme as M, fixAll as N, MIN_CONTRAST_TEXT as O, suggestFix as P, TOKEN_GROUPS as S, deriveAppTokens as T, darkTokens as _, themeFromPalette as a, BASE_TOKENS as b, useTheme as c, DEFAULT_SETTINGS as d, collectColors as f, themeFromRoles as g, suggestThemes as h, rolesFromPalette as i, checkRamp as j, MIN_RAMP_STEP_DELTA_E as k, DEFAULT_STORAGE_KEY as l, inferRoles as m, coloursFromFile as n, ThemeProvider as o, detectSiteName as p, dominantColours as r, applyTokens as s, ThemeSwitcher as t, prePaintScript as u, isDarkTheme as v, completeTokens as w, PRESETS as x, toDark as y };