@custardui/custardui 2.1.1 → 2.1.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/custardui.js +674 -440
  2. package/dist/custardui.js.map +1 -1
  3. package/dist/custardui.min.js +2 -2
  4. package/dist/custardui.min.js.map +1 -1
  5. package/dist/types/src/browser.d.ts.map +1 -1
  6. package/dist/types/src/lib/features/adaptation/types.d.ts +6 -1
  7. package/dist/types/src/lib/features/adaptation/types.d.ts.map +1 -1
  8. package/dist/types/src/lib/features/focus/services/focus-service.svelte.d.ts.map +1 -1
  9. package/dist/types/src/lib/features/highlight/services/highlight-service.svelte.d.ts +0 -1
  10. package/dist/types/src/lib/features/highlight/services/highlight-service.svelte.d.ts.map +1 -1
  11. package/dist/types/src/lib/features/labels/label-manager.d.ts +19 -0
  12. package/dist/types/src/lib/features/labels/label-manager.d.ts.map +1 -0
  13. package/dist/types/src/lib/features/labels/label-registry-store.svelte.d.ts +27 -0
  14. package/dist/types/src/lib/features/labels/label-registry-store.svelte.d.ts.map +1 -0
  15. package/dist/types/src/lib/features/labels/label-utils.d.ts +12 -0
  16. package/dist/types/src/lib/features/labels/label-utils.d.ts.map +1 -0
  17. package/dist/types/src/lib/features/labels/types.d.ts +12 -0
  18. package/dist/types/src/lib/features/labels/types.d.ts.map +1 -0
  19. package/dist/types/src/lib/features/placeholder/placeholder-manager.d.ts +1 -1
  20. package/dist/types/src/lib/features/placeholder/types.d.ts +2 -2
  21. package/dist/types/src/lib/features/placeholder/types.d.ts.map +1 -1
  22. package/dist/types/src/lib/features/settings/intro-manager.svelte.d.ts +2 -2
  23. package/dist/types/src/lib/features/settings/intro-manager.svelte.d.ts.map +1 -1
  24. package/dist/types/src/lib/features/toggles/types.d.ts +5 -0
  25. package/dist/types/src/lib/features/toggles/types.d.ts.map +1 -1
  26. package/dist/types/src/lib/features/url/url-constants.d.ts +13 -0
  27. package/dist/types/src/lib/features/url/url-constants.d.ts.map +1 -0
  28. package/dist/types/src/lib/features/url/url-encoding-utils.d.ts +35 -0
  29. package/dist/types/src/lib/features/url/url-encoding-utils.d.ts.map +1 -0
  30. package/dist/types/src/lib/features/url/url-state-generator.d.ts +17 -0
  31. package/dist/types/src/lib/features/url/url-state-generator.d.ts.map +1 -0
  32. package/dist/types/src/lib/features/url/url-state-manager.d.ts +10 -26
  33. package/dist/types/src/lib/features/url/url-state-manager.d.ts.map +1 -1
  34. package/dist/types/src/lib/features/url/url-state-parser.d.ts +17 -0
  35. package/dist/types/src/lib/features/url/url-state-parser.d.ts.map +1 -0
  36. package/dist/types/src/lib/features/url/url-state-shaper.d.ts +49 -0
  37. package/dist/types/src/lib/features/url/url-state-shaper.d.ts.map +1 -0
  38. package/dist/types/src/lib/registry.d.ts +1 -0
  39. package/dist/types/src/lib/registry.d.ts.map +1 -1
  40. package/dist/types/src/lib/runtime.svelte.d.ts +1 -3
  41. package/dist/types/src/lib/runtime.svelte.d.ts.map +1 -1
  42. package/dist/types/src/lib/stores/active-state-store.svelte.d.ts +8 -3
  43. package/dist/types/src/lib/stores/active-state-store.svelte.d.ts.map +1 -1
  44. package/dist/types/src/lib/stores/color-scheme-store.svelte.d.ts +13 -0
  45. package/dist/types/src/lib/stores/color-scheme-store.svelte.d.ts.map +1 -0
  46. package/dist/types/src/lib/stores/derived-store.svelte.d.ts +2 -6
  47. package/dist/types/src/lib/stores/derived-store.svelte.d.ts.map +1 -1
  48. package/dist/types/src/lib/stores/element-store.svelte.d.ts +2 -2
  49. package/dist/types/src/lib/stores/element-store.svelte.d.ts.map +1 -1
  50. package/dist/types/src/lib/types/config.d.ts +5 -4
  51. package/dist/types/src/lib/types/config.d.ts.map +1 -1
  52. package/dist/types/src/lib/types/index.d.ts +1 -1
  53. package/dist/types/src/lib/types/index.d.ts.map +1 -1
  54. package/dist/types/tests/lib/features/labels/label-manager.test.d.ts +2 -0
  55. package/dist/types/tests/lib/features/labels/label-manager.test.d.ts.map +1 -0
  56. package/dist/types/tests/lib/features/labels/label-registry-store.test.d.ts +2 -0
  57. package/dist/types/tests/lib/features/labels/label-registry-store.test.d.ts.map +1 -0
  58. package/dist/types/tests/lib/features/labels/label-utils.test.d.ts +2 -0
  59. package/dist/types/tests/lib/features/labels/label-utils.test.d.ts.map +1 -0
  60. package/dist/types/tests/lib/stores/color-scheme-store.test.d.ts +2 -0
  61. package/dist/types/tests/lib/stores/color-scheme-store.test.d.ts.map +1 -0
  62. package/dist/types/tests/lib/stores/derived-store.test.d.ts +2 -0
  63. package/dist/types/tests/lib/stores/derived-store.test.d.ts.map +1 -0
  64. package/package.json +5 -5
  65. package/dist/types/src/lib/features/render/assets.d.ts +0 -12
  66. package/dist/types/src/lib/features/render/assets.d.ts.map +0 -1
  67. package/dist/types/src/lib/features/render/render.d.ts +0 -3
  68. package/dist/types/src/lib/features/render/render.d.ts.map +0 -1
  69. package/dist/types/src/lib/features/render/types.d.ts +0 -19
  70. package/dist/types/src/lib/features/render/types.d.ts.map +0 -1
package/dist/custardui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @custardui/custardui v2.1.1
2
+ * @custardui/custardui v2.1.2-beta.0
3
3
  * (c) 2026 Chan Ger Teck
4
4
  * Released under the MIT License.
5
5
  */
@@ -34,7 +34,7 @@
34
34
  */
35
35
  function getScriptAttributes() {
36
36
  let scriptTag = document.currentScript;
37
- const defaults = { baseURL: '', configPath: '/custardui.config.json' };
37
+ const defaults = { baseURL: '/', configPath: '/custardui.config.json' };
38
38
  if (!scriptTag || !scriptTag.hasAttribute('data-base-url')) {
39
39
  const dataAttrMatch = document.querySelector('script[data-base-url]');
40
40
  if (dataAttrMatch) {
@@ -9203,8 +9203,8 @@
9203
9203
  config.placeholders.forEach((def) => {
9204
9204
  placeholderRegistryStore.register({
9205
9205
  ...def,
9206
- // adaptationPlaceholder implies hidden from user-facing settings
9207
- hiddenFromSettings: def.adaptationPlaceholder ? true : def.hiddenFromSettings,
9206
+ // siteManaged implies hidden from user-facing settings
9207
+ hiddenFromSettings: def.siteManaged ? true : def.hiddenFromSettings,
9208
9208
  source: 'config',
9209
9209
  });
9210
9210
  });
@@ -9264,7 +9264,7 @@
9264
9264
  }
9265
9265
  /**
9266
9266
  * Filters a record of incoming placeholders to only those that can be set by users.
9267
- * Extends filterValidPlaceholders() by also excluding adaptation-only placeholders.
9267
+ * Extends filterValidPlaceholders() by also excluding siteManaged placeholders.
9268
9268
  * Use this for persistence loads and URL delta application.
9269
9269
  */
9270
9270
  filterUserSettablePlaceholders(placeholders = {}) {
@@ -9272,8 +9272,8 @@
9272
9272
  const userSettable = {};
9273
9273
  for (const [key, value] of Object.entries(valid)) {
9274
9274
  const def = placeholderRegistryStore.get(key);
9275
- if (def?.adaptationPlaceholder) {
9276
- // Silently skip — adaptation-only placeholders cannot be user-set
9275
+ if (def?.siteManaged) {
9276
+ // Silently skip — site-managed placeholders cannot be user-set
9277
9277
  continue;
9278
9278
  }
9279
9279
  userSettable[key] = value;
@@ -9461,8 +9461,8 @@
9461
9461
  const defaults = this.computeDefaultState();
9462
9462
  const validatedTabs = this.filterValidTabs(newState.tabs ?? {});
9463
9463
  const validatedPlaceholders = placeholderManager.filterUserSettablePlaceholders(newState.placeholders ?? {});
9464
- const validatedShownToggles = this.filterValidToggles(newState.shownToggles ?? defaults.shownToggles ?? []);
9465
- const validatedPeekToggles = this.filterValidToggles(newState.peekToggles ?? defaults.peekToggles ?? []);
9464
+ const validatedShownToggles = this.filterNonSiteManagedToggleIds(this.filterValidToggles(newState.shownToggles ?? defaults.shownToggles ?? []));
9465
+ const validatedPeekToggles = this.filterNonSiteManagedToggleIds(this.filterValidToggles(newState.peekToggles ?? defaults.peekToggles ?? []));
9466
9466
 
9467
9467
  this.state = {
9468
9468
  shownToggles: validatedShownToggles,
@@ -9499,20 +9499,28 @@
9499
9499
  }
9500
9500
 
9501
9501
  /**
9502
- * Applies adaptation defaults on top of the config defaults, before persisted state.
9502
+ * Applies adaptation preset on top of the config defaults, before persisted state.
9503
9503
  * User choices applied later via applyState() will override these.
9504
9504
  *
9505
- * @param defaults The defaults section from the adaptation config
9505
+ * @param preset The preset section from the adaptation config
9506
9506
  */
9507
- applyAdaptationDefaults(defaults) {
9508
- if (!defaults) return;
9507
+ applyAdaptationDefaults(preset) {
9508
+ if (!preset) return;
9509
9509
 
9510
- if (defaults.toggles) {
9511
- this.applyToggleMap(defaults.toggles);
9510
+ if (preset.toggles) {
9511
+ this.applyToggleMap(preset.toggles);
9512
9512
  }
9513
9513
 
9514
- if (defaults.placeholders) {
9515
- const validated = placeholderManager.filterValidPlaceholders(defaults.placeholders);
9514
+ if (preset.tabs) {
9515
+ const validated = this.filterValidTabs(preset.tabs);
9516
+
9517
+ if (!this.state.tabs) this.state.tabs = {};
9518
+
9519
+ Object.assign(this.state.tabs, validated);
9520
+ }
9521
+
9522
+ if (preset.placeholders) {
9523
+ const validated = placeholderManager.filterValidPlaceholders(preset.placeholders);
9516
9524
 
9517
9525
  if (!this.state.placeholders) this.state.placeholders = {};
9518
9526
 
@@ -9569,11 +9577,11 @@
9569
9577
  }
9570
9578
  }
9571
9579
 
9572
- // 3. Seed author-controlled (adaptationPlaceholder) defaults.
9580
+ // 3. Seed site-managed (siteManaged) defaults.
9573
9581
  // These are set by adaptations when active, and fall back to defaultValue when no adaptation is active.
9574
9582
  // This is intentionally separate from regular user-settable placeholder defaults (see PR #206).
9575
9583
  for (const def of placeholderRegistryStore.definitions) {
9576
- if (def.adaptationPlaceholder && def.defaultValue !== undefined && def.defaultValue !== '') {
9584
+ if (def.siteManaged && def.defaultValue !== undefined && def.defaultValue !== '') {
9577
9585
  placeholders[def.name] = def.defaultValue;
9578
9586
  }
9579
9587
  }
@@ -9631,13 +9639,13 @@
9631
9639
  */
9632
9640
  applyToggleDelta(deltaState) {
9633
9641
  // eslint-disable-next-line svelte/prefer-svelte-reactivity
9634
- const toShow = new Set(this.filterValidToggles(deltaState.shownToggles ?? []));
9642
+ const toShow = new Set(this.filterNonSiteManagedToggleIds(this.filterValidToggles(deltaState.shownToggles ?? [])));
9635
9643
 
9636
9644
  // eslint-disable-next-line svelte/prefer-svelte-reactivity
9637
- const toPeek = new Set(this.filterValidToggles(deltaState.peekToggles ?? []));
9645
+ const toPeek = new Set(this.filterNonSiteManagedToggleIds(this.filterValidToggles(deltaState.peekToggles ?? [])));
9638
9646
 
9639
9647
  // eslint-disable-next-line svelte/prefer-svelte-reactivity
9640
- const toHide = new Set(this.filterValidToggles(deltaState.hiddenToggles ?? []));
9648
+ const toHide = new Set(this.filterNonSiteManagedToggleIds(this.filterValidToggles(deltaState.hiddenToggles ?? [])));
9641
9649
 
9642
9650
  // eslint-disable-next-line svelte/prefer-svelte-reactivity
9643
9651
  const allMentioned = new Set([...toShow, ...toPeek, ...toHide]);
@@ -9685,6 +9693,18 @@
9685
9693
  Object.assign(this.state.placeholders, validatedPlaceholders);
9686
9694
  }
9687
9695
 
9696
+ /**
9697
+ * Removes toggle IDs belonging to siteManaged toggles.
9698
+ * Used to prevent user-supplied state (URL, localStorage) from overriding site-controlled toggles.
9699
+ */
9700
+ filterNonSiteManagedToggleIds(ids) {
9701
+ return ids.filter((id) => {
9702
+ const toggle = this.config.toggles?.find((t) => t.toggleId === id);
9703
+
9704
+ return !toggle?.siteManaged;
9705
+ });
9706
+ }
9707
+
9688
9708
  /**
9689
9709
  * Validates an incoming tab record against the configuration.
9690
9710
  * Drops any groupId that doesn't exist in `config.tabGroups`,
@@ -9826,14 +9846,14 @@
9826
9846
  set(this.#detectedPlaceholders, value, true);
9827
9847
  }
9828
9848
 
9829
- #hasPageElements = user_derived(() => this.detectedToggles.size > 0 || this.detectedTabGroups.size > 0);
9849
+ #hasElementsOnCurrentPage = user_derived(() => this.detectedToggles.size > 0 || this.detectedTabGroups.size > 0 || this.detectedPlaceholders.size > 0);
9830
9850
 
9831
- get hasPageElements() {
9832
- return get(this.#hasPageElements);
9851
+ get hasElementsOnCurrentPage() {
9852
+ return get(this.#hasElementsOnCurrentPage);
9833
9853
  }
9834
9854
 
9835
- set hasPageElements(value) {
9836
- set(this.#hasPageElements, value);
9855
+ set hasElementsOnCurrentPage(value) {
9856
+ set(this.#hasElementsOnCurrentPage, value);
9837
9857
  }
9838
9858
 
9839
9859
  registerToggle(id) {
@@ -9937,21 +9957,15 @@
9937
9957
  /* derived-store.svelte.ts generated by Svelte v5.46.1 */
9938
9958
 
9939
9959
  class DerivedStateStore {
9940
- #assetsManager = state(undefined);
9941
-
9942
- get assetsManager() {
9943
- return get(this.#assetsManager);
9944
- }
9945
-
9946
- set assetsManager(value) {
9947
- set(this.#assetsManager, value, true);
9948
- }
9960
+ #menuToggles = user_derived(
9961
+ // Menu toggles are those that are either global or
9962
+ // local but present and registered in the DOM
9963
+ () => {
9964
+ if (!activeStateStore.config.toggles) return [];
9949
9965
 
9950
- #menuToggles = user_derived(() => {
9951
- if (!activeStateStore.config.toggles) return [];
9952
-
9953
- return activeStateStore.config.toggles.filter((t) => !t.isLocal || elementStore.detectedToggles.has(t.toggleId));
9954
- });
9966
+ return activeStateStore.config.toggles.filter((t) => (!t.isLocal || elementStore.detectedToggles.has(t.toggleId)) && !t.siteManaged);
9967
+ }
9968
+ );
9955
9969
 
9956
9970
  get menuToggles() {
9957
9971
  return get(this.#menuToggles);
@@ -10019,23 +10033,19 @@
10019
10033
  set hasMenuOptions(value) {
10020
10034
  set(this.#hasMenuOptions, value);
10021
10035
  }
10022
-
10023
- setAssetsManager(manager) {
10024
- this.assetsManager = manager;
10025
- }
10026
10036
  }
10027
10037
 
10028
10038
  const derivedStore = new DerivedStateStore();
10029
10039
 
10030
10040
  var root$w = from_html(`<div><div role="alert"><button type="button" class="close-btn svelte-ysaqmb" aria-label="Dismiss intro">×</button> <p class="text svelte-ysaqmb"> </p></div></div>`);
10031
10041
 
10032
- const $$css$o = {
10042
+ const $$css$p = {
10033
10043
  hash: 'svelte-ysaqmb',
10034
10044
  code: '\n /* Animation */\n @keyframes svelte-ysaqmb-popIn {\n 0% {\n opacity: 0;\n transform: scale(0.9) translateY(-50%);\n }\n 100% {\n opacity: 1;\n transform: scale(1) translateY(-50%);\n }\n }\n\n /* Reset transform for top/bottom positions */\n @keyframes svelte-ysaqmb-popInVertical {\n 0% {\n opacity: 0;\n transform: scale(0.9);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Simplified Pulse Animation - Shadow Only */\n @keyframes svelte-ysaqmb-pulse {\n 0% {\n transform: scale(1);\n box-shadow:\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 0 0 0 rgba(62, 132, 244, 0.7);\n }\n 50% {\n transform: scale(1);\n box-shadow:\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 0 0 10px rgba(62, 132, 244, 0);\n }\n 100% {\n transform: scale(1);\n box-shadow:\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 0 0 0 rgba(62, 132, 244, 0);\n }\n }\n\n /* Wrapper handles Positioning & Entry Animation */.cv-callout-wrapper.svelte-ysaqmb {position:fixed;z-index:9999;\n\n /* Default animation (centered ones) */\n animation: svelte-ysaqmb-popIn 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;}\n\n /* Inner handles Visuals & Pulse Animation */.cv-callout.svelte-ysaqmb {background:var(--cv-callout-bg, var(--cv-bg));padding:1rem 1.25rem;border-radius:0.5rem;box-shadow:0 4px 6px -1px var(--cv-shadow),\n 0 2px 4px -1px var(--cv-shadow); /* adapt shadow? */max-width:250px;font-size:0.9rem;line-height:1.5;color:var(--cv-callout-text, var(--cv-text));display:flex;align-items:flex-start;gap:0.75rem;font-family:inherit;border:2px solid var(--cv-border);}\n\n /* Apply pulse to inner callout if enabled */.cv-callout.cv-pulse.svelte-ysaqmb {\n animation: svelte-ysaqmb-pulse 2s infinite 0.5s;}\n\n /* Arrow Base */.cv-callout.svelte-ysaqmb::before {content:\'\';position:absolute;width:1rem;height:1rem;background:var(--cv-callout-bg, var(--cv-bg));transform:rotate(45deg);border:2px solid var(--cv-border);z-index:-1;}.close-btn.svelte-ysaqmb {background:transparent;border:none;color:currentColor;opacity:0.7;font-size:1.25rem;line-height:1;cursor:pointer;padding:0;margin:-0.25rem -0.5rem 0 0;transition:opacity 0.15s;flex-shrink:0;}.close-btn.svelte-ysaqmb:hover {color:currentColor;opacity:1;}.text.svelte-ysaqmb {margin:0;flex:1;font-weight:500;}\n\n /* \n Position Specifics (Applied to Wrapper)\n */\n\n /* Right-side positions (Icon on Right -> Callout on Left) */.pos-top-right.svelte-ysaqmb,\n .pos-middle-right.svelte-ysaqmb,\n .pos-bottom-right.svelte-ysaqmb {right:80px;}.pos-top-right.svelte-ysaqmb,\n .pos-bottom-right.svelte-ysaqmb {\n animation-name: svelte-ysaqmb-popInVertical;}\n\n /* X Button Spacing Adjustments */.pos-top-right.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb),\n .pos-middle-right.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb),\n .pos-bottom-right.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb) {margin-right:0;margin-left:-0.5rem;}\n\n /* Left-side positions (Icon on Left -> Callout on Right) */.pos-top-left.svelte-ysaqmb,\n .pos-middle-left.svelte-ysaqmb,\n .pos-bottom-left.svelte-ysaqmb {left:80px;}.pos-top-left.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb),\n .pos-middle-left.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb),\n .pos-bottom-left.svelte-ysaqmb .close-btn:where(.svelte-ysaqmb) {order:2; /* Move to end */margin-right:-0.5rem;margin-left:0;}.pos-top-left.svelte-ysaqmb,\n .pos-bottom-left.svelte-ysaqmb {\n animation-name: svelte-ysaqmb-popInVertical;}\n\n /* Vertical Alignment */.pos-middle-right.svelte-ysaqmb,\n .pos-middle-left.svelte-ysaqmb {top:50%;\n /* transform handled by popIn animation (translateY -50%) */}.pos-top-right.svelte-ysaqmb,\n .pos-top-left.svelte-ysaqmb {top:20px;}.pos-bottom-right.svelte-ysaqmb,\n .pos-bottom-left.svelte-ysaqmb {bottom:20px;}\n\n /* Arrow Positioning (Child of .callout, dependent on Wrapper .pos-*) */\n\n /* Pointing Right */.pos-top-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-middle-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-bottom-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before {right:-0.5rem;border-left:none;border-bottom:none;}\n\n /* Pointing Left */.pos-top-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-middle-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-bottom-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before {left:-0.5rem;border-right:none;border-top:none;}\n\n /* Vertical placement of arrow */.pos-middle-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-middle-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before {top:50%;margin-top:-0.5rem;}.pos-top-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-top-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before {top:1.25rem;}.pos-bottom-right.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before,\n .pos-bottom-left.svelte-ysaqmb .cv-callout:where(.svelte-ysaqmb)::before {bottom:1.25rem;}\n\n @media print {.cv-callout-wrapper.svelte-ysaqmb {display:none !important;}\n }'
10035
10045
  };
10036
10046
 
10037
10047
  function IntroCallout($$anchor, $$props) {
10038
- append_styles$1($$anchor, $$css$o);
10048
+ append_styles$1($$anchor, $$css$p);
10039
10049
 
10040
10050
  let position = prop($$props, 'position', 3, 'middle-left'),
10041
10051
  message = prop($$props, 'message', 3, 'Customize your reading experience here.'),
@@ -10103,17 +10113,17 @@
10103
10113
  append($$anchor, svg);
10104
10114
  }
10105
10115
 
10106
- var root_1$f = from_html(`<button type="button" class="cv-dismiss-btn svelte-122ln5" aria-label="Dismiss settings icon">✕</button>`);
10116
+ var root_1$g = from_html(`<button type="button" class="cv-dismiss-btn svelte-122ln5" aria-label="Dismiss settings icon">✕</button>`);
10107
10117
  var root$u = from_html(`<div role="none"><button type="button" class="cv-settings-main-btn svelte-122ln5"><span class="cv-gear svelte-122ln5"><!></span></button> <button type="button" class="cv-collapse-btn svelte-122ln5" aria-label="Collapse settings icon"> </button> <!></div>`);
10108
10118
 
10109
- const $$css$n = {
10119
+ const $$css$o = {
10110
10120
  hash: 'svelte-122ln5',
10111
10121
  code: '.cv-settings-main-btn.svelte-122ln5 {appearance:none;-webkit-appearance:none;background:transparent;border:none;padding:0;margin:0;flex:1;height:100%;width:100%;display:flex;align-items:inherit;justify-content:inherit;color:inherit;cursor:inherit;border-radius:inherit;}.cv-settings-main-btn.svelte-122ln5:focus-visible {outline:2px solid currentColor;outline-offset:-2px;}.cv-gear.svelte-122ln5 {display:flex;align-items:center;justify-content:center;width:18px;height:18px;}.cv-gear.svelte-122ln5 svg {width:18px;height:18px;}.cv-gear.svelte-122ln5 svg path {fill:currentColor;}.cv-settings-icon.svelte-122ln5 {position:fixed;background:var(--cv-icon-bg, rgba(255, 255, 255, 0.92));color:var(--cv-icon-color, rgba(0, 0, 0, 0.9));opacity:var(--cv-icon-opacity, 0.6);display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:bold;cursor:grab; /* Default cursor */box-shadow:0 4px 12px rgba(0, 0, 0, 0.15);border:2px solid rgba(0, 0, 0, 0.2);z-index:9998;transition:width 0.3s ease,\n background 0.3s ease,\n color 0.3s ease,\n opacity 0.3s ease,\n border-color 0.3s ease,\n transform 0.4s ease; /* transform transition drives the peek slide animation */touch-action:none; /* Crucial for touch dragging */font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;box-sizing:border-box;user-select:none; /* Prevent text selection while dragging */}.cv-settings-icon.svelte-122ln5:active {cursor:grabbing;}.cv-settings-icon.svelte-122ln5:hover {background:var(--cv-icon-bg, rgba(255, 255, 255, 1));color:var(--cv-icon-color, rgba(0, 0, 0, 1));opacity:1;border-color:rgba(0, 0, 0, 0.3);}\n\n /* Remove transform transition during drag so it tracks the pointer without lag */.cv-settings-icon.cv-is-dragging.svelte-122ln5 {transition:width 0.3s ease,\n background 0.3s ease,\n color 0.3s ease,\n opacity 0.3s ease,\n border-color 0.3s ease;}\n\n /* When collapsed, dim the strip */.cv-settings-icon.cv-is-collapsed.svelte-122ln5 {opacity:0.5;}.cv-settings-icon.cv-is-collapsed.svelte-122ln5:hover {opacity:0.85;}.cv-collapse-btn.svelte-122ln5 {position:absolute;top:0;bottom:0;width:16px;display:flex;align-items:center;justify-content:center;background:rgba(0, 0, 0, 0.12);border:none;padding:0;cursor:pointer;font-size:13px;line-height:1;color:inherit;opacity:0.5;transition:opacity 0.15s ease, background 0.15s ease;}.cv-collapse-btn[data-side=\'left\'].svelte-122ln5 {left:0; /* outer = screen-edge side for left icons */border-radius:0 6px 6px 0;}.cv-collapse-btn[data-side=\'right\'].svelte-122ln5 {right:0; /* outer = screen-edge side for right icons */border-radius:6px 0 0 6px;}.cv-collapse-btn.svelte-122ln5:hover {opacity:1;background:rgba(0, 0, 0, 0.22);}\n\n /* Hide collapse tab when already collapsed */.cv-settings-icon.cv-is-collapsed.svelte-122ln5 .cv-collapse-btn:where(.svelte-122ln5) {display:none;}.cv-dismiss-btn.svelte-122ln5 {position:absolute;bottom:calc(100% + 4px);width:16px;height:16px;display:flex;align-items:center;justify-content:center;background:rgba(0, 0, 0, 0.15);border:none;border-radius:50%;padding:0;cursor:pointer;font-size:9px;line-height:1;color:inherit;opacity:0.5;transition:opacity 0.15s ease, background 0.15s ease;}.cv-dismiss-btn[data-side=\'left\'].svelte-122ln5 {left:0;}.cv-dismiss-btn[data-side=\'right\'].svelte-122ln5 {right:0;}.cv-dismiss-btn.svelte-122ln5:hover {opacity:1;background:rgba(0, 0, 0, 0.25);}\n\n\n /* Top-right */.cv-settings-top-right.svelte-122ln5 {top:20px;right:0;border-radius:18px 0 0 18px;padding-left:6px;justify-content:flex-start;border-right:none;}\n\n /* Top-left */.cv-settings-top-left.svelte-122ln5 {top:20px;left:0;border-radius:0 18px 18px 0;padding-right:6px;justify-content:flex-end;border-left:none;}\n\n /* Bottom-right */.cv-settings-bottom-right.svelte-122ln5 {bottom:20px;right:0;border-radius:18px 0 0 18px;padding-left:6px;justify-content:flex-start;border-right:none;}\n\n /* Bottom-left */.cv-settings-bottom-left.svelte-122ln5 {bottom:20px;left:0;border-radius:0 18px 18px 0;padding-right:6px;justify-content:flex-end;border-left:none;}\n\n /* Middle-left */.cv-settings-middle-left.svelte-122ln5 {top:50%;left:0;\n /* transform handled by inline style now */border-radius:0 18px 18px 0;padding-right:6px;justify-content:flex-end;border-left:none;}\n\n /* Middle-right */.cv-settings-middle-right.svelte-122ln5 {top:50%;right:0;\n /* transform handled by inline style now */border-radius:18px 0 0 18px;padding-left:6px;justify-content:flex-start;border-right:none;}.cv-settings-top-right.svelte-122ln5,\n .cv-settings-middle-right.svelte-122ln5,\n .cv-settings-bottom-right.svelte-122ln5,\n .cv-settings-top-left.svelte-122ln5,\n .cv-settings-middle-left.svelte-122ln5,\n .cv-settings-bottom-left.svelte-122ln5 {height:36px;width:36px;}.cv-settings-middle-right.svelte-122ln5:hover,\n .cv-settings-top-right.svelte-122ln5:hover,\n .cv-settings-bottom-right.svelte-122ln5:hover,\n .cv-settings-top-left.svelte-122ln5:hover,\n .cv-settings-middle-left.svelte-122ln5:hover,\n .cv-settings-bottom-left.svelte-122ln5:hover {width:55px;}.cv-pulse {\n animation: svelte-122ln5-pulse 2s infinite;}\n\n @keyframes svelte-122ln5-pulse {\n 0% {\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.15),\n 0 0 0 0 rgba(62, 132, 244, 0.7);\n }\n 70% {\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.15),\n 0 0 0 10px rgba(62, 132, 244, 0);\n }\n 100% {\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.15),\n 0 0 0 0 rgba(62, 132, 244, 0);\n }\n }\n\n @media (max-width: 768px) {.cv-settings-top-right.svelte-122ln5,\n .cv-settings-top-left.svelte-122ln5 {top:10px;}.cv-settings-bottom-right.svelte-122ln5,\n .cv-settings-bottom-left.svelte-122ln5 {bottom:10px;}.cv-settings-top-right.svelte-122ln5,\n .cv-settings-bottom-right.svelte-122ln5,\n .cv-settings-middle-right.svelte-122ln5 {right:0;}.cv-settings-top-left.svelte-122ln5,\n .cv-settings-bottom-left.svelte-122ln5,\n .cv-settings-middle-left.svelte-122ln5 {left:0;}.cv-settings-icon.svelte-122ln5 {width:60px;height:32px;}.cv-settings-icon.svelte-122ln5:hover {width:75px;}\n }\n\n @media print {.cv-settings-icon.svelte-122ln5 {display:none !important;}\n }'
10112
10122
  };
10113
10123
 
10114
10124
  function SettingsIcon($$anchor, $$props) {
10115
10125
  push($$props, true);
10116
- append_styles$1($$anchor, $$css$n);
10126
+ append_styles$1($$anchor, $$css$o);
10117
10127
 
10118
10128
  /* eslint-disable @typescript-eslint/no-explicit-any */
10119
10129
  const iconSettingsStore = getContext(ICON_SETTINGS_CTX);
@@ -10358,7 +10368,7 @@
10358
10368
 
10359
10369
  {
10360
10370
  var consequent = ($$anchor) => {
10361
- var button_2 = root_1$f();
10371
+ var button_2 = root_1$g();
10362
10372
 
10363
10373
  button_2.__click = (e) => {
10364
10374
  e.stopPropagation();
@@ -10677,7 +10687,12 @@
10677
10687
  const PARAM_HIDE_TOGGLE = 't-hide';
10678
10688
  const PARAM_TABS = 'tabs';
10679
10689
  const PARAM_PH = 'ph';
10690
+ const PARAM_CV_SHOW = 'cv-show';
10691
+ const PARAM_CV_HIDE = 'cv-hide';
10692
+ const PARAM_CV_HIGHLIGHT = 'cv-highlight';
10693
+ /** Parameters owned by URLStateManager */
10680
10694
  const MANAGED_PARAMS = [PARAM_SHOW_TOGGLE, PARAM_PEEK_TOGGLE, PARAM_HIDE_TOGGLE, PARAM_TABS, PARAM_PH];
10695
+
10681
10696
  /**
10682
10697
  * Encodes a list of IDs into a comma-separated query-safe string.
10683
10698
  *
@@ -10752,12 +10767,12 @@
10752
10767
  }
10753
10768
  return result;
10754
10769
  }
10755
- // --- URL Parsing ---
10770
+
10756
10771
  /**
10757
10772
  * Parses toggle visibility state from the current URL search string.
10758
10773
  * Returns partial state containing only the toggle fields that are present.
10759
10774
  */
10760
- function parseTogglesFromSearch(search) {
10775
+ function parseTogglesFromURL(search) {
10761
10776
  const partial = {};
10762
10777
  const showIds = splitAndDecode(search, PARAM_SHOW_TOGGLE);
10763
10778
  if (showIds.length > 0)
@@ -10774,7 +10789,7 @@
10774
10789
  * Parses tab group selections from the current URL search string.
10775
10790
  * Returns partial state containing the `tabs` record, or empty object if absent.
10776
10791
  */
10777
- function parseTabsFromSearch(search) {
10792
+ function parseTabsFromURL(search) {
10778
10793
  const tabs = decodePairs(search, PARAM_TABS);
10779
10794
  return Object.keys(tabs).length > 0 ? { tabs } : {};
10780
10795
  }
@@ -10782,11 +10797,169 @@
10782
10797
  * Parses placeholder values from the current URL search string.
10783
10798
  * Returns partial state containing the `placeholders` record, or empty object if absent.
10784
10799
  */
10785
- function parsePlaceholdersFromSearch(search) {
10800
+ function parsePlaceholdersFromURL(search) {
10786
10801
  const placeholders = decodePairs(search, PARAM_PH);
10787
10802
  return Object.keys(placeholders).length > 0 ? { placeholders } : {};
10788
10803
  }
10789
- // --- URL Generation ---
10804
+
10805
+ /**
10806
+ * Strips placeholder entries that should not appear in shareable URLs:
10807
+ * - Tab-group-derived placeholders (source: 'tabgroup') — implied by ?tabs=
10808
+ * - Site-managed placeholders (siteManaged: true) — site-controlled, not shareable
10809
+ */
10810
+ function stripNonShareablePlaceholders(placeholders, config) {
10811
+ const shareable = {};
10812
+ for (const [key, value] of Object.entries(placeholders)) {
10813
+ const definition = placeholderRegistryStore.get(key) || config.placeholders?.find(p => p.name === key);
10814
+ if (!definition)
10815
+ continue; // skip unknown keys (injection prevention)
10816
+ // Note: PlaceholderDefinition from registry has 'source', but config doesn't.
10817
+ // That's fine as 'tabgroup' placeholders are mostly a runtime artifact.
10818
+ if ('source' in definition && definition.source === 'tabgroup')
10819
+ continue; // implied by ?tabs=
10820
+ if ('siteManaged' in definition && definition.siteManaged)
10821
+ continue; // site-managed, not shareable
10822
+ shareable[key] = value;
10823
+ }
10824
+ return shareable;
10825
+ }
10826
+ /**
10827
+ * Filters the current toggle state (shown, peeked) and derives the explicit
10828
+ * hidden list for the shareable URL.
10829
+ */
10830
+ function getShareableToggles(currentState, pageTogglesSet, config) {
10831
+ const currentShown = currentState.shownToggles ?? [];
10832
+ const currentPeek = currentState.peekToggles ?? [];
10833
+ const shouldInclude = (id) => {
10834
+ const toggleConfig = config.toggles?.find(t => t.toggleId === id);
10835
+ // Case 1: Not found in configuration
10836
+ if (!toggleConfig) {
10837
+ return pageTogglesSet.has(id);
10838
+ }
10839
+ // Site-managed toggles are never included in shareable URLs
10840
+ if (toggleConfig.siteManaged)
10841
+ return false;
10842
+ // Case 2: Configured as Global
10843
+ if (!toggleConfig.isLocal) {
10844
+ return true;
10845
+ }
10846
+ // Case 3: Configured as Local
10847
+ return pageTogglesSet.has(id);
10848
+ };
10849
+ const shareableShown = currentShown.filter(shouldInclude);
10850
+ const shareablePeek = currentPeek.filter(shouldInclude);
10851
+ const shownSet = new Set(shareableShown);
10852
+ const peekSet = new Set(shareablePeek);
10853
+ const absoluteHide = [];
10854
+ const relevantToggles = new Set(pageTogglesSet);
10855
+ for (const t of (config.toggles ?? [])) {
10856
+ if (!t.isLocal && !t.siteManaged)
10857
+ relevantToggles.add(t.toggleId);
10858
+ }
10859
+ // Build a set of siteManaged toggle IDs to exclude from absoluteHide
10860
+ const siteManagedToggleIds = new Set((config.toggles ?? []).filter(t => t.siteManaged).map(t => t.toggleId));
10861
+ for (const id of relevantToggles) {
10862
+ if (!shownSet.has(id) && !peekSet.has(id) && !siteManagedToggleIds.has(id)) {
10863
+ absoluteHide.push(id);
10864
+ }
10865
+ }
10866
+ const result = {};
10867
+ if (shareableShown.length > 0)
10868
+ result.shownToggles = shareableShown;
10869
+ if (shareablePeek.length > 0)
10870
+ result.peekToggles = shareablePeek;
10871
+ if (absoluteHide.length > 0)
10872
+ result.hiddenToggles = absoluteHide;
10873
+ return result;
10874
+ }
10875
+ /**
10876
+ * Filters the active tab selections for the shareable URL.
10877
+ */
10878
+ function getShareableTabs(currentState, pageTabGroupsSet, config) {
10879
+ if (!currentState.tabs)
10880
+ return {};
10881
+ const shareableTabs = {};
10882
+ for (const [groupId, tabId] of Object.entries(currentState.tabs)) {
10883
+ const groupConfig = config.tabGroups?.find(g => g.groupId === groupId);
10884
+ let shouldInclude = false;
10885
+ if (!groupConfig) {
10886
+ // Unknown group: Only include if explicitly detected on page to prevent injection
10887
+ shouldInclude = pageTabGroupsSet.has(groupId);
10888
+ }
10889
+ else if (!groupConfig.isLocal) {
10890
+ // Global group: Always include
10891
+ shouldInclude = true;
10892
+ }
10893
+ else {
10894
+ // Local group: Only include if detected on page
10895
+ shouldInclude = pageTabGroupsSet.has(groupId);
10896
+ }
10897
+ if (shouldInclude) {
10898
+ shareableTabs[groupId] = tabId;
10899
+ }
10900
+ }
10901
+ return Object.keys(shareableTabs).length > 0 ? { tabs: shareableTabs } : {};
10902
+ }
10903
+ /**
10904
+ * Filters the custom placeholder values for the shareable URL.
10905
+ */
10906
+ function getShareablePlaceholders(currentState, pagePlaceholdersSet, config) {
10907
+ if (!currentState.placeholders)
10908
+ return {};
10909
+ const strippedPlaceholders = stripNonShareablePlaceholders(currentState.placeholders, config);
10910
+ const shareablePlaceholders = {};
10911
+ for (const [key, value] of Object.entries(strippedPlaceholders)) {
10912
+ const definition = placeholderRegistryStore.get(key) || config.placeholders?.find(p => p.name === key);
10913
+ let shouldInclude = false;
10914
+ if (!definition) {
10915
+ // Note: definition is guaranteed to exist here due to stripNonShareablePlaceholders,
10916
+ // but we handle it explicitly for clarity and future-proofing.
10917
+ shouldInclude = pagePlaceholdersSet.has(key);
10918
+ }
10919
+ else if (!definition.isLocal) {
10920
+ // Global placeholder: Always include
10921
+ shouldInclude = true;
10922
+ }
10923
+ else {
10924
+ // Local placeholder: Only include if detected on page
10925
+ shouldInclude = pagePlaceholdersSet.has(key);
10926
+ }
10927
+ if (shouldInclude) {
10928
+ shareablePlaceholders[key] = value;
10929
+ }
10930
+ }
10931
+ return Object.keys(shareablePlaceholders).length > 0 ? { placeholders: shareablePlaceholders } : {};
10932
+ }
10933
+ /**
10934
+ * Computes a shareable state object from the current state.
10935
+ *
10936
+ * Toggles, tabs, and placeholders marked as `isLocal: true` are only included
10937
+ * if they are present on the current page.
10938
+ *
10939
+ * Global elements (not `isLocal`) are always included regardless of whether
10940
+ * they are detected on the current page.
10941
+ *
10942
+ * Every toggle known to the page (or global) is explicitly encoded as shown,
10943
+ * peeked, or hidden, so the recipient's view exactly matches the sender's
10944
+ * regardless of their local settings.
10945
+ *
10946
+ * Tab-group-derived placeholders are omitted — the `?tabs=` param is their source of truth.
10947
+ *
10948
+ * @param currentState The current application state.
10949
+ * @param elementsOnCurrentPage The active elements detected on the current page.
10950
+ * @param config The application configuration.
10951
+ */
10952
+ function computeShareableSettingState(currentState, elementsOnCurrentPage, config) {
10953
+ const pageTogglesSet = new Set(elementsOnCurrentPage.toggles);
10954
+ const pageTabGroupsSet = new Set(elementsOnCurrentPage.tabGroups);
10955
+ const pagePlaceholdersSet = new Set(elementsOnCurrentPage.placeholders);
10956
+ return {
10957
+ ...getShareableToggles(currentState, pageTogglesSet, config),
10958
+ ...getShareableTabs(currentState, pageTabGroupsSet, config),
10959
+ ...getShareablePlaceholders(currentState, pagePlaceholdersSet, config),
10960
+ };
10961
+ }
10962
+
10790
10963
  /**
10791
10964
  * Builds the query string fragment for the managed URL parameters from a state object.
10792
10965
  *
@@ -10797,7 +10970,7 @@
10797
10970
  * By building the string directly, each value is encoded exactly once,
10798
10971
  * and structural separators (`,` `:`) remain as literal characters in the URL.
10799
10972
  */
10800
- function buildManagedSearch(state) {
10973
+ function generateManagedQuery(state) {
10801
10974
  const parts = [];
10802
10975
  if (state.shownToggles && state.shownToggles.length > 0) {
10803
10976
  parts.push(`${PARAM_SHOW_TOGGLE}=${encodeList(state.shownToggles)}`);
@@ -10819,100 +10992,17 @@
10819
10992
  /**
10820
10993
  * Builds a full absolute URL string from the base URL and managed params.
10821
10994
  */
10822
- function buildFullUrl(url, managedSearch) {
10995
+ function buildFullUrl(url, managedQuery) {
10823
10996
  const preservedSearch = url.searchParams.toString();
10824
- const search = [preservedSearch, managedSearch].filter(Boolean).join('&');
10997
+ const search = [preservedSearch, managedQuery].filter(Boolean).join('&');
10825
10998
  return url.origin + url.pathname + (search ? `?${search}` : '') + (url.hash || '');
10826
10999
  }
10827
- /**
10828
- * Strips placeholder entries that should not appear in shareable URLs:
10829
- * - Tab-group-derived placeholders (source: 'tabgroup') — implied by ?tabs=
10830
- * - Adaptation-only placeholders (adaptationPlaceholder: true) — author-controlled, not shareable
10831
- */
10832
- function stripNonShareablePlaceholders(placeholders) {
10833
- const shareable = {};
10834
- for (const [key, value] of Object.entries(placeholders)) {
10835
- const definition = placeholderRegistryStore.get(key);
10836
- if (definition?.source === 'tabgroup')
10837
- continue; // implied by ?tabs=
10838
- if (definition?.adaptationPlaceholder)
10839
- continue; // author-only, not shareable
10840
- shareable[key] = value;
10841
- }
10842
- return shareable;
10843
- }
10844
- /**
10845
- * Computes a shareable state object from the current state.
10846
- *
10847
- * Every toggle known to the page is explicitly encoded as shown, peeked, or hidden,
10848
- * so the recipient's view exactly matches the sender's regardless of their local settings.
10849
- *
10850
- * Toggles, tabs, and placeholders NOT present on the current page are omitted,
10851
- * preventing cross-page state pollution.
10852
- *
10853
- * Tab-group-derived placeholders are omitted — the `?tabs=` param is their source of truth.
10854
- *
10855
- * @param currentState The current application state.
10856
- * @param pageElements The active elements detected on the current page.
10857
- */
10858
- function computeShareableState(currentState, pageElements) {
10859
- const currentShown = currentState.shownToggles ?? [];
10860
- const currentPeek = currentState.peekToggles ?? [];
10861
- const pageTogglesSet = new Set(pageElements.toggles);
10862
- const pageTabGroupsSet = new Set(pageElements.tabGroups);
10863
- const pagePlaceholdersSet = new Set(pageElements.placeholders);
10864
- // 1. Filter toggles to only those present on the page
10865
- const pageShown = currentShown.filter((id) => pageTogglesSet.has(id));
10866
- const pagePeek = currentPeek.filter((id) => pageTogglesSet.has(id));
10867
- const shownSet = new Set(pageShown);
10868
- const peekSet = new Set(pagePeek);
10869
- // Every toggle on the page that isn't shown or peeked must be explicitly hidden.
10870
- const absoluteHide = [];
10871
- for (const id of pageTogglesSet) {
10872
- if (!shownSet.has(id) && !peekSet.has(id)) {
10873
- absoluteHide.push(id);
10874
- }
10875
- }
10876
- const shareable = {};
10877
- if (pageShown.length > 0)
10878
- shareable.shownToggles = pageShown;
10879
- if (pagePeek.length > 0)
10880
- shareable.peekToggles = pagePeek;
10881
- if (absoluteHide.length > 0)
10882
- shareable.hiddenToggles = absoluteHide;
10883
- // 2. Filter tabs to only those present on the page
10884
- if (currentState.tabs) {
10885
- const pageTabs = {};
10886
- for (const [groupId, tabId] of Object.entries(currentState.tabs)) {
10887
- if (pageTabGroupsSet.has(groupId)) {
10888
- pageTabs[groupId] = tabId;
10889
- }
10890
- }
10891
- if (Object.keys(pageTabs).length > 0) {
10892
- shareable.tabs = pageTabs;
10893
- }
10894
- }
10895
- // 3. Filter placeholders to only those present on the page
10896
- if (currentState.placeholders) {
10897
- const shareablePlaceholders = stripNonShareablePlaceholders(currentState.placeholders);
10898
- const pagePlaceholders = {};
10899
- for (const [key, value] of Object.entries(shareablePlaceholders)) {
10900
- if (pagePlaceholdersSet.has(key)) {
10901
- pagePlaceholders[key] = value;
10902
- }
10903
- }
10904
- if (Object.keys(pagePlaceholders).length > 0) {
10905
- shareable.placeholders = pagePlaceholders;
10906
- }
10907
- }
10908
- return shareable;
10909
- }
10910
- // --- URL State Manager ---
11000
+
10911
11001
  /**
10912
11002
  * URL State Manager for CustardUI.
10913
11003
  * Handles encoding/decoding of view states as human-readable URL parameters.
10914
11004
  *
10915
- * URL Schema:
11005
+ * URL Schema (defined in url-constants.ts):
10916
11006
  * ?t-show=A,B — toggle IDs to explicitly show
10917
11007
  * ?t-peek=C — toggle IDs to explicitly peek
10918
11008
  * ?t-hide=D — toggle IDs to explicitly hide
@@ -10944,37 +11034,29 @@
10944
11034
  return null;
10945
11035
  const search = window.location.search;
10946
11036
  return {
10947
- ...parseTogglesFromSearch(search),
10948
- ...parseTabsFromSearch(search),
10949
- ...parsePlaceholdersFromSearch(search),
11037
+ ...parseTogglesFromURL(search),
11038
+ ...parseTabsFromURL(search),
11039
+ ...parsePlaceholdersFromURL(search),
10950
11040
  };
10951
11041
  }
10952
11042
  /**
10953
- * Generates a shareable URL that encodes the full current state.
10954
- *
10955
- * Encodes every toggle on the page explicitly (shown, peeked, or hidden)
10956
- * so the recipient sees the exact same view regardless of their local settings.
10957
- *
10958
- * Tab-group-derived placeholders are omitted from the URL — they are implied
10959
- * by the `?tabs=` parameter and will be re-derived by the recipient's store.
10960
- *
10961
- * Toggles, tabs, and placeholders NOT present on the current page are omitted,
10962
- * preventing cross-page state pollution.
11043
+ * Generates a shareable URL that encodes the current state based on Config and State.
10963
11044
  *
10964
11045
  * @param currentState The full application state to encode.
10965
- * @param pageElements The active elements detected on the current page.
11046
+ * @param config The application configuration.
11047
+ * @param elementsOnCurrentPage The active elements detected on the current page.
10966
11048
  */
10967
- static generateShareableURL(currentState, pageElements = { toggles: [], tabGroups: [], placeholders: [] }) {
11049
+ static generateShareableURL(currentState, config, elementsOnCurrentPage = { toggles: [], tabGroups: [], placeholders: [] }) {
10968
11050
  const url = new URL(window.location.href);
10969
11051
  for (const param of MANAGED_PARAMS) {
10970
11052
  url.searchParams.delete(param);
10971
11053
  }
10972
- let managedSearch = '';
11054
+ let managedQuery = '';
10973
11055
  if (currentState) {
10974
- const shareable = computeShareableState(currentState, pageElements);
10975
- managedSearch = buildManagedSearch(shareable);
11056
+ const shareable = computeShareableSettingState(currentState, elementsOnCurrentPage, config);
11057
+ managedQuery = generateManagedQuery(shareable);
10976
11058
  }
10977
- return buildFullUrl(url, managedSearch);
11059
+ return buildFullUrl(url, managedQuery);
10978
11060
  }
10979
11061
  /**
10980
11062
  * Clears all managed parameters from the current browser URL.
@@ -11176,19 +11258,19 @@
11176
11258
  append($$anchor, svg);
11177
11259
  }
11178
11260
 
11179
- var root_1$e = from_html(`<p class="description svelte-gwkhja"> </p>`);
11261
+ var root_1$f = from_html(`<p class="description svelte-gwkhja"> </p>`);
11180
11262
  var root_3$7 = from_html(`<span class="segment-icon svelte-gwkhja"><!></span>`);
11181
11263
  var root_2$a = from_html(`<button type="button"><!> <span class="segment-label svelte-gwkhja"> </span></button>`);
11182
11264
  var root$k = from_html(`<div class="card svelte-gwkhja"><div class="content svelte-gwkhja"><div><p class="title svelte-gwkhja"> </p> <!></div> <div class="segmented svelte-gwkhja" role="group" aria-label="Visibility"></div></div></div>`);
11183
11265
 
11184
- const $$css$m = {
11266
+ const $$css$n = {
11185
11267
  hash: 'svelte-gwkhja',
11186
11268
  code: '.card.svelte-gwkhja {background:var(--cv-bg);border:1px solid var(--cv-border);border-radius:var(--cv-card-radius, 0.5rem);transition:background 0.15s ease;}.card.svelte-gwkhja:hover {background:var(--cv-bg-hover);}.content.svelte-gwkhja {display:flex;align-items:center;justify-content:space-between;padding:0.75rem;}.title.svelte-gwkhja {font-weight:500;font-size:0.875rem;color:var(--cv-text);margin:0;}.description.svelte-gwkhja {font-size:0.75rem;color:var(--cv-text-secondary);margin:0.125rem 0 0 0;}.segmented.svelte-gwkhja {display:flex;border:1px solid var(--cv-border);border-radius:0.375rem;overflow:hidden;flex-shrink:0;}.segment-btn.svelte-gwkhja {display:flex;align-items:center;gap:0.25rem;background:transparent;border:none;border-left:1px solid var(--cv-border);padding:0.3rem 0.6rem;font-size:0.8rem;font-weight:500;color:var(--cv-text-secondary);cursor:pointer;transition:background 0.15s ease, color 0.15s ease;font-family:inherit;line-height:1;}.segment-icon.svelte-gwkhja {display:flex;align-items:center;justify-content:center;width:14px;height:14px;flex-shrink:0;}.segment-icon.svelte-gwkhja svg {width:100%;height:100%;}.segment-label.svelte-gwkhja {font-size:0.75rem;}.segment-btn.svelte-gwkhja:first-child {border-left:none;}.segment-btn.svelte-gwkhja:hover:not(.active) {background:var(--cv-bg-hover);color:var(--cv-text);}.segment-btn.active.svelte-gwkhja {background:var(--cv-primary);color:white;box-shadow:0 1px 3px rgba(0, 0, 0, 0.15);}'
11187
11269
  };
11188
11270
 
11189
11271
  function ToggleItem($$anchor, $$props) {
11190
11272
  push($$props, true);
11191
- append_styles$1($$anchor, $$css$m);
11273
+ append_styles$1($$anchor, $$css$n);
11192
11274
 
11193
11275
  let value = prop($$props, 'value', 15, 'show'),
11194
11276
  onchange = prop($$props, 'onchange', 3, () => {});
@@ -11206,7 +11288,7 @@
11206
11288
 
11207
11289
  {
11208
11290
  var consequent = ($$anchor) => {
11209
- var p_1 = root_1$e();
11291
+ var p_1 = root_1$f();
11210
11292
  var text_1 = child(p_1, true);
11211
11293
 
11212
11294
  reset(p_1);
@@ -11284,18 +11366,18 @@
11284
11366
 
11285
11367
  delegate(['click']);
11286
11368
 
11287
- var root_1$d = from_html(`<p class="description svelte-uub3h8"> </p>`);
11369
+ var root_1$e = from_html(`<p class="description svelte-uub3h8"> </p>`);
11288
11370
  var root_2$9 = from_html(`<option> </option>`);
11289
11371
  var root$j = from_html(`<div class="root svelte-uub3h8"><div class="header svelte-uub3h8"><label class="label svelte-uub3h8"> </label> <!></div> <select class="select svelte-uub3h8"></select></div>`);
11290
11372
 
11291
- const $$css$l = {
11373
+ const $$css$m = {
11292
11374
  hash: 'svelte-uub3h8',
11293
11375
  code: '.root.svelte-uub3h8 {display:flex;flex-direction:column;gap:0.5rem;padding:0.75rem;background:var(--cv-bg);border:1px solid var(--cv-border);border-radius:var(--cv-card-radius, 0.5rem);transition:background 0.15s ease;}.root.svelte-uub3h8:hover {background:var(--cv-bg-hover);}\n\n /* Remove special handling for last child since they are now separate cards */.root.svelte-uub3h8:last-child {border-bottom:1px solid var(--cv-border);}.header.svelte-uub3h8 {display:flex;flex-direction:column;gap:0.25rem;}.label.svelte-uub3h8 {font-size:0.875rem;color:var(--cv-text);margin:0;line-height:1.4;font-weight:500;display:block;cursor:pointer;}.description.svelte-uub3h8 {font-size:0.75rem;color:var(--cv-text-secondary);margin:0;line-height:1.4;}.select.svelte-uub3h8 {width:100%;border-radius:0.5rem;background:var(--cv-input-bg);border:1px solid var(--cv-input-border);color:var(--cv-text);padding:0.5rem 0.75rem;font-size:0.875rem;cursor:pointer;transition:all 0.15s ease;font-family:inherit;}.select.svelte-uub3h8:hover {border-color:var(--cv-text-secondary);}.select.svelte-uub3h8:focus {outline:none;border-color:var(--cv-primary);box-shadow:0 0 0 2px var(--cv-focus-ring);}'
11294
11376
  };
11295
11377
 
11296
11378
  function TabGroupItem($$anchor, $$props) {
11297
11379
  push($$props, true);
11298
- append_styles$1($$anchor, $$css$l);
11380
+ append_styles$1($$anchor, $$css$m);
11299
11381
 
11300
11382
  let activeTabId = prop($$props, 'activeTabId', 15, ''),
11301
11383
  onchange = prop($$props, 'onchange', 3, () => {});
@@ -11318,7 +11400,7 @@
11318
11400
 
11319
11401
  {
11320
11402
  var consequent = ($$anchor) => {
11321
- var p = root_1$d();
11403
+ var p = root_1$e();
11322
11404
  var text_1 = child(p, true);
11323
11405
 
11324
11406
  reset(p);
@@ -11384,14 +11466,14 @@
11384
11466
 
11385
11467
  var root$i = from_html(`<div class="placeholder-item svelte-1vp05mb"><label class="placeholder-label svelte-1vp05mb"> </label> <input class="placeholder-input svelte-1vp05mb" type="text"/></div>`);
11386
11468
 
11387
- const $$css$k = {
11469
+ const $$css$l = {
11388
11470
  hash: 'svelte-1vp05mb',
11389
11471
  code: '.placeholder-item.svelte-1vp05mb {display:flex;flex-direction:column;gap:0.25rem;}.placeholder-label.svelte-1vp05mb {font-size:0.85rem;font-weight:500;color:var(--cv-text);}.placeholder-input.svelte-1vp05mb {padding:0.5rem 0.75rem;border:1px solid var(--cv-input-border);border-radius:var(--cv-card-radius, 0.5rem);font-size:0.9rem;transition:border-color 0.2s;background:var(--cv-input-bg);color:var(--cv-text);}.placeholder-input.svelte-1vp05mb:focus {outline:none;border-color:var(--cv-primary);box-shadow:0 0 0 2px var(--cv-focus-ring);}'
11390
11472
  };
11391
11473
 
11392
11474
  function PlaceholderItem($$anchor, $$props) {
11393
11475
  push($$props, true);
11394
- append_styles$1($$anchor, $$css$k);
11476
+ append_styles$1($$anchor, $$css$l);
11395
11477
 
11396
11478
  let value = prop($$props, 'value', 15, ''),
11397
11479
  onchange = prop($$props, 'onchange', 3, () => {});
@@ -11471,7 +11553,7 @@
11471
11553
  }
11472
11554
  }
11473
11555
 
11474
- var root_1$c = from_html(`<button type="button">Customize</button>`);
11556
+ var root_1$d = from_html(`<button type="button">Customize</button>`);
11475
11557
  var root_3$6 = from_html(`<p class="description svelte-16uy9h6"> </p>`);
11476
11558
  var root_5$2 = from_html(`<div class="section svelte-16uy9h6"><div class="section-heading svelte-16uy9h6">Toggles</div> <div class="toggles-container svelte-16uy9h6"></div></div>`);
11477
11559
  var root_7$2 = from_html(`<div class="section svelte-16uy9h6"><div class="section-heading svelte-16uy9h6">Placeholders</div> <div class="placeholders-container svelte-16uy9h6"></div></div>`);
@@ -11487,14 +11569,14 @@
11487
11569
  var root_22 = from_html(`<div></div>`);
11488
11570
  var root$h = from_html(`<div class="modal-overlay svelte-16uy9h6" role="presentation"><div class="modal-box cv-custom-state-modal svelte-16uy9h6" role="dialog" aria-modal="true"><header class="header svelte-16uy9h6"><div class="header-content svelte-16uy9h6"><div class="modal-icon svelte-16uy9h6"><!></div> <div class="title svelte-16uy9h6"> </div></div> <button type="button" class="close-btn svelte-16uy9h6" aria-label="Close modal"><!></button></header> <main class="main svelte-16uy9h6"><div class="tabs svelte-16uy9h6"><!> <button type="button">Share</button></div> <!></main> <footer class="footer svelte-16uy9h6"><!> <div class="footer-attribution svelte-16uy9h6"><span class="footer-tagline svelte-16uy9h6">Browser-side page customisations provided by</span> <a href="https://custardui.js.org" target="_blank" rel="noopener noreferrer" class="footer-link svelte-16uy9h6">custardui.js.org</a></div> <button type="button" class="done-btn svelte-16uy9h6">Done</button></footer></div></div>`);
11489
11571
 
11490
- const $$css$j = {
11572
+ const $$css$k = {
11491
11573
  hash: 'svelte-16uy9h6',
11492
11574
  code: '\n /* Modal Overlay & Modal Frame */.modal-overlay.svelte-16uy9h6 {position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0, 0, 0, 0.5);display:flex;align-items:center;justify-content:center;z-index:10002;}.modal-box.svelte-16uy9h6 {background:var(--cv-bg);border-radius:var(--cv-modal-radius, 0.75rem);box-shadow:0 25px 50px -12px var(--cv-shadow);max-width:32rem;width:90vw;max-height:80vh;display:flex;flex-direction:column;}.header.svelte-16uy9h6 {display:flex;align-items:center;justify-content:space-between;padding:0.5rem 1rem;border-bottom:1px solid var(--cv-border);}.header-content.svelte-16uy9h6 {display:flex;align-items:center;gap:0.75rem;}.modal-icon.svelte-16uy9h6 {position:relative;width:1rem;height:1rem;display:flex;align-items:center;justify-content:center;border-radius:9999px;color:var(--cv-text);}.modal-icon.svelte-16uy9h6 svg {fill:currentColor;}.title.svelte-16uy9h6 {font-size:1.125rem;font-weight:bold;color:var(--cv-text);margin:0;}.close-btn.svelte-16uy9h6 {width:2rem;height:2rem;display:flex;align-items:center;justify-content:center;border-radius:9999px;background:transparent;border:none;color:var(--cv-text-secondary);cursor:pointer;transition:all 0.2s ease;}.close-btn.svelte-16uy9h6:hover {background:rgba(62, 132, 244, 0.1);color:var(--cv-primary);}.main.svelte-16uy9h6 {padding:1rem;flex:1;display:flex;flex-direction:column;overflow-y:auto;max-height:calc(80vh - 8rem);min-height:var(--cv-modal-min-height, 20rem);}.description.svelte-16uy9h6 {font-size:0.875rem;color:var(--cv-text);margin:0 0 1rem 0;line-height:1.4;}\n\n /* Tabs */.tabs.svelte-16uy9h6 {display:flex;margin-bottom:1rem;border-bottom:2px solid var(--cv-border);}.tab.svelte-16uy9h6 {background:transparent;border:none;padding:0.5rem 1rem;font-size:0.9rem;font-weight:600;color:var(--cv-text-secondary);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px;}.tab.active.svelte-16uy9h6 {color:var(--cv-primary);border-bottom-color:var(--cv-primary);}.tab-content.svelte-16uy9h6 {display:none;}.tab-content.active.svelte-16uy9h6 {display:block;}\n\n /* Section Styling */.section.svelte-16uy9h6 {display:flex;flex-direction:column;gap:0.75rem;margin-bottom:1.5rem;}.section-heading.svelte-16uy9h6 {font-size:0.7rem;font-weight:600;color:var(--cv-text-secondary);text-transform:var(--cv-section-label-transform, uppercase);letter-spacing:0.08em;margin:0;}.toggles-container.svelte-16uy9h6 {display:flex;flex-direction:column;gap:0.5rem;overflow:hidden;}\n\n /* Tab Groups Section specific */.tabgroups-container.svelte-16uy9h6 {border-radius:0.5rem;}\n\n /* Nav Toggle Card */.tabgroup-card.svelte-16uy9h6 {background:var(--cv-bg);border-bottom:1px solid var(--cv-border);}.tabgroup-card.header-card.svelte-16uy9h6 {display:flex;align-items:center;justify-content:space-between;padding:0.75rem;border:1px solid var(--cv-border);border-radius:0.5rem;margin-bottom:0.75rem;}.tabgroup-row.svelte-16uy9h6 {display:flex;align-items:center;justify-content:space-between;width:100%;gap:1rem;}.logo-box.svelte-16uy9h6 {width:3rem;height:3rem;background:var(--cv-modal-icon-bg);border-radius:0.5rem;display:flex;align-items:center;justify-content:center;flex-shrink:0;}.nav-icon.svelte-16uy9h6 {width:2rem;height:2rem;color:var(--cv-text);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:color 0.2s ease;}.tabgroup-info.svelte-16uy9h6 {flex:1;display:flex;flex-direction:column;gap:0.25rem;}.tabgroup-title.svelte-16uy9h6 {font-weight:500;font-size:0.875rem;color:var(--cv-text);margin:0 0 0 0;}.tabgroup-description.svelte-16uy9h6 {font-size:0.75rem;color:var(--cv-text-secondary);margin:0;line-height:1.3;}\n\n /* Toggle Switch */.toggle-switch.svelte-16uy9h6 {position:relative;display:inline-flex;align-items:center;width:44px;height:24px;background:var(--cv-switch-bg);border-radius:9999px;padding:2px;box-sizing:border-box;cursor:pointer;transition:background-color 0.2s ease;border:none;}.toggle-switch.svelte-16uy9h6 input:where(.svelte-16uy9h6) {display:none;}.toggle-switch.svelte-16uy9h6 .switch-bg:where(.svelte-16uy9h6) {position:absolute;inset:0;border-radius:9999px;background:var(--cv-switch-bg);transition:background-color 0.2s ease;pointer-events:none;}.toggle-switch.svelte-16uy9h6 .switch-knob:where(.svelte-16uy9h6) {position:relative;width:20px;height:20px;background:var(--cv-switch-knob);border-radius:50%;box-shadow:0 1px 2px rgba(0, 0, 0, 0.1);transition:transform 0.2s ease;transform:translateX(0);}.toggle-switch.svelte-16uy9h6 input:where(.svelte-16uy9h6):checked ~ .switch-knob:where(.svelte-16uy9h6) {transform:translateX(20px);}.toggle-switch.svelte-16uy9h6 input:where(.svelte-16uy9h6):checked ~ .switch-bg:where(.svelte-16uy9h6) {background:var(--cv-primary);}\n\n /* Tab Groups List */.tab-groups-list.svelte-16uy9h6 {display:flex;flex-direction:column;gap:0.75rem;}\n\n /* Footer */.footer.svelte-16uy9h6 {padding:0.75rem 1rem;border-top:1px solid var(--cv-border);display:flex;align-items:center;justify-content:space-between;background:var(--cv-bg);border-bottom-left-radius:var(--cv-modal-radius, 0.75rem);border-bottom-right-radius:var(--cv-modal-radius, 0.75rem);}.footer-attribution.svelte-16uy9h6 {display:flex;flex-direction:column;align-items:center;text-align:center;gap:0.1rem;opacity:0.5;transition:opacity 0.15s ease;}.footer-attribution.svelte-16uy9h6:hover {opacity:1;}.footer-tagline.svelte-16uy9h6 {font-size:0.6rem;color:var(--cv-text-secondary);letter-spacing:0.04em;}.footer-link.svelte-16uy9h6 {color:var(--cv-text-secondary);text-decoration:none;font-size:0.68rem;font-weight:600;letter-spacing:0.08em;transition:color 0.15s ease;}.footer-link.svelte-16uy9h6:hover {color:var(--cv-primary);}.reset-btn.svelte-16uy9h6 {display:flex;align-items:center;gap:0.4rem;background:transparent;border:none;font-size:0.875rem;font-weight:500;color:var(--cv-text-secondary);cursor:pointer;padding:0.4rem 0.5rem;border-radius:0.5rem;transition:all 0.2s ease;}.reset-btn.svelte-16uy9h6:hover {background:var(--cv-danger-bg);color:var(--cv-danger);}.done-btn.svelte-16uy9h6 {background:var(--cv-primary);color:white;border:none;padding:0.5rem 1.1rem;border-radius:0.5rem;font-weight:600;font-size:0.875rem;cursor:pointer;box-shadow:0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08);transition:background-color 0.15s ease, box-shadow 0.15s ease;}.done-btn.svelte-16uy9h6:hover {background:var(--cv-primary-hover);box-shadow:0 3px 6px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);}\n\n /* Share Tab Styles */.share-content.svelte-16uy9h6 {display:flex;flex-direction:column;gap:1rem;align-items:center;text-align:center;padding:1rem 0;}.share-instruction.svelte-16uy9h6 {font-size:0.95rem;color:var(--cv-text-secondary);margin-bottom:0.5rem;}.share-action-btn.svelte-16uy9h6 {display:flex;align-items:center;justify-content:center;gap:0.75rem;width:100%;max-width:320px;padding:0.75rem 1rem;border-radius:0.5rem;font-weight:500;font-size:0.95rem;cursor:pointer;transition:all 0.2s ease;border:1px solid var(--cv-border);background:var(--cv-bg);color:var(--cv-text);}.share-action-btn.svelte-16uy9h6:hover {border-color:var(--cv-primary);color:var(--cv-primary);background:var(--cv-bg-hover);}.share-action-btn.primary.svelte-16uy9h6 {background:var(--cv-primary);border-color:var(--cv-primary);color:white;}.share-action-btn.primary.svelte-16uy9h6:hover {background:var(--cv-primary-hover);border-color:var(--cv-primary-hover);}.btn-icon.svelte-16uy9h6 {display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;}\n\n /* Placeholder Inputs */.placeholders-container.svelte-16uy9h6 {display:flex;flex-direction:column;gap:0.75rem;}'
11493
11575
  };
11494
11576
 
11495
11577
  function Modal($$anchor, $$props) {
11496
11578
  push($$props, true);
11497
- append_styles$1($$anchor, $$css$j);
11579
+ append_styles$1($$anchor, $$css$k);
11498
11580
 
11499
11581
  /* eslint-disable @typescript-eslint/no-explicit-any */
11500
11582
  let onclose = prop($$props, 'onclose', 3, () => {}),
@@ -11593,7 +11675,7 @@
11593
11675
  }
11594
11676
 
11595
11677
  async function copyShareUrl() {
11596
- const url = URLStateManager.generateShareableURL(activeStateStore.state, {
11678
+ const url = URLStateManager.generateShareableURL(activeStateStore.state, activeStateStore.config, {
11597
11679
  toggles: elementStore.detectedToggles,
11598
11680
  tabGroups: elementStore.detectedTabGroups,
11599
11681
  placeholders: elementStore.detectedPlaceholders
@@ -11663,7 +11745,7 @@
11663
11745
 
11664
11746
  {
11665
11747
  var consequent = ($$anchor) => {
11666
- var button_1 = root_1$c();
11748
+ var button_1 = root_1$d();
11667
11749
 
11668
11750
  button_1.__click = () => set(activeTab, 'customize');
11669
11751
  template_effect(() => set_class(button_1, 1, `tab ${get(activeTab) === 'customize' ? 'active' : ''}`, 'svelte-16uy9h6'));
@@ -12963,23 +13045,23 @@
12963
13045
  return zoom;
12964
13046
  }
12965
13047
 
12966
- var root_1$b = from_html(`<div role="alert" aria-live="polite"> </div>`);
13048
+ var root_1$c = from_html(`<div role="alert" aria-live="polite"> </div>`);
12967
13049
  var root$g = from_html(`<div class="toast-container svelte-14irt8g"></div>`);
12968
13050
 
12969
- const $$css$i = {
13051
+ const $$css$j = {
12970
13052
  hash: 'svelte-14irt8g',
12971
13053
  code: '.toast-container.svelte-14irt8g {position:fixed;top:20px;left:50%;transform:translateX(-50%);z-index:20000;display:flex;flex-direction:column;align-items:center;gap:10px;pointer-events:none; /* Let clicks pass through container */}.toast-item.svelte-14irt8g {background:rgba(0, 0, 0, 0.85);color:white;padding:10px 20px;border-radius:4px;font-size:14px;box-shadow:0 4px 6px rgba(0, 0, 0, 0.1);pointer-events:auto; /* Re-enable clicks on toasts */max-width:300px;text-align:center;}'
12972
13054
  };
12973
13055
 
12974
13056
  function Toast($$anchor, $$props) {
12975
13057
  push($$props, false);
12976
- append_styles$1($$anchor, $$css$i);
13058
+ append_styles$1($$anchor, $$css$j);
12977
13059
  init();
12978
13060
 
12979
13061
  var div = root$g();
12980
13062
 
12981
13063
  each(div, 13, () => toast.items, (t) => t.id, ($$anchor, t) => {
12982
- var div_1 = root_1$b();
13064
+ var div_1 = root_1$c();
12983
13065
  var text = child(div_1, true);
12984
13066
 
12985
13067
  reset(div_1);
@@ -13002,14 +13084,14 @@
13002
13084
 
13003
13085
  var root$f = from_html(`<div class="floating-bar svelte-bs8cbd"><div class="mode-toggle svelte-bs8cbd"><button type="button" title="Highlight selected elements">Highlight</button> <button type="button" title="Show only selected elements">Show</button> <button type="button" title="Hide selected elements">Hide</button></div> <span class="divider svelte-bs8cbd"></span> <span class="count svelte-bs8cbd"> </span> <button type="button" class="btn clear svelte-bs8cbd">Clear</button> <button type="button" class="btn preview svelte-bs8cbd">Preview</button> <button type="button" class="btn generate svelte-bs8cbd">Copy Link</button> <button type="button" class="btn exit svelte-bs8cbd">Exit</button></div>`);
13004
13086
 
13005
- const $$css$h = {
13087
+ const $$css$i = {
13006
13088
  hash: 'svelte-bs8cbd',
13007
13089
  code: '.floating-bar.svelte-bs8cbd {position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background-color:#2c2c2c;color:#f1f1f1;border-radius:8px;padding:8px 12px;box-shadow:0 8px 20px rgba(0, 0, 0, 0.4);display:grid;grid-template-columns:auto auto 1fr auto auto auto auto;align-items:center;gap:12px;z-index:99999;font-family:system-ui,\n -apple-system,\n sans-serif;font-size:14px;border:1px solid #4a4a4a;pointer-events:auto;white-space:nowrap;min-width:500px;}.mode-toggle.svelte-bs8cbd {display:flex;background:#1a1a1a;border-radius:6px;padding:2px;border:1px solid #4a4a4a;}.mode-btn.svelte-bs8cbd {background:transparent;color:#aeaeae;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-weight:500;font-size:13px;transition:all 0.2s;}.mode-btn.svelte-bs8cbd:hover {color:#fff;}.mode-btn.active.svelte-bs8cbd {background:#4a4a4a;color:#fff;box-shadow:0 1px 3px rgba(0, 0, 0, 0.2);}.divider.svelte-bs8cbd {width:1px;height:20px;background:#4a4a4a;margin:0 4px;}.count.svelte-bs8cbd {font-weight:500;min-width:120px;text-align:center;font-size:13px;color:#ccc;}.btn.svelte-bs8cbd {background-color:#0078d4;color:white;border:none;padding:6px 12px;border-radius:5px;cursor:pointer;font-weight:500;transition:background-color 0.2s;font-size:13px;}.btn.svelte-bs8cbd:hover {background-color:#005a9e;}.btn.clear.svelte-bs8cbd {background-color:transparent;border:1px solid #5a5a5a;color:#dadada;}.btn.clear.svelte-bs8cbd:hover {background-color:#3a3a3a;color:white;}.btn.preview.svelte-bs8cbd {background-color:#333;border:1px solid #555;}.btn.preview.svelte-bs8cbd:hover {background-color:#444;}.btn.exit.svelte-bs8cbd {background-color:transparent;color:#ff6b6b;padding:6px 10px;}.btn.exit.svelte-bs8cbd:hover {background-color:rgba(255, 107, 107, 0.1);}\n\n @media (max-width: 600px) {.floating-bar.svelte-bs8cbd {display:flex;flex-wrap:wrap;min-width:unset;width:90%;max-width:400px;height:auto;padding:12px;gap:10px;bottom:30px;}.mode-toggle.svelte-bs8cbd {margin-right:auto;order:1;}.btn.exit.svelte-bs8cbd {margin-left:auto;order:2;}.divider.svelte-bs8cbd {display:none;}.count.svelte-bs8cbd {width:100%;text-align:center;order:3;padding:8px 0;border-top:1px solid #3a3a3a;border-bottom:1px solid #3a3a3a;margin:4px 0;}.btn.clear.svelte-bs8cbd,\n .btn.preview.svelte-bs8cbd,\n .btn.generate.svelte-bs8cbd {flex:1;text-align:center;font-size:12px;padding:8px 4px;order:4;}.btn.generate.svelte-bs8cbd {flex:1.5;}\n }'
13008
13090
  };
13009
13091
 
13010
13092
  function ShareToolbar($$anchor, $$props) {
13011
13093
  push($$props, false);
13012
- append_styles$1($$anchor, $$css$h);
13094
+ append_styles$1($$anchor, $$css$i);
13013
13095
 
13014
13096
  function handleClear() {
13015
13097
  shareStore.clearAllSelections();
@@ -13089,16 +13171,16 @@
13089
13171
 
13090
13172
  var root_2$7 = from_html(`<span class="id-badge svelte-64gpkh" title="ID detection active"> </span>`);
13091
13173
  var root_3$5 = from_html(`<button type="button" class="action-btn up svelte-64gpkh" title="Select Parent">↰</button>`);
13092
- var root_1$a = from_html(`<div class="hover-helper svelte-64gpkh"><div class="info svelte-64gpkh"><span class="tag svelte-64gpkh"> </span> <!></div> <button type="button"> </button> <!></div>`);
13174
+ var root_1$b = from_html(`<div class="hover-helper svelte-64gpkh"><div class="info svelte-64gpkh"><span class="tag svelte-64gpkh"> </span> <!></div> <button type="button"> </button> <!></div>`);
13093
13175
 
13094
- const $$css$g = {
13176
+ const $$css$h = {
13095
13177
  hash: 'svelte-64gpkh',
13096
13178
  code: '.hover-helper.svelte-64gpkh {position:fixed;z-index:99999;background-color:#333;color:white;padding:4px 8px;border-radius:4px;display:flex;align-items:center;gap:8px;box-shadow:0 2px 5px rgba(0, 0, 0, 0.2);font-family:monospace;pointer-events:auto;}.info.svelte-64gpkh {display:flex;flex-direction:column;align-items:flex-start;line-height:1;gap:2px;}.tag.svelte-64gpkh {font-size:12px;font-weight:bold;color:#aeaeae;}.id-badge.svelte-64gpkh {font-size:10px;color:#64d2ff;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.action-btn.svelte-64gpkh {background:#555;border:none;color:white;border-radius:3px;cursor:pointer;padding:2px 6px;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;transition:background-color 0.1s;}.action-btn.svelte-64gpkh:hover {background:#777;}.action-btn.deselect.svelte-64gpkh {background-color:#d13438;}.action-btn.deselect.svelte-64gpkh:hover {background-color:#a42628;}'
13097
13179
  };
13098
13180
 
13099
13181
  function HoverHelper($$anchor, $$props) {
13100
13182
  push($$props, true);
13101
- append_styles$1($$anchor, $$css$g);
13183
+ append_styles$1($$anchor, $$css$h);
13102
13184
 
13103
13185
  // Derived state for easier access
13104
13186
  let target = user_derived(() => shareStore.currentHoverTarget);
@@ -13197,7 +13279,7 @@
13197
13279
 
13198
13280
  {
13199
13281
  var consequent_2 = ($$anchor) => {
13200
- var div = root_1$a();
13282
+ var div = root_1$b();
13201
13283
  var div_1 = child(div);
13202
13284
  var span = child(div_1);
13203
13285
  var text = child(span, true);
@@ -13273,17 +13355,17 @@
13273
13355
  delegate(['click']);
13274
13356
 
13275
13357
  var root_2$6 = from_html(`<button type="button"></button>`);
13276
- var root_1$9 = from_html(`<div class="cv-color-swatches svelte-1r78n4c" role="none"></div>`);
13358
+ var root_1$a = from_html(`<div class="cv-color-swatches svelte-1r78n4c" role="none"></div>`);
13277
13359
  var root$e = from_html(`<div class="cv-color-picker svelte-1r78n4c" role="none"><button type="button" class="cv-color-trigger svelte-1r78n4c" title="Choose highlight color" aria-label="Choose highlight color"><span class="cv-color-dot svelte-1r78n4c"></span></button> <!></div>`);
13278
13360
 
13279
- const $$css$f = {
13361
+ const $$css$g = {
13280
13362
  hash: 'svelte-1r78n4c',
13281
13363
  code: '.cv-color-picker.svelte-1r78n4c {position:fixed;transform:translateX(-50%) translateY(-100%);display:flex;flex-direction:column;align-items:center;gap:4px;pointer-events:auto;z-index:9500;\n /* Nudge down so the trigger peeks above the element edge */margin-top:8px;}.cv-color-trigger.svelte-1r78n4c {width:22px;height:16px;border-radius:100px;border:1.5px solid rgba(0, 0, 0, 0.18);background:white;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;box-shadow:0 2px 8px rgba(0, 0, 0, 0.15);transition:box-shadow 0.15s;}.cv-color-trigger.svelte-1r78n4c:hover {box-shadow:0 3px 12px rgba(0, 0, 0, 0.22);}.cv-color-dot.svelte-1r78n4c {width:10px;height:10px;border-radius:50%;display:block;border:1px solid rgba(0, 0, 0, 0.12);}.cv-color-swatches.svelte-1r78n4c {display:flex;flex-direction:row;gap:4px;background:white;border-radius:100px;padding:4px 6px;box-shadow:0 4px 16px rgba(0, 0, 0, 0.18);border:1px solid rgba(0, 0, 0, 0.1);}.cv-color-swatch.svelte-1r78n4c {width:16px;height:16px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;transition:transform 0.1s, border-color 0.1s;}.cv-color-swatch.svelte-1r78n4c:hover {transform:scale(1.2);border-color:rgba(0, 0, 0, 0.3);}.cv-color-swatch.active.svelte-1r78n4c {border-color:rgba(0, 0, 0, 0.5);transform:scale(1.15);}'
13282
13364
  };
13283
13365
 
13284
13366
  function HighlightColorPicker($$anchor, $$props) {
13285
13367
  push($$props, true);
13286
- append_styles$1($$anchor, $$css$f);
13368
+ append_styles$1($$anchor, $$css$g);
13287
13369
 
13288
13370
  let isExpanded = state(false);
13289
13371
  let rect = state(proxy({ top: 0, left: 0, width: 0 }));
@@ -13357,7 +13439,7 @@
13357
13439
 
13358
13440
  {
13359
13441
  var consequent = ($$anchor) => {
13360
- var div_1 = root_1$9();
13442
+ var div_1 = root_1$a();
13361
13443
 
13362
13444
  each(div_1, 21, () => HIGHLIGHT_COLORS, index, ($$anchor, color) => {
13363
13445
  var button_1 = root_2$6();
@@ -13400,20 +13482,20 @@
13400
13482
 
13401
13483
  delegate(['click', 'dblclick']);
13402
13484
 
13403
- var root_1$8 = from_html(`<span class="cv-annotation-tab-preview svelte-1r1spmr"> </span>`);
13485
+ var root_1$9 = from_html(`<span class="cv-annotation-tab-preview svelte-1r1spmr"> </span>`);
13404
13486
  var root_2$5 = from_html(`<span class="cv-annotation-tab-icon svelte-1r1spmr"> </span>`);
13405
13487
  var root_4$2 = from_html(`<button type="button"> </button>`);
13406
13488
  var root_3$4 = from_html(`<div class="cv-annotation-panel svelte-1r1spmr" role="none"><textarea class="cv-annotation-textarea svelte-1r1spmr" placeholder="Add a note…" rows="3"></textarea> <div class="cv-annotation-footer svelte-1r1spmr"><div class="cv-corner-selector svelte-1r1spmr" role="group" aria-label="Anchor corner"></div> <span class="cv-char-counter svelte-1r1spmr"> </span></div></div>`);
13407
13489
  var root$d = from_html(`<div class="cv-annotation-editor svelte-1r1spmr" role="none"><button type="button" aria-label="Annotation"><!></button> <!></div>`);
13408
13490
 
13409
- const $$css$e = {
13491
+ const $$css$f = {
13410
13492
  hash: 'svelte-1r1spmr',
13411
13493
  code: '.cv-annotation-editor.svelte-1r1spmr {position:fixed;z-index:9400;pointer-events:auto;display:flex;flex-direction:column;align-items:flex-start;gap:2px;}.cv-annotation-tab.svelte-1r1spmr {height:20px;padding:0 8px;border-radius:100px;border:1.5px solid rgba(0, 0, 0, 0.18);background:white;cursor:pointer;display:flex;align-items:center;gap:4px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.15);transition:box-shadow 0.15s;max-width:160px;overflow:hidden;}.cv-annotation-tab.svelte-1r1spmr:hover {box-shadow:0 3px 12px rgba(0, 0, 0, 0.22);}.cv-annotation-tab--has-text.svelte-1r1spmr {background:#fffbe6;border-color:rgba(180, 83, 9, 0.4);}.cv-annotation-tab-icon.svelte-1r1spmr {font-size:10px;line-height:1;color:#6b7280;}.cv-annotation-tab-preview.svelte-1r1spmr {font-size:9px;font-weight:600;color:#1a1a1a;font-family:ui-sans-serif, system-ui, sans-serif;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:130px;}.cv-annotation-panel.svelte-1r1spmr {background:white;border-radius:8px;border:1px solid rgba(0, 0, 0, 0.12);box-shadow:0 4px 16px rgba(0, 0, 0, 0.18);padding:8px;width:220px;display:flex;flex-direction:column;gap:6px;}.cv-annotation-textarea.svelte-1r1spmr {width:100%;box-sizing:border-box;resize:vertical;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;padding:5px 7px;font-size:11px;font-family:ui-sans-serif, system-ui, sans-serif;color:#1a1a1a;line-height:1.5;outline:none;min-height:56px;}.cv-annotation-textarea.svelte-1r1spmr:focus {border-color:#b45309;box-shadow:0 0 0 2px rgba(180, 83, 9, 0.15);}.cv-annotation-footer.svelte-1r1spmr {display:flex;align-items:center;justify-content:space-between;}.cv-corner-selector.svelte-1r1spmr {display:flex;gap:2px;}.cv-corner-btn.svelte-1r1spmr {width:20px;height:20px;border-radius:4px;border:1px solid rgba(0, 0, 0, 0.12);background:white;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:10px;color:#6b7280;padding:0;transition:background 0.1s, border-color 0.1s;}.cv-corner-btn.svelte-1r1spmr:hover {background:#fef3c7;border-color:#b45309;color:#1a1a1a;}.cv-corner-btn.active.svelte-1r1spmr {background:#fef3c7;border-color:#b45309;color:#92400e;font-weight:700;}.cv-char-counter.svelte-1r1spmr {font-size:9px;color:#9ca3af;font-family:ui-sans-serif, system-ui, sans-serif;font-variant-numeric:tabular-nums;}'
13412
13494
  };
13413
13495
 
13414
13496
  function HighlightAnnotationEditor($$anchor, $$props) {
13415
13497
  push($$props, true);
13416
- append_styles$1($$anchor, $$css$e);
13498
+ append_styles$1($$anchor, $$css$f);
13417
13499
 
13418
13500
  let isExpanded = state(false);
13419
13501
  let rect = state(proxy({ top: 0, left: 0, width: 0, height: 0, bottom: 0, right: 0 }));
@@ -13500,7 +13582,7 @@
13500
13582
 
13501
13583
  {
13502
13584
  var consequent = ($$anchor) => {
13503
- var span = root_1$8();
13585
+ var span = root_1$9();
13504
13586
  var text = child(span, true);
13505
13587
 
13506
13588
  reset(span);
@@ -13605,14 +13687,14 @@
13605
13687
  var root_3$3 = from_html(`<div><span class="selection-label svelte-1dbf58w"> </span></div>`);
13606
13688
  var root$c = from_html(`<div class="share-overlay-ui"><!> <!> <!> <!></div>`);
13607
13689
 
13608
- const $$css$d = {
13690
+ const $$css$e = {
13609
13691
  hash: 'svelte-1dbf58w',
13610
13692
  code: '\n /* Global styles injected when active */body.cv-share-active {cursor:default;user-select:none;-webkit-user-select:none;}\n\n /* Highlight outlines */.cv-highlight-target {outline:2px dashed #0078d4 !important;outline-offset:2px;cursor:crosshair;}.cv-share-selected {outline:3px solid #005a9e !important;outline-offset:2px;background-color:rgba(0, 120, 212, 0.05);}.cv-highlight-target-hide {outline:2px dashed #d13438 !important;outline-offset:2px;cursor:crosshair;}.cv-share-selected-hide {outline:3px solid #a4262c !important;outline-offset:2px;background-color:rgba(209, 52, 56, 0.05);}.cv-highlight-target-mode {outline:2px dashed #d97706 !important;outline-offset:2px;cursor:crosshair;}.cv-share-selected-highlight {outline:3px solid #b45309 !important;outline-offset:2px;background-color:rgba(245, 158, 11, 0.05);}.selection-box.svelte-1dbf58w {position:fixed;border:1px solid rgba(0, 120, 212, 0.4);background-color:rgba(0, 120, 212, 0.1);pointer-events:none;z-index:10000;box-sizing:border-box;}.selection-box.hide-mode.svelte-1dbf58w {border:1px solid rgba(209, 52, 56, 0.4);background-color:rgba(209, 52, 56, 0.1);}.selection-box.highlight-mode.svelte-1dbf58w {border:1px solid rgba(255, 140, 0, 0.6); /* Orange/Gold for highlight */background-color:rgba(255, 140, 0, 0.1);}.selection-label.svelte-1dbf58w {position:absolute;top:-24px;left:0;background:#0078d4;color:white;padding:2px 6px;font-size:11px;border-radius:3px;white-space:nowrap;font-family:sans-serif;opacity:0.9;}.hide-mode.svelte-1dbf58w .selection-label:where(.svelte-1dbf58w) {background:#d13438;}.highlight-mode.svelte-1dbf58w .selection-label:where(.svelte-1dbf58w) {background:#d97706; /* Darker orange for text bg */}'
13611
13693
  };
13612
13694
 
13613
13695
  function ShareOverlay($$anchor, $$props) {
13614
13696
  push($$props, true);
13615
- append_styles$1($$anchor, $$css$d);
13697
+ append_styles$1($$anchor, $$css$e);
13616
13698
 
13617
13699
  let excludedTags = prop($$props, 'excludedTags', 19, () => ['HEADER', 'NAV', 'FOOTER']),
13618
13700
  excludedIds = prop($$props, 'excludedIds', 19, () => []);
@@ -13935,16 +14017,16 @@
13935
14017
  pop();
13936
14018
  }
13937
14019
 
13938
- var root_1$7 = from_html(`<div class="cv-focus-banner-wrapper svelte-1yqpn7e"><div id="cv-exit-focus-banner" data-cv-scroll-offset="" class="svelte-1yqpn7e"><span>You are viewing a 'focused view' generated by CustardUI.</span> <button type="button" class="svelte-1yqpn7e">See Original Page</button></div></div>`);
14020
+ var root_1$8 = from_html(`<div class="cv-focus-banner-wrapper svelte-1yqpn7e"><div id="cv-exit-focus-banner" data-cv-scroll-offset="" class="svelte-1yqpn7e"><span>You are viewing a 'focused view' generated by CustardUI.</span> <button type="button" class="svelte-1yqpn7e">See Original Page</button></div></div>`);
13939
14021
 
13940
- const $$css$c = {
14022
+ const $$css$d = {
13941
14023
  hash: 'svelte-1yqpn7e',
13942
14024
  code: '.cv-focus-banner-wrapper.svelte-1yqpn7e {position:fixed;top:0;left:0;right:0;z-index:9000;background-color:#f3cb52;box-shadow:0 2px 8px rgba(44, 26, 14, 0.15);font-family:system-ui, sans-serif;}#cv-exit-focus-banner.svelte-1yqpn7e {color:#2c1a0e;padding:10px 20px;display:flex;align-items:center;justify-content:center;gap:16px;}button.svelte-1yqpn7e {background:#804b18;color:#fdf6e3;border:none;padding:4px 12px;border-radius:4px;cursor:pointer;font-weight:600;}button.svelte-1yqpn7e:hover {background:#c4853a;}'
13943
14025
  };
13944
14026
 
13945
14027
  function FocusBanner($$anchor, $$props) {
13946
14028
  push($$props, false);
13947
- append_styles$1($$anchor, $$css$c);
14029
+ append_styles$1($$anchor, $$css$d);
13948
14030
 
13949
14031
  function handleExit() {
13950
14032
  focusStore.exit();
@@ -13957,7 +14039,7 @@
13957
14039
 
13958
14040
  {
13959
14041
  var consequent = ($$anchor) => {
13960
- var div = root_1$7();
14042
+ var div = root_1$8();
13961
14043
  var div_1 = child(div);
13962
14044
  var button = sibling(child(div_1), 2);
13963
14045
 
@@ -14169,13 +14251,13 @@
14169
14251
 
14170
14252
  /**
14171
14253
  * Initializes the manager. Should be called when the component is ready
14172
- * and we know there are elements on the page.
14254
+ * and we know there are elements on the current page (toggles, tab groups, or placeholders).
14173
14255
  */
14174
- init(hasPageElements, settingsEnabled) {
14256
+ init(hasElementsOnCurrentPage, settingsEnabled) {
14175
14257
  const options = this.getOptions();
14176
14258
 
14177
14259
  if (settingsEnabled && !this.hasChecked && options?.show) {
14178
- if (hasPageElements) {
14260
+ if (hasElementsOnCurrentPage) {
14179
14261
  this.hasChecked = true;
14180
14262
  this.checkAndShow();
14181
14263
  }
@@ -14203,14 +14285,14 @@
14203
14285
 
14204
14286
  var root$b = from_html(`<div class="cv-widget-root" data-cv-share-ignore=""><!> <!> <!> <!> <!> <!></div>`);
14205
14287
 
14206
- const $$css$b = {
14288
+ const $$css$c = {
14207
14289
  hash: 'svelte-1vlfixd',
14208
14290
  code: '\n /* Root should allow clicks to pass through to the page unless hitting checking/interactive element */.cv-widget-root {position:fixed;top:0;left:0;width:0;height:0;z-index:9999;pointer-events:none; /* Crucial: Allow clicks to pass through */\n\n /* Light Theme Defaults */--cv-bg: white;--cv-text: rgba(0, 0, 0, 0.9);--cv-text-secondary: rgba(0, 0, 0, 0.6);--cv-border: rgba(0, 0, 0, 0.1);--cv-bg-hover: rgba(0, 0, 0, 0.05);--cv-primary: #3e84f4;--cv-primary-hover: #2563eb;--cv-danger: #dc2626;--cv-danger-bg: rgba(220, 38, 38, 0.1);--cv-shadow: rgba(0, 0, 0, 0.25);--cv-input-bg: white;--cv-input-border: rgba(0, 0, 0, 0.15);--cv-switch-bg: rgba(0, 0, 0, 0.1);--cv-switch-knob: white;--cv-modal-icon-bg: rgba(0, 0, 0, 0.08);--cv-icon-bg: rgba(255, 255, 255, 0.92);--cv-icon-color: rgba(0, 0, 0, 0.9);--cv-focus-ring: rgba(62, 132, 244, 0.2);--cv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);--cv-modal-radius: 0.75rem;--cv-card-radius: 0.5rem;--cv-section-label-transform: uppercase;font-family:inherit; /* Inherit font from host */}\n\n /* But interactive children need pointer-events back */.cv-widget-root > * {pointer-events:auto;}\n\n /* Exception: ShareOverlay manages its own pointer events */.cv-widget-root .cv-share-overlay {pointer-events:none; /* Overlay often passes clicks until specialized handles active */}.cv-widget-root[data-theme=\'dark\'] {\n /* Dark Theme Overrides */--cv-bg: #101722;--cv-text: #e2e8f0;--cv-text-secondary: rgba(255, 255, 255, 0.6);--cv-border: rgba(255, 255, 255, 0.1);--cv-bg-hover: rgba(255, 255, 255, 0.05);--cv-primary: #3e84f4;--cv-primary-hover: #60a5fa;--cv-danger: #f87171;--cv-danger-bg: rgba(248, 113, 113, 0.1);--cv-shadow: rgba(0, 0, 0, 0.5);--cv-input-bg: #1e293b;--cv-input-border: rgba(255, 255, 255, 0.1);--cv-switch-bg: rgba(255, 255, 255, 0.1);--cv-switch-knob: #e2e8f0;--cv-modal-icon-bg: rgba(255, 255, 255, 0.08);--cv-icon-bg: #1e293b;--cv-icon-color: #e2e8f0;--cv-focus-ring: rgba(62, 132, 244, 0.5);--cv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);--cv-modal-radius: 0.75rem;--cv-card-radius: 0.5rem;--cv-section-label-transform: uppercase;}.cv-hidden {display:none !important;}'
14209
14291
  };
14210
14292
 
14211
14293
  function UIRoot($$anchor, $$props) {
14212
14294
  push($$props, true);
14213
- append_styles$1($$anchor, $$css$b);
14295
+ append_styles$1($$anchor, $$css$c);
14214
14296
 
14215
14297
  const { persistenceManager, resetToDefault } = getContext(RUNTIME_CALLBACKS_CTX);
14216
14298
  const iconSettingsStore = getContext(ICON_SETTINGS_CTX);
@@ -14252,7 +14334,7 @@
14252
14334
 
14253
14335
  // --- Effects ---
14254
14336
  user_effect(() => {
14255
- introManager.init(elementStore.hasPageElements, get(settingsEnabled));
14337
+ introManager.init(elementStore.hasElementsOnCurrentPage, get(settingsEnabled));
14256
14338
  });
14257
14339
 
14258
14340
  // --- Modal Actions ---
@@ -14795,14 +14877,14 @@
14795
14877
 
14796
14878
  var root$a = from_html(`<div class="cv-context-divider svelte-1a535nn" role="button" tabindex="0"> </div>`);
14797
14879
 
14798
- const $$css$a = {
14880
+ const $$css$b = {
14799
14881
  hash: 'svelte-1a535nn',
14800
14882
  code: '.cv-context-divider.svelte-1a535nn {padding:12px;margin:16px 0;background-color:#f8f8f8;border-top:1px dashed #ccc;border-bottom:1px dashed #ccc;color:#555;text-align:center;cursor:pointer;font-family:system-ui, sans-serif;font-size:13px;transition:background-color 0.2s;}.cv-context-divider.svelte-1a535nn:hover {background-color:#e8e8e8;color:#333;}'
14801
14883
  };
14802
14884
 
14803
14885
  function FocusDivider($$anchor, $$props) {
14804
14886
  push($$props, true);
14805
- append_styles$1($$anchor, $$css$a);
14887
+ append_styles$1($$anchor, $$css$b);
14806
14888
 
14807
14889
  // Component is mounted manually via `mount`, use props for communication.
14808
14890
  let hiddenCount = prop($$props, 'hiddenCount', 3, 0);
@@ -14948,18 +15030,18 @@
14948
15030
  var root_3$2 = from_html(`<!> <span class="cv-ribbon-text cv-ribbon-text--right svelte-1asb212"> </span> <span class="cv-ribbon-grip svelte-1asb212" aria-hidden="true"><span class="svelte-1asb212"></span><span class="svelte-1asb212"></span> <span class="svelte-1asb212"></span><span class="svelte-1asb212"></span> <span class="svelte-1asb212"></span><span class="svelte-1asb212"></span></span>`, 1);
14949
15031
  var root_6$1 = from_html(`<span>▾</span>`);
14950
15032
  var root_5$1 = from_html(`<span class="cv-ribbon-grip svelte-1asb212" aria-hidden="true"><span class="svelte-1asb212"></span><span class="svelte-1asb212"></span> <span class="svelte-1asb212"></span><span class="svelte-1asb212"></span> <span class="svelte-1asb212"></span><span class="svelte-1asb212"></span></span> <span class="cv-ribbon-text svelte-1asb212"> </span> <!>`, 1);
14951
- var root_1$6 = from_html(`<button type="button"><!></button>`);
15033
+ var root_1$7 = from_html(`<button type="button"><!></button>`);
14952
15034
  var root_7$1 = from_html(`<div class="cv-annotation-card svelte-1asb212" role="region" aria-label="Annotation"><button type="button" class="cv-card-close svelte-1asb212" aria-label="Collapse annotation">✕</button> <span class="cv-card-text svelte-1asb212"> </span></div>`);
14953
15035
  var root$9 = from_html(`<div><!></div>`);
14954
15036
 
14955
- const $$css$9 = {
15037
+ const $$css$a = {
14956
15038
  hash: 'svelte-1asb212',
14957
15039
  code: '\n /* ==============================\n CONTAINER (position, drag, opacity)\n ============================== */.cv-annotation-container.svelte-1asb212 {position:absolute;z-index:100;pointer-events:auto;touch-action:none;user-select:none;cursor:default;opacity:0.88;transition:opacity 0.2s ease, z-index 0s;}.cv-annotation-container.svelte-1asb212:hover {opacity:1;z-index:110;}\n\n /* ==============================\n RIBBON (home-plate)\n ============================== */.cv-annotation-ribbon.svelte-1asb212 {border:none;padding:6px 20px 6px 8px;min-width:28px;min-height:24px;background:var(--cv-highlight-color);cursor:default;box-shadow:0 2px 8px rgba(0, 0, 0, 0.15);display:flex;align-items:center;justify-content:flex-start;gap:5px;transform-origin:center center;}.cv-annotation-ribbon--intro.svelte-1asb212 {\n animation: svelte-1asb212-cv-wiggle-intro 0.75s ease-in-out forwards;}.cv-annotation-ribbon--periodic.svelte-1asb212 {\n animation: svelte-1asb212-cv-wiggle-periodic 5s ease-in-out infinite;}.cv-annotation-ribbon--right.svelte-1asb212 {padding:6px 8px 6px 20px;justify-content:flex-end;}.cv-annotation-ribbon--empty.svelte-1asb212 {min-width:24px;padding:6px 16px 6px 8px;}.cv-annotation-ribbon--expandable.svelte-1asb212 {cursor:pointer;}.cv-annotation-ribbon--expandable.svelte-1asb212:hover {filter:brightness(1.1);}\n\n /* ==============================\n RIBBON TEXT (single line)\n ============================== */.cv-ribbon-text.svelte-1asb212 {display:block;font-family:\'Segoe Print\', \'Bradley Hand\', \'Chilanka\', cursive;font-size:13px;font-weight:700;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px;color:#fff;text-shadow:0 1px 3px rgba(0, 0, 0, 0.25);}.cv-ribbon-text--right.svelte-1asb212 {text-align:right;}.cv-ribbon-chevron.svelte-1asb212 {font-size:22px;opacity:1;flex-shrink:0;line-height:1;color:#fff;text-shadow:0 1px 4px rgba(0, 0, 0, 0.4);}.cv-ribbon-chevron--bounce.svelte-1asb212 {\n animation: svelte-1asb212-cv-chevron-bounce 3s ease-in-out infinite;}\n\n /* ==============================\n DRAG GRIP (6-dot grid on flat side)\n ============================== */.cv-ribbon-grip.svelte-1asb212 {display:grid;grid-template-columns:repeat(2, 3px);gap:3px;flex-shrink:0;opacity:0.7;cursor:grab;padding:2px;}.cv-ribbon-grip.svelte-1asb212:active {cursor:grabbing;}.cv-ribbon-grip.svelte-1asb212 > span:where(.svelte-1asb212) {width:3px;height:3px;border-radius:50%;background:rgba(255, 255, 255, 0.9);box-shadow:0 0 1px rgba(0, 0, 0, 0.4);}\n\n /* ==============================\n CARD (sticky note)\n ============================== */.cv-annotation-card.svelte-1asb212 {background:#FFFDF5;border:1.5px solid var(--cv-highlight-color);border-radius:4px;padding:10px 12px;max-width:280px;min-width:120px;box-shadow:0 4px 20px rgba(0, 0, 0, 0.18);position:relative;\n animation: svelte-1asb212-cv-cardPop 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;}.cv-card-close.svelte-1asb212 {position:absolute;top:3px;right:5px;border:none;background:transparent;cursor:pointer;font-size:12px;color:#aaa;padding:2px 4px;line-height:1;font-family:sans-serif;}.cv-card-close.svelte-1asb212:hover {color:#555;}.cv-card-text.svelte-1asb212 {display:block;font-family:\'Segoe Print\', \'Bradley Hand\', \'Chilanka\', cursive;font-size:13px;font-weight:600;color:#333;line-height:1.45;word-break:break-word;white-space:pre-wrap;padding-right:15px;}\n\n /* ==============================\n ANIMATIONS\n ============================== */\n @keyframes svelte-1asb212-cv-wiggle-intro {\n 0% { transform: rotate(0deg); }\n 10% { transform: rotate(-6deg); }\n 25% { transform: rotate(6deg); }\n 40% { transform: rotate(-5deg); }\n 55% { transform: rotate(5deg); }\n 68% { transform: rotate(-3deg); }\n 80% { transform: rotate(2.5deg); }\n 90% { transform: rotate(-1deg); }\n 100% { transform: rotate(0deg); }\n }\n\n @keyframes svelte-1asb212-cv-wiggle-periodic {\n 0%, 85%, 100% { transform: rotate(0deg); }\n 87% { transform: rotate(1.2deg); }\n 90% { transform: rotate(-1.2deg); }\n 93% { transform: rotate(0.8deg); }\n 96% { transform: rotate(-0.5deg); }\n }\n\n @keyframes svelte-1asb212-cv-cardPop {\n from { opacity: 0; transform: scale(0.9) translateY(5px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n }\n\n @keyframes svelte-1asb212-cv-chevron-bounce {\n 0%, 70%, 100% { transform: translateY(0); }\n 78% { transform: translateY(-3px); }\n 86% { transform: translateY(1px); }\n 93% { transform: translateY(-1.5px); }\n }'
14958
15040
  };
14959
15041
 
14960
15042
  function HighlightTextAnnotation($$anchor, $$props) {
14961
15043
  push($$props, true);
14962
- append_styles$1($$anchor, $$css$9);
15044
+ append_styles$1($$anchor, $$css$a);
14963
15045
 
14964
15046
  const corner = user_derived(() => $$props.annotationCorner ?? DEFAULT_ANNOTATION_CORNER);
14965
15047
  const hasText = user_derived(() => $$props.annotation.length > 0);
@@ -15121,9 +15203,9 @@
15121
15203
  const pointsRight = c === 'tl' || c === 'bl';
15122
15204
 
15123
15205
  if (pointsRight) {
15124
- return 'polygon(0% 0%, 80% 0%, 100% 50%, 80% 100%, 0% 100%)';
15206
+ return 'polygon(0% 0%, calc(100% - 14px) 0%, 100% 50%, calc(100% - 14px) 100%, 0% 100%)';
15125
15207
  } else {
15126
- return 'polygon(20% 0%, 100% 0%, 100% 100%, 20% 100%, 0% 50%)';
15208
+ return 'polygon(14px 0%, 100% 0%, 100% 100%, 14px 100%, 0% 50%)';
15127
15209
  }
15128
15210
  }
15129
15211
 
@@ -15138,7 +15220,7 @@
15138
15220
 
15139
15221
  {
15140
15222
  var consequent_4 = ($$anchor) => {
15141
- var button = root_1$6();
15223
+ var button = root_1$7();
15142
15224
  let classes_1;
15143
15225
 
15144
15226
  button.__click = handleInteraction;
@@ -15294,15 +15376,15 @@
15294
15376
 
15295
15377
  delegate(['pointerdown', 'pointermove', 'pointerup', 'click']);
15296
15378
 
15297
- var root_1$5 = from_html(`<div class="cv-annotation-container svelte-ii1txw"><div role="img" aria-label="Annotation marker"></div> <button type="button" class="cv-empty-dismiss svelte-ii1txw" aria-label="Dismiss marker">✕</button></div>`);
15379
+ var root_1$6 = from_html(`<div class="cv-annotation-container svelte-ii1txw"><div role="img" aria-label="Annotation marker"></div> <button type="button" class="cv-empty-dismiss svelte-ii1txw" aria-label="Dismiss marker">✕</button></div>`);
15298
15380
 
15299
- const $$css$8 = {
15381
+ const $$css$9 = {
15300
15382
  hash: 'svelte-ii1txw',
15301
15383
  code: '.cv-annotation-container.svelte-ii1txw {position:absolute;z-index:100;pointer-events:auto;touch-action:none;user-select:none;opacity:0.95;transition:opacity 0.2s ease, z-index 0s;}.cv-annotation-container.svelte-ii1txw:hover {opacity:1;z-index:110;}.cv-empty-ribbon.svelte-ii1txw {min-width:45px;min-height:22px;background:var(--cv-highlight-color);display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(0, 0, 0, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.22);transform-origin:center center;padding:5px 22px 5px 10px;opacity:0.95;transition:opacity 0.2s ease;}.cv-annotation-container.svelte-ii1txw:hover .cv-empty-ribbon:where(.svelte-ii1txw) {opacity:1;}.cv-empty-ribbon--right.svelte-ii1txw {padding:5px 10px 5px 22px;}.cv-empty-ribbon--intro.svelte-ii1txw {\n animation: svelte-ii1txw-cv-wiggle-intro 0.75s ease-in-out forwards;}.cv-empty-ribbon--periodic.svelte-ii1txw {\n animation: svelte-ii1txw-cv-wiggle-periodic 5s ease-in-out infinite;}\n\n /* Dismiss button — hidden until container is hovered */.cv-empty-dismiss.svelte-ii1txw {position:absolute;border:none;background:rgba(100, 100, 100, 0.55);color:#fff;font-size:8px;cursor:pointer;width:14px;height:14px;display:flex;align-items:center;justify-content:center;padding:0;line-height:1;border-radius:50%;box-shadow:0 1px 4px rgba(0, 0, 0, 0.2);opacity:0;pointer-events:none;transition:opacity 0.15s ease, background 0.15s ease, color 0.15s ease;}.cv-annotation-container.svelte-ii1txw:hover .cv-empty-dismiss:where(.svelte-ii1txw) {opacity:1;pointer-events:auto;}.cv-empty-dismiss.svelte-ii1txw:hover {background:rgba(80, 80, 80, 0.8);box-shadow:0 1px 6px rgba(0, 0, 0, 0.28);}\n\n @keyframes svelte-ii1txw-cv-wiggle-intro {\n 0% { transform: rotate(0deg); }\n 10% { transform: rotate(-6deg); }\n 25% { transform: rotate(6deg); }\n 40% { transform: rotate(-5deg); }\n 55% { transform: rotate(5deg); }\n 68% { transform: rotate(-3deg); }\n 80% { transform: rotate(2.5deg); }\n 90% { transform: rotate(-1deg); }\n 100% { transform: rotate(0deg); }\n }\n\n @keyframes svelte-ii1txw-cv-wiggle-periodic {\n 0%, 85%, 100% { transform: rotate(0deg); }\n 87% { transform: rotate(1.2deg); }\n 90% { transform: rotate(-1.2deg); }\n 93% { transform: rotate(0.8deg); }\n 96% { transform: rotate(-0.5deg); }\n }'
15302
15384
  };
15303
15385
 
15304
15386
  function HighlightEmptyAnnotation($$anchor, $$props) {
15305
- append_styles$1($$anchor, $$css$8);
15387
+ append_styles$1($$anchor, $$css$9);
15306
15388
 
15307
15389
  const corner = user_derived(() => $$props.annotationCorner ?? DEFAULT_ANNOTATION_CORNER);
15308
15390
  const isRightCorner = user_derived(() => get(corner) === 'tr' || get(corner) === 'br');
@@ -15367,7 +15449,7 @@
15367
15449
 
15368
15450
  {
15369
15451
  var consequent = ($$anchor) => {
15370
- var div = root_1$5();
15452
+ var div = root_1$6();
15371
15453
  var div_1 = child(div);
15372
15454
  let classes;
15373
15455
  var button = sibling(div_1, 2);
@@ -15410,17 +15492,17 @@
15410
15492
  delegate(['click']);
15411
15493
 
15412
15494
  var root_2$3 = from_html(`<button type="button" aria-label="Previous highlight">↑</button> <button type="button" aria-label="Next highlight">↓</button>`, 1);
15413
- var root_1$4 = from_html(`<div class="cv-highlight-group svelte-1mz0neo"><div class="cv-highlight-marker svelte-1mz0neo"></div> <!> <div class="cv-highlight-pill svelte-1mz0neo"><a href="https://custardui.js.org" target="_blank" rel="noopener noreferrer" class="svelte-1mz0neo">Annotated by: CustardUI↗</a></div> <!></div>`);
15495
+ var root_1$5 = from_html(`<div class="cv-highlight-group svelte-1mz0neo"><div class="cv-highlight-marker svelte-1mz0neo"></div> <!> <div class="cv-highlight-pill svelte-1mz0neo"><a href="https://custardui.js.org" target="_blank" rel="noopener noreferrer" class="svelte-1mz0neo">Annotated by: CustardUI↗</a></div> <!></div>`);
15414
15496
  var root$8 = from_html(`<div class="cv-highlight-overlay svelte-1mz0neo"></div>`);
15415
15497
 
15416
- const $$css$7 = {
15498
+ const $$css$8 = {
15417
15499
  hash: 'svelte-1mz0neo',
15418
15500
  code: '.cv-highlight-overlay.svelte-1mz0neo {position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:8000;}.cv-highlight-group.svelte-1mz0neo {position:absolute;pointer-events:none;}.cv-highlight-marker.svelte-1mz0neo {position:absolute;inset:0;pointer-events:none;\n \n /* Marker Style */border:3.5px solid var(--cv-highlight-color);border-radius:200px 15px 225px 15px / 15px 225px 15px 255px;transform:rotate(-0.5deg);\n \n /* 3D INTERNAL VOLUME:\n Adds depth to the yellow border itself so it looks rounded.\n */box-shadow:inset 0 1px 2px rgba(129, 73, 25, 0.2),\n inset 0 -1px 1px rgba(255, 255, 255, 0.7);\n\n /* 2A-3 DOUBLE LIGHT PROJECTION:\n Stacks multiple drop-shadows to cast into the box interior.\n */filter:/* Sharp contact shadow for grounding */\n drop-shadow(0 2px 2px rgba(44, 26, 14, 0.15)) \n /* Light Source A: Casts shadow from top-left to bottom-right */\n drop-shadow(-8px 12px 10px rgba(44, 26, 14, 0.12))\n /* Light Source B: Casts shadow from top-right to bottom-left */\n drop-shadow(8px 12px 10px rgba(44, 26, 14, 0.12));\n \n animation: svelte-1mz0neo-highlightFadeIn 0.3s ease-out forwards;}.cv-nav-arrow.svelte-1mz0neo {position:absolute;z-index:10;right:-5px;pointer-events:auto;width:14px;height:14px;border-radius:100px;border:1px solid var(--cv-highlight-color);background:white;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:7px;color:#814919;font-weight:700;font-family:ui-sans-serif, system-ui, sans-serif;line-height:1;padding:0;box-shadow:0 4px 12px rgba(44, 26, 14, 0.15);opacity:0.7;}.cv-nav-arrow.svelte-1mz0neo:hover {opacity:1;}.cv-nav-arrow--up.svelte-1mz0neo {top:0px;}.cv-nav-arrow--down.svelte-1mz0neo {bottom:0px;}.cv-nav-arrow--hidden.svelte-1mz0neo {visibility:hidden;pointer-events:none;}.cv-highlight-pill.svelte-1mz0neo {position:absolute;z-index:10;bottom:-2px;right:14px;background:white;height:14px;padding:0 8px;display:flex;align-items:center;border-radius:100px;border:1px solid var(--cv-highlight-color);pointer-events:auto;white-space:nowrap;\n \n /* Stronger shadow to match the frame\'s new altitude */box-shadow:0 4px 12px rgba(44, 26, 14, 0.15);}.cv-highlight-pill.svelte-1mz0neo a:where(.svelte-1mz0neo) {font-size:8px;font-weight:700;color:#814919;text-decoration:none;font-family:ui-sans-serif, system-ui, sans-serif;line-height:1;}.cv-highlight-pill.svelte-1mz0neo:hover a:where(.svelte-1mz0neo) {opacity:0.8;}\n\n @keyframes svelte-1mz0neo-highlightFadeIn {\n from { \n opacity: 0; \n transform: scale(0.98) rotate(-1deg); \n }\n to { \n opacity: 1; \n transform: scale(1) rotate(-0.5deg); \n }\n }'
15419
15501
  };
15420
15502
 
15421
15503
  function HighlightOverlay($$anchor, $$props) {
15422
15504
  push($$props, true);
15423
- append_styles$1($$anchor, $$css$7);
15505
+ append_styles$1($$anchor, $$css$8);
15424
15506
 
15425
15507
  let rects = user_derived(() => $$props.box.rects);
15426
15508
 
@@ -15437,7 +15519,7 @@
15437
15519
  var div = root$8();
15438
15520
 
15439
15521
  each(div, 23, () => get(rects), (rect) => rect.element, ($$anchor, rect, i) => {
15440
- var div_1 = root_1$4();
15522
+ var div_1 = root_1$5();
15441
15523
  var node = sibling(child(div_1), 2);
15442
15524
 
15443
15525
  {
@@ -15629,7 +15711,6 @@
15629
15711
 
15630
15712
  /* highlight-service.svelte.ts generated by Svelte v5.46.1 */
15631
15713
 
15632
- const HIGHLIGHT_PARAM = 'cv-highlight';
15633
15714
  const BODY_HIGHLIGHT_CLASS = 'cv-highlight-mode';
15634
15715
 
15635
15716
  const ARROW_OVERLAY_ID = 'cv-highlight-overlay';
@@ -15851,8 +15932,6 @@
15851
15932
 
15852
15933
  /* focus-service.svelte.ts generated by Svelte v5.46.1 */
15853
15934
 
15854
- const SHOW_PARAM = 'cv-show';
15855
- const HIDE_PARAM = 'cv-hide';
15856
15935
  const BODY_SHOW_CLASS = 'cv-show-mode';
15857
15936
  const HIDDEN_CLASS = 'cv-hidden';
15858
15937
  const SHOW_ELEMENT_CLASS = 'cv-show-element';
@@ -15910,9 +15989,9 @@
15910
15989
  // eslint-disable-next-line svelte/prefer-svelte-reactivity
15911
15990
  const url = new URL(window.location.href);
15912
15991
 
15913
- const showDescriptors = url.searchParams.get(SHOW_PARAM);
15914
- const hideDescriptors = url.searchParams.get(HIDE_PARAM);
15915
- const highlightDescriptors = url.searchParams.get(HIGHLIGHT_PARAM);
15992
+ const showDescriptors = url.searchParams.get(PARAM_CV_SHOW);
15993
+ const hideDescriptors = url.searchParams.get(PARAM_CV_HIDE);
15994
+ const highlightDescriptors = url.searchParams.get(PARAM_CV_HIGHLIGHT);
15916
15995
  const hasAnyMode = showDescriptors || hideDescriptors || highlightDescriptors;
15917
15996
 
15918
15997
  if (!hasAnyMode) {
@@ -16198,18 +16277,18 @@
16198
16277
 
16199
16278
  let changed = false;
16200
16279
 
16201
- if (url.searchParams.has(SHOW_PARAM)) {
16202
- url.searchParams.delete(SHOW_PARAM);
16280
+ if (url.searchParams.has(PARAM_CV_SHOW)) {
16281
+ url.searchParams.delete(PARAM_CV_SHOW);
16203
16282
  changed = true;
16204
16283
  }
16205
16284
 
16206
- if (url.searchParams.has(HIDE_PARAM)) {
16207
- url.searchParams.delete(HIDE_PARAM);
16285
+ if (url.searchParams.has(PARAM_CV_HIDE)) {
16286
+ url.searchParams.delete(PARAM_CV_HIDE);
16208
16287
  changed = true;
16209
16288
  }
16210
16289
 
16211
- if (url.searchParams.has(HIGHLIGHT_PARAM)) {
16212
- url.searchParams.delete(HIGHLIGHT_PARAM);
16290
+ if (url.searchParams.has(PARAM_CV_HIGHLIGHT)) {
16291
+ url.searchParams.delete(PARAM_CV_HIGHLIGHT);
16213
16292
  changed = true;
16214
16293
  }
16215
16294
 
@@ -16226,6 +16305,131 @@
16226
16305
  }
16227
16306
  }
16228
16307
 
16308
+ /* label-registry-store.svelte.ts generated by Svelte v5.46.1 */
16309
+
16310
+ class LabelRegistryStore {
16311
+ _labels = new SvelteMap();
16312
+
16313
+ /**
16314
+ * Registers a label definition. Overwrites any existing entry with the same name.
16315
+ */
16316
+ register(def) {
16317
+ this._labels.set(def.name, { ...def });
16318
+ }
16319
+
16320
+ /**
16321
+ * Merges overrides onto an existing label entry.
16322
+ * Warns and skips if the label name is not registered.
16323
+ */
16324
+ override(name, overrides) {
16325
+ const existing = this._labels.get(name);
16326
+
16327
+ if (!existing) {
16328
+ console.warn(`[CustardUI] Label "${name}" is not in the config and cannot be overridden.`);
16329
+
16330
+ return;
16331
+ }
16332
+
16333
+ this._labels.set(name, { ...existing, ...overrides });
16334
+ }
16335
+
16336
+ /**
16337
+ * Returns the label definition for the given name, or undefined if not registered.
16338
+ */
16339
+ get(name) {
16340
+ return this._labels.get(name);
16341
+ }
16342
+ }
16343
+
16344
+ const labelRegistryStore = new LabelRegistryStore();
16345
+
16346
+ /**
16347
+ * Manages registration and adaptation overrides for label definitions.
16348
+ */
16349
+ const labelManager = {
16350
+ /**
16351
+ * Registers all labels from the config into the label registry store.
16352
+ */
16353
+ registerConfigLabels(config) {
16354
+ for (const label of (config.labels ?? [])) {
16355
+ labelRegistryStore.register(label);
16356
+ }
16357
+ },
16358
+ /**
16359
+ * Applies adaptation preset overrides to registered labels.
16360
+ * Unknown label names produce a warning and are skipped.
16361
+ */
16362
+ applyAdaptationOverrides(overrides) {
16363
+ for (const [name, override] of Object.entries(overrides)) {
16364
+ labelRegistryStore.override(name, override);
16365
+ }
16366
+ },
16367
+ };
16368
+
16369
+ /* color-scheme-store.svelte.ts generated by Svelte v5.46.1 */
16370
+
16371
+ class ColorSchemeStore {
16372
+ #isDark = state(false);
16373
+
16374
+ get isDark() {
16375
+ return get(this.#isDark);
16376
+ }
16377
+
16378
+ set isDark(value) {
16379
+ set(this.#isDark, value, true);
16380
+ }
16381
+
16382
+ #mq = null;
16383
+ #handler = null;
16384
+
16385
+ #removeListener() {
16386
+ if (this.#mq && this.#handler) {
16387
+ this.#mq.removeEventListener('change', this.#handler);
16388
+ this.#mq = null;
16389
+ this.#handler = null;
16390
+ }
16391
+ }
16392
+
16393
+ init(scheme = 'light') {
16394
+ this.#removeListener();
16395
+
16396
+ if (scheme === 'dark') {
16397
+ this.isDark = true;
16398
+
16399
+ return;
16400
+ }
16401
+
16402
+ if (scheme === 'auto') {
16403
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
16404
+ // SSR or environment without matchMedia — default to light
16405
+ this.isDark = false;
16406
+
16407
+ return;
16408
+ }
16409
+
16410
+ this.#mq = window.matchMedia('(prefers-color-scheme: dark)');
16411
+
16412
+ this.#handler = (e) => {
16413
+ this.isDark = e.matches;
16414
+ };
16415
+
16416
+ this.isDark = this.#mq.matches;
16417
+ this.#mq.addEventListener('change', this.#handler);
16418
+
16419
+ return;
16420
+ }
16421
+
16422
+ // 'light' (default)
16423
+ this.isDark = false;
16424
+ }
16425
+
16426
+ destroy() {
16427
+ this.#removeListener();
16428
+ }
16429
+ }
16430
+
16431
+ const colorSchemeStore = new ColorSchemeStore();
16432
+
16229
16433
  /**
16230
16434
  * DOM Scanner for Variable Interpolation
16231
16435
  *
@@ -16526,18 +16730,23 @@
16526
16730
 
16527
16731
  /* runtime.svelte.ts generated by Svelte v5.46.1 */
16528
16732
 
16529
- function stripAdaptationPlaceholders(state) {
16530
- if (!state.placeholders) return state;
16733
+ function stripSiteManaged(state) {
16734
+ // Strip siteManaged toggle values
16735
+ const siteManagedToggleIds = new Set((activeStateStore.config.toggles ?? []).filter((t) => t.siteManaged).map((t) => t.toggleId));
16531
16736
 
16532
- const filtered = {};
16737
+ const shownToggles = (state.shownToggles ?? []).filter((id) => !siteManagedToggleIds.has(id));
16738
+ const peekToggles = (state.peekToggles ?? []).filter((id) => !siteManagedToggleIds.has(id));
16533
16739
 
16534
- for (const [key, value] of Object.entries(state.placeholders)) {
16740
+ // Strip siteManaged placeholder keys
16741
+ const placeholders = {};
16742
+
16743
+ for (const [key, value] of Object.entries(state.placeholders ?? {})) {
16535
16744
  const def = placeholderRegistryStore.get(key);
16536
16745
 
16537
- if (!def?.adaptationPlaceholder) filtered[key] = value;
16746
+ if (!def?.siteManaged) placeholders[key] = value;
16538
16747
  }
16539
16748
 
16540
- return { ...state, placeholders: filtered };
16749
+ return { ...state, shownToggles, peekToggles, placeholders };
16541
16750
  }
16542
16751
 
16543
16752
  /**
@@ -16565,11 +16774,8 @@
16565
16774
  // Initialize adaptation store
16566
16775
  adaptationStore.init(opt.adaptationConfig ?? null);
16567
16776
 
16568
- // Store assetsManager for component access
16569
- derivedStore.setAssetsManager(opt.assetsManager);
16570
-
16571
16777
  // Initial State Resolution:
16572
- // URL (Sparse Override) > Persistence (Full) > Adaptation Defaults > Config Default
16778
+ // URL (Sparse Override) > Persistence (Full) > Adaptation Preset > Config Default
16573
16779
  this.resolveInitialState(opt.adaptationConfig ?? null);
16574
16780
 
16575
16781
  // Resolve Exclusions
@@ -16595,6 +16801,15 @@
16595
16801
  // Register tab-group placeholders AFTER global config placeholders to preserve precedence
16596
16802
  placeholderManager.registerTabGroupPlaceholders(config);
16597
16803
 
16804
+ // Register label definitions
16805
+ labelManager.registerConfigLabels(config);
16806
+
16807
+ // Initialize color scheme for site for general color resolution
16808
+ // Ensure any previous listeners cleaned up before re-initializing
16809
+ colorSchemeStore.destroy();
16810
+
16811
+ colorSchemeStore.init(configFile.colorScheme ?? 'light');
16812
+
16598
16813
  // Initialize UI Options from Settings
16599
16814
  uiStore.setUIOptions({
16600
16815
  showTabGroups: settings.showTabGroups ?? true,
@@ -16608,7 +16823,7 @@
16608
16823
  * Resolves the starting application state by layering sources:
16609
16824
  *
16610
16825
  * 1. **Baseline**: `ActiveStateStore` initializes with defaults from the config file.
16611
- * 2. **Adaptation Defaults**: If an adaptation is active, its defaults are applied
16826
+ * 2. **Adaptation Preset**: If an adaptation is active, its preset is applied
16612
16827
  * on top of the config defaults (before persisted state, so user choices can win).
16613
16828
  * 3. **Persistence**: If local storage has a saved state, it replaces the baseline (`applyState`).
16614
16829
  * 4. **URL Overrides**: If the URL contains parameters (`?t-show=X`), these are applied
@@ -16616,9 +16831,13 @@
16616
16831
  * retain their values from persistence/defaults.
16617
16832
  */
16618
16833
  resolveInitialState(adaptationConfig) {
16619
- // 1. Apply adaptation defaults on top of config defaults (before persisted state)
16620
- if (adaptationConfig?.defaults) {
16621
- activeStateStore.applyAdaptationDefaults(adaptationConfig.defaults);
16834
+ // 1. Apply adaptation preset on top of config defaults (before persisted state)
16835
+ if (adaptationConfig?.preset) {
16836
+ activeStateStore.applyAdaptationDefaults(adaptationConfig.preset);
16837
+
16838
+ if (adaptationConfig.preset.labels) {
16839
+ labelManager.applyAdaptationOverrides(adaptationConfig.preset.labels);
16840
+ }
16622
16841
  }
16623
16842
 
16624
16843
  // 2. Apply persisted base state on top of defaults (user choices win over adaptation defaults).
@@ -16674,7 +16893,7 @@
16674
16893
  this.destroyEffectRoot = effect_root(() => {
16675
16894
  // Automatic Persistence
16676
16895
  user_effect(() => {
16677
- this.persistenceManager.persistState(stripAdaptationPlaceholders(activeStateStore.state));
16896
+ this.persistenceManager.persistState(stripSiteManaged(activeStateStore.state));
16678
16897
  this.persistenceManager.persistTabNavVisibility(uiStore.isTabGroupNavHeadingVisible);
16679
16898
  });
16680
16899
 
@@ -16745,9 +16964,9 @@
16745
16964
  this.persistenceManager.clearAll();
16746
16965
  activeStateStore.reset();
16747
16966
 
16748
- // Re-apply adaptation defaults so adaptation-controlled placeholders are not wiped by reset.
16749
- if (adaptationStore.activeConfig?.defaults) {
16750
- activeStateStore.applyAdaptationDefaults(adaptationStore.activeConfig.defaults);
16967
+ // Re-apply adaptation preset so adaptation-controlled placeholders are not wiped by reset.
16968
+ if (adaptationStore.activeConfig?.preset) {
16969
+ activeStateStore.applyAdaptationDefaults(adaptationStore.activeConfig.preset);
16751
16970
  }
16752
16971
 
16753
16972
  uiStore.reset();
@@ -16758,6 +16977,7 @@
16758
16977
  this.observer?.disconnect();
16759
16978
  this.destroyEffectRoot?.();
16760
16979
  this.focusService.destroy();
16980
+ colorSchemeStore.destroy();
16761
16981
 
16762
16982
  if (this.onHashChange) {
16763
16983
  window.removeEventListener('hashchange', this.onHashChange);
@@ -16765,52 +16985,6 @@
16765
16985
  }
16766
16986
  }
16767
16987
 
16768
- class AssetsManager {
16769
- assets;
16770
- baseURL;
16771
- constructor(assets, baseURL = '') {
16772
- this.assets = assets;
16773
- this.baseURL = baseURL;
16774
- if (!this.validate()) {
16775
- console.warn('Invalid assets:', this.assets);
16776
- }
16777
- }
16778
- // Check each asset has content or src
16779
- validate() {
16780
- return Object.values(this.assets).every((a) => a.src || a.content);
16781
- }
16782
- get(assetId) {
16783
- const asset = this.assets[assetId];
16784
- if (!asset)
16785
- return undefined;
16786
- // If there's a baseURL and the asset has a src property, prepend the baseURL
16787
- if (this.baseURL && asset.src) {
16788
- // Create a shallow copy to avoid mutating the original asset
16789
- return {
16790
- ...asset,
16791
- src: this.prependBaseURL(asset.src),
16792
- };
16793
- }
16794
- return asset;
16795
- }
16796
- prependBaseURL(path) {
16797
- // Don't prepend if the path is already absolute (starts with http:// or https://)
16798
- if (path.startsWith('http://') || path.startsWith('https://')) {
16799
- return path;
16800
- }
16801
- // Ensure baseURL doesn't end with / and path starts with /
16802
- const cleanBaseURL = this.baseURL.endsWith('/') ? this.baseURL.slice(0, -1) : this.baseURL;
16803
- const cleanPath = path.startsWith('/') ? path : '/' + path;
16804
- return cleanBaseURL + cleanPath;
16805
- }
16806
- loadFromJSON(json) {
16807
- this.assets = json;
16808
- }
16809
- loadAdditionalAssets(additionalAssets) {
16810
- this.assets = { ...this.assets, ...additionalAssets };
16811
- }
16812
- }
16813
-
16814
16988
  var root$7 = from_svg(`<svg><polyline points="6 9 12 15 18 9"></polyline></svg>`);
16815
16989
 
16816
16990
  function IconChevronDown($$anchor, $$props) {
@@ -16853,86 +17027,9 @@
16853
17027
  append($$anchor, svg);
16854
17028
  }
16855
17029
 
16856
- /** --- Basic renderers --- */
16857
- function renderImage(el, asset) {
16858
- if (!asset.src)
16859
- return;
16860
- el.innerHTML = '';
16861
- const img = document.createElement('img');
16862
- img.src = asset.src;
16863
- img.alt = asset.alt || '';
16864
- // Apply custom styling if provided
16865
- if (asset.className) {
16866
- img.className = asset.className;
16867
- }
16868
- if (asset.style) {
16869
- img.setAttribute('style', asset.style);
16870
- }
16871
- // Default styles (can be overridden by asset.style)
16872
- img.style.maxWidth = img.style.maxWidth || '100%';
16873
- img.style.height = img.style.height || 'auto';
16874
- img.style.display = img.style.display || 'block';
16875
- el.appendChild(img);
16876
- }
16877
- function renderText(el, asset) {
16878
- if (asset.content != null) {
16879
- el.textContent = asset.content;
16880
- }
16881
- // Apply custom styling if provided
16882
- if (asset.className) {
16883
- el.className = asset.className;
16884
- }
16885
- if (asset.style) {
16886
- el.setAttribute('style', asset.style);
16887
- }
16888
- }
16889
- function renderHtml(el, asset) {
16890
- if (asset.content != null) {
16891
- el.innerHTML = asset.content;
16892
- }
16893
- // Apply custom styling if provided
16894
- if (asset.className) {
16895
- el.className = asset.className;
16896
- }
16897
- if (asset.style) {
16898
- el.setAttribute('style', asset.style);
16899
- }
16900
- }
16901
- /** --- Unified asset renderer --- */
16902
- function detectAssetType(asset) {
16903
- // If src exists, it's an image
16904
- if (asset.src)
16905
- return 'image';
16906
- // If content contains HTML tags, it's HTML
16907
- if (asset.content && /<[^>]+>/.test(asset.content)) {
16908
- return 'html';
16909
- }
16910
- return 'text';
16911
- }
16912
- function renderAssetInto(el, assetId, assetsManager) {
16913
- const asset = assetsManager.get(assetId);
16914
- if (!asset)
16915
- return;
16916
- const type = asset.type || detectAssetType(asset);
16917
- switch (type) {
16918
- case 'image':
16919
- renderImage(el, asset);
16920
- break;
16921
- case 'text':
16922
- renderText(el, asset);
16923
- break;
16924
- case 'html':
16925
- renderHtml(el, asset);
16926
- break;
16927
- default:
16928
- el.innerHTML = asset.content || String(asset);
16929
- console.warn('[Custard] Unknown asset type:', type);
16930
- }
16931
- }
16932
-
16933
17030
  var root_2$2 = from_html(`<span class="cv-placeholder-label svelte-1ka2eec"> </span>`);
16934
17031
  var root_3$1 = from_html(`<button type="button"></button>`);
16935
- var root_1$3 = from_html(`<div class="cv-toggle-placeholder svelte-1ka2eec" role="group"><!> <div class="cv-state-dots svelte-1ka2eec" role="group" aria-label="Visibility states"></div></div>`);
17032
+ var root_1$4 = from_html(`<div class="cv-toggle-placeholder svelte-1ka2eec" role="group"><!> <div class="cv-state-dots svelte-1ka2eec" role="group" aria-label="Visibility states"></div></div>`);
16936
17033
  var root_4 = from_html(`<div class="cv-toggle-label svelte-1ka2eec"> </div>`);
16937
17034
  var root_6 = from_html(`<button type="button"></button>`);
16938
17035
  var root_5 = from_html(`<div class="cv-state-dots cv-state-dots--floating svelte-1ka2eec" role="group" aria-label="Visibility states"></div>`);
@@ -16941,18 +17038,17 @@
16941
17038
  var root_7 = from_html(`<button type="button" class="cv-expand-btn svelte-1ka2eec"><!></button>`);
16942
17039
  var root$5 = from_html(`<!> <div><!> <!> <div class="cv-toggle-content svelte-1ka2eec"><div class="cv-toggle-inner svelte-1ka2eec"><!></div></div> <!></div>`, 1);
16943
17040
 
16944
- const $$css$6 = {
17041
+ const $$css$7 = {
16945
17042
  hash: 'svelte-1ka2eec',
16946
17043
  code: ':host {display:block;position:relative;z-index:1;overflow:visible;}\n\n /* Host visibility control */:host([hidden]) {display:none;}.cv-toggle-wrapper.svelte-1ka2eec {position:relative;width:100%;transition:all 0.35s cubic-bezier(0.4, 0, 0.2, 1);margin-bottom:4px;}.cv-toggle-wrapper.hidden.svelte-1ka2eec {margin-bottom:0;}.cv-toggle-wrapper.peek-mode.svelte-1ka2eec {margin-bottom:28px;}.cv-toggle-content.svelte-1ka2eec {overflow:hidden;transition:max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.3s ease,\n overflow 0s 0s;}.cv-toggle-inner.svelte-1ka2eec {display:flow-root; /* Ensures margins of children are contained */}\n\n /* Hidden State */.hidden.svelte-1ka2eec .cv-toggle-content:where(.svelte-1ka2eec) {opacity:0;pointer-events:none;}\n\n /* Bordered State */.has-border.svelte-1ka2eec {box-sizing:border-box;border:2px dashed rgba(0, 0, 0, 0.15);border-bottom:none;box-shadow:0 2px 8px rgba(0, 0, 0, 0.05),\n inset 0 -15px 10px -10px rgba(0, 0, 0, 0.1);border-radius:8px 8px 0 0;padding:12px 0 0 0;margin-top:4px;}\n\n /* Visible / Expanded State */.expanded.svelte-1ka2eec .cv-toggle-content:where(.svelte-1ka2eec) {opacity:1;transform:translateY(0);overflow:visible;transition:max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.3s ease,\n overflow 0s 0.35s;}\n\n /* When expanded, complete the border */.has-border.expanded.svelte-1ka2eec {border-bottom:2px dashed rgba(0, 0, 0, 0.15);border-radius:8px;padding-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.05);}\n\n /* Peek State — smoother gradient */.peeking.svelte-1ka2eec .cv-toggle-content:where(.svelte-1ka2eec) {opacity:1;mask-image:linear-gradient(to bottom, black 30%, rgba(0,0,0,0.5) 70%, transparent 100%);-webkit-mask-image:linear-gradient(to bottom, black 30%, rgba(0,0,0,0.5) 70%, transparent 100%);}\n\n /* Label Style */.cv-toggle-label.svelte-1ka2eec {position:absolute;top:-12px;left:0;background:#e0e0e0;color:#333;font-size:0.75rem;font-weight:600;padding:2px 8px;border-radius:4px;z-index:10;pointer-events:auto;box-shadow:0 1px 2px rgba(0, 0, 0, 0.1);}\n\n /* Adjust label position if bordered */.has-border.svelte-1ka2eec .cv-toggle-label:where(.svelte-1ka2eec) {top:-10px;left:0;}\n\n /* Hidden-state placeholder bar */.cv-toggle-placeholder.svelte-1ka2eec {display:flex;align-items:center;justify-content:space-between;padding:4px 8px;min-height:24px;border:1px solid rgba(0, 0, 0, 0.06);border-radius:6px;background:rgba(0, 0, 0, 0.015);margin-bottom:4px;transition:border-color 0.2s ease, background 0.2s ease;}.cv-toggle-placeholder.svelte-1ka2eec:hover {border-color:rgba(0, 0, 0, 0.12);background:rgba(0, 0, 0, 0.025);}.cv-placeholder-label.svelte-1ka2eec {font-size:0.7rem;font-weight:500;color:rgba(0, 0, 0, 0.35);letter-spacing:0.02em;user-select:none;}\n\n /* 3-dot state indicator */.cv-state-dots.svelte-1ka2eec {display:flex;align-items:center;gap:5px;}\n\n /* Floating position (top-right of content) */.cv-state-dots--floating.svelte-1ka2eec {position:absolute;top:-2px;right:0;z-index:10;opacity:0;transition:opacity 0.2s ease;}.cv-toggle-wrapper.svelte-1ka2eec:hover .cv-state-dots--floating:where(.svelte-1ka2eec),\n .cv-state-dots--floating.svelte-1ka2eec:focus-within {opacity:1;}\n\n /* Adjust floating dots when bordered */.has-border.svelte-1ka2eec .cv-state-dots--floating:where(.svelte-1ka2eec) {top:4px;right:8px;}.cv-dot.svelte-1ka2eec {position:relative;width:7px;height:7px;border-radius:50%;border:1.5px solid rgba(0, 0, 0, 0.2);background:transparent;padding:0;cursor:pointer;transition:all 0.15s ease;flex-shrink:0;}\n\n /* Expand tap target to ~20px while keeping dot visually small */.cv-dot.svelte-1ka2eec::before {content:\'\';position:absolute;top:50%;left:50%;width:20px;height:20px;transform:translate(-50%, -50%);border-radius:50%;}.cv-dot.svelte-1ka2eec:hover {border-color:rgba(0, 0, 0, 0.5);transform:scale(1.3);}.cv-dot.active.svelte-1ka2eec {background:var(--cv-primary, #3E84F4);border-color:var(--cv-primary, #3E84F4);}.cv-dot.active.svelte-1ka2eec:hover {transform:scale(1.3);}\n\n /* Expand Button — upgraded to pill style */.cv-expand-btn.svelte-1ka2eec {position:absolute;bottom:-28px;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:4px;background:rgba(0, 0, 0, 0.04);border:1px solid rgba(0, 0, 0, 0.08);border-radius:999px;padding:3px 12px;cursor:pointer;z-index:100;color:#666;font-size:0.7rem;font-weight:500;font-family:inherit;line-height:1;transition:all 0.2s ease;}.cv-expand-btn.svelte-1ka2eec:hover {background:rgba(0, 0, 0, 0.08);border-color:rgba(0, 0, 0, 0.15);color:#333;transform:translateX(-50%) scale(1.02);}.cv-expand-btn.svelte-1ka2eec svg {display:block;width:14px;height:14px;opacity:0.6;flex-shrink:0;}.cv-expand-btn.svelte-1ka2eec:hover svg {opacity:1;}.cv-expand-label.svelte-1ka2eec {white-space:nowrap;}'
16947
17044
  };
16948
17045
 
16949
17046
  function Toggle($$anchor, $$props) {
16950
17047
  push($$props, true);
16951
- append_styles$1($$anchor, $$css$6);
17048
+ append_styles$1($$anchor, $$css$7);
16952
17049
 
16953
17050
  // Props using Svelte 5 runes
16954
17051
  let toggleId = prop($$props, 'toggleId', 7, ''),
16955
- assetId = prop($$props, 'assetId', 7, ''),
16956
17052
  showPeekBorder = prop($$props, 'showPeekBorder', 7, false),
16957
17053
  showLabel = prop($$props, 'showLabel', 7, false),
16958
17054
  showInlineControl = prop($$props, 'showInlineControl', 7, false),
@@ -16993,6 +17089,8 @@
16993
17089
  if (placeholderId()) elementStore.registerPlaceholder(get(placeholderName));
16994
17090
  });
16995
17091
 
17092
+ let isSiteManaged = user_derived(() => get(toggleConfig)?.siteManaged ?? false);
17093
+
16996
17094
  // Derive label text from config
16997
17095
  let labelText = user_derived(() => {
16998
17096
  if (!get(toggleConfig)) return '';
@@ -17002,7 +17100,6 @@
17002
17100
 
17003
17101
  let localExpanded = state(false);
17004
17102
  let isUnconstrained = state(false /* New state to track if we can release max-height */);
17005
- let hasRendered = state(false);
17006
17103
  let contentEl;
17007
17104
  let innerEl;
17008
17105
  let scrollHeight = state(0);
@@ -17121,14 +17218,6 @@
17121
17218
  get(toggleIds).forEach((id) => activeStateStore.updateToggleState(id, targetState));
17122
17219
  }
17123
17220
 
17124
- // Reactive asset rendering - renders assets when toggle becomes visible
17125
- user_effect(() => {
17126
- if (get(showFullContent) && assetId() && !get(hasRendered) && derivedStore.assetsManager && contentEl) {
17127
- renderAssetInto(contentEl, assetId(), derivedStore.assetsManager);
17128
- set(hasRendered, true);
17129
- }
17130
- });
17131
-
17132
17221
  var $$exports = {
17133
17222
  get toggleId() {
17134
17223
  return toggleId();
@@ -17139,15 +17228,6 @@
17139
17228
  flushSync();
17140
17229
  },
17141
17230
 
17142
- get assetId() {
17143
- return assetId();
17144
- },
17145
-
17146
- set assetId($$value = '') {
17147
- assetId($$value);
17148
- flushSync();
17149
- },
17150
-
17151
17231
  get showPeekBorder() {
17152
17232
  return showPeekBorder();
17153
17233
  },
@@ -17190,7 +17270,7 @@
17190
17270
 
17191
17271
  {
17192
17272
  var consequent_1 = ($$anchor) => {
17193
- var div = root_1$3();
17273
+ var div = root_1$4();
17194
17274
  var node_1 = child(div);
17195
17275
 
17196
17276
  {
@@ -17238,7 +17318,7 @@
17238
17318
  };
17239
17319
 
17240
17320
  if_block(node, ($$render) => {
17241
- if (showInlineControl() && !get(isPlaceholderMode) && get(isHidden)) $$render(consequent_1);
17321
+ if (showInlineControl() && !get(isPlaceholderMode) && !get(isSiteManaged) && get(isHidden)) $$render(consequent_1);
17242
17322
  });
17243
17323
  }
17244
17324
 
@@ -17293,7 +17373,7 @@
17293
17373
  };
17294
17374
 
17295
17375
  if_block(node_3, ($$render) => {
17296
- if (showInlineControl() && !get(isPlaceholderMode) && !get(isHidden)) $$render(consequent_3);
17376
+ if (showInlineControl() && !get(isPlaceholderMode) && !get(isSiteManaged) && !get(isHidden)) $$render(consequent_3);
17297
17377
  });
17298
17378
  }
17299
17379
 
@@ -17361,7 +17441,7 @@
17361
17441
  'peek-mode': get(peekState),
17362
17442
  hidden: get(isHidden),
17363
17443
  'has-border': showPeekBorder() && get(peekState),
17364
- 'has-inline-control': showInlineControl() && !get(isPlaceholderMode)
17444
+ 'has-inline-control': showInlineControl() && !get(isPlaceholderMode) && !get(isSiteManaged)
17365
17445
  });
17366
17446
 
17367
17447
  styles = set_style(div_5, '', styles, { 'max-height': get(currentMaxHeight) });
@@ -17379,7 +17459,6 @@
17379
17459
  Toggle,
17380
17460
  {
17381
17461
  toggleId: { attribute: 'toggle-id', reflect: true, type: 'String' },
17382
- assetId: { attribute: 'asset-id', reflect: true, type: 'String' },
17383
17462
 
17384
17463
  showPeekBorder: {
17385
17464
  attribute: 'show-peek-border',
@@ -17404,14 +17483,14 @@
17404
17483
 
17405
17484
  var root$4 = from_html(`<div><!></div>`);
17406
17485
 
17407
- const $$css$5 = {
17486
+ const $$css$6 = {
17408
17487
  hash: 'svelte-8qj5x2',
17409
17488
  code: ':host {display:block;}:host(.cv-hidden) {display:none !important;}:host(.cv-visible) {display:block !important;}:host([active=\'true\']) {display:block;}.cv-tab-content.svelte-8qj5x2 {display:none;\n animation: svelte-8qj5x2-fade-in 0.2s ease-in-out;padding-top:1rem;padding-bottom:0.5rem;padding-left:0;padding-right:0;}.cv-tab-content.active.svelte-8qj5x2 {display:block;}\n\n /* Hide cv-tab-header source element; content is extracted to nav link */.svelte-8qj5x2::slotted(cv-tab-header) {display:none !important;}\n\n /* Allow cv-tab-body to flow naturally */.svelte-8qj5x2::slotted(cv-tab-body) {display:block;}\n\n @keyframes svelte-8qj5x2-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }'
17410
17489
  };
17411
17490
 
17412
17491
  function Tab($$anchor, $$props) {
17413
17492
  push($$props, true);
17414
- append_styles$1($$anchor, $$css$5);
17493
+ append_styles$1($$anchor, $$css$6);
17415
17494
 
17416
17495
  // Props using Svelte 5 runes
17417
17496
  // tabId and header are used in TabGroup directly.
@@ -17453,7 +17532,7 @@
17453
17532
  true
17454
17533
  ));
17455
17534
 
17456
- var root_1$2 = from_svg(`<path d="M4 2v13l4-2.5L12 15V2H4z"></path>`);
17535
+ var root_1$3 = from_svg(`<path d="M4 2v13l4-2.5L12 15V2H4z"></path>`);
17457
17536
  var root_2$1 = from_svg(`<path d="M4 2v13l4-2.5L12 15V2H4zm1 1h6v10.5l-3-1.88L5 13.5V3z"></path>`);
17458
17537
  var root$3 = from_svg(`<svg><!></svg>`);
17459
17538
 
@@ -17480,7 +17559,7 @@
17480
17559
 
17481
17560
  {
17482
17561
  var consequent = ($$anchor) => {
17483
- var path = root_1$2();
17562
+ var path = root_1$3();
17484
17563
 
17485
17564
  append($$anchor, path);
17486
17565
  };
@@ -17501,18 +17580,18 @@
17501
17580
  }
17502
17581
 
17503
17582
  var root_2 = from_html(`<li class="cv-tabgroup-item svelte-1ujqpe3"><div><a role="tab" title="Double-click a tab to 'mark' it in all similar tab groups."><span class="cv-tab-header-text svelte-1ujqpe3"><!></span></a> <button type="button"><!></button></div></li>`);
17504
- var root_1$1 = from_html(`<ul class="cv-tabgroup-nav svelte-1ujqpe3" role="tablist"></ul>`);
17583
+ var root_1$2 = from_html(`<ul class="cv-tabgroup-nav svelte-1ujqpe3" role="tablist"></ul>`);
17505
17584
  var root_3 = from_html(`<link rel="stylesheet"/>`);
17506
17585
  var root$2 = from_html(`<div class="cv-tabgroup-container"><!> <!> <div class="cv-tabgroup-content"><!></div> <div class="cv-tabgroup-bottom-border svelte-1ujqpe3"></div></div>`);
17507
17586
 
17508
- const $$css$4 = {
17587
+ const $$css$5 = {
17509
17588
  hash: 'svelte-1ujqpe3',
17510
17589
  code: ':host {display:block;margin-bottom:24px;}\n\n /* Tab navigation styles */ul.cv-tabgroup-nav.svelte-1ujqpe3 {display:flex;flex-wrap:wrap;padding-left:0;margin-top:0.5rem;margin-bottom:0;list-style:none;border-bottom:1px solid var(--cv-border, rgba(128, 128, 128, 0.3));align-items:stretch;gap:0.5rem;}.cv-tabgroup-item.svelte-1ujqpe3 {margin-bottom:-1px;list-style:none;display:flex;align-items:stretch;}.cv-tabgroup-link.svelte-1ujqpe3 {display:flex;align-items:center;justify-content:center;padding:0.5rem 0.75rem;color:inherit;opacity:0.7;text-decoration:none;background-color:transparent !important;border:none;border-bottom:2px solid transparent;transition:opacity 0.15s ease-in-out,\n border-color 0.15s ease-in-out;cursor:pointer;min-height:2.5rem;box-sizing:border-box;font-weight:500;}.cv-tabgroup-link.svelte-1ujqpe3 p {margin:0;display:inline;}.cv-tabgroup-link.svelte-1ujqpe3:hover,\n .cv-tabgroup-link.svelte-1ujqpe3:focus {opacity:1;border-bottom-color:var(--cv-border, rgba(128, 128, 128, 0.3));isolation:isolate;}.cv-tabgroup-link.active.svelte-1ujqpe3 {opacity:1;background-color:transparent !important;}.cv-tabgroup-link.svelte-1ujqpe3:focus {outline:0;}.cv-tab-wrapper.svelte-1ujqpe3 {display:flex;align-items:center;border-bottom:2px solid transparent;transition:border-color 0.15s ease-in-out;}.cv-tab-wrapper.svelte-1ujqpe3:hover,\n .cv-tab-wrapper.svelte-1ujqpe3:focus-within {border-bottom-color:var(--cv-border, rgba(128, 128, 128, 0.3));}.cv-tab-wrapper.active.svelte-1ujqpe3 {border-bottom-color:currentColor;}.cv-tab-header-text.svelte-1ujqpe3 {line-height:1;}.cv-tab-marked-icon.svelte-1ujqpe3 {display:inline-flex;align-items:center;justify-content:center;line-height:0;flex-shrink:0;opacity:0;transition:opacity 0.15s ease-out;background:none;border:none;padding:0 8px 0 0;margin:0;cursor:pointer;color:inherit;height:100%;}.cv-tab-wrapper.svelte-1ujqpe3:hover .cv-tab-marked-icon:where(.svelte-1ujqpe3),\n .cv-tab-wrapper.svelte-1ujqpe3:focus-within .cv-tab-marked-icon:where(.svelte-1ujqpe3),\n .cv-tab-marked-icon.is-marked.svelte-1ujqpe3 {opacity:1;}.cv-tab-marked-icon.svelte-1ujqpe3 svg {vertical-align:middle;width:14px;height:14px;}.cv-tabgroup-bottom-border.svelte-1ujqpe3 {border-bottom:1px solid var(--cv-border, rgba(128, 128, 128, 0.3));}\n\n @media print {ul.cv-tabgroup-nav.svelte-1ujqpe3 {display:none !important;}\n }'
17511
17590
  };
17512
17591
 
17513
17592
  function TabGroup($$anchor, $$props) {
17514
17593
  push($$props, true);
17515
- append_styles$1($$anchor, $$css$4);
17594
+ append_styles$1($$anchor, $$css$5);
17516
17595
 
17517
17596
  // ID of the tabgroup Group
17518
17597
  let groupId = prop($$props, 'groupId', 7),
@@ -17745,7 +17824,7 @@
17745
17824
 
17746
17825
  {
17747
17826
  var consequent = ($$anchor) => {
17748
- var ul = root_1$1();
17827
+ var ul = root_1$2();
17749
17828
 
17750
17829
  each(ul, 21, () => get(tabs), (tab) => tab.id, ($$anchor, tab) => {
17751
17830
  const splitIds = user_derived(() => splitTabIds(get(tab).rawId));
@@ -17855,13 +17934,13 @@
17855
17934
  true
17856
17935
  ));
17857
17936
 
17858
- const $$css$3 = {
17937
+ const $$css$4 = {
17859
17938
  hash: 'svelte-1hl11lz',
17860
17939
  code: ':host {display:none; /* Semantic container only, usually read by parent and hidden */}'
17861
17940
  };
17862
17941
 
17863
17942
  function TabHeader($$anchor, $$props) {
17864
- append_styles$1($$anchor, $$css$3);
17943
+ append_styles$1($$anchor, $$css$4);
17865
17944
 
17866
17945
  var fragment = comment();
17867
17946
  var node = first_child(fragment);
@@ -17873,10 +17952,10 @@
17873
17952
 
17874
17953
  customElements.define('cv-tab-header', create_custom_element(TabHeader, {}, ['default'], [], true));
17875
17954
 
17876
- const $$css$2 = { hash: 'svelte-eizj8y', code: ':host {display:block;}' };
17955
+ const $$css$3 = { hash: 'svelte-eizj8y', code: ':host {display:block;}' };
17877
17956
 
17878
17957
  function TabBody($$anchor, $$props) {
17879
- append_styles$1($$anchor, $$css$2);
17958
+ append_styles$1($$anchor, $$css$3);
17880
17959
 
17881
17960
  var fragment = comment();
17882
17961
  var node = first_child(fragment);
@@ -17889,11 +17968,11 @@
17889
17968
  customElements.define('cv-tab-body', create_custom_element(TabBody, {}, ['default'], [], true));
17890
17969
 
17891
17970
  var root$1 = from_html(`<span class="cv-var"> </span>`);
17892
- const $$css$1 = { hash: 'svelte-1tffxwo', code: ':host {display:inline;}' };
17971
+ const $$css$2 = { hash: 'svelte-1tffxwo', code: ':host {display:inline;}' };
17893
17972
 
17894
17973
  function Placeholder($$anchor, $$props) {
17895
17974
  push($$props, true);
17896
- append_styles$1($$anchor, $$css$1);
17975
+ append_styles$1($$anchor, $$css$2);
17897
17976
 
17898
17977
  let name = prop($$props, 'name', 7),
17899
17978
  fallback = prop($$props, 'fallback', 7),
@@ -18017,17 +18096,17 @@
18017
18096
  true
18018
18097
  ));
18019
18098
 
18020
- var root_1 = from_html(`<label class="placeholder-label svelte-dpk3ag"> </label>`);
18099
+ var root_1$1 = from_html(`<label class="placeholder-label svelte-dpk3ag"> </label>`);
18021
18100
  var root = from_html(`<div><!> <input type="text"/></div>`);
18022
18101
 
18023
- const $$css = {
18102
+ const $$css$1 = {
18024
18103
  hash: 'svelte-dpk3ag',
18025
18104
  code: ':host {display:inline-block;width:auto;margin:0 0.25rem; /* Add breathing room for inline text */}\n\n /* Host display overrides based on layout */:host([layout=\'stacked\']),\n :host([layout=\'horizontal\']) {display:block;width:100%;margin:0 0 0.5rem 0; /* Reset margins for block layouts */}\n \n /* Wrapper Grid/Flex Layouts */.cv-input-wrapper.svelte-dpk3ag {display:flex;width:100%;box-sizing:border-box;}\n\n /* INLINE */.cv-input-wrapper.inline.svelte-dpk3ag {display:inline-block;width:auto;}\n\n /* STACKED */.cv-input-wrapper.stacked.svelte-dpk3ag {flex-direction:column;gap:0.25rem;}\n\n /* HORIZONTAL */.cv-input-wrapper.horizontal.svelte-dpk3ag {flex-direction:row;align-items:center;gap:0.75rem;}\n\n /* Label Styles */.placeholder-label.svelte-dpk3ag {font-size:0.85rem;font-weight:500;color:var(--cv-text, #333);white-space:nowrap;}.stacked.svelte-dpk3ag .placeholder-label:where(.svelte-dpk3ag) {margin-bottom:2px;width:100%; /* Ensure label context is full width */text-align:left; /* Reset text align */}\n\n /* Input Styles */.placeholder-input.svelte-dpk3ag {padding:0.5rem 0.75rem;border:1px solid var(--cv-input-border, rgba(0, 0, 0, 0.1));border-radius:0.375rem;font-size:0.9rem;transition:all 0.2s;background:var(--cv-input-bg, white);color:var(--cv-text, #333);box-sizing:border-box;width:100%;}.stacked.svelte-dpk3ag .placeholder-input:where(.svelte-dpk3ag) {width:100%;}.inline.svelte-dpk3ag .placeholder-input:where(.svelte-dpk3ag) {width:var(--cv-input-width, auto);padding:0.3rem 0.5rem;display:inline-block;text-align:center;}.horizontal.svelte-dpk3ag .placeholder-input:where(.svelte-dpk3ag) {width:var(--cv-input-width, auto);flex:1;}\n\n /* APPEARANCES */\n \n /* Outline (Default) - handled by base styles above */\n\n /* Underline */.placeholder-input.underline.svelte-dpk3ag {border:none;border-bottom:1px solid var(--cv-input-border, rgba(0, 0, 0, 0.2));border-radius:0;background:transparent;padding-left:0;padding-right:0;}.placeholder-input.underline.svelte-dpk3ag:focus {box-shadow:none;border-bottom-color:var(--cv-primary, #3e84f4);}\n\n /* Ghost */.placeholder-input.ghost.svelte-dpk3ag {border-color:transparent;background:transparent;}.placeholder-input.ghost.svelte-dpk3ag:hover {background:var(--cv-input-bg-hover, rgba(0,0,0,0.05));}.placeholder-input.ghost.svelte-dpk3ag:focus {background:var(--cv-input-bg, white);border-color:var(--cv-primary, #3e84f4);box-shadow:0 0 0 2px var(--cv-focus-ring, rgba(62, 132, 244, 0.2));}\n\n /* Focus states for standard inputs */.placeholder-input.svelte-dpk3ag:not(.underline):focus {outline:none;border-color:var(--cv-primary, #3e84f4);box-shadow:0 0 0 2px var(--cv-focus-ring, rgba(62, 132, 244, 0.2));}'
18026
18105
  };
18027
18106
 
18028
18107
  function PlaceholderInput($$anchor, $$props) {
18029
18108
  push($$props, true);
18030
- append_styles$1($$anchor, $$css);
18109
+ append_styles$1($$anchor, $$css$1);
18031
18110
 
18032
18111
  let name = prop($$props, 'name', 7),
18033
18112
  label = prop($$props, 'label', 7),
@@ -18139,7 +18218,7 @@
18139
18218
 
18140
18219
  {
18141
18220
  var consequent = ($$anchor) => {
18142
- var label_1 = root_1();
18221
+ var label_1 = root_1$1();
18143
18222
  var text = child(label_1, true);
18144
18223
 
18145
18224
  reset(label_1);
@@ -18200,6 +18279,178 @@
18200
18279
  true
18201
18280
  ));
18202
18281
 
18282
+ /**
18283
+ * Single-letter shorthand color aliases.
18284
+ * Each maps to a light-theme and dark-theme hex value.
18285
+ */
18286
+ const SHORTHAND_COLORS = {
18287
+ r: { light: '#fca5a5', dark: '#dc2626' }, // Pale red / Deep red
18288
+ g: { light: '#4ade80', dark: '#16a34a' }, // Neon green / Forest green
18289
+ b: { light: '#93c5fd', dark: '#2563eb' }, // Light blue / Royal blue
18290
+ c: { light: '#67e8f9', dark: '#0d9488' }, // Aqua cyan / Teal cyan
18291
+ m: { light: '#f0abfc', dark: '#a21caf' }, // Bright magenta / Deep magenta
18292
+ y: { light: '#fde047', dark: '#92400e' }, // Bright yellow / Golden yellow
18293
+ w: { light: '#f1f5f9', dark: '#94a3b8' }, // White / Silver grey
18294
+ k: { light: '#e2e8f0', dark: '#0f172a' }, // Light grey / Pure black
18295
+ };
18296
+ /**
18297
+ * Resolves a color value, expanding single-letter shorthands to hex.
18298
+ * Pass `isDark=true` to get the dark-theme variant of a shorthand.
18299
+ * Non-shorthand values are returned unchanged.
18300
+ */
18301
+ function resolveColor(color, isDark) {
18302
+ const trimmed = color.trim();
18303
+ const entry = SHORTHAND_COLORS[trimmed];
18304
+ if (entry)
18305
+ return isDark ? entry.dark : entry.light;
18306
+ return trimmed;
18307
+ }
18308
+ /**
18309
+ * Computes a contrasting text color (black or white) for a given background color.
18310
+ * Supports #rrggbb and #rgb hex strings. Falls back to white for non-hex inputs.
18311
+ */
18312
+ function computeTextColor(bgColor) {
18313
+ const hex = bgColor.replace(/^#/, '');
18314
+ let r, g, b;
18315
+ if (hex.length === 3) {
18316
+ r = parseInt((hex[0] ?? '') + (hex[0] ?? ''), 16);
18317
+ g = parseInt((hex[1] ?? '') + (hex[1] ?? ''), 16);
18318
+ b = parseInt((hex[2] ?? '') + (hex[2] ?? ''), 16);
18319
+ }
18320
+ else if (hex.length === 6) {
18321
+ r = parseInt(hex.slice(0, 2), 16);
18322
+ g = parseInt(hex.slice(2, 4), 16);
18323
+ b = parseInt(hex.slice(4, 6), 16);
18324
+ }
18325
+ else {
18326
+ return '#ffffff';
18327
+ }
18328
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
18329
+ return luminance > 0.5 ? '#000000' : '#ffffff';
18330
+ }
18331
+
18332
+ var root_1 = from_html(`<span class="cv-label svelte-10fc57e"><!></span>`);
18333
+
18334
+ const $$css = {
18335
+ hash: 'svelte-10fc57e',
18336
+ code: ':host {display:inline;}.cv-label.svelte-10fc57e {display:inline-flex;align-items:center;padding:1px 8px;border-radius:999px;font-size:0.75em;font-weight:600;white-space:nowrap;line-height:1.5;letter-spacing:0.02em;vertical-align:middle;}'
18337
+ };
18338
+
18339
+ function Label($$anchor, $$props) {
18340
+ push($$props, true);
18341
+ append_styles$1($$anchor, $$css);
18342
+
18343
+ let name = prop($$props, 'name', 7, ''),
18344
+ color = prop($$props, 'color', 7, '');
18345
+
18346
+ const DEFAULT_COLOR = '#6b7280';
18347
+ let hasSlotContent = state(false);
18348
+
18349
+ user_effect(() => {
18350
+ const host = $$props.$$host;
18351
+
18352
+ function update() {
18353
+ set(hasSlotContent, Array.from(host.childNodes).some((n) => n.nodeType === Node.ELEMENT_NODE || (n.textContent?.trim() ?? '') !== ''), true);
18354
+ }
18355
+
18356
+ update();
18357
+
18358
+ const observer = new MutationObserver(update);
18359
+
18360
+ observer.observe(host, { childList: true, characterData: true, subtree: true });
18361
+
18362
+ return () => observer.disconnect();
18363
+ });
18364
+
18365
+ let labelDef = user_derived(() => labelRegistryStore.get(name()));
18366
+ let rawColor = user_derived(() => get(labelDef)?.color ?? (color() || DEFAULT_COLOR));
18367
+ let bgColor = user_derived(() => resolveColor(get(rawColor), colorSchemeStore.isDark));
18368
+ let textColor = user_derived(() => computeTextColor(get(bgColor)));
18369
+
18370
+ var $$exports = {
18371
+ get name() {
18372
+ return name();
18373
+ },
18374
+
18375
+ set name($$value = '') {
18376
+ name($$value);
18377
+ flushSync();
18378
+ },
18379
+
18380
+ get color() {
18381
+ return color();
18382
+ },
18383
+
18384
+ set color($$value = '') {
18385
+ color($$value);
18386
+ flushSync();
18387
+ }
18388
+ };
18389
+
18390
+ var fragment = comment();
18391
+ var node = first_child(fragment);
18392
+
18393
+ {
18394
+ var consequent_1 = ($$anchor) => {
18395
+ var span = root_1();
18396
+ let styles;
18397
+ var node_1 = child(span);
18398
+
18399
+ {
18400
+ var consequent = ($$anchor) => {
18401
+ var text$1 = text();
18402
+
18403
+ template_effect(() => set_text(text$1, get(labelDef).value));
18404
+ append($$anchor, text$1);
18405
+ };
18406
+
18407
+ var alternate = ($$anchor) => {
18408
+ var fragment_2 = comment();
18409
+ var node_2 = first_child(fragment_2);
18410
+
18411
+ slot(node_2, $$props, 'default', {});
18412
+ append($$anchor, fragment_2);
18413
+ };
18414
+
18415
+ if_block(node_1, ($$render) => {
18416
+ if (get(labelDef)?.value) $$render(consequent); else $$render(alternate, false);
18417
+ });
18418
+ }
18419
+
18420
+ reset(span);
18421
+ template_effect(() => styles = set_style(span, '', styles, { background: get(bgColor), color: get(textColor) }));
18422
+ append($$anchor, span);
18423
+ };
18424
+
18425
+ var alternate_1 = ($$anchor) => {
18426
+ var fragment_3 = comment();
18427
+ var node_3 = first_child(fragment_3);
18428
+
18429
+ slot(node_3, $$props, 'default', {});
18430
+ append($$anchor, fragment_3);
18431
+ };
18432
+
18433
+ if_block(node, ($$render) => {
18434
+ if (get(labelDef)?.value || get(hasSlotContent)) $$render(consequent_1); else $$render(alternate_1, false);
18435
+ });
18436
+ }
18437
+
18438
+ append($$anchor, fragment);
18439
+
18440
+ return pop($$exports);
18441
+ }
18442
+
18443
+ customElements.define('cv-label', create_custom_element(
18444
+ Label,
18445
+ {
18446
+ name: { attribute: 'name', reflect: true, type: 'String' },
18447
+ color: { attribute: 'color', reflect: true, type: 'String' }
18448
+ },
18449
+ ['default'],
18450
+ [],
18451
+ true
18452
+ ));
18453
+
18203
18454
  // --- No Public API Exports ---
18204
18455
  // The script auto-initializes via initializeFromScript().
18205
18456
  /**
@@ -18225,7 +18476,7 @@
18225
18476
  // Fetch Config first to retrieve storageKey prefix
18226
18477
  const configFile = await fetchConfig(configPath, baseURL);
18227
18478
  // Determine effective baseURL (data attribute takes precedence)
18228
- const effectiveBaseURL = baseURL || configFile.baseUrl || '';
18479
+ const effectiveBaseURL = baseURL;
18229
18480
  // Initialize Adaptation early (before AppRuntime):
18230
18481
  // - Theme CSS injected ASAP (FOUC prevention)
18231
18482
  // - ?adapt= param cleaned before URLStateManager.parseURL() runs
@@ -18234,24 +18485,7 @@
18234
18485
  if (adaptationConfig?.id) {
18235
18486
  AdaptationManager.rewriteUrlIndicator(adaptationConfig.id);
18236
18487
  }
18237
- // Initialize Assets
18238
- let assetsManager;
18239
- if (configFile.assetsJsonPath) {
18240
- const assetsPath = prependBaseUrl(configFile.assetsJsonPath, effectiveBaseURL);
18241
- try {
18242
- const assetsJson = await (await fetch(assetsPath)).json();
18243
- assetsManager = new AssetsManager(assetsJson, effectiveBaseURL);
18244
- }
18245
- catch (error) {
18246
- console.error(`[Custard] Failed to load assets JSON from ${assetsPath}:`, error);
18247
- assetsManager = new AssetsManager({}, effectiveBaseURL);
18248
- }
18249
- }
18250
- else {
18251
- assetsManager = new AssetsManager({}, effectiveBaseURL);
18252
- }
18253
18488
  const coreOptions = {
18254
- assetsManager,
18255
18489
  configFile,
18256
18490
  rootEl: document.body,
18257
18491
  storageKey: configFile.storageKey,