@shohojdhara/atomix 0.6.4 → 0.6.6

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 (83) hide show
  1. package/dist/atomix.css +117 -38
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/atomix.umd.js +1 -1
  6. package/dist/atomix.umd.js.map +1 -1
  7. package/dist/atomix.umd.min.js +1 -1
  8. package/dist/charts.d.ts +30 -1
  9. package/dist/charts.js +625 -846
  10. package/dist/charts.js.map +1 -1
  11. package/dist/core.d.ts +30 -1
  12. package/dist/core.js +659 -873
  13. package/dist/core.js.map +1 -1
  14. package/dist/forms.d.ts +30 -1
  15. package/dist/forms.js +1171 -1402
  16. package/dist/forms.js.map +1 -1
  17. package/dist/heavy.d.ts +31 -89
  18. package/dist/heavy.js +975 -1195
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +383 -140
  21. package/dist/index.esm.js +1567 -1679
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +1556 -1667
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.min.js +1 -1
  26. package/dist/index.min.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/Accordion/Accordion.tsx +2 -5
  29. package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
  30. package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
  31. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
  32. package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
  33. package/src/components/AtomixGlass/README.md +2 -1
  34. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
  35. package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
  36. package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
  37. package/src/components/AtomixGlass/glass-utils.ts +456 -22
  38. package/src/components/AtomixGlass/shader-utils.ts +19 -77
  39. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
  40. package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
  41. package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
  42. package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
  43. package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
  44. package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
  45. package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
  46. package/src/components/Badge/Badge.tsx +4 -4
  47. package/src/components/Button/Button.tsx +2 -6
  48. package/src/components/Callout/Callout.test.tsx +4 -3
  49. package/src/components/Callout/Callout.tsx +2 -5
  50. package/src/components/Dropdown/Dropdown.tsx +3 -7
  51. package/src/components/Form/Checkbox.tsx +2 -8
  52. package/src/components/Form/Input.tsx +2 -9
  53. package/src/components/Form/Radio.tsx +2 -9
  54. package/src/components/Form/Select.test.tsx +6 -6
  55. package/src/components/Form/Select.tsx +2 -7
  56. package/src/components/Form/Textarea.stories.tsx +5 -5
  57. package/src/components/Form/Textarea.tsx +2 -9
  58. package/src/components/Messages/Messages.tsx +2 -8
  59. package/src/components/Modal/Modal.tsx +4 -5
  60. package/src/components/Navigation/Nav/Nav.tsx +2 -6
  61. package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
  62. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
  63. package/src/components/Pagination/Pagination.tsx +2 -10
  64. package/src/components/Popover/Popover.tsx +2 -9
  65. package/src/components/Progress/Progress.tsx +2 -7
  66. package/src/components/Rating/Rating.tsx +2 -10
  67. package/src/components/Spinner/Spinner.tsx +2 -7
  68. package/src/components/Steps/Steps.tsx +2 -10
  69. package/src/components/Tabs/Tabs.tsx +2 -9
  70. package/src/components/Toggle/Toggle.tsx +2 -10
  71. package/src/components/Tooltip/Tooltip.tsx +2 -5
  72. package/src/lib/composables/useAtomixGlass.ts +42 -143
  73. package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
  74. package/src/lib/composables/usePerformanceMonitor.ts +5 -66
  75. package/src/lib/constants/components.ts +363 -46
  76. package/src/lib/types/components.ts +33 -1
  77. package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
  78. package/src/styles/02-tools/_tools.button.scss +51 -42
  79. package/src/styles/02-tools/_tools.glass.scss +45 -3
  80. package/src/styles/06-components/_components.atomix-glass.scss +116 -79
  81. package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
  82. package/src/components/AtomixGlass/animation-system.ts +0 -578
  83. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/core.js CHANGED
@@ -516,6 +516,62 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
516
516
  SIZES: [ "xs", "sm", "md", "lg", "xl", "none" ],
517
517
  DEFAULT: "md"
518
518
  }
519
+ }, GLASS_DEFAULTS_BUTTON = {
520
+ displacementScale: 16,
521
+ saturation: 180,
522
+ elasticity: 0
523
+ }, GLASS_DEFAULTS_BADGE = {
524
+ displacementScale: 14,
525
+ borderRadius: 16,
526
+ elasticity: 0
527
+ }, GLASS_DEFAULTS_ACCORDION = {
528
+ displacementScale: 18,
529
+ elasticity: 0
530
+ }, GLASS_DEFAULTS_CALLOUT = {
531
+ displacementScale: 22,
532
+ borderRadius: 8,
533
+ elasticity: 0
534
+ }, GLASS_DEFAULTS_SPINNER = {
535
+ displacementScale: 12,
536
+ elasticity: 0
537
+ }, GLASS_BORDER_GRADIENT = {
538
+ BASE_ANGLE: 135,
539
+ ANGLE_MULTIPLIER: .5,
540
+ VELOCITY_ANGLE_MULTIPLIER: .5,
541
+ CHROMATIC_OFFSET: 1.5,
542
+ STOP_1: {
543
+ MIN: 10,
544
+ BASE: 33,
545
+ get MULTIPLIER() {
546
+ return .009 * this.BASE;
547
+ }
548
+ },
549
+ STOP_2: {
550
+ MAX: 90,
551
+ BASE: 66,
552
+ get MULTIPLIER() {
553
+ return .006 * this.BASE;
554
+ }
555
+ },
556
+ OPACITY: {
557
+ /** Matches $glass-border-1-opacity (0.08) */
558
+ BASE_1: .08,
559
+ get BASE_2() {
560
+ return 3.33 * this.BASE_1;
561
+ },
562
+ get BASE_3() {
563
+ return 2.66 * this.BASE_1;
564
+ },
565
+ get BASE_4() {
566
+ return 5 * this.BASE_1;
567
+ },
568
+ get MULTIPLIER_LOW() {
569
+ return .066 * this.BASE_1;
570
+ },
571
+ get MULTIPLIER_HIGH() {
572
+ return .1 * this.BASE_1;
573
+ }
574
+ }
519
575
  }, ATOMIX_GLASS = {
520
576
  BASE_CLASS: "c-atomix-glass",
521
577
  CONTAINER_CLASS: "c-atomix-glass__container",
@@ -527,6 +583,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
527
583
  BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
528
584
  BORDER_1_CLASS: "c-atomix-glass__border-1",
529
585
  BORDER_2_CLASS: "c-atomix-glass__border-2",
586
+ /** Centralized liquid glass rim configuration */
587
+ BORDER: {
588
+ WIDTH_CSS_VAR: "--atomix-glass-border-width",
589
+ DEFAULT_WIDTH: "0.5px",
590
+ GRADIENT_CSS_VARS: {
591
+ GRADIENT_1: "--atomix-glass-border-gradient-1",
592
+ GRADIENT_2: "--atomix-glass-border-gradient-2"
593
+ },
594
+ GRADIENT: GLASS_BORDER_GRADIENT,
595
+ OVER_LIGHT: {
596
+ opacity: .7
597
+ },
598
+ DARK: {
599
+ opacity: .35
600
+ }
601
+ },
530
602
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
531
603
  HOVER_2_CLASS: "c-atomix-glass__hover-2",
532
604
  HOVER_3_CLASS: "c-atomix-glass__hover-3",
@@ -555,25 +627,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
555
627
  SHADER: "c-atomix-glass--shader"
556
628
  },
557
629
  DEFAULTS: {
558
- DISPLACEMENT_SCALE: 70,
630
+ /** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
631
+ DISPLACEMENT_SCALE: 28,
559
632
  get BLUR_AMOUNT() {
560
- return .15 * this.DISPLACEMENT_SCALE;
561
- // Dynamically computed based on displacement
562
- },
563
- get SATURATION() {
564
- return 100 + .5 * this.DISPLACEMENT_SCALE;
565
- // Saturate relative to intensity
566
- },
633
+ // Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
634
+ return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
635
+ },
636
+ /** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
637
+ SATURATION: 180,
567
638
  get ABERRATION_INTENSITY() {
568
- return .03 * this.DISPLACEMENT_SCALE;
569
- // Scale aberration with displacement
570
- },
571
- ELASTICITY: .15,
639
+ return .02 * this.DISPLACEMENT_SCALE;
640
+ },
641
+ ELASTICITY: .05,
572
642
  get CORNER_RADIUS() {
573
643
  return 16;
574
644
  // Use 16 to match SCSS design system (was 20)
575
645
  },
576
- PADDING: "0",
577
646
  MODE: "standard",
578
647
  OVER_LIGHT: !1,
579
648
  ENABLE_OVER_LIGHT_LAYERS: !0,
@@ -589,19 +658,29 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
589
658
  },
590
659
  CONSTANTS: {
591
660
  ACTIVATION_ZONE: 200,
592
- LERP_FACTOR: .08,
661
+ LERP_FACTOR: .05,
662
+ // Lower = more viscous, liquid-smooth tracking (Apple feel)
593
663
  SMOOTHSTEP_POWER: 2.5,
594
664
  MIN_BLUR: .1,
595
665
  MOUSE_INFLUENCE_DIVISOR: 100,
596
666
  EDGE_FADE_PIXELS: 2,
597
- // Elasticity physics constants
598
- ELASTICITY_TRANSLATION_FACTOR: .1,
667
+ // Interaction intensity multipliers shared by the hook and the imperative style updater
668
+ INTERACTION: {
669
+ HOVER_INTENSITY: 1.4,
670
+ ACTIVE_INTENSITY: 1.6
671
+ },
672
+ // Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
673
+ ELASTICITY_TRANSLATION_FACTOR: .06,
674
+ // Subtler elastic shift (was 0.1)
599
675
  ELASTICITY_DISTANCE_THRESHOLD: 200,
600
676
  ELASTICITY_COMPRESSION_FACTOR: .3,
601
- ELASTICITY_STIFFNESS: .1,
602
- ELASTICITY_DAMPING: .76,
677
+ ELASTICITY_STIFFNESS: .06,
678
+ // Softer springs = gentler motion (was 0.1)
679
+ ELASTICITY_DAMPING: .88,
680
+ // Fast settling, no wobble (was 0.76)
603
681
  ELASTICITY_VELOCITY_FACTOR: .65,
604
- ELASTICITY_STRETCH_RATIO: .45,
682
+ ELASTICITY_STRETCH_RATIO: .25,
683
+ // Less visible surface tension stretch (was 0.45)
605
684
  ELASTICITY_MAGNIFICATION_BASE: 1.02,
606
685
  // Note: This default must match the SCSS variable --atomix-radius-md
607
686
  // @see src/styles/01-settings/_settings.global.scss
@@ -615,55 +694,16 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
615
694
  },
616
695
  // Gradient calculation constants
617
696
  GRADIENT: {
618
- BASE_ANGLE: 135,
619
- // Base angle for border gradients (degrees)
620
- ANGLE_MULTIPLIER: 1.2,
621
- // Multiplier for mouse influence on angle
622
- VELOCITY_ANGLE_MULTIPLIER: 2.5,
623
- // How much velocity affects gradient rotation
624
- CHROMATIC_OFFSET: 1.5,
625
- // Degree offset for chromatic rim layers
626
- BORDER_STOP_1: {
627
- MIN: 10,
628
- // Minimum percentage for border stop 1
629
- BASE: 33,
630
- // Base percentage for border stop 1
631
- get MULTIPLIER() {
632
- return .009 * this.BASE;
633
- }
634
- },
635
- BORDER_STOP_2: {
636
- MAX: 90,
637
- // Maximum percentage for border stop 2
638
- BASE: 66,
639
- // Base percentage for border stop 2
640
- get MULTIPLIER() {
641
- return .006 * this.BASE;
642
- }
643
- },
644
- BORDER_OPACITY: {
645
- BASE_1: .12,
646
- // Base opacity for border gradient 1
647
- get BASE_2() {
648
- return 3.33 * this.BASE_1;
649
- },
650
- // Base opacity for border gradient 2
651
- get BASE_3() {
652
- return 2.66 * this.BASE_1;
653
- },
654
- // Base opacity for border gradient 3
655
- get BASE_4() {
656
- return 5 * this.BASE_1;
657
- },
658
- // Base opacity for border gradient 4
659
- get MULTIPLIER_LOW() {
660
- return .066 * this.BASE_1;
661
- },
662
- // Low multiplier for mouse influence on opacity
663
- get MULTIPLIER_HIGH() {
664
- return .1 * this.BASE_1;
665
- }
666
- },
697
+ BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
698
+ ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
699
+ VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
700
+ CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
701
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
702
+ BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
703
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
704
+ BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
705
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
706
+ BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
667
707
  CENTER_POSITION: 50,
668
708
  // Center position percentage (50%)
669
709
  HOVER_POSITION: {
@@ -696,8 +736,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
696
736
  return 2 * this.BLACK_STOP;
697
737
  },
698
738
  // End percentage for black hover 1
699
- WHITE_START: .5,
700
- // Start opacity for white hover 1
739
+ WHITE_START: .35,
740
+ // Gentler hover flash Apple hover is barely visible
701
741
  get WHITE_STOP() {
702
742
  return this.BLACK_END - 10;
703
743
  }
@@ -715,8 +755,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
715
755
  return 2 * this.BLACK_STOP;
716
756
  },
717
757
  // End percentage for black hover 2
718
- WHITE_START: 1,
719
- // Start opacity for white hover 2
758
+ WHITE_START: .7,
759
+ // Gentler hover flash
720
760
  get WHITE_STOP() {
721
761
  return this.BLACK_END;
722
762
  }
@@ -734,8 +774,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
734
774
  return 2 * this.BLACK_STOP;
735
775
  },
736
776
  // End percentage for black hover 3
737
- WHITE_START: 1,
738
- // Start opacity for white hover 3
777
+ WHITE_START: .7,
778
+ // Gentler hover flash
739
779
  get WHITE_STOP() {
740
780
  return this.BLACK_END;
741
781
  }
@@ -745,13 +785,13 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
745
785
  BASE_GRADIENT: {
746
786
  ANGLE: 135,
747
787
  // Gradient angle in degrees
748
- BLACK_START_BASE: .15,
788
+ BLACK_START_BASE: .1,
749
789
  // Base start opacity for black
750
790
  get BLACK_START_MULTIPLIER() {
751
791
  return .02 * this.BLACK_START_BASE;
752
792
  },
753
793
  // Multiplier for mouse X influence on start
754
- BLACK_MID_BASE: .1,
794
+ BLACK_MID_BASE: .07,
755
795
  // Base mid opacity for black
756
796
  get BLACK_MID_MULTIPLIER() {
757
797
  return .02 * this.BLACK_MID_BASE;
@@ -772,7 +812,7 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
772
812
  }
773
813
  },
774
814
  OVERLAY_GRADIENT: {
775
- BLACK_START_BASE: .12,
815
+ BLACK_START_BASE: .08,
776
816
  // Base start opacity for black overlay
777
817
  get BLACK_START_MULTIPLIER() {
778
818
  return .025 * this.BLACK_START_BASE;
@@ -796,14 +836,14 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
796
836
  return .416 * this.BLACK_START_BASE;
797
837
  }
798
838
  },
799
- // Overlay highlight constants
839
+ // Overlay highlight constants — Apple places specular at the top-center
800
840
  OVERLAY_HIGHLIGHT: {
801
- POSITION_X: 20,
802
- // X position percentage
803
- POSITION_Y: 20,
804
- // Y position percentage
805
- WHITE_OPACITY: .4,
806
- // White opacity in gradient
841
+ POSITION_X: 50,
842
+ // Centered horizontal — Apple's top-center specular
843
+ POSITION_Y: 5,
844
+ // Very top — catches light like a curved glass surface
845
+ WHITE_OPACITY: .28,
846
+ // Softer specular visible but not glaring
807
847
  get STOP() {
808
848
  return 150 * this.WHITE_OPACITY;
809
849
  },
@@ -824,6 +864,10 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
824
864
  SATURATION: {
825
865
  HIGH_CONTRAST: 200
826
866
  },
867
+ // Container shadows — hairline inner catch + soft floating lift (Apple player bar)
868
+ CONTAINER_SHADOW: {
869
+ LIGHT: "inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08)"
870
+ },
827
871
  // Phase 1: Animation System Constants
828
872
  ANIMATION: {
829
873
  // Breathing effect timing (in milliseconds)
@@ -863,7 +907,44 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
863
907
  }
864
908
  }
865
909
  }
866
- }, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
910
+ };
911
+
912
+ /**
913
+ * Default theme colors for components
914
+ */
915
+ /**
916
+ * Button-specific constants
917
+ */
918
+ /**
919
+ * Component Utilities
920
+ *
921
+ * Helper functions for component development with the new customization system
922
+ */
923
+ /**
924
+ * Merge multiple class names
925
+ */
926
+ function mergeClassNames(...classes) {
927
+ return classes.filter(Boolean).join(" ");
928
+ }
929
+
930
+ /**
931
+ * Utility to merge multiple React refs into one
932
+ */ function setRef(ref, value) {
933
+ "function" == typeof ref ? ref(value) : ref && (
934
+ // This is safe because we're checking that ref exists first
935
+ ref.current = value);
936
+ }
937
+
938
+ /**
939
+ * Combines two React refs into a single ref function
940
+ * This is used when you need to use and forward a ref at the same time
941
+ */ function useForkRef(refA, refB) {
942
+ return React.useMemo((() => null == refA && null == refB ? null : refValue => {
943
+ setRef(refA, refValue), setRef(refB, refValue);
944
+ }), [ refA, refB ]);
945
+ }
946
+
947
+ const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
867
948
  x: rect.left + rect.width / 2,
868
949
  y: rect.top + rect.height / 2
869
950
  } : {
@@ -871,37 +952,37 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
871
952
  y: 0
872
953
  }, calculateMouseInfluence = mouseOffset => {
873
954
  if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
874
- // Bounded calculation keeps the glass effect subtle and stable
875
- const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
955
+ // Clamp influence to keep mouse response subtle and stable.
956
+ const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
876
957
  return Math.min(.8, influence);
877
958
  // Tighter cap to prevent blur/filter blow-out
878
- }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$2.MIN_BLUR : Math.max(CONSTANTS$2.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$2.MAX_SIZE && size.height <= CONSTANTS$2.MAX_SIZE, parseBorderRadiusValue = value => {
959
+ }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$3.MIN_BLUR : Math.max(CONSTANTS$3.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$3.MAX_SIZE && size.height <= CONSTANTS$3.MAX_SIZE, parseBorderRadiusValue = value => {
879
960
  if ("number" == typeof value) return Math.max(0, value);
880
- if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
961
+ if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
881
962
  const trimmedValue = value.trim();
882
963
  // Handle px values
883
964
  if (trimmedValue.endsWith("px")) {
884
965
  const parsed = parseFloat(trimmedValue);
885
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
966
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
886
967
  }
887
968
  // Handle rem values (assume 16px = 1rem)
888
969
  if (trimmedValue.endsWith("rem")) {
889
970
  const parsed = parseFloat(trimmedValue);
890
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
971
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
891
972
  }
892
973
  // Handle em values (assume 16px = 1em for simplicity)
893
974
  if (trimmedValue.endsWith("em")) {
894
975
  const parsed = parseFloat(trimmedValue);
895
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
976
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
896
977
  }
897
978
  // Handle percentage (convert to approximate px value, assuming 200px container)
898
979
  if (trimmedValue.endsWith("%")) {
899
980
  const parsed = parseFloat(trimmedValue);
900
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
981
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
901
982
  }
902
983
  // Handle unitless numbers
903
984
  const numValue = parseFloat(trimmedValue);
904
- return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
985
+ return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
905
986
  }, extractBorderRadiusFromElement = element => {
906
987
  if (!element || !element.props) return null;
907
988
  // Check inline styles first (highest priority)
@@ -917,11 +998,11 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
917
998
  // If element has children, recursively check them
918
999
  if (element.props.children) {
919
1000
  const childRadius = extractBorderRadiusFromChildren(element.props.children);
920
- if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
1001
+ if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
921
1002
  }
922
1003
  return null;
923
1004
  }, extractBorderRadiusFromChildren = children => {
924
- if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1005
+ if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
925
1006
  try {
926
1007
  const childArray = React.Children.toArray(children);
927
1008
  for (let i = 0; i < childArray.length; i++) {
@@ -934,17 +1015,78 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
934
1015
  } catch (error) {
935
1016
  // Silently handle errors
936
1017
  }
937
- return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1018
+ return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
938
1019
  }, smoothstep = t => {
939
1020
  const clamped = Math.max(0, Math.min(1, t));
940
1021
  return clamped * clamped * (3 - 2 * clamped);
941
- }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
1022
+ }, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), clamp = (value, min, max) => "number" != typeof value || isNaN(value) ? min : Math.max(min, Math.min(max, value)), smoothstepEdge = (edge0, edge1, x) => "number" != typeof edge0 || "number" != typeof edge1 || "number" != typeof x ? 0 : smoothstep((x - edge0) / (edge1 - edge0)), easeInOutCubic = t => {
1023
+ if ("number" != typeof t || isNaN(t)) return 0;
1024
+ const clamped = Math.max(0, Math.min(1, t));
1025
+ return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
1026
+ }, easeOutQuart = t => {
1027
+ if ("number" != typeof t || isNaN(t)) return 0;
1028
+ const clamped = Math.max(0, Math.min(1, t));
1029
+ return 1 - Math.pow(1 - clamped, 4);
1030
+ }, vec2Length = (x, y) => {
1031
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
1032
+ const maxComponent = Math.max(Math.abs(x), Math.abs(y));
1033
+ if (0 === maxComponent) return 0;
1034
+ const scaledX = x / maxComponent, scaledY = y / maxComponent;
1035
+ return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
1036
+ }, getInteractionIntensity = (isHovered, isActive) => ({
1037
+ hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
1038
+ activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
1039
+ })
1040
+ /**
1041
+ * Spring-damper integration helper
1042
+ * Calculates the next value based on velocity, stiffness, and damping.
1043
+ */ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
942
1044
  const newVelocity = (velocity + (target - current) * stiffness) * damping;
943
1045
  return {
944
1046
  value: current + newVelocity,
945
1047
  velocity: newVelocity
946
1048
  };
947
- }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
1049
+ };
1050
+
1051
+ /**
1052
+ * Calculate element center from bounding rect
1053
+ */
1054
+ /**
1055
+ * Normalizes a layout inset for use in CSS custom properties.
1056
+ *
1057
+ * @param value - Raw inset from `style` (number, px string, or `auto`).
1058
+ * @param fallback - Value used when `value` is undefined.
1059
+ */
1060
+ function formatGlassInsetValue(value, fallback = "auto") {
1061
+ return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
1062
+ }
1063
+
1064
+ /**
1065
+ * Determines whether the glass should use fixed/sticky layout semantics.
1066
+ *
1067
+ * @param explicit - Value of the `isFixedOrSticky` prop.
1068
+ * @param position - `position` from the consumer `style` object.
1069
+ */
1070
+ /** Coerces a value to a finite number, returning `fallback` when invalid. */
1071
+ function toSafeNumber(value, fallback = 0) {
1072
+ return "number" != typeof value || isNaN(value) ? fallback : value;
1073
+ }
1074
+
1075
+ /**
1076
+ * Calculates the target frame rate for shader time-animation loops.
1077
+ *
1078
+ * Balances visual quality against distortion complexity and `animationSpeed`.
1079
+ */
1080
+ /**
1081
+ * Computes per-channel displacement scale for the SVG chromatic-aberration filter.
1082
+ */
1083
+ function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
1084
+ return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
1085
+ }
1086
+
1087
+ /**
1088
+ * Get displacement map URL based on mode
1089
+ */ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
948
1090
  switch (mode) {
949
1091
  case "standard":
950
1092
  return displacementMap;
@@ -961,13 +1103,28 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
961
1103
  default:
962
1104
  return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
963
1105
  }
964
- }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
965
- style: {
966
- position: "absolute",
967
- width: "100%",
968
- height: "100%",
969
- inset: 0
970
- },
1106
+ }, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
1107
+ result: "RED_DISPLACED",
1108
+ channelResult: "RED_CHANNEL",
1109
+ aberrationFactor: 0,
1110
+ colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
1111
+ }, {
1112
+ result: "GREEN_DISPLACED",
1113
+ channelResult: "GREEN_CHANNEL",
1114
+ aberrationFactor: .02,
1115
+ colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
1116
+ }, {
1117
+ result: "BLUE_DISPLACED",
1118
+ channelResult: "BLUE_CHANNEL",
1119
+ aberrationFactor: .03,
1120
+ colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
1121
+ } ], FILTER_SVG_STYLE = {
1122
+ position: "absolute",
1123
+ width: "100%",
1124
+ height: "100%",
1125
+ inset: 0
1126
+ }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
1127
+ style: FILTER_SVG_STYLE,
971
1128
  "aria-hidden": "true",
972
1129
  children: jsxs("defs", {
973
1130
  children: [ jsxs("radialGradient", {
@@ -1021,43 +1178,21 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1021
1178
  dx: "0",
1022
1179
  dy: "0",
1023
1180
  result: "CENTER_ORIGINAL"
1024
- }), jsx("feDisplacementMap", {
1025
- in: "SourceGraphic",
1026
- in2: "DISPLACEMENT_MAP",
1027
- scale: displacementScale * ("shader" === mode ? 1 : -1),
1028
- xChannelSelector: "R",
1029
- yChannelSelector: "B",
1030
- result: "RED_DISPLACED"
1031
- }), jsx("feColorMatrix", {
1032
- in: "RED_DISPLACED",
1033
- type: "matrix",
1034
- values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
1035
- result: "RED_CHANNEL"
1036
- }), jsx("feDisplacementMap", {
1037
- in: "SourceGraphic",
1038
- in2: "DISPLACEMENT_MAP",
1039
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
1040
- xChannelSelector: "R",
1041
- yChannelSelector: "B",
1042
- result: "GREEN_DISPLACED"
1043
- }), jsx("feColorMatrix", {
1044
- in: "GREEN_DISPLACED",
1045
- type: "matrix",
1046
- values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
1047
- result: "GREEN_CHANNEL"
1048
- }), jsx("feDisplacementMap", {
1049
- in: "SourceGraphic",
1050
- in2: "DISPLACEMENT_MAP",
1051
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
1052
- xChannelSelector: "R",
1053
- yChannelSelector: "B",
1054
- result: "BLUE_DISPLACED"
1055
- }), jsx("feColorMatrix", {
1056
- in: "BLUE_DISPLACED",
1057
- type: "matrix",
1058
- values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
1059
- result: "BLUE_CHANNEL"
1060
- }), jsx("feBlend", {
1181
+ }), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
1182
+ children: [ jsx("feDisplacementMap", {
1183
+ in: "SourceGraphic",
1184
+ in2: "DISPLACEMENT_MAP",
1185
+ scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
1186
+ xChannelSelector: "R",
1187
+ yChannelSelector: "B",
1188
+ result: channel.result
1189
+ }), jsx("feColorMatrix", {
1190
+ in: channel.result,
1191
+ type: "matrix",
1192
+ values: channel.colorMatrix,
1193
+ result: channel.channelResult
1194
+ }) ]
1195
+ }, channel.channelResult))), jsx("feBlend", {
1061
1196
  in: "GREEN_CHANNEL",
1062
1197
  in2: "BLUE_CHANNEL",
1063
1198
  mode: "screen",
@@ -1098,24 +1233,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1098
1233
  });
1099
1234
 
1100
1235
  /**
1101
- * Default theme colors for components
1102
- */
1103
- /**
1104
- * Button-specific constants
1236
+ * Module-level LRU cache for shader displacement maps.
1237
+ *
1238
+ * Shared across all `AtomixGlassContainer` instances so identical size and
1239
+ * variant combinations are generated once.
1105
1240
  */ GlassFilterComponent.displayName = "GlassFilter";
1106
1241
 
1107
- // Memoize component to prevent unnecessary re-renders
1242
+ /** Shallow prop comparison to avoid redundant SVG filter regeneration. */
1108
1243
  const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
1109
1244
  x: 0,
1110
1245
  y: 0
1111
- }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
1246
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
1112
1247
  width: 0,
1113
1248
  height: 0
1114
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
1115
- // Phase 1: Animation System props
1116
- shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
1249
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
1117
1250
  // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
1118
- const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
1251
+ const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), containerRef = useForkRef(ref, null), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
1119
1252
  // Lazy load shader utilities only when shader mode is needed
1120
1253
  useEffect((() => {
1121
1254
  "shader" === mode ?
@@ -1193,15 +1326,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1193
1326
  shaderGeneratorRef.current = null;
1194
1327
  }
1195
1328
  };
1196
- }), [ mode, glassSize, shaderVariant ]),
1197
- // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
1198
- useEffect((() => {
1329
+ }), [ mode, glassSize, shaderVariant ]), useEffect((() => {
1199
1330
  // Only run animations in shader mode with time animation enabled
1200
1331
  if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
1201
1332
  // Cancel any existing animation frame
1202
1333
  return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
1203
1334
  animationFrameRef.current = null));
1204
- const baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed || 1)), complexity = withMultiLayerDistortion ? Math.max(1, (distortionOctaves || 3) / 3 + .25 * Math.max(0, (distortionLacunarity || 2) - 2) + Math.max(0, (distortionGain || .5) - .5)) : 1, frameInterval = 1e3 / Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
1335
+ const targetFps = function(options) {
1336
+ const {distortionQuality: distortionQuality, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5} = options, baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed)), complexity = withMultiLayerDistortion ? Math.max(1, distortionOctaves / 3 + .25 * Math.max(0, distortionLacunarity - 2) + Math.max(0, distortionGain - .5)) : 1;
1337
+ return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
1338
+ }({
1339
+ distortionQuality: distortionQuality,
1340
+ animationSpeed: animationSpeed,
1341
+ withMultiLayerDistortion: withMultiLayerDistortion,
1342
+ distortionOctaves: distortionOctaves,
1343
+ distortionLacunarity: distortionLacunarity,
1344
+ distortionGain: distortionGain
1345
+ }), frameInterval = 1e3 / targetFps;
1205
1346
  let lastUpdate = 0, isCancelled = !1;
1206
1347
  const animate = currentTime => {
1207
1348
  if (!isCancelled) {
@@ -1225,88 +1366,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1225
1366
  };
1226
1367
  }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
1227
1368
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
1228
- const [rectCache, setRectCache] = useState(null);
1229
- useEffect((() => {
1230
- if (!ref || "function" == typeof ref) return;
1231
- const element = ref.current;
1232
- if (element) try {
1233
- setRectCache(element.getBoundingClientRect());
1234
- } catch (error) {
1235
- console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
1236
- }
1237
- }), [ ref, glassSize ]);
1238
- const liquidBlur = useMemo((() => {
1239
- const defaultBlur = {
1240
- baseBlur: blurAmount,
1241
- edgeBlur: 1.25 * blurAmount,
1242
- centerBlur: 1.1 * blurAmount,
1243
- flowBlur: 1.2 * blurAmount
1244
- };
1245
- // Enhanced validation for liquid blur
1246
- if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
1247
- try {
1248
- const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = 2 * blurAmount, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * .15), edgeIntensity = .15 * mouseInfluence, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = .1 * mouseInfluence, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, 1.2 * baseBlur);
1249
- // NOTE: hover/active multipliers intentionally omitted here —
1250
- // they belong on opacity layers, not the blur filter itself.
1251
- return {
1252
- baseBlur: clampBlur(baseBlur),
1253
- edgeBlur: clampBlur(edgeBlur),
1254
- centerBlur: clampBlur(centerBlur),
1255
- flowBlur: clampBlur(flowBlur)
1256
- };
1257
- } catch (error) {
1258
- return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
1259
- defaultBlur;
1260
- }
1261
- }), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
1262
- try {
1263
- const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
1264
- // Validate blur values before using them
1265
- return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
1266
- backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1.05}) brightness(${overLightConfig?.brightness || 1.05})`
1267
- } : {
1268
- backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1}) brightness(${overLightConfig?.brightness || 1})`
1269
- };
1270
- // Single-pass fallback: stronger radius to match perceived blur of multi-pass
1271
- } catch (error) {
1272
- return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
1273
- {
1274
- backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
1275
- };
1276
- }
1277
- }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
1369
+ const containerVars = useMemo((() => {
1278
1370
  try {
1279
- // Safe extraction of mouse offset values
1280
- const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
1281
1371
  return {
1282
- "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
1283
- "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
1284
- "--atomix-glass-container-shadow": overLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig?.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset",
1285
- "--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
1286
- // Background and shadow values use design token-aligned RGB values
1287
- "--atomix-glass-container-bg": overLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none",
1288
- "--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
1289
- "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
1372
+ "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
1290
1373
  };
1291
1374
  } catch (error) {
1292
1375
  return console.warn("AtomixGlassContainer: Error generating container variables", error),
1293
1376
  {
1294
- "--atomix-glass-container-padding": "0 0",
1295
- "--atomix-glass-container-radius": "0px",
1296
- "--atomix-glass-container-backdrop": "none",
1297
- "--atomix-glass-container-shadow": "none",
1298
- "--atomix-glass-container-shadow-opacity": 1,
1299
- "--atomix-glass-container-bg": "none",
1300
- "--atomix-glass-container-text-shadow": "none"
1377
+ "--atomix-glass-container-radius": "0px"
1301
1378
  };
1302
1379
  }
1303
- }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
1380
+ }), [ borderRadius ]);
1304
1381
  return jsx("div", {
1305
- ref: el => {
1306
- // Handle forwarded ref
1307
- "function" == typeof ref ? ref(el) : ref && (ref.current = el);
1308
- },
1309
- className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
1382
+ ref: containerRef,
1383
+ className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
1310
1384
  style: {
1311
1385
  ...style,
1312
1386
  ...containerVars
@@ -1324,8 +1398,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1324
1398
  blurAmount: blurAmount,
1325
1399
  mode: mode,
1326
1400
  id: filterId,
1327
- displacementScale: "number" != typeof displacementScale || isNaN(displacementScale) ? 0 : displacementScale,
1328
- aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
1401
+ displacementScale: toSafeNumber(displacementScale),
1402
+ aberrationIntensity: toSafeNumber(aberrationIntensity),
1329
1403
  shaderMapUrl: shaderMapUrl
1330
1404
  }), jsx("div", {
1331
1405
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
@@ -1347,8 +1421,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1347
1421
  });
1348
1422
  }));
1349
1423
 
1350
- // ─── Blur multiplier constants (module-level, never change at runtime) ────────
1351
- AtomixGlassContainer.displayName = "AtomixGlassContainer";
1424
+ /**
1425
+ * Internal glass surface that owns backdrop-filter, SVG distortion, and content.
1426
+ *
1427
+ * Layout and stacking styles are applied via the `style` prop from the parent.
1428
+ * The root wrapper supplies CSS custom properties only.
1429
+ */ AtomixGlassContainer.displayName = "AtomixGlassContainer";
1352
1430
 
1353
1431
  // Singleton instance
1354
1432
  const globalMouseTracker = new
@@ -1463,28 +1541,32 @@ class {
1463
1541
  */ getSubscriberCount() {
1464
1542
  return this.listeners.size;
1465
1543
  }
1466
- }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
1544
+ }, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
1467
1545
  if (!wrapperElement && !containerElement) return;
1468
1546
  if (!validateGlassSize(params.glassSize)) return;
1469
- const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
1547
+ const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, isFixedOrSticky: isFixedOrSticky = !1, borderAnimated: borderAnimated = !0, borderOpacityMultiplier: borderOpacityMultiplier = 1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), overLightConfig = {
1470
1548
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
1471
1549
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
1472
1550
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
1473
1551
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
1474
1552
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
1475
1553
  saturationBoost: baseOverLightConfig.saturationBoost
1476
- }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, stretchMagnitude = ((pos1, pos2) => {
1477
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
1478
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
1479
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
1480
- })({
1481
- x: 0,
1482
- y: 0
1483
- }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
1554
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
1555
+ /**
1556
+ * Computes tension factor from elastic translation magnitude (0–1).
1557
+ */
1558
+ function(elasticTranslation) {
1559
+ const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
1560
+ return smoothstep(magnitude / 80);
1561
+ }
1562
+ /**
1563
+ * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1564
+ * to avoid React re-renders on mouse movement.
1565
+ */ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
1484
1566
  // Calculate mouse influence
1485
1567
  // Update Wrapper Styles (glassVars)
1486
1568
  if (wrapperElement) {
1487
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, velocityRotation = (mouseVelocity.x + elasticVelocity.x) * (GRADIENT.VELOCITY_ANGLE_MULTIPLIER || 2.5), borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = GRADIENT.CHROMATIC_OFFSET || 1.5, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, borderOpacities = [ (GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
1569
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
1488
1570
  hover1: {
1489
1571
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
1490
1572
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -1501,28 +1583,55 @@ class {
1501
1583
  x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
1502
1584
  y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
1503
1585
  }, opacityValues = {
1504
- hover1: isHovered || isActive ? .5 : 0,
1505
- hover2: isActive ? .5 : 0,
1506
- hover3: isHovered ? .4 : isActive ? .8 : 0,
1507
- base: isOverLight ? overLightConfig.opacity : 0,
1508
- over: isOverLight ? 1.1 * overLightConfig.opacity : 0
1586
+ // hover-1: ambient highlight glow present on hover and during press
1587
+ hover1: isHovered || isActive ? 1 : 0,
1588
+ // hover-2: press depth shadow only fires on active (mousedown)
1589
+ hover2: isActive ? 1 : 0,
1590
+ // hover-3: global soft-light surface shift half-strength on hover, full on press
1591
+ hover3: isActive ? 1 : isHovered ? .55 : 0,
1592
+ // Dark chrome: faint smoky tint; over-light keeps stronger fill
1593
+ base: isOverLight ? overLightConfig.opacity : .14,
1594
+ over: isOverLight ? 1.1 * overLightConfig.opacity : .1
1509
1595
  }, style = wrapperElement.style;
1510
1596
  style.setProperty("--atomix-glass-transform", transformStyle || "none");
1511
1597
  // Parallax for content (liquid refraction feel)
1512
1598
  const parallaxFactor = .38 + .12 * tensionFactor;
1513
1599
  style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
1514
- style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
1600
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
1515
1601
  // ── Chromatic Rim Lighting ──────────────────────────────────────
1516
- // Layer 1: Core White/Blue highlight
1517
- style.setProperty("--atomix-glass-border-gradient-1", `linear-gradient(${angleB}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
1518
- // Layer 2: Subtle Red/Warm highlight (offset angle)
1519
- style.setProperty("--atomix-glass-border-gradient-2", `linear-gradient(${angleR}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
1520
- // Hover gradients
1521
- style.setProperty("--atomix-glass-hover-1-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`),
1522
- style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`),
1523
- style.setProperty("--atomix-glass-hover-3-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`),
1524
- style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`),
1525
- style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`),
1602
+ const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
1603
+ if (borderAnimated && !effectiveWithoutEffects) {
1604
+ const borderCssVars =
1605
+ /**
1606
+ * Builds animated chromatic rim CSS variables for border layers 1 and 2.
1607
+ * When empty, SCSS static conic/linear fallbacks apply.
1608
+ */
1609
+ function(params) {
1610
+ const {mouseOffset: mouseOffset, mouseVelocity: mouseVelocity, elasticVelocity: elasticVelocity, borderOpacity: borderOpacity, opacityMultiplier: opacityMultiplier = 1, tensionFactor: tensionFactor = 0} = params, mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), velocityRotation = (mouseVelocity.x + elasticVelocity.x) * BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER, borderGradientAngle = BORDER_GRADIENT.BASE_ANGLE + mx * BORDER_GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = BORDER_GRADIENT.CHROMATIC_OFFSET, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(BORDER_GRADIENT.STOP_1.MIN, BORDER_GRADIENT.STOP_1.BASE + my * BORDER_GRADIENT.STOP_1.MULTIPLIER), borderStop2 = Math.min(BORDER_GRADIENT.STOP_2.MAX, BORDER_GRADIENT.STOP_2.BASE + my * BORDER_GRADIENT.STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, opacities = BORDER_GRADIENT.OPACITY, borderOpacities = [ (opacities.BASE_1 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_2 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow, (opacities.BASE_3 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_4 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = borderOpacity * opacityMultiplier, gradient1 = `linear-gradient(${angleB}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`, gradient2 = `linear-gradient(${angleR}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
1611
+ return {
1612
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
1613
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
1614
+ };
1615
+ }({
1616
+ mouseOffset: mouseOffset,
1617
+ mouseVelocity: mouseVelocity,
1618
+ elasticVelocity: elasticVelocity,
1619
+ borderOpacity: overLightConfig.borderOpacity,
1620
+ opacityMultiplier: borderOpacityMultiplier,
1621
+ tensionFactor: tensionFactor
1622
+ });
1623
+ style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
1624
+ style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
1625
+ } else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
1626
+ // Hover gradients — cursor-relative radial positions for realistic light tracking.
1627
+ // hover-1: white overlay highlight following cursor (works on both dark + light)
1628
+ style.setProperty("--atomix-glass-hover-1-gradient", `radial-gradient(65% 55% at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, 0.24) 0%, rgba(${whiteColor}, 0.06) 45%, rgba(${whiteColor}, 0) 72%)`),
1629
+ // hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
1630
+ style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.22) 0%, rgba(${blackColor}, 0.06) 50%, rgba(${blackColor}, 0) 72%)` : `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.18) 0%, rgba(${blackColor}, 0.04) 50%, rgba(${blackColor}, 0) 72%)`),
1631
+ // hover-3: full-surface soft-light tint; linear gradient angled with cursor X
1632
+ style.setProperty("--atomix-glass-hover-3-gradient", `linear-gradient(${150 + .3 * mx}deg, rgba(${whiteColor}, ${isOverLight ? .08 : .12}) 0%, rgba(${whiteColor}, 0.04) 55%, rgba(${whiteColor}, 0) 100%)`),
1633
+ style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `linear-gradient(180deg, rgba(${blackColor}, 0.42) 0%, rgba(${blackColor}, 0.22) 55%, rgba(${blackColor}, 0.12) 100%)`),
1634
+ style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `radial-gradient(120% 80% at 50% 0%, rgba(${whiteColor}, 0.14) 0%, rgba(${whiteColor}, 0) 55%)`),
1526
1635
  // Opacities
1527
1636
  style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
1528
1637
  style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
@@ -1559,151 +1668,16 @@ class {
1559
1668
  backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})`;
1560
1669
  // Container variables
1561
1670
  const style = containerElement.style;
1562
- style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
1671
+ style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
1563
1672
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
1564
1673
  // Shadows
1565
- style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset"),
1674
+ style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.35 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.15 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.06 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.08 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : ATOMIX_GLASS.CONSTANTS.CONTAINER_SHADOW.LIGHT),
1566
1675
  style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
1567
1676
  style.setProperty("--atomix-glass-container-bg", isOverLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none"),
1568
1677
  style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
1569
- style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
1678
+ style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0 4px 16px rgba(0, 0, 0, 0.14), 0 1px 4px rgba(0, 0, 0, 0.10)");
1570
1679
  }
1571
- };
1572
-
1573
- /**
1574
- * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1575
- * to avoid React re-renders on mouse movement.
1576
- */
1577
- /**
1578
- * Animation System for AtomixGlass Component
1579
- *
1580
- * Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
1581
- * - Feature 1.1: Time-Based Animation System
1582
- * - Feature 1.2: Multi-Layer Distortion System (FBM)
1583
- *
1584
- * @packageDocumentation
1585
- */
1586
- // ============================================================================
1587
- // Noise Functions for FBM (Feature 1.2)
1588
- // ============================================================================
1589
- /**
1590
- * Perlin noise implementation for smooth gradient noise
1591
- *
1592
- * @param x - X coordinate
1593
- * @param y - Y coordinate
1594
- * @returns Noise value in range [0, 1]
1595
- */
1596
- function perlinNoise(x, y) {
1597
- // Simplified Perlin noise using pseudo-random gradients
1598
- const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = fade(xf), v = fade(yf), A = p[X] + Y & 255, B = p[X + 1] + Y & 255, ga = grad(p[A], xf, yf), gb = grad(p[B], xf - 1, yf), gc = grad(p[A + 1 & 255], xf, yf - 1), gd = grad(p[B + 1 & 255], xf - 1, yf - 1), lerpX1 = lerp(ga, gb, u), lerpX2 = lerp(gc, gd, u);
1599
- // Scale to [0, 1] range
1600
- return (lerp(lerpX1, lerpX2, v) + 1) / 2;
1601
- }
1602
-
1603
- // ============================================================================
1604
- // Fractal Brownian Motion (FBM) Engine (Feature 1.2)
1605
- // ============================================================================
1606
- /**
1607
- * Creates an FBM engine with configurable parameters
1608
- *
1609
- * @param config - FBM configuration (octaves, lacunarity, gain)
1610
- * @returns Object with fbm function
1611
- *
1612
- * @example
1613
- * ```typescript
1614
- * const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
1615
- *
1616
- * // Generate noise at position (0.5, 0.5) with time animation
1617
- * const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
1618
- * ```
1619
- */ function createFBMEngine(config) {
1620
- /**
1621
- * Fractal Brownian Motion function
1622
- * Combines multiple octaves of noise for complex, natural patterns
1623
- *
1624
- * @param x - X coordinate
1625
- * @param y - Y coordinate
1626
- * @param time - Optional time value for animation
1627
- * @returns FBM noise value in range [0, 1]
1628
- */
1629
- const fbm = (x, y, time = 0) => {
1630
- let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
1631
- // Convert to seconds for reasonable animation speed
1632
- for (let i = 0; i < config.octaves; i++)
1633
- // Apply time-based phase shift to all octaves
1634
- value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
1635
- frequency *= config.lacunarity, // Increase frequency
1636
- amplitude *= config.gain;
1637
- return value;
1638
- };
1639
- /**
1640
- * Get FBM with simple time factor
1641
- */ return {
1642
- fbm: fbm,
1643
- fbmWithTime: (x, y, time) => fbm(x, y, time)
1644
- };
1645
- }
1646
-
1647
- /**
1648
- * Gets optimal FBM config based on quality preset
1649
- *
1650
- * @param quality - Quality preset level
1651
- * @returns FBM configuration for the quality level
1652
- */ const fbmEngineCache = new Map;
1653
-
1654
- // ============================================================================
1655
- // Shader Utility Functions for Time-Based Effects
1656
- // ============================================================================
1657
- /**
1658
- * Liquid glass distortion with time-based animation
1659
- * Uses FBM to create organic, flowing liquid effects
1660
- *
1661
- * @param uv - UV coordinates (normalized 0-1)
1662
- * @param time - Elapsed time in milliseconds
1663
- * @param config - FBM configuration
1664
- * @returns Distorted UV coordinates
1665
- */ function liquidGlassWithTime(uv, time, config) {
1666
- const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
1667
- let fbmEngine = fbmEngineCache.get(configKey);
1668
- fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
1669
- // Animate noise with time
1670
- const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
1671
- return {
1672
- x: uv.x + .04 * (animatedNoise - .5),
1673
- y: uv.y + .04 * (animatedNoise - .5)
1674
- };
1675
- }
1676
-
1677
- // ============================================================================
1678
- // Helper Functions
1679
- // ============================================================================
1680
- /**
1681
- * Fade curve for smooth interpolation (Perlin's fade function)
1682
- */ function fade(t) {
1683
- return t * t * t * (t * (6 * t - 15) + 10);
1684
- }
1685
-
1686
- /**
1687
- * Linear interpolation
1688
- */ function lerp(a, b, t) {
1689
- return a + t * (b - a);
1690
- }
1691
-
1692
- /**
1693
- * Gradient calculation for Perlin noise
1694
- */ function grad(hash, x, y) {
1695
- const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
1696
- return (1 & h ? -u : u) + (2 & h ? -v : v);
1697
- }
1698
-
1699
- /**
1700
- * Permutation table for Perlin noise
1701
- */ const p = (() => {
1702
- const permutation = [];
1703
- for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
1704
- // Duplicate for overflow handling
1705
- return [ ...permutation, ...permutation ];
1706
- })(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
1680
+ }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
1707
1681
 
1708
1682
  const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
1709
1683
  parentElement && backgroundDetectionCache.set(parentElement, {
@@ -1718,12 +1692,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
1718
1692
  * Composable hook for AtomixGlass component logic
1719
1693
  * Manages all state, calculations, and event handlers
1720
1694
  */
1721
- function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1, withTimeAnimation:
1722
- // Default priority
1723
- // Phase 1: Animation System Props
1724
- withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED, withMultiLayerDistortion: withMultiLayerDistortion = ATOMIX_GLASS.DEFAULTS.WITH_MULTI_LAYER_DISTORTION, distortionOctaves: distortionOctaves = ATOMIX_GLASS.DEFAULTS.DISTORTION_OCTAVES, distortionLacunarity: distortionLacunarity = ATOMIX_GLASS.DEFAULTS.DISTORTION_LACUNARITY, distortionGain: distortionGain = ATOMIX_GLASS.DEFAULTS.DISTORTION_GAIN, distortionQuality: distortionQuality = ATOMIX_GLASS.DEFAULTS.DISTORTION_QUALITY}) {
1695
+ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, border: border, withBorder: withBorder = !0, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1}) {
1725
1696
  // State
1726
- const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1697
+ const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
1698
+ /**
1699
+ * Resolves `border` and legacy `withBorder` into a single configuration object.
1700
+ */
1701
+ function(border, withBorder) {
1702
+ const legacyDefault = withBorder ?? !0;
1703
+ return void 0 === border ? {
1704
+ enabled: legacyDefault,
1705
+ width: BORDER.DEFAULT_WIDTH,
1706
+ opacityMultiplier: 1,
1707
+ animated: !0
1708
+ } : "boolean" == typeof border ? {
1709
+ enabled: border,
1710
+ width: BORDER.DEFAULT_WIDTH,
1711
+ opacityMultiplier: 1,
1712
+ animated: !0
1713
+ } : {
1714
+ enabled: border.enabled ?? legacyDefault,
1715
+ width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
1716
+ opacityMultiplier: border.opacity ?? 1,
1717
+ animated: !1 !== border.animated
1718
+ };
1719
+ /**
1720
+ * Formats border width for CSS custom properties.
1721
+ */
1722
+ var value;
1723
+ }(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1727
1724
  x: 0,
1728
1725
  y: 0
1729
1726
  }), internalMouseOffsetRef = useRef({
@@ -1747,52 +1744,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1747
1744
  }), scaleVelocityRef = useRef({
1748
1745
  x: 0,
1749
1746
  y: 0
1750
- });
1751
- useRef(0);
1752
- const mouseVelocityRef = useRef({
1747
+ }), mouseVelocityRef = useRef({
1753
1748
  x: 0,
1754
1749
  y: 0
1755
- }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
1756
- // If quality preset is provided, use it as base
1757
- const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
1758
- // Override with custom values if provided
1759
- var quality;
1760
- return {
1761
- octaves: distortionOctaves ?? preset.octaves,
1762
- lacunarity: distortionLacunarity ?? preset.lacunarity,
1763
- gain: distortionGain ?? preset.gain
1764
- };
1765
- }), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
1766
- /**
1767
- * Animation loop for time-based effects
1768
- */
1769
- useEffect((() => {
1770
- if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
1771
- let lastFrameTime = performance.now();
1772
- /**
1773
- * Animation frame handler
1774
- */ const animate = currentTime => {
1775
- // Calculate delta time
1776
- const deltaTime = currentTime - lastFrameTime;
1777
- lastFrameTime = currentTime;
1778
- // Apply animation speed multiplier
1779
- const scaledDelta = deltaTime * animationSpeed;
1780
- elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
1781
- // Continue animation loop
1782
- animationFrameIdRef.current = requestAnimationFrame(animate);
1783
- };
1784
- // Start animation
1785
- // Cleanup
1786
- return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
1787
- () => {
1788
- null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
1789
- animationFrameIdRef.current = null);
1790
- };
1791
- }), [ effectiveWithTimeAnimation, animationSpeed ]);
1792
- /**
1793
- * Get current shader time for animations
1794
- */
1795
- const getShaderTime = useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
1750
+ }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
1796
1751
  const [glassSize, setGlassSize] = useState({
1797
1752
  width: 270,
1798
1753
  height: 69
@@ -1852,9 +1807,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1852
1807
  effectiveBorderRadius: effectiveBorderRadius,
1853
1808
  cachedRectRef: cachedRectRef
1854
1809
  }), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
1855
- /**
1856
- * Apply time-based distortion to UV coordinates
1857
- */
1858
1810
  // Extract border-radius from children
1859
1811
  useEffect((() => {
1860
1812
  const extractRadius = () => {
@@ -2014,25 +1966,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2014
1966
  * Get effective overLight value based on configuration
2015
1967
  */
2016
1968
  const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
2017
- const isOverLight = getEffectiveOverLight(), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, baseConfig = {
1969
+ const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
2018
1970
  isOverLight: isOverLight,
2019
1971
  threshold: .7,
2020
1972
  opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
2021
- contrast: 1.4,
2022
- brightness: .9,
2023
- saturationBoost: 1.3,
2024
- // Fixed value dynamic saturation amplifies perceived displacement
2025
- shadowIntensity: .9,
2026
- borderOpacity: .7
1973
+ // Dark UI (Apple Music): neutral contrast + slight brightness lift
1974
+ contrast: isOverLight ? 1.4 : 1.02,
1975
+ brightness: isOverLight ? .9 : 1.02,
1976
+ saturationBoost: isOverLight ? 1.3 : 1,
1977
+ shadowIntensity: isOverLight ? .9 : 1,
1978
+ borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
2027
1979
  };
2028
1980
  if ("object" == typeof overLight && null !== overLight) {
2029
- const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
1981
+ const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), validatedBorderOpacity = validateConfigValue(objConfig.borderOpacity, .1, 1, baseConfig.borderOpacity), finalConfig = {
2030
1982
  ...baseConfig,
2031
1983
  threshold: validatedThreshold,
2032
1984
  opacity: validatedOpacity * hoverIntensity * activeIntensity,
2033
1985
  contrast: validatedContrast,
2034
1986
  brightness: validatedBrightness,
2035
- saturationBoost: validatedSaturationBoost
1987
+ saturationBoost: validatedSaturationBoost,
1988
+ borderOpacity: validatedBorderOpacity
2036
1989
  };
2037
1990
  return "undefined" == typeof process || process.env, finalConfig;
2038
1991
  }
@@ -2057,8 +2010,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2057
2010
  };
2058
2011
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2059
2012
  internalGlobalMousePositionRef.current = {
2060
- x: lerp$1(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
2061
- y: lerp$1(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
2013
+ x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
2014
+ y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
2062
2015
  };
2063
2016
  // ── Calculate Elastic Physics ─────────────────────────────────────
2064
2017
  let targetElasticTranslation = {
@@ -2130,12 +2083,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2130
2083
  withLiquidBlur: withLiquidBlur,
2131
2084
  blurAmount: blurAmount,
2132
2085
  saturation: saturation,
2133
- padding: padding,
2134
- isFixedOrSticky: isFixedOrSticky
2086
+ isFixedOrSticky: isFixedOrSticky,
2087
+ borderAnimated: resolvedBorder.animated,
2088
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
2135
2089
  }), Math.abs(mouseVelocityRef.current.x) < .001 && Math.abs(mouseVelocityRef.current.y) < .001 && Math.abs(elasticVelocityRef.current.x) < .001 && Math.abs(elasticVelocityRef.current.y) < .001 && Math.abs(scaleVelocityRef.current.x) < .001 && Math.abs(scaleVelocityRef.current.y) < .001 && Math.abs(internalMouseOffsetRef.current.x - targetMouseOffsetRef.current.x) < .001 && Math.abs(internalMouseOffsetRef.current.y - targetMouseOffsetRef.current.y) < .001 ? stopLerpLoop() : lerpRafRef.current = requestAnimationFrame(tick);
2136
2090
  };
2137
2091
  lerpRafRef.current = requestAnimationFrame(tick);
2138
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2092
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2139
2093
  if (externalGlobalMousePosition && externalMouseOffset) return;
2140
2094
  if (effectiveWithoutEffects) return;
2141
2095
  const container = mouseContainer?.current || glassRef.current;
@@ -2199,9 +2153,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2199
2153
  withLiquidBlur: withLiquidBlur,
2200
2154
  blurAmount: blurAmount,
2201
2155
  saturation: saturation,
2202
- padding: padding
2156
+ borderAnimated: resolvedBorder.animated,
2157
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
2203
2158
  });
2204
- }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
2159
+ }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
2205
2160
  // Event handlers
2206
2161
  const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
2207
2162
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
@@ -2221,9 +2176,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2221
2176
  mouseOffset: mouseOffset,
2222
2177
  // This is now static (refs or props) unless prop changes
2223
2178
  overLightConfig: overLightConfig,
2179
+ resolvedBorder: resolvedBorder,
2224
2180
  transformStyle: transformStyle,
2225
- getShaderTime: getShaderTime,
2226
- applyTimeBasedDistortion: applyTimeBasedDistortion,
2227
2181
  handleMouseEnter: handleMouseEnter,
2228
2182
  handleMouseLeave: handleMouseLeave,
2229
2183
  handleMouseDown: handleMouseDown,
@@ -2281,148 +2235,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2281
2235
  *
2282
2236
  * @returns Performance tier classification
2283
2237
  */
2284
- /** Map an FPS value to a semantic color token string. */
2285
- const getQualityColor = quality => {
2286
- switch (quality) {
2287
- case "high":
2288
- return "var(--atomix-color-success, #4ade80)";
2289
-
2290
- case "medium":
2291
- return "var(--atomix-color-warning, #fbbf24)";
2292
-
2293
- case "low":
2294
- return "var(--atomix-color-danger, #ef4444)";
2295
-
2296
- default:
2297
- return "#9ca3af";
2298
- }
2299
- }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
2300
-
2301
- /** Map a quality level string to a semantic color token string. */
2302
- // Inject keyframes once
2303
- if ("undefined" != typeof document) {
2304
- const styleId = "perf-dashboard-keyframes";
2305
- if (!document.getElementById(styleId)) {
2306
- const styleEl = document.createElement("style");
2307
- styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
2308
- document.head.appendChild(styleEl);
2309
- }
2310
- }
2311
-
2312
- /**
2313
- * PerformanceDashboard - Real-time performance monitoring overlay.
2314
- *
2315
- * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
2316
- * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
2317
- */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
2318
- if (!isVisible) return null;
2319
- const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
2320
- var fps;
2321
- const isCritical = metrics.fps < 45;
2322
- return jsxs("div", {
2323
- className: "c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg",
2324
- style: {
2325
- zIndex: 9999,
2326
- minWidth: "12.5rem",
2327
- // 200px
2328
- backgroundColor: "rgba(17, 24, 39, 0.95)",
2329
- backdropFilter: "blur(8px)",
2330
- transition: "opacity 0.3s ease"
2331
- },
2332
- children: [ jsxs("div", {
2333
- className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
2334
- children: [ jsx("span", {
2335
- className: "u-text-sm u-font-bold u-text-white",
2336
- children: "Performance Monitor"
2337
- }), onClose && jsx("button", {
2338
- className: "u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white",
2339
- onClick: onClose,
2340
- "aria-label": "Close performance dashboard",
2341
- style: {
2342
- transition: "color 0.2s ease"
2343
- },
2344
- children: "×"
2345
- }) ]
2346
- }), jsxs("div", {
2347
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2348
- children: [ jsx("span", {
2349
- className: "u-text-gray-400 u-me-3",
2350
- children: "FPS"
2351
- }), jsx("span", {
2352
- className: "u-font-bold",
2353
- style: {
2354
- color: fpsColor
2355
- },
2356
- children: Math.round(metrics.fps)
2357
- }) ]
2358
- }), jsxs("div", {
2359
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2360
- children: [ jsx("span", {
2361
- className: "u-text-gray-400 u-me-3",
2362
- children: "Frame Time"
2363
- }), jsxs("span", {
2364
- className: "u-font-bold",
2365
- children: [ metrics.frameTime.toFixed(2), "ms" ]
2366
- }) ]
2367
- }), jsxs("div", {
2368
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2369
- children: [ jsx("span", {
2370
- className: "u-text-gray-400 u-me-3",
2371
- children: "Quality"
2372
- }), jsx("span", {
2373
- className: "u-font-bold u-text-uppercase",
2374
- style: {
2375
- fontSize: "0.6875rem",
2376
- // 11px
2377
- color: getQualityColor(metrics.qualityLevel)
2378
- },
2379
- children: metrics.qualityLevel
2380
- }) ]
2381
- }), metrics.gpuMemory && jsxs("div", {
2382
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2383
- children: [ jsx("span", {
2384
- className: "u-text-gray-400 u-me-3",
2385
- children: "GPU Memory"
2386
- }), jsxs("span", {
2387
- className: "u-font-bold",
2388
- children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
2389
- }) ]
2390
- }), metrics.isAutoScaling && jsx("div", {
2391
- className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
2392
- style: {
2393
- fontSize: "0.625rem",
2394
- // 10px
2395
- color: "#6b7280"
2396
- },
2397
- children: "Auto-scaling active"
2398
- }), jsxs("div", {
2399
- className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
2400
- children: [ jsx("div", {
2401
- className: "u-rounded-full",
2402
- style: {
2403
- width: "0.5rem",
2404
- height: "0.5rem",
2405
- flexShrink: 0,
2406
- backgroundColor: fpsColor,
2407
- ...isCritical && {
2408
- animation: "perf-dashboard-pulse 1s infinite"
2409
- }
2410
- }
2411
- }), jsx("span", {
2412
- className: "u-text-xs",
2413
- style: {
2414
- fontSize: "0.625rem",
2415
- // 10px
2416
- color: fpsColor
2417
- },
2418
- children: getFpsLabel(metrics.fps)
2419
- }) ]
2420
- }) ]
2421
- });
2422
- }));
2423
-
2424
- PerformanceDashboard.displayName = "PerformanceDashboard";
2425
-
2426
2238
  /**
2427
2239
  * Mobile optimization presets
2428
2240
  *
@@ -2542,18 +2354,13 @@ const PERFORMANCE_PRESET = {
2542
2354
  saturation: 70
2543
2355
  }
2544
2356
  }
2545
- }, AtomixGlassInner = forwardRef((function({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
2546
- const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
2547
- // Helper to merge refs
2548
- function(...refs) {
2549
- return node => {
2550
- refs.forEach((ref => {
2551
- "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
2552
- }));
2553
- };
2554
- }
2555
- // Internal implementation with forwardRef
2556
- (ref, internalWrapperRef)), [ ref ]), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = propsIsFixedOrSticky || "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
2357
+ }, AtomixGlassInner = forwardRef((function({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, border: border, withBorder: withBorder = !0, debugBorderRadius: debugBorderRadius = !1, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
2358
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
2359
+ position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
2360
+ var explicit, position;
2361
+ /**
2362
+ * Extracts layout-related properties from a React `CSSProperties` object.
2363
+ */ const {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown, resolvedBorder: resolvedBorder} = useAtomixGlass({
2557
2364
  glassRef: glassRef,
2558
2365
  contentRef: contentRef,
2559
2366
  wrapperRef: internalWrapperRef,
@@ -2573,20 +2380,13 @@ const PERFORMANCE_PRESET = {
2573
2380
  blurAmount: blurAmount,
2574
2381
  saturation: saturation,
2575
2382
  withLiquidBlur: withLiquidBlur,
2576
- padding: padding,
2383
+ border: border,
2384
+ withBorder: withBorder,
2385
+ debugBorderRadius: debugBorderRadius,
2577
2386
  style: style,
2578
- isFixedOrSticky: isFixedOrSticky,
2579
- // Phase 1: Animation System props
2580
- withTimeAnimation: withTimeAnimation,
2581
- animationSpeed: animationSpeed,
2582
- withMultiLayerDistortion: withMultiLayerDistortion,
2583
- distortionOctaves: distortionOctaves,
2584
- distortionLacunarity: distortionLacunarity,
2585
- distortionGain: distortionGain,
2586
- distortionQuality: distortionQuality
2387
+ isFixedOrSticky: isFixedOrSticky
2587
2388
  });
2588
- // Responsive breakpoint system - automatically adjusts parameters based on viewport
2589
- !
2389
+ (
2590
2390
  /**
2591
2391
  * Responsive Glass Parameters Hook
2592
2392
  *
@@ -2744,7 +2544,7 @@ const PERFORMANCE_PRESET = {
2744
2544
  }
2745
2545
  /**
2746
2546
  * Get GPU memory info if available (Chrome DevTools only)
2747
- */ ({
2547
+ */)({
2748
2548
  baseParams: {
2749
2549
  ...useMemo((() =>
2750
2550
  /**
@@ -2778,9 +2578,7 @@ const PERFORMANCE_PRESET = {
2778
2578
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
2779
2579
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
2780
2580
  debug: !1
2781
- });
2782
- // Performance monitoring - tracks FPS, frame time, memory usage
2783
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
2581
+ }),
2784
2582
  /**
2785
2583
  * Performance Monitor Hook
2786
2584
  *
@@ -2815,7 +2613,13 @@ const PERFORMANCE_PRESET = {
2815
2613
  timestamp: 0,
2816
2614
  isAutoScaling: !0,
2817
2615
  lowFpsCount: 0
2818
- }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled), frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
2616
+ }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
2617
+ // Sync external `enabled` prop changes into internal state
2618
+ useEffect((() => {
2619
+ setIsEnabled(enabled ?? !0);
2620
+ }), [ enabled ]);
2621
+ // Refs for frame tracking
2622
+ const frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
2819
2623
  setMetrics((prev => ({
2820
2624
  ...prev,
2821
2625
  ...newMetrics,
@@ -2935,191 +2739,214 @@ const PERFORMANCE_PRESET = {
2935
2739
  /**
2936
2740
  * Reset to auto-scaling mode
2937
2741
  */ var fps, currentQuality;
2938
- return {
2939
- metrics: metrics,
2940
- recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
2941
- isUnderperforming: metrics.fps < minFps,
2942
- setQualityLevel: setQualityLevel,
2943
- resetAutoScaling: resetAutoScaling,
2944
- toggleMonitoring: toggleMonitoring
2945
- };
2742
+ fps = metrics.fps, currentQuality = metrics.qualityLevel, metrics.fps;
2946
2743
  }({
2947
2744
  enabled: debugPerformance,
2948
- // Enable when debugPerformance is true
2949
2745
  debug: !1,
2950
2746
  showOverlay: !1
2951
2747
  });
2952
- // Auto-start performance monitoring when debugPerformance is enabled
2953
- React.useEffect((() => {
2954
- debugPerformance && toggleMonitoring();
2955
- // eslint-disable-next-line react-hooks/exhaustive-deps
2956
- }), [ debugPerformance ]);
2957
- // Re-run when debugPerformance changes
2958
- const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
2959
- if (!isFixedOrSticky) return {};
2960
- const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
2961
- return {
2962
- ...p && {
2963
- position: p
2964
- },
2965
- ...void 0 !== t && {
2966
- top: t
2967
- },
2968
- ...void 0 !== l && {
2969
- left: l
2970
- },
2971
- ...void 0 !== r && {
2972
- right: r
2973
- },
2974
- ...void 0 !== b && {
2975
- bottom: b
2976
- }
2977
- };
2978
- }), [ isFixedOrSticky, restStyle ]);
2979
- // Calculate base style with transforms
2980
- // When layout is hoisted to the root, strip those props from the container
2981
- useMemo((() => {
2982
- if (isFixedOrSticky) {
2983
- const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
2984
- return {
2985
- ...visualStyle
2986
- };
2748
+ const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
2749
+ ...restStyle,
2750
+ ...void 0 !== customZIndex && {
2751
+ zIndex: customZIndex
2987
2752
  }
2753
+ })), [ restStyle, customZIndex ]), componentClassName = mergeClassNames(ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className), positionStyles = useMemo((() =>
2754
+ /**
2755
+ * Returns the internal positioning context for effect layers relative to the root.
2756
+ */
2757
+ function(isFixedOrSticky, restStyle) {
2988
2758
  return {
2989
- ...restStyle
2759
+ position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2760
+ top: 0,
2761
+ left: 0,
2762
+ right: "auto",
2763
+ bottom: "auto"
2990
2764
  };
2991
- }), [ isFixedOrSticky, restStyle ]);
2992
- // Build className with state modifiers
2993
- const componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
2994
- position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2995
- top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
2996
- left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
2997
- right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
2998
- bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
2999
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
3000
- // Keep a reference to positionStyles to avoid unused-variable lint,
3001
- // but sizing is driven by explicit width/height or measured size.
3002
- positionStyles.position;
3003
- const resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
2765
+ }
2766
+ /**
2767
+ * Computes `--atomix-glass-width` and `--atomix-glass-height` values.
2768
+ *
2769
+ * Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
2770
+ * elements default to `100%`.
2771
+ */ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
2772
+ const {width: width, height: height, restStyle: restStyle, glassSize: glassSize, isFixedOrSticky: isFixedOrSticky} = options, resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
3004
2773
  return {
3005
2774
  width: resolveLength(effectiveWidth, glassSize.width),
3006
2775
  height: resolveLength(effectiveHeight, glassSize.height)
3007
2776
  };
3008
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
3009
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
3010
- return {
3011
- borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
3012
- borderStop1: Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER),
3013
- borderStop2: Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER),
3014
- borderOpacities: [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ],
3015
- hoverPositions: {
3016
- hover1: {
3017
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
3018
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
3019
- },
3020
- hover2: {
3021
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
3022
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
3023
- },
3024
- hover3: {
3025
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
3026
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
3027
- }
3028
- },
3029
- basePosition: {
3030
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
3031
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
3032
- },
3033
- mx: mx,
3034
- my: my,
3035
- absMx: absMx,
3036
- absMy: absMy
3037
- };
3038
- }), [ mouseOffset.x, mouseOffset.y ]), clampedOverLightOpacity = Math.max(0, Math.min(1, overLightConfig?.opacity ?? .4)), clampedBorderOpacity = Math.max(0, Math.min(1, overLightConfig?.borderOpacity ?? 1)), opacityValues = useMemo((() => ({
3039
- hover1: isHovered || isActive ? .5 : 0,
3040
- hover2: isActive ? .5 : 0,
3041
- hover3: isHovered ? .4 : isActive ? .8 : 0,
3042
- base: isOverLight ? clampedOverLightOpacity || .4 : 0,
3043
- over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
3044
- })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
3045
- const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues;
2777
+ }
2778
+ /**
2779
+ * Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
2780
+ *
2781
+ * These variables drive layer geometry, transforms, and stacking offsets. They
2782
+ * must not include layout properties that would interfere with backdrop-filter.
2783
+ */ ({
2784
+ width: width,
2785
+ height: height,
2786
+ restStyle: restStyle,
2787
+ glassSize: glassSize,
2788
+ isFixedOrSticky: isFixedOrSticky
2789
+ })), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
2790
+ const {effectiveBorderRadius: effectiveBorderRadius, transformStyle: transformStyle, adjustedSize: adjustedSize, isOverLight: isOverLight, customZIndex: customZIndex, isFixedOrSticky: isFixedOrSticky, positionStyles: positionStyles, restStyle: restStyle, borderWidth: borderWidth = ATOMIX_GLASS.BORDER.DEFAULT_WIDTH} = input, layerPosition =
2791
+ /**
2792
+ * Resolves the `--atomix-glass-position` value for decorative layers.
2793
+ *
2794
+ * Fixed/sticky layers use the same positioning mode as the container; in-flow
2795
+ * layers default to the internal absolute positioning context.
2796
+ */
2797
+ function(isFixedOrSticky, positionStyles, restStyle) {
2798
+ return isFixedOrSticky ? `${function(style) {
2799
+ const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
2800
+ return {
2801
+ ...null != position && {
2802
+ position: position
2803
+ },
2804
+ ...void 0 !== top && {
2805
+ top: top
2806
+ },
2807
+ ...void 0 !== left && {
2808
+ left: left
2809
+ },
2810
+ ...void 0 !== right && {
2811
+ right: right
2812
+ },
2813
+ ...void 0 !== bottom && {
2814
+ bottom: bottom
2815
+ },
2816
+ ...void 0 !== inset && {
2817
+ inset: inset
2818
+ }
2819
+ };
2820
+ }
2821
+ /**
2822
+ * Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
2823
+ *
2824
+ * For fixed and sticky modes, insets mirror the container so sibling layers remain
2825
+ * aligned. In-flow modes, insets follow the consumer `style` when a non-default
2826
+ * `position` is provided.
2827
+ */ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
2828
+ }(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
2829
+ if (isFixedOrSticky) return {
2830
+ top: formatGlassInsetValue(restStyle.top, 0),
2831
+ left: formatGlassInsetValue(restStyle.left, 0),
2832
+ right: formatGlassInsetValue(restStyle.right, "auto"),
2833
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
2834
+ };
2835
+ const position = restStyle.position;
2836
+ return null != position && "static" !== position && "relative" !== position ? {
2837
+ top: formatGlassInsetValue(restStyle.top, 0),
2838
+ left: formatGlassInsetValue(restStyle.left, 0),
2839
+ right: formatGlassInsetValue(restStyle.right, "auto"),
2840
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
2841
+ } : {
2842
+ top: "0px",
2843
+ left: "0px",
2844
+ right: "auto",
2845
+ bottom: "auto"
2846
+ };
2847
+ }(isFixedOrSticky, restStyle);
3046
2848
  return {
3047
2849
  ...void 0 !== customZIndex && {
3048
2850
  "--atomix-glass-base-z-index": customZIndex
3049
2851
  },
3050
2852
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
3051
2853
  "--atomix-glass-transform": transformStyle || "none",
3052
- "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3053
- "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3054
- "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
3055
- "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
3056
- "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
3057
- "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
2854
+ "--atomix-glass-container-position": layerPosition,
2855
+ "--atomix-glass-position": layerPosition,
2856
+ "--atomix-glass-top": layerInsets.top,
2857
+ "--atomix-glass-left": layerInsets.left,
2858
+ "--atomix-glass-right": layerInsets.right,
2859
+ "--atomix-glass-bottom": layerInsets.bottom,
3058
2860
  "--atomix-glass-width": adjustedSize.width,
3059
2861
  "--atomix-glass-height": adjustedSize.height,
3060
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
3061
- "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
3062
- "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3063
- "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3064
- "--atomix-glass-hover-1-opacity": opacityValues.hover1,
3065
- "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
3066
- "--atomix-glass-hover-2-opacity": opacityValues.hover2,
3067
- "--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
3068
- "--atomix-glass-hover-3-opacity": opacityValues.hover3,
3069
- "--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
3070
- "--atomix-glass-base-opacity": opacityValues.base,
3071
- "--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
3072
- "--atomix-glass-overlay-opacity": opacityValues.over,
3073
- "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
3074
- "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
3075
- "--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
2862
+ // Aliases maintained for backward compatibility and consumer overrides.
2863
+ "--atomix-glass-container-width": adjustedSize.width,
2864
+ "--atomix-glass-container-height": adjustedSize.height,
2865
+ [ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
2866
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
3076
2867
  };
3077
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, clampedBorderOpacity, customZIndex, isFixedOrSticky, positionStyles.position, rootLayoutStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), renderBackgroundLayer = layerType => jsx("div", {
3078
- className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
2868
+ }
2869
+ /**
2870
+ * Applies mode-specific multipliers and accessibility overrides to container effects.
2871
+ */ ({
2872
+ effectiveBorderRadius: effectiveBorderRadius,
2873
+ transformStyle: transformStyle,
2874
+ adjustedSize: adjustedSize,
2875
+ isOverLight: isOverLight,
2876
+ customZIndex: customZIndex,
2877
+ isFixedOrSticky: isFixedOrSticky,
2878
+ positionStyles: positionStyles,
2879
+ restStyle: restStyle,
2880
+ borderWidth: resolvedBorder.width
2881
+ })), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
2882
+ const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
2883
+ x: 0,
2884
+ y: 0
2885
+ }, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
2886
+ if (options.effectiveWithoutEffects) return {
2887
+ displacementScale: 0,
2888
+ blurAmount: 0,
2889
+ saturation: resolveSaturation(),
2890
+ aberrationIntensity: 0,
2891
+ mouseOffset: zeroMouse,
2892
+ globalMousePosition: zeroMouse
2893
+ };
2894
+ let resolvedDisplacement = options.displacementScale;
2895
+ "shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
2896
+ let resolvedAberration = options.aberrationIntensity;
2897
+ return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
2898
+ {
2899
+ displacementScale: resolvedDisplacement,
2900
+ blurAmount: options.blurAmount,
2901
+ saturation: resolveSaturation(),
2902
+ aberrationIntensity: resolvedAberration,
2903
+ mouseOffset: options.mouseOffset,
2904
+ globalMousePosition: options.globalMousePosition
2905
+ };
2906
+ }({
2907
+ displacementScale: displacementScale,
2908
+ blurAmount: blurAmount,
2909
+ saturation: saturation,
2910
+ aberrationIntensity: aberrationIntensity,
2911
+ mode: mode,
2912
+ effectiveWithoutEffects: effectiveWithoutEffects,
2913
+ effectiveHighContrast: effectiveHighContrast,
2914
+ isOverLight: isOverLight,
2915
+ saturationBoost: overLightConfig.saturationBoost,
2916
+ mouseOffset: mouseOffset,
2917
+ globalMousePosition: globalMousePosition
2918
+ })), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
2919
+ "aria-hidden": "true",
2920
+ className: mergeClassNames(ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS)
3079
2921
  });
3080
- // Calculate position and size styles for internal layers
3081
- // When root is fixed/sticky, internal layers use absolute (relative to root)
3082
- return jsxs("div", {
2922
+ return jsxs("div", {
3083
2923
  ...rest,
3084
2924
  ref: mergedRef,
3085
2925
  className: componentClassName,
3086
- style: {
3087
- ...glassVars
3088
- },
2926
+ style: glassVars,
3089
2927
  role: role || (onClick ? "button" : void 0),
3090
2928
  tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
3091
2929
  "aria-label": ariaLabel,
3092
2930
  "aria-describedby": ariaDescribedBy,
3093
2931
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
3094
- "aria-pressed": onClick ? isActive : void 0,
3095
2932
  onKeyDown: onClick ? handleKeyDown : void 0,
3096
2933
  children: [ jsx(AtomixGlassContainer, {
3097
2934
  ref: glassRef,
3098
2935
  contentRef: contentRef,
3099
2936
  className: className,
3100
- style: {
3101
- ...restStyle
3102
- },
2937
+ style: containerStyle,
3103
2938
  borderRadius: effectiveBorderRadius,
3104
- displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
3105
- blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
3106
- saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
3107
- aberrationIntensity: effectiveWithoutEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
2939
+ displacementScale: containerEffects.displacementScale,
2940
+ blurAmount: containerEffects.blurAmount,
2941
+ saturation: containerEffects.saturation,
2942
+ aberrationIntensity: containerEffects.aberrationIntensity,
3108
2943
  glassSize: glassSize,
3109
- padding: padding,
3110
- mouseOffset: effectiveWithoutEffects ? {
3111
- x: 0,
3112
- y: 0
3113
- } : mouseOffset,
3114
- globalMousePosition: effectiveWithoutEffects ? {
3115
- x: 0,
3116
- y: 0
3117
- } : globalMousePosition,
2944
+ mouseOffset: containerEffects.mouseOffset,
2945
+ globalMousePosition: containerEffects.globalMousePosition,
3118
2946
  onMouseEnter: handleMouseEnter,
3119
2947
  onMouseLeave: handleMouseLeave,
3120
2948
  onMouseDown: handleMouseDown,
3121
2949
  onMouseUp: handleMouseUp,
3122
- isHovered: isHovered,
3123
2950
  isActive: isActive,
3124
2951
  overLight: isOverLight,
3125
2952
  overLightConfig: {
@@ -3135,8 +2962,6 @@ const PERFORMANCE_PRESET = {
3135
2962
  shaderVariant: shaderVariant,
3136
2963
  withLiquidBlur: withLiquidBlur,
3137
2964
  isFixedOrSticky: isFixedOrSticky,
3138
- // Phase 1: Animation System props
3139
- shaderTime: getShaderTime(),
3140
2965
  withTimeAnimation: withTimeAnimation,
3141
2966
  animationSpeed: animationSpeed,
3142
2967
  withMultiLayerDistortion: withMultiLayerDistortion,
@@ -3147,32 +2972,39 @@ const PERFORMANCE_PRESET = {
3147
2972
  children: children
3148
2973
  }), Boolean(onClick) && jsxs(Fragment, {
3149
2974
  children: [ jsx("div", {
2975
+ "aria-hidden": "true",
3150
2976
  className: ATOMIX_GLASS.HOVER_1_CLASS
3151
2977
  }), jsx("div", {
2978
+ "aria-hidden": "true",
3152
2979
  className: ATOMIX_GLASS.HOVER_2_CLASS
3153
2980
  }), jsx("div", {
2981
+ "aria-hidden": "true",
3154
2982
  className: ATOMIX_GLASS.HOVER_3_CLASS
3155
2983
  }) ]
3156
- }), renderBackgroundLayer("dark"), renderBackgroundLayer("black"), shouldRenderOverLightLayers && jsxs(Fragment, {
2984
+ }), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
2985
+ children: renderBackgroundLayer(layerType)
2986
+ }, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
3157
2987
  children: [ jsx("div", {
2988
+ "aria-hidden": "true",
3158
2989
  className: ATOMIX_GLASS.BASE_LAYER_CLASS
3159
2990
  }), jsx("div", {
2991
+ "aria-hidden": "true",
3160
2992
  className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
3161
2993
  }), jsx("div", {
2994
+ "aria-hidden": "true",
3162
2995
  className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
3163
2996
  }) ]
3164
- }), withBorder && jsxs(Fragment, {
2997
+ }), resolvedBorder.enabled && jsxs(Fragment, {
3165
2998
  children: [ jsx("span", {
2999
+ "aria-hidden": "true",
3166
3000
  className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
3167
3001
  }), jsx("span", {
3002
+ "aria-hidden": "true",
3168
3003
  className: ATOMIX_GLASS.BORDER_1_CLASS
3169
3004
  }), jsx("span", {
3005
+ "aria-hidden": "true",
3170
3006
  className: ATOMIX_GLASS.BORDER_2_CLASS
3171
3007
  }) ]
3172
- }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
3173
- metrics: performanceMetrics,
3174
- isVisible: !0,
3175
- onClose: () => {}
3176
3008
  }) ]
3177
3009
  });
3178
3010
  }));
@@ -3182,10 +3014,7 @@ const PERFORMANCE_PRESET = {
3182
3014
  * Default preset for most mobile devices
3183
3015
  */ AtomixGlassInner.displayName = "AtomixGlass";
3184
3016
 
3185
- /**
3186
- * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
3187
- * Ref is forwarded to the root `<div>` element.
3188
- */
3017
+ /** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
3189
3018
  const AtomixGlass = memo(AtomixGlassInner), DefaultIcon = () => jsx("i", {
3190
3019
  className: "c-accordion__icon",
3191
3020
  "aria-hidden": "true",
@@ -3364,10 +3193,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
3364
3193
  });
3365
3194
  if (glass) {
3366
3195
  // Default glass settings for accordions
3367
- const defaultGlassProps = {
3368
- displacementScale: 20,
3369
- elasticity: 0
3370
- }, glassProps = !0 === glass ? defaultGlassProps : {
3196
+ const defaultGlassProps = GLASS_DEFAULTS_ACCORDION, glassProps = !0 === glass ? defaultGlassProps : {
3371
3197
  ...defaultGlassProps,
3372
3198
  ...glass
3373
3199
  };
@@ -3444,10 +3270,10 @@ const Accordion = AccordionWithSubcomponents, Badge = memo((({label: label, var
3444
3270
  if (glass) {
3445
3271
  // Default glass settings for badges
3446
3272
  const defaultGlassProps = {
3447
- displacementScale: 20,
3448
- borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : 16,
3449
- className: "c-badge--glass",
3450
- elasticity: 0
3273
+ ...GLASS_DEFAULTS_BADGE,
3274
+ // Override borderRadius dynamically if the ref is available
3275
+ borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : GLASS_DEFAULTS_BADGE.borderRadius,
3276
+ className: "c-badge--glass"
3451
3277
  }, glassProps = !0 === glass ? defaultGlassProps : {
3452
3278
  ...defaultGlassProps,
3453
3279
  ...glass
@@ -3697,12 +3523,7 @@ const Spinner = memo( forwardRef((({size: size = "md", variant: variant = "prim
3697
3523
  })
3698
3524
  });
3699
3525
  if (glass) {
3700
- const defaultGlassProps = {
3701
- displacementScale: 20,
3702
- blurAmount: 1,
3703
- borderRadius: 999,
3704
- mode: "shader"
3705
- }, glassProps = !0 === glass ? defaultGlassProps : {
3526
+ const defaultGlassProps = GLASS_DEFAULTS_SPINNER, glassProps = !0 === glass ? defaultGlassProps : {
3706
3527
  ...defaultGlassProps,
3707
3528
  ...glass
3708
3529
  };
@@ -3982,11 +3803,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3982
3803
  // This is a safe fallback for disabled links.
3983
3804
  if (glass) {
3984
3805
  // Default glass props
3985
- const defaultGlassProps = {
3986
- displacementScale: 20,
3987
- blurAmount: 0,
3988
- saturation: 200
3989
- }, glassProps = !0 === glass ? defaultGlassProps : {
3806
+ const defaultGlassProps = GLASS_DEFAULTS_BUTTON, glassProps = !0 === glass ? defaultGlassProps : {
3990
3807
  ...defaultGlassProps,
3991
3808
  ...glass
3992
3809
  };
@@ -4426,11 +4243,7 @@ const Callout = memo((({title: title, children: children, icon: icon, variant:
4426
4243
  // Determine appropriate ARIA attributes based on variant
4427
4244
  if (glass) {
4428
4245
  // Default glass settings for callouts
4429
- const defaultGlassProps = {
4430
- displacementScale: 30,
4431
- borderRadius: 8,
4432
- elasticity: 0
4433
- }, glassProps = !0 === glass ? defaultGlassProps : {
4246
+ const defaultGlassProps = GLASS_DEFAULTS_CALLOUT, glassProps = !0 === glass ? defaultGlassProps : {
4434
4247
  ...defaultGlassProps,
4435
4248
  ...glass
4436
4249
  };
@@ -4527,40 +4340,15 @@ ListGroup.displayName = "ListGroup";
4527
4340
 
4528
4341
  // Adapted from https://github.com/shuding/liquid-glass
4529
4342
  // Constants
4530
- const smoothStep = (a, b, t) => {
4531
- // Add input validation
4532
- if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
4533
- const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
4534
- return clamped * clamped * (3 - 2 * clamped);
4535
- }, calculateLength = (x, y) => {
4536
- // Add input validation and error handling
4537
- if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
4538
- // Prevent potential overflow
4539
- const maxX = Math.max(Math.abs(x), Math.abs(y));
4540
- if (0 === maxX) return 0;
4541
- const scaledX = x / maxX, scaledY = y / maxX;
4542
- return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
4543
- }, roundedRectSDF = (x, y, width, height, radius) => {
4343
+ const roundedRectSDF = (x, y, width, height, radius) => {
4544
4344
  // Add input validation
4545
4345
  if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
4546
4346
  const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
4547
- return Math.min(Math.max(qx, qy), 0) + calculateLength(Math.max(qx, 0), Math.max(qy, 0)) - radius;
4347
+ return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
4548
4348
  }, createTexture = (x, y) => ({
4549
4349
  x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
4550
4350
  y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
4551
- }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), clampValue = (value, min, max) =>
4552
- // Add input validation
4553
- "number" != typeof value || "number" != typeof min || "number" != typeof max || isNaN(value) ? min : isNaN(min) ? 0 : isNaN(max) ? 1 : Math.max(min, Math.min(max, value)), easeInOutCubic = t => {
4554
- // Add input validation
4555
- if ("number" != typeof t || isNaN(t)) return 0;
4556
- const clampedT = Math.max(0, Math.min(1, t));
4557
- return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
4558
- }, easeOutQuart = t => {
4559
- // Add input validation
4560
- if ("number" != typeof t || isNaN(t)) return 0;
4561
- const clampedT = Math.max(0, Math.min(1, t));
4562
- return 1 - Math.pow(1 - clampedT, 4);
4563
- }, noise2D = (x, y) => {
4351
+ }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
4564
4352
  // Add input validation
4565
4353
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
4566
4354
  const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = easeInOutCubic(xf), v = easeInOutCubic(yf), hash = (i, j) => {
@@ -4599,13 +4387,13 @@ const smoothStep = (a, b, t) => {
4599
4387
  x: .5,
4600
4388
  y: .5
4601
4389
  };
4602
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothStep(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
4390
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothstepEdge(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
4603
4391
  // Add input validation
4604
4392
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
4605
4393
  x: 0,
4606
4394
  y: 0
4607
4395
  };
4608
- const distance = calculateLength(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
4396
+ const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
4609
4397
  // Limit distance to prevent extreme values
4610
4398
  return {
4611
4399
  x: x * (1 + distortion),
@@ -4617,7 +4405,7 @@ const smoothStep = (a, b, t) => {
4617
4405
  x: 0,
4618
4406
  y: 0
4619
4407
  };
4620
- const distance = calculateLength(x, y);
4408
+ const distance = vec2Length(x, y);
4621
4409
  // Prevent division by zero and extreme values
4622
4410
  if (0 === distance) return {
4623
4411
  x: 0,
@@ -4628,8 +4416,8 @@ const smoothStep = (a, b, t) => {
4628
4416
  x: Math.cos(angle) * distance * intensity,
4629
4417
  y: Math.sin(angle) * distance * intensity
4630
4418
  };
4631
- })(ix, iy, .015 * baseDisplacement), scaled = smoothStep(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
4632
- return createTexture(clampValue(finalX * scaled + .5, 0, 1), clampValue(finalY * scaled + .5, 0, 1));
4419
+ })(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
4420
+ return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
4633
4421
  },
4634
4422
  // Premium Apple-style fluid glass with enhanced organic flow
4635
4423
  appleFluid: (uv, mousePosition) => {
@@ -4637,8 +4425,8 @@ const smoothStep = (a, b, t) => {
4637
4425
  x: .5,
4638
4426
  y: .5
4639
4427
  };
4640
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothStep(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
4641
- return createTexture(clampValue(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clampValue(totalY + .5, 0, 1));
4428
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothstepEdge(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
4429
+ return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
4642
4430
  },
4643
4431
  // High-end glass with advanced refraction and depth
4644
4432
  premiumGlass: (uv, mousePosition) => {
@@ -4646,7 +4434,7 @@ const smoothStep = (a, b, t) => {
4646
4434
  x: .5,
4647
4435
  y: .5
4648
4436
  };
4649
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), centerDistance = calculateLength(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
4437
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), centerDistance = vec2Length(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
4650
4438
  // Multi-layer depth effect
4651
4439
  let depthX = 0, depthY = 0;
4652
4440
  for (let layer = 0; layer < 3; layer++) {
@@ -4654,8 +4442,8 @@ const smoothStep = (a, b, t) => {
4654
4442
  depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
4655
4443
  }
4656
4444
  // Glass refraction with mouse influence
4657
- const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothStep(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
4658
- return createTexture(clampValue(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clampValue(finalY + .5, 0, 1));
4445
+ const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothstepEdge(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
4446
+ return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
4659
4447
  },
4660
4448
  // Metallic liquid effect with shimmer
4661
4449
  liquidMetal: (uv, mousePosition) => {
@@ -4663,8 +4451,8 @@ const smoothStep = (a, b, t) => {
4663
4451
  x: .5,
4664
4452
  y: .5
4665
4453
  };
4666
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = calculateLength(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothStep(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
4667
- return createTexture(clampValue(totalX + .5, 0, 1), clampValue(totalY + .5, 0, 1));
4454
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = vec2Length(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothstepEdge(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
4455
+ return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
4668
4456
  },
4669
4457
  // basiBasi - Expert Premium Glass Shader
4670
4458
  // The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
@@ -4673,7 +4461,7 @@ const smoothStep = (a, b, t) => {
4673
4461
  x: .5,
4674
4462
  y: .5
4675
4463
  };
4676
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
4464
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
4677
4465
  // Add input validation
4678
4466
  "number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(intensity) ? .5 : .5 * (Math.sin(8 * x + 2 * time) * Math.cos(8 * y - 2 * time) * .5 + Math.sin(8 * (x + .5) * 1.3 - 2 * time * .8) * Math.cos(8 * (y - .3) * 1.3 + 2 * time * .8) * .3 + Math.sin(8 * (x - .3) * .7 + 2 * time * 1.2) * Math.cos(8 * (y + .4) * .7 - 2 * time * 1.2) * .2 + 1) * intensity)(ix, iy, time, .8), causticDistortion = .02 * (causticIntensity - .5), refractionAngle = Math.atan2(iy, ix), spectralDispersion = ((x, y, angle) => {
4679
4467
  // Add input validation
@@ -4691,7 +4479,7 @@ const smoothStep = (a, b, t) => {
4691
4479
  y: 0
4692
4480
  }
4693
4481
  };
4694
- const distance = calculateLength(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
4482
+ const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
4695
4483
  return {
4696
4484
  r: {
4697
4485
  x: Math.cos(angle) * redOffset,
@@ -4731,8 +4519,8 @@ const smoothStep = (a, b, t) => {
4731
4519
  return turbulence;
4732
4520
  })(6 * ix, 6 * iy, time, 6), turbulenceX = .012 * Math.cos(turbulence * Math.PI * 2), turbulenceY = .012 * Math.sin(turbulence * Math.PI * 2), microSurface = ((x, y, time) =>
4733
4521
  // Add input validation
4734
- "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = calculateLength(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = calculateLength(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothStep(.92, -.12, distanceToEdge), edgeSoftness = smoothStep(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
4735
- return createTexture(clampValue(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clampValue(finalY + .5, 0, 1));
4522
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = vec2Length(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = vec2Length(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothstepEdge(.92, -.12, distanceToEdge), edgeSoftness = smoothstepEdge(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
4523
+ return createTexture(clamp(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clamp(finalY + .5, 0, 1));
4736
4524
  },
4737
4525
  // Aliases for compatibility
4738
4526
  plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
@@ -4774,8 +4562,8 @@ const smoothStep = (a, b, t) => {
4774
4562
  let dx = pos.x * w - x, dy = pos.y * h - y;
4775
4563
  // Apply edge smoothing for Apple-like effect
4776
4564
  const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
4777
- dx *= smoothStep(0, .2, edgeFactor), dy *= smoothStep(0, .2, edgeFactor), maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)),
4778
- rawValues.push(dx, dy);
4565
+ dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
4566
+ maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
4779
4567
  }
4780
4568
  // Improved normalization to prevent artifacts while maintaining intensity
4781
4569
  maxScale = Math.max(maxScale, 1);
@@ -4785,9 +4573,9 @@ const smoothStep = (a, b, t) => {
4785
4573
  let rawIndex = 0;
4786
4574
  for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
4787
4575
  const dx = rawValues[rawIndex++] || 0, dy = rawValues[rawIndex++] || 0, edgeDistance = Math.min(x, y, w - x - 1, h - y - 1), edgeFactor = Math.min(1, edgeDistance / 2), r = dx * edgeFactor / maxScale + .5, g = dy * edgeFactor / maxScale + .5, pixelIndex = 4 * (y * w + x);
4788
- data[pixelIndex] = clampValue(255 * r, 0, 255), // Red channel (X displacement)
4789
- data[pixelIndex + 1] = clampValue(255 * g, 0, 255), // Green channel (Y displacement)
4790
- data[pixelIndex + 2] = clampValue(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
4576
+ data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
4577
+ data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
4578
+ data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
4791
4579
  data[pixelIndex + 3] = 255;
4792
4580
  }
4793
4581
  return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
@@ -4815,9 +4603,7 @@ const smoothStep = (a, b, t) => {
4815
4603
  return this.canvasDPI;
4816
4604
  }
4817
4605
  },
4818
- createFBMEngine: createFBMEngine,
4819
- fragmentShaders: fragmentShaders,
4820
- liquidGlassWithTime: liquidGlassWithTime
4606
+ fragmentShaders: fragmentShaders
4821
4607
  }, Symbol.toStringTag, {
4822
4608
  value: "Module"
4823
4609
  }));