@shohojdhara/atomix 0.6.4 → 0.6.5

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 (77) 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 +566 -597
  10. package/dist/charts.js.map +1 -1
  11. package/dist/core.d.ts +30 -1
  12. package/dist/core.js +600 -624
  13. package/dist/core.js.map +1 -1
  14. package/dist/forms.d.ts +30 -1
  15. package/dist/forms.js +1122 -1163
  16. package/dist/forms.js.map +1 -1
  17. package/dist/heavy.d.ts +31 -89
  18. package/dist/heavy.js +1015 -1045
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +378 -104
  21. package/dist/index.esm.js +10959 -10837
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +10935 -10812
  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 -355
  31. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -249
  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 +411 -6
  38. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
  39. package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
  40. package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
  41. package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
  42. package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
  43. package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
  44. package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
  45. package/src/components/Badge/Badge.tsx +4 -4
  46. package/src/components/Button/Button.tsx +2 -6
  47. package/src/components/Callout/Callout.test.tsx +4 -3
  48. package/src/components/Callout/Callout.tsx +2 -5
  49. package/src/components/Dropdown/Dropdown.tsx +3 -7
  50. package/src/components/Form/Checkbox.tsx +2 -8
  51. package/src/components/Form/Input.tsx +2 -9
  52. package/src/components/Form/Radio.tsx +2 -9
  53. package/src/components/Form/Select.tsx +2 -7
  54. package/src/components/Form/Textarea.tsx +2 -9
  55. package/src/components/Messages/Messages.tsx +2 -8
  56. package/src/components/Modal/Modal.tsx +4 -5
  57. package/src/components/Navigation/Nav/Nav.tsx +2 -6
  58. package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
  59. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
  60. package/src/components/Pagination/Pagination.tsx +2 -10
  61. package/src/components/Popover/Popover.tsx +2 -9
  62. package/src/components/Progress/Progress.tsx +2 -7
  63. package/src/components/Rating/Rating.tsx +2 -10
  64. package/src/components/Spinner/Spinner.tsx +2 -7
  65. package/src/components/Steps/Steps.tsx +2 -10
  66. package/src/components/Tabs/Tabs.tsx +2 -9
  67. package/src/components/Toggle/Toggle.tsx +2 -10
  68. package/src/components/Tooltip/Tooltip.tsx +2 -5
  69. package/src/lib/composables/useAtomixGlass.ts +41 -10
  70. package/src/lib/composables/useAtomixGlassStyles.ts +59 -75
  71. package/src/lib/composables/usePerformanceMonitor.ts +5 -0
  72. package/src/lib/constants/components.ts +358 -46
  73. package/src/lib/types/components.ts +33 -1
  74. package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
  75. package/src/styles/02-tools/_tools.glass.scss +45 -3
  76. package/src/styles/06-components/_components.atomix-glass.scss +114 -77
  77. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/heavy.js CHANGED
@@ -25,7 +25,56 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
25
25
  ACTIVE: "c-btn--active",
26
26
  SELECTED: "c-btn--selected"
27
27
  }
28
- }, VIDEO_PLAYER_CLASSES_BASE = "c-video-player", VIDEO_PLAYER_CLASSES_VIDEO = "c-video-player__video", VIDEO_PLAYER_CLASSES_YOUTUBE = "c-video-player--youtube", VIDEO_PLAYER_CLASSES_LOADING = "c-video-player__loading", VIDEO_PLAYER_CLASSES_SPINNER = "c-video-player__spinner", VIDEO_PLAYER_CLASSES_CONTROLS = "c-video-player__controls", VIDEO_PLAYER_CLASSES_CONTROLS_VISIBLE = "c-video-player__controls--visible", VIDEO_PLAYER_CLASSES_PROGRESS_CONTAINER = "c-video-player__progress-container", VIDEO_PLAYER_CLASSES_PROGRESS_BAR = "c-video-player__progress-bar", VIDEO_PLAYER_CLASSES_PROGRESS_BUFFERED = "c-video-player__progress-buffered", VIDEO_PLAYER_CLASSES_PROGRESS_PLAYED = "c-video-player__progress-played", VIDEO_PLAYER_CLASSES_PROGRESS_THUMB = "c-video-player__progress-thumb", VIDEO_PLAYER_CLASSES_CONTROLS_ROW = "c-video-player__controls-row", VIDEO_PLAYER_CLASSES_CONTROLS_LEFT = "c-video-player__controls-left", VIDEO_PLAYER_CLASSES_CONTROLS_RIGHT = "c-video-player__controls-right", VIDEO_PLAYER_CLASSES_CONTROL_BUTTON = "c-video-player__control-button", VIDEO_PLAYER_CLASSES_VOLUME_CONTAINER = "c-video-player__volume-container", VIDEO_PLAYER_CLASSES_VOLUME_SLIDER = "c-video-player__volume-slider", VIDEO_PLAYER_CLASSES_VOLUME_BAR = "c-video-player__volume-bar", VIDEO_PLAYER_CLASSES_VOLUME_FILL = "c-video-player__volume-fill", VIDEO_PLAYER_CLASSES_TIME_DISPLAY = "c-video-player__time-display", VIDEO_PLAYER_CLASSES_SETTINGS_CONTAINER = "c-video-player__settings-container", VIDEO_PLAYER_CLASSES_SETTINGS_MENU = "c-video-player__settings-menu", VIDEO_PLAYER_CLASSES_SETTINGS_TABS = "c-video-player__settings-tabs", VIDEO_PLAYER_CLASSES_SETTINGS_TAB = "c-video-player__settings-tab", VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE = "c-video-player__settings-tab--active", VIDEO_PLAYER_CLASSES_SETTINGS_CONTENT = "c-video-player__settings-content", VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS = "c-video-player__settings-options", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION = "c-video-player__settings-option", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE = "c-video-player__settings-option--active", VIDEO_PLAYER_CLASSES_AMBIENT = "c-video-player--ambient", VIDEO_PLAYER_CLASSES_AMBIENT_CANVAS = "c-video-player__ambient-canvas", VIDEO_PLAYER_CLASSES_GLASS = "c-video-player--glass", VIDEO_PLAYER_CLASSES_GLASS_OVERLAY = "c-video-player__glass-overlay", VIDEO_PLAYER_CLASSES_GLASS_CONTENT = "c-video-player__glass-content", ATOMIX_GLASS = {
28
+ }, VIDEO_PLAYER_CLASSES_BASE = "c-video-player", VIDEO_PLAYER_CLASSES_VIDEO = "c-video-player__video", VIDEO_PLAYER_CLASSES_YOUTUBE = "c-video-player--youtube", VIDEO_PLAYER_CLASSES_LOADING = "c-video-player__loading", VIDEO_PLAYER_CLASSES_SPINNER = "c-video-player__spinner", VIDEO_PLAYER_CLASSES_CONTROLS = "c-video-player__controls", VIDEO_PLAYER_CLASSES_CONTROLS_VISIBLE = "c-video-player__controls--visible", VIDEO_PLAYER_CLASSES_PROGRESS_CONTAINER = "c-video-player__progress-container", VIDEO_PLAYER_CLASSES_PROGRESS_BAR = "c-video-player__progress-bar", VIDEO_PLAYER_CLASSES_PROGRESS_BUFFERED = "c-video-player__progress-buffered", VIDEO_PLAYER_CLASSES_PROGRESS_PLAYED = "c-video-player__progress-played", VIDEO_PLAYER_CLASSES_PROGRESS_THUMB = "c-video-player__progress-thumb", VIDEO_PLAYER_CLASSES_CONTROLS_ROW = "c-video-player__controls-row", VIDEO_PLAYER_CLASSES_CONTROLS_LEFT = "c-video-player__controls-left", VIDEO_PLAYER_CLASSES_CONTROLS_RIGHT = "c-video-player__controls-right", VIDEO_PLAYER_CLASSES_CONTROL_BUTTON = "c-video-player__control-button", VIDEO_PLAYER_CLASSES_VOLUME_CONTAINER = "c-video-player__volume-container", VIDEO_PLAYER_CLASSES_VOLUME_SLIDER = "c-video-player__volume-slider", VIDEO_PLAYER_CLASSES_VOLUME_BAR = "c-video-player__volume-bar", VIDEO_PLAYER_CLASSES_VOLUME_FILL = "c-video-player__volume-fill", VIDEO_PLAYER_CLASSES_TIME_DISPLAY = "c-video-player__time-display", VIDEO_PLAYER_CLASSES_SETTINGS_CONTAINER = "c-video-player__settings-container", VIDEO_PLAYER_CLASSES_SETTINGS_MENU = "c-video-player__settings-menu", VIDEO_PLAYER_CLASSES_SETTINGS_TABS = "c-video-player__settings-tabs", VIDEO_PLAYER_CLASSES_SETTINGS_TAB = "c-video-player__settings-tab", VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE = "c-video-player__settings-tab--active", VIDEO_PLAYER_CLASSES_SETTINGS_CONTENT = "c-video-player__settings-content", VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS = "c-video-player__settings-options", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION = "c-video-player__settings-option", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE = "c-video-player__settings-option--active", VIDEO_PLAYER_CLASSES_AMBIENT = "c-video-player--ambient", VIDEO_PLAYER_CLASSES_AMBIENT_CANVAS = "c-video-player__ambient-canvas", VIDEO_PLAYER_CLASSES_GLASS = "c-video-player--glass", VIDEO_PLAYER_CLASSES_GLASS_OVERLAY = "c-video-player__glass-overlay", VIDEO_PLAYER_CLASSES_GLASS_CONTENT = "c-video-player__glass-content", GLASS_DEFAULTS_BUTTON = {
29
+ displacementScale: 16,
30
+ saturation: 180,
31
+ elasticity: 0
32
+ }, GLASS_DEFAULTS_BADGE = {
33
+ displacementScale: 14,
34
+ borderRadius: 16,
35
+ elasticity: 0
36
+ }, GLASS_DEFAULTS_SPINNER = {
37
+ displacementScale: 12,
38
+ elasticity: 0
39
+ }, GLASS_BORDER_GRADIENT = {
40
+ BASE_ANGLE: 135,
41
+ ANGLE_MULTIPLIER: .5,
42
+ VELOCITY_ANGLE_MULTIPLIER: .5,
43
+ CHROMATIC_OFFSET: 1.5,
44
+ STOP_1: {
45
+ MIN: 10,
46
+ BASE: 33,
47
+ get MULTIPLIER() {
48
+ return .009 * this.BASE;
49
+ }
50
+ },
51
+ STOP_2: {
52
+ MAX: 90,
53
+ BASE: 66,
54
+ get MULTIPLIER() {
55
+ return .006 * this.BASE;
56
+ }
57
+ },
58
+ OPACITY: {
59
+ /** Matches $glass-border-1-opacity (0.08) */
60
+ BASE_1: .08,
61
+ get BASE_2() {
62
+ return 3.33 * this.BASE_1;
63
+ },
64
+ get BASE_3() {
65
+ return 2.66 * this.BASE_1;
66
+ },
67
+ get BASE_4() {
68
+ return 5 * this.BASE_1;
69
+ },
70
+ get MULTIPLIER_LOW() {
71
+ return .066 * this.BASE_1;
72
+ },
73
+ get MULTIPLIER_HIGH() {
74
+ return .1 * this.BASE_1;
75
+ }
76
+ }
77
+ }, ATOMIX_GLASS = {
29
78
  BASE_CLASS: "c-atomix-glass",
30
79
  CONTAINER_CLASS: "c-atomix-glass__container",
31
80
  INNER_CLASS: "c-atomix-glass__inner",
@@ -36,6 +85,22 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
36
85
  BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
37
86
  BORDER_1_CLASS: "c-atomix-glass__border-1",
38
87
  BORDER_2_CLASS: "c-atomix-glass__border-2",
88
+ /** Centralized liquid glass rim configuration */
89
+ BORDER: {
90
+ WIDTH_CSS_VAR: "--atomix-glass-border-width",
91
+ DEFAULT_WIDTH: "0.5px",
92
+ GRADIENT_CSS_VARS: {
93
+ GRADIENT_1: "--atomix-glass-border-gradient-1",
94
+ GRADIENT_2: "--atomix-glass-border-gradient-2"
95
+ },
96
+ GRADIENT: GLASS_BORDER_GRADIENT,
97
+ OVER_LIGHT: {
98
+ opacity: .7
99
+ },
100
+ DARK: {
101
+ opacity: .35
102
+ }
103
+ },
39
104
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
40
105
  HOVER_2_CLASS: "c-atomix-glass__hover-2",
41
106
  HOVER_3_CLASS: "c-atomix-glass__hover-3",
@@ -64,25 +129,22 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
64
129
  SHADER: "c-atomix-glass--shader"
65
130
  },
66
131
  DEFAULTS: {
67
- DISPLACEMENT_SCALE: 70,
132
+ /** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
133
+ DISPLACEMENT_SCALE: 28,
68
134
  get BLUR_AMOUNT() {
69
- return .15 * this.DISPLACEMENT_SCALE;
70
- // Dynamically computed based on displacement
71
- },
72
- get SATURATION() {
73
- return 100 + .5 * this.DISPLACEMENT_SCALE;
74
- // Saturate relative to intensity
75
- },
135
+ // Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
136
+ return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
137
+ },
138
+ /** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
139
+ SATURATION: 180,
76
140
  get ABERRATION_INTENSITY() {
77
- return .03 * this.DISPLACEMENT_SCALE;
78
- // Scale aberration with displacement
79
- },
80
- ELASTICITY: .15,
141
+ return .02 * this.DISPLACEMENT_SCALE;
142
+ },
143
+ ELASTICITY: .05,
81
144
  get CORNER_RADIUS() {
82
145
  return 16;
83
146
  // Use 16 to match SCSS design system (was 20)
84
147
  },
85
- PADDING: "0",
86
148
  MODE: "standard",
87
149
  OVER_LIGHT: !1,
88
150
  ENABLE_OVER_LIGHT_LAYERS: !0,
@@ -98,19 +160,24 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
98
160
  },
99
161
  CONSTANTS: {
100
162
  ACTIVATION_ZONE: 200,
101
- LERP_FACTOR: .08,
163
+ LERP_FACTOR: .05,
164
+ // Lower = more viscous, liquid-smooth tracking (Apple feel)
102
165
  SMOOTHSTEP_POWER: 2.5,
103
166
  MIN_BLUR: .1,
104
167
  MOUSE_INFLUENCE_DIVISOR: 100,
105
168
  EDGE_FADE_PIXELS: 2,
106
- // Elasticity physics constants
107
- ELASTICITY_TRANSLATION_FACTOR: .1,
169
+ // Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
170
+ ELASTICITY_TRANSLATION_FACTOR: .06,
171
+ // Subtler elastic shift (was 0.1)
108
172
  ELASTICITY_DISTANCE_THRESHOLD: 200,
109
173
  ELASTICITY_COMPRESSION_FACTOR: .3,
110
- ELASTICITY_STIFFNESS: .1,
111
- ELASTICITY_DAMPING: .76,
174
+ ELASTICITY_STIFFNESS: .06,
175
+ // Softer springs = gentler motion (was 0.1)
176
+ ELASTICITY_DAMPING: .88,
177
+ // Fast settling, no wobble (was 0.76)
112
178
  ELASTICITY_VELOCITY_FACTOR: .65,
113
- ELASTICITY_STRETCH_RATIO: .45,
179
+ ELASTICITY_STRETCH_RATIO: .25,
180
+ // Less visible surface tension stretch (was 0.45)
114
181
  ELASTICITY_MAGNIFICATION_BASE: 1.02,
115
182
  // Note: This default must match the SCSS variable --atomix-radius-md
116
183
  // @see src/styles/01-settings/_settings.global.scss
@@ -124,55 +191,16 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
124
191
  },
125
192
  // Gradient calculation constants
126
193
  GRADIENT: {
127
- BASE_ANGLE: 135,
128
- // Base angle for border gradients (degrees)
129
- ANGLE_MULTIPLIER: 1.2,
130
- // Multiplier for mouse influence on angle
131
- VELOCITY_ANGLE_MULTIPLIER: 2.5,
132
- // How much velocity affects gradient rotation
133
- CHROMATIC_OFFSET: 1.5,
134
- // Degree offset for chromatic rim layers
135
- BORDER_STOP_1: {
136
- MIN: 10,
137
- // Minimum percentage for border stop 1
138
- BASE: 33,
139
- // Base percentage for border stop 1
140
- get MULTIPLIER() {
141
- return .009 * this.BASE;
142
- }
143
- },
144
- BORDER_STOP_2: {
145
- MAX: 90,
146
- // Maximum percentage for border stop 2
147
- BASE: 66,
148
- // Base percentage for border stop 2
149
- get MULTIPLIER() {
150
- return .006 * this.BASE;
151
- }
152
- },
153
- BORDER_OPACITY: {
154
- BASE_1: .12,
155
- // Base opacity for border gradient 1
156
- get BASE_2() {
157
- return 3.33 * this.BASE_1;
158
- },
159
- // Base opacity for border gradient 2
160
- get BASE_3() {
161
- return 2.66 * this.BASE_1;
162
- },
163
- // Base opacity for border gradient 3
164
- get BASE_4() {
165
- return 5 * this.BASE_1;
166
- },
167
- // Base opacity for border gradient 4
168
- get MULTIPLIER_LOW() {
169
- return .066 * this.BASE_1;
170
- },
171
- // Low multiplier for mouse influence on opacity
172
- get MULTIPLIER_HIGH() {
173
- return .1 * this.BASE_1;
174
- }
175
- },
194
+ BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
195
+ ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
196
+ VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
197
+ CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
198
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
199
+ BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
200
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
201
+ BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
202
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
203
+ BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
176
204
  CENTER_POSITION: 50,
177
205
  // Center position percentage (50%)
178
206
  HOVER_POSITION: {
@@ -205,8 +233,8 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
205
233
  return 2 * this.BLACK_STOP;
206
234
  },
207
235
  // End percentage for black hover 1
208
- WHITE_START: .5,
209
- // Start opacity for white hover 1
236
+ WHITE_START: .35,
237
+ // Gentler hover flash Apple hover is barely visible
210
238
  get WHITE_STOP() {
211
239
  return this.BLACK_END - 10;
212
240
  }
@@ -224,8 +252,8 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
224
252
  return 2 * this.BLACK_STOP;
225
253
  },
226
254
  // End percentage for black hover 2
227
- WHITE_START: 1,
228
- // Start opacity for white hover 2
255
+ WHITE_START: .7,
256
+ // Gentler hover flash
229
257
  get WHITE_STOP() {
230
258
  return this.BLACK_END;
231
259
  }
@@ -243,8 +271,8 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
243
271
  return 2 * this.BLACK_STOP;
244
272
  },
245
273
  // End percentage for black hover 3
246
- WHITE_START: 1,
247
- // Start opacity for white hover 3
274
+ WHITE_START: .7,
275
+ // Gentler hover flash
248
276
  get WHITE_STOP() {
249
277
  return this.BLACK_END;
250
278
  }
@@ -254,13 +282,13 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
254
282
  BASE_GRADIENT: {
255
283
  ANGLE: 135,
256
284
  // Gradient angle in degrees
257
- BLACK_START_BASE: .15,
285
+ BLACK_START_BASE: .1,
258
286
  // Base start opacity for black
259
287
  get BLACK_START_MULTIPLIER() {
260
288
  return .02 * this.BLACK_START_BASE;
261
289
  },
262
290
  // Multiplier for mouse X influence on start
263
- BLACK_MID_BASE: .1,
291
+ BLACK_MID_BASE: .07,
264
292
  // Base mid opacity for black
265
293
  get BLACK_MID_MULTIPLIER() {
266
294
  return .02 * this.BLACK_MID_BASE;
@@ -281,7 +309,7 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
281
309
  }
282
310
  },
283
311
  OVERLAY_GRADIENT: {
284
- BLACK_START_BASE: .12,
312
+ BLACK_START_BASE: .08,
285
313
  // Base start opacity for black overlay
286
314
  get BLACK_START_MULTIPLIER() {
287
315
  return .025 * this.BLACK_START_BASE;
@@ -305,14 +333,14 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
305
333
  return .416 * this.BLACK_START_BASE;
306
334
  }
307
335
  },
308
- // Overlay highlight constants
336
+ // Overlay highlight constants — Apple places specular at the top-center
309
337
  OVERLAY_HIGHLIGHT: {
310
- POSITION_X: 20,
311
- // X position percentage
312
- POSITION_Y: 20,
313
- // Y position percentage
314
- WHITE_OPACITY: .4,
315
- // White opacity in gradient
338
+ POSITION_X: 50,
339
+ // Centered horizontal — Apple's top-center specular
340
+ POSITION_Y: 5,
341
+ // Very top — catches light like a curved glass surface
342
+ WHITE_OPACITY: .28,
343
+ // Softer specular visible but not glaring
316
344
  get STOP() {
317
345
  return 150 * this.WHITE_OPACITY;
318
346
  },
@@ -333,6 +361,10 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
333
361
  SATURATION: {
334
362
  HIGH_CONTRAST: 200
335
363
  },
364
+ // Container shadows — hairline inner catch + soft floating lift (Apple player bar)
365
+ CONTAINER_SHADOW: {
366
+ LIGHT: "inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 8px 32px rgba(0, 0, 0, 0.28), 0 2px 8px rgba(0, 0, 0, 0.16)"
367
+ },
336
368
  // Phase 1: Animation System Constants
337
369
  ANIMATION: {
338
370
  // Breathing effect timing (in milliseconds)
@@ -372,111 +404,490 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
372
404
  }
373
405
  }
374
406
  }
375
- }, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
376
- x: rect.left + rect.width / 2,
377
- y: rect.top + rect.height / 2
378
- } : {
379
- x: 0,
380
- y: 0
381
- }, calculateMouseInfluence = mouseOffset => {
382
- if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
383
- // Bounded calculation keeps the glass effect subtle and stable
384
- const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
385
- return Math.min(.8, influence);
386
- // Tighter cap to prevent blur/filter blow-out
387
- }, 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 => {
388
- if ("number" == typeof value) return Math.max(0, value);
389
- if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
390
- const trimmedValue = value.trim();
391
- // Handle px values
392
- if (trimmedValue.endsWith("px")) {
393
- const parsed = parseFloat(trimmedValue);
394
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
395
- }
396
- // Handle rem values (assume 16px = 1rem)
397
- if (trimmedValue.endsWith("rem")) {
398
- const parsed = parseFloat(trimmedValue);
399
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
400
- }
401
- // Handle em values (assume 16px = 1em for simplicity)
402
- if (trimmedValue.endsWith("em")) {
403
- const parsed = parseFloat(trimmedValue);
404
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
405
- }
406
- // Handle percentage (convert to approximate px value, assuming 200px container)
407
- if (trimmedValue.endsWith("%")) {
408
- const parsed = parseFloat(trimmedValue);
409
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
410
- }
411
- // Handle unitless numbers
412
- const numValue = parseFloat(trimmedValue);
413
- return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
414
- }, extractBorderRadiusFromElement = element => {
415
- if (!element || !element.props) return null;
416
- // Check inline styles first (highest priority)
417
- if (element.props.style) {
418
- const radiusFromStyle = (style => {
419
- if (!style) return null;
420
- // Check various border-radius properties
421
- const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
422
- return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
423
- })(element.props.style);
424
- if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
425
- }
426
- // If element has children, recursively check them
427
- if (element.props.children) {
428
- const childRadius = extractBorderRadiusFromChildren(element.props.children);
429
- if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
430
- }
431
- return null;
432
- }, extractBorderRadiusFromChildren = children => {
433
- if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
407
+ };
408
+
409
+ var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
410
+
411
+ function getDefaultExportFromCjs(x) {
412
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
413
+ }
414
+
415
+ var fails$8 = function(exec) {
434
416
  try {
435
- const childArray = React.Children.toArray(children);
436
- for (let i = 0; i < childArray.length; i++) {
437
- const child = childArray[i];
438
- if ( React.isValidElement(child)) {
439
- const radius = extractBorderRadiusFromElement(child);
440
- if (null !== radius) return radius;
441
- }
442
- }
417
+ return !!exec();
443
418
  } catch (error) {
444
- // Silently handle errors
419
+ return !0;
445
420
  }
446
- return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
447
- }, smoothstep = t => {
448
- const clamped = Math.max(0, Math.min(1, t));
449
- return clamped * clamped * (3 - 2 * clamped);
450
- }, 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) => {
451
- const newVelocity = (velocity + (target - current) * stiffness) * damping;
421
+ }, functionBindNative = !fails$8((function() {
422
+ // eslint-disable-next-line es/no-function-prototype-bind -- safe
423
+ var test = function() {/* empty */}.bind();
424
+ // eslint-disable-next-line no-prototype-builtins -- safe
425
+ return "function" != typeof test || test.hasOwnProperty("prototype");
426
+ })), NATIVE_BIND$3 = functionBindNative, FunctionPrototype$1 = Function.prototype, call$5 = FunctionPrototype$1.call, uncurryThisWithBind = NATIVE_BIND$3 && FunctionPrototype$1.bind.bind(call$5, call$5), functionUncurryThis = NATIVE_BIND$3 ? uncurryThisWithBind : function(fn) {
427
+ return function() {
428
+ return call$5.apply(fn, arguments);
429
+ };
430
+ }, objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf), check = function(it) {
431
+ return it && it.Math === Math && it;
432
+ }, globalThis_1 =
433
+ // eslint-disable-next-line es/no-global-this -- safe
434
+ check("object" == typeof globalThis && globalThis) || check("object" == typeof window && window) ||
435
+ // eslint-disable-next-line no-restricted-globals -- safe
436
+ check("object" == typeof self && self) || check("object" == typeof commonjsGlobal && commonjsGlobal) || check("object" == typeof commonjsGlobal && commonjsGlobal) ||
437
+ // eslint-disable-next-line no-new-func -- fallback
438
+ function() {
439
+ return this;
440
+ }() || Function("return this")(), NATIVE_BIND$2 = functionBindNative, FunctionPrototype = Function.prototype, apply$1 = FunctionPrototype.apply, call$4 = FunctionPrototype.call, functionApply = "object" == typeof Reflect && Reflect.apply || (NATIVE_BIND$2 ? call$4.bind(apply$1) : function() {
441
+ return call$4.apply(apply$1, arguments);
442
+ }), uncurryThis$7 = functionUncurryThis, toString$3 = uncurryThis$7({}.toString), stringSlice = uncurryThis$7("".slice), classofRaw$2 = function(it) {
443
+ return stringSlice(toString$3(it), 8, -1);
444
+ }, classofRaw$1 = classofRaw$2, uncurryThis$6 = functionUncurryThis, functionUncurryThisClause = function(fn) {
445
+ // Nashorn bug:
446
+ // https://github.com/zloirock/core-js/issues/1128
447
+ // https://github.com/zloirock/core-js/issues/1130
448
+ if ("Function" === classofRaw$1(fn)) return uncurryThis$6(fn);
449
+ }, documentAll = "object" == typeof document && document.all, isCallable$8 = void 0 === documentAll && void 0 !== documentAll ? function(argument) {
450
+ return "function" == typeof argument || argument === documentAll;
451
+ } : function(argument) {
452
+ return "function" == typeof argument;
453
+ }, objectGetOwnPropertyDescriptor = {}, descriptors = !fails$8((function() {
454
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
455
+ return 7 !== Object.defineProperty({}, 1, {
456
+ get: function() {
457
+ return 7;
458
+ }
459
+ })[1];
460
+ })), NATIVE_BIND$1 = functionBindNative, call$3 = Function.prototype.call, functionCall = NATIVE_BIND$1 ? call$3.bind(call$3) : function() {
461
+ return call$3.apply(call$3, arguments);
462
+ }, objectPropertyIsEnumerable = {}, $propertyIsEnumerable = {}.propertyIsEnumerable, getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor, NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({
463
+ 1: 2
464
+ }, 1);
465
+
466
+ // `Object.prototype.propertyIsEnumerable` method implementation
467
+ // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
468
+ objectPropertyIsEnumerable.f = NASHORN_BUG ? function(V) {
469
+ var descriptor = getOwnPropertyDescriptor$1(this, V);
470
+ return !!descriptor && descriptor.enumerable;
471
+ } : $propertyIsEnumerable;
472
+
473
+ var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
452
474
  return {
453
- value: current + newVelocity,
454
- velocity: newVelocity
475
+ enumerable: !(1 & bitmap),
476
+ configurable: !(2 & bitmap),
477
+ writable: !(4 & bitmap),
478
+ value: value
455
479
  };
456
- }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
457
- switch (mode) {
458
- case "standard":
459
- return displacementMap;
480
+ }, fails$5 = fails$8, classof$3 = classofRaw$2, $Object$3 = Object, split = functionUncurryThis("".split), indexedObject = fails$5((function() {
481
+ // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
482
+ // eslint-disable-next-line no-prototype-builtins -- safe
483
+ return !$Object$3("z").propertyIsEnumerable(0);
484
+ })) ? function(it) {
485
+ return "String" === classof$3(it) ? split(it, "") : $Object$3(it);
486
+ } : $Object$3, isNullOrUndefined$2 = function(it) {
487
+ return null == it;
488
+ }, isNullOrUndefined$1 = isNullOrUndefined$2, $TypeError$6 = TypeError, requireObjectCoercible$3 = function(it) {
489
+ if (isNullOrUndefined$1(it)) throw new $TypeError$6("Can't call method on " + it);
490
+ return it;
491
+ }, IndexedObject = indexedObject, requireObjectCoercible$2 = requireObjectCoercible$3, toIndexedObject$2 = function(it) {
492
+ return IndexedObject(requireObjectCoercible$2(it));
493
+ }, isCallable$7 = isCallable$8, isObject$5 = function(it) {
494
+ return "object" == typeof it ? null !== it : isCallable$7(it);
495
+ }, path$3 = {}, path$2 = path$3, globalThis$a = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
496
+ return isCallable$6(variable) ? variable : void 0;
497
+ }, navigator$1 = globalThis_1.navigator, userAgent$1 = navigator$1 && navigator$1.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
460
498
 
461
- case "polar":
462
- return polarDisplacementMap;
499
+ v8 && (
500
+ // in old Chrome, versions of V8 isn't V8 = Chrome / 10
501
+ // but their correct versions are not interesting for us
502
+ version = (match = v8.split("."))[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1])),
503
+ // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
504
+ // so check `userAgent` even if `.v8` exists, but 0
505
+ !version && userAgent && (!(match = userAgent.match(/Edge\/(\d+)/)) || match[1] >= 74) && (match = userAgent.match(/Chrome\/(\d+)/)) && (version = +match[1]);
463
506
 
464
- case "prominent":
465
- return prominentDisplacementMap;
507
+ var V8_VERSION = version, fails$4 = fails$8, $String$3 = globalThis_1.String, symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$4((function() {
508
+ var symbol = Symbol("symbol detection");
509
+ // Chrome 38 Symbol has incorrect toString conversion
510
+ // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
511
+ // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
512
+ // of course, fail.
513
+ return !$String$3(symbol) || !(Object(symbol) instanceof Symbol) ||
514
+ // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
515
+ !Symbol.sham && V8_VERSION && V8_VERSION < 41;
516
+ })), useSymbolAsUid = symbolConstructorDetection && !Symbol.sham && "symbol" == typeof Symbol.iterator, isCallable$5 = isCallable$8, isPrototypeOf$1 = objectIsPrototypeOf, $Object$2 = Object, isSymbol$2 = useSymbolAsUid ? function(it) {
517
+ return "symbol" == typeof it;
518
+ } : function(it) {
519
+ var $Symbol = function(namespace, method) {
520
+ return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(globalThis$a[namespace]) : path$2[namespace] && path$2[namespace][method] || globalThis$a[namespace] && globalThis$a[namespace][method];
521
+ }("Symbol");
522
+ return isCallable$5($Symbol) && isPrototypeOf$1($Symbol.prototype, $Object$2(it));
523
+ }, $String$2 = String, isCallable$4 = isCallable$8, $TypeError$5 = TypeError, aCallable$2 = function(argument) {
524
+ if (isCallable$4(argument)) return argument;
525
+ throw new $TypeError$5(function(argument) {
526
+ try {
527
+ return $String$2(argument);
528
+ } catch (error) {
529
+ return "Object";
530
+ }
531
+ }(argument) + " is not a function");
532
+ }, aCallable$1 = aCallable$2, isNullOrUndefined = isNullOrUndefined$2, call$2 = functionCall, isCallable$3 = isCallable$8, isObject$4 = isObject$5, $TypeError$4 = TypeError, sharedStore = {
533
+ exports: {}
534
+ }, globalThis$6 = globalThis_1, defineProperty = Object.defineProperty, globalThis$5 = globalThis_1, store$1 = sharedStore.exports = globalThis$5["__core-js_shared__"] || function(key, value) {
535
+ try {
536
+ defineProperty(globalThis$6, key, {
537
+ value: value,
538
+ configurable: !0,
539
+ writable: !0
540
+ });
541
+ } catch (error) {
542
+ globalThis$6[key] = value;
543
+ }
544
+ return value;
545
+ }("__core-js_shared__", {});
466
546
 
467
- case "shader":
468
- return shaderMapUrl || displacementMap;
547
+ /* eslint-disable es/no-symbol -- required for testing */ (store$1.versions || (store$1.versions = [])).push({
548
+ version: "3.43.0",
549
+ mode: "pure",
550
+ copyright: "© 2014-2025 Denis Pushkarev (zloirock.ru)",
551
+ license: "https://github.com/zloirock/core-js/blob/v3.43.0/LICENSE",
552
+ source: "https://github.com/zloirock/core-js"
553
+ });
469
554
 
470
- default:
471
- return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
555
+ var key, value, store = sharedStore.exports, requireObjectCoercible$1 = requireObjectCoercible$3, $Object$1 = Object, hasOwnProperty = functionUncurryThis({}.hasOwnProperty), hasOwnProperty_1 = Object.hasOwn || function(it, key) {
556
+ return hasOwnProperty($Object$1(requireObjectCoercible$1(it)), key);
557
+ }, uncurryThis$3 = functionUncurryThis, id = 0, postfix = Math.random(), toString$2 = uncurryThis$3(1.1.toString), hasOwn$2 = hasOwnProperty_1, NATIVE_SYMBOL = symbolConstructorDetection, USE_SYMBOL_AS_UID = useSymbolAsUid, Symbol$1 = globalThis_1.Symbol, WellKnownSymbolsStore = store[key = "wks"] || (store[key] = value || {}), createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1.for || Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || function(key) {
558
+ return "Symbol(" + (void 0 === key ? "" : key) + ")_" + toString$2(++id + postfix, 36);
559
+ }, wellKnownSymbol$5 = function(name) {
560
+ return hasOwn$2(WellKnownSymbolsStore, name) || (WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn$2(Symbol$1, name) ? Symbol$1[name] : createWellKnownSymbol("Symbol." + name)),
561
+ WellKnownSymbolsStore[name];
562
+ }, call$1 = functionCall, isObject$3 = isObject$5, isSymbol$1 = isSymbol$2, $TypeError$3 = TypeError, TO_PRIMITIVE = wellKnownSymbol$5("toPrimitive"), toPrimitive = function(input, pref) {
563
+ if (!isObject$3(input) || isSymbol$1(input)) return input;
564
+ var result, func, exoticToPrim = (func = input[TO_PRIMITIVE], isNullOrUndefined(func) ? void 0 : aCallable$1(func));
565
+ if (exoticToPrim) {
566
+ if (void 0 === pref && (pref = "default"), result = call$1(exoticToPrim, input, pref),
567
+ !isObject$3(result) || isSymbol$1(result)) return result;
568
+ throw new $TypeError$3("Can't convert object to primitive value");
472
569
  }
473
- }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
474
- style: {
475
- position: "absolute",
476
- width: "100%",
477
- height: "100%",
478
- inset: 0
479
- },
570
+ return void 0 === pref && (pref = "number"), function(input, pref) {
571
+ var fn, val;
572
+ if ("string" === pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
573
+ if (isCallable$3(fn = input.valueOf) && !isObject$4(val = call$2(fn, input))) return val;
574
+ if ("string" !== pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
575
+ throw new $TypeError$4("Can't convert object to primitive value");
576
+ }(input, pref);
577
+ }, isSymbol = isSymbol$2, toPropertyKey$2 = function(argument) {
578
+ var key = toPrimitive(argument, "string");
579
+ return isSymbol(key) ? key : key + "";
580
+ }, isObject$2 = isObject$5, document$1 = globalThis_1.document, EXISTS = isObject$2(document$1) && isObject$2(document$1.createElement), ie8DomDefine = !descriptors && !fails$8((function() {
581
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
582
+ return 7 !== Object.defineProperty((it = "div", EXISTS ? document$1.createElement(it) : {}), "a", {
583
+ get: function() {
584
+ return 7;
585
+ }
586
+ }).a;
587
+ var it;
588
+ })), DESCRIPTORS$3 = descriptors, call = functionCall, propertyIsEnumerableModule = objectPropertyIsEnumerable, createPropertyDescriptor$1 = createPropertyDescriptor$2, toIndexedObject$1 = toIndexedObject$2, toPropertyKey$1 = toPropertyKey$2, hasOwn$1 = hasOwnProperty_1, IE8_DOM_DEFINE$1 = ie8DomDefine, $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
589
+
590
+ // `Object.getOwnPropertyDescriptor` method
591
+ // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
592
+ objectGetOwnPropertyDescriptor.f = DESCRIPTORS$3 ? $getOwnPropertyDescriptor$1 : function(O, P) {
593
+ if (O = toIndexedObject$1(O), P = toPropertyKey$1(P), IE8_DOM_DEFINE$1) try {
594
+ return $getOwnPropertyDescriptor$1(O, P);
595
+ } catch (error) {/* empty */}
596
+ if (hasOwn$1(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]);
597
+ };
598
+
599
+ var fails$2 = fails$8, isCallable$2 = isCallable$8, replacement = /#|\.prototype\./, isForced$1 = function(feature, detection) {
600
+ var value = data[normalize(feature)];
601
+ return value === POLYFILL || value !== NATIVE && (isCallable$2(detection) ? fails$2(detection) : !!detection);
602
+ }, normalize = isForced$1.normalize = function(string) {
603
+ return String(string).replace(replacement, ".").toLowerCase();
604
+ }, data = isForced$1.data = {}, NATIVE = isForced$1.NATIVE = "N", POLYFILL = isForced$1.POLYFILL = "P", isForced_1 = isForced$1, aCallable = aCallable$2, NATIVE_BIND = functionBindNative, bind$1 = functionUncurryThisClause(functionUncurryThisClause.bind), objectDefineProperty = {}, v8PrototypeDefineBug = descriptors && fails$8((function() {
605
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
606
+ return 42 !== Object.defineProperty((function() {/* empty */}), "prototype", {
607
+ value: 42,
608
+ writable: !1
609
+ }).prototype;
610
+ })), isObject$1 = isObject$5, $String$1 = String, $TypeError$2 = TypeError, DESCRIPTORS$1 = descriptors, IE8_DOM_DEFINE = ie8DomDefine, V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug, anObject = function(argument) {
611
+ if (isObject$1(argument)) return argument;
612
+ throw new $TypeError$2($String$1(argument) + " is not an object");
613
+ }, toPropertyKey = toPropertyKey$2, $TypeError$1 = TypeError, $defineProperty = Object.defineProperty, $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
614
+
615
+ // `Object.defineProperty` method
616
+ // https://tc39.es/ecma262/#sec-object.defineproperty
617
+ objectDefineProperty.f = DESCRIPTORS$1 ? V8_PROTOTYPE_DEFINE_BUG ? function(O, P, Attributes) {
618
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), "function" == typeof O && "prototype" === P && "value" in Attributes && "writable" in Attributes && !Attributes.writable) {
619
+ var current = $getOwnPropertyDescriptor(O, P);
620
+ current && current.writable && (O[P] = Attributes.value, Attributes = {
621
+ configurable: "configurable" in Attributes ? Attributes.configurable : current.configurable,
622
+ enumerable: "enumerable" in Attributes ? Attributes.enumerable : current.enumerable,
623
+ writable: !1
624
+ });
625
+ }
626
+ return $defineProperty(O, P, Attributes);
627
+ } : $defineProperty : function(O, P, Attributes) {
628
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), IE8_DOM_DEFINE) try {
629
+ return $defineProperty(O, P, Attributes);
630
+ } catch (error) {/* empty */}
631
+ if ("get" in Attributes || "set" in Attributes) throw new $TypeError$1("Accessors not supported");
632
+ return "value" in Attributes && (O[P] = Attributes.value), O;
633
+ };
634
+
635
+ var definePropertyModule = objectDefineProperty, createPropertyDescriptor = createPropertyDescriptor$2, createNonEnumerableProperty$1 = descriptors ? function(object, key, value) {
636
+ return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
637
+ } : function(object, key, value) {
638
+ return object[key] = value, object;
639
+ }, globalThis$2 = globalThis_1, apply = functionApply, uncurryThis$1 = functionUncurryThisClause, isCallable$1 = isCallable$8, getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f, isForced = isForced_1, path$1 = path$3, bind = function(fn, that) {
640
+ return aCallable(fn), void 0 === that ? fn : NATIVE_BIND ? bind$1(fn, that) : function() {
641
+ return fn.apply(that, arguments);
642
+ };
643
+ }, createNonEnumerableProperty = createNonEnumerableProperty$1, hasOwn = hasOwnProperty_1, wrapConstructor = function(NativeConstructor) {
644
+ var Wrapper = function(a, b, c) {
645
+ if (this instanceof Wrapper) {
646
+ switch (arguments.length) {
647
+ case 0:
648
+ return new NativeConstructor;
649
+
650
+ case 1:
651
+ return new NativeConstructor(a);
652
+
653
+ case 2:
654
+ return new NativeConstructor(a, b);
655
+ }
656
+ return new NativeConstructor(a, b, c);
657
+ }
658
+ return apply(NativeConstructor, this, arguments);
659
+ };
660
+ return Wrapper.prototype = NativeConstructor.prototype, Wrapper;
661
+ }, _export = function(options, source) {
662
+ var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE, key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor, TARGET = options.target, GLOBAL = options.global, STATIC = options.stat, PROTO = options.proto, nativeSource = GLOBAL ? globalThis$2 : STATIC ? globalThis$2[TARGET] : globalThis$2[TARGET] && globalThis$2[TARGET].prototype, target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET], targetPrototype = target.prototype;
663
+ for (key in source)
664
+ // contains in native
665
+ USE_NATIVE = !(FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? "." : "#") + key, options.forced)) && nativeSource && hasOwn(nativeSource, key),
666
+ targetProperty = target[key], USE_NATIVE && (nativeProperty = options.dontCallGetSet ? (descriptor = getOwnPropertyDescriptor(nativeSource, key)) && descriptor.value : nativeSource[key]),
667
+ // export native or implementation
668
+ sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key], (FORCED || PROTO || typeof targetProperty != typeof sourceProperty) && (
669
+ // bind methods to global for calling from export context
670
+ resultProperty = options.bind && USE_NATIVE ? bind(sourceProperty, globalThis$2) : options.wrap && USE_NATIVE ? wrapConstructor(sourceProperty) : PROTO && isCallable$1(sourceProperty) ? uncurryThis$1(sourceProperty) : sourceProperty,
671
+ // add a flag to not completely full polyfills
672
+ (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) && createNonEnumerableProperty(resultProperty, "sham", !0),
673
+ createNonEnumerableProperty(target, key, resultProperty), PROTO && (hasOwn(path$1, VIRTUAL_PROTOTYPE = TARGET + "Prototype") || createNonEnumerableProperty(path$1, VIRTUAL_PROTOTYPE, {}),
674
+ // export virtual prototype methods
675
+ createNonEnumerableProperty(path$1[VIRTUAL_PROTOTYPE], key, sourceProperty),
676
+ // export real prototype methods
677
+ options.real && targetPrototype && (FORCED || !targetPrototype[key]) && createNonEnumerableProperty(targetPrototype, key, sourceProperty)));
678
+ }, ceil = Math.ceil, floor = Math.floor, trunc = Math.trunc || function(x) {
679
+ var n = +x;
680
+ return (n > 0 ? floor : ceil)(n);
681
+ }, toIntegerOrInfinity$2 = function(argument) {
682
+ var number = +argument;
683
+ // eslint-disable-next-line no-self-compare -- NaN check
684
+ return number != number || 0 === number ? 0 : trunc(number);
685
+ }, toIntegerOrInfinity$1 = toIntegerOrInfinity$2, min$1 = Math.min, globalThis$1 = globalThis_1, path = path$3, getBuiltInPrototypeMethod$2 = function(CONSTRUCTOR, METHOD) {
686
+ var Namespace = path[CONSTRUCTOR + "Prototype"], pureMethod = Namespace && Namespace[METHOD];
687
+ if (pureMethod) return pureMethod;
688
+ var NativeConstructor = globalThis$1[CONSTRUCTOR], NativePrototype = NativeConstructor && NativeConstructor.prototype;
689
+ return NativePrototype && NativePrototype[METHOD];
690
+ };
691
+
692
+ /**
693
+ * Component Utilities
694
+ *
695
+ * Helper functions for component development with the new customization system
696
+ */
697
+ /**
698
+ * Merge multiple class names
699
+ */
700
+ function mergeClassNames(...classes) {
701
+ return classes.filter(Boolean).join(" ");
702
+ }
703
+
704
+ /**
705
+ * Check if a URL is a YouTube URL
706
+ */ function isYouTubeUrl(url) {
707
+ return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
708
+ }
709
+
710
+ /**
711
+ * Extract YouTube video ID from URL
712
+ */
713
+ /**
714
+ * Utility to merge multiple React refs into one
715
+ */
716
+ function setRef(ref, value) {
717
+ "function" == typeof ref ? ref(value) : ref && (
718
+ // This is safe because we're checking that ref exists first
719
+ ref.current = value);
720
+ }
721
+
722
+ /**
723
+ * Combines two React refs into a single ref function
724
+ * This is used when you need to use and forward a ref at the same time
725
+ */ function useForkRef(refA, refB) {
726
+ return React.useMemo((() => null == refA && null == refB ? null : refValue => {
727
+ setRef(refA, refValue), setRef(refB, refValue);
728
+ }), [ refA, refB ]);
729
+ }
730
+
731
+ const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
732
+ x: rect.left + rect.width / 2,
733
+ y: rect.top + rect.height / 2
734
+ } : {
735
+ x: 0,
736
+ y: 0
737
+ }, calculateMouseInfluence = mouseOffset => {
738
+ if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
739
+ // Clamp influence to keep mouse response subtle and stable.
740
+ const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
741
+ return Math.min(.8, influence);
742
+ // Tighter cap to prevent blur/filter blow-out
743
+ }, 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 => {
744
+ if ("number" == typeof value) return Math.max(0, value);
745
+ if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
746
+ const trimmedValue = value.trim();
747
+ // Handle px values
748
+ if (trimmedValue.endsWith("px")) {
749
+ const parsed = parseFloat(trimmedValue);
750
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
751
+ }
752
+ // Handle rem values (assume 16px = 1rem)
753
+ if (trimmedValue.endsWith("rem")) {
754
+ const parsed = parseFloat(trimmedValue);
755
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
756
+ }
757
+ // Handle em values (assume 16px = 1em for simplicity)
758
+ if (trimmedValue.endsWith("em")) {
759
+ const parsed = parseFloat(trimmedValue);
760
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
761
+ }
762
+ // Handle percentage (convert to approximate px value, assuming 200px container)
763
+ if (trimmedValue.endsWith("%")) {
764
+ const parsed = parseFloat(trimmedValue);
765
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
766
+ }
767
+ // Handle unitless numbers
768
+ const numValue = parseFloat(trimmedValue);
769
+ return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
770
+ }, extractBorderRadiusFromElement = element => {
771
+ if (!element || !element.props) return null;
772
+ // Check inline styles first (highest priority)
773
+ if (element.props.style) {
774
+ const radiusFromStyle = (style => {
775
+ if (!style) return null;
776
+ // Check various border-radius properties
777
+ const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
778
+ return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
779
+ })(element.props.style);
780
+ if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
781
+ }
782
+ // If element has children, recursively check them
783
+ if (element.props.children) {
784
+ const childRadius = extractBorderRadiusFromChildren(element.props.children);
785
+ if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
786
+ }
787
+ return null;
788
+ }, extractBorderRadiusFromChildren = children => {
789
+ if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
790
+ try {
791
+ const childArray = React.Children.toArray(children);
792
+ for (let i = 0; i < childArray.length; i++) {
793
+ const child = childArray[i];
794
+ if ( React.isValidElement(child)) {
795
+ const radius = extractBorderRadiusFromElement(child);
796
+ if (null !== radius) return radius;
797
+ }
798
+ }
799
+ } catch (error) {
800
+ // Silently handle errors
801
+ }
802
+ return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
803
+ }, smoothstep = t => {
804
+ const clamped = Math.max(0, Math.min(1, t));
805
+ return clamped * clamped * (3 - 2 * clamped);
806
+ }, 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) => {
807
+ const newVelocity = (velocity + (target - current) * stiffness) * damping;
808
+ return {
809
+ value: current + newVelocity,
810
+ velocity: newVelocity
811
+ };
812
+ };
813
+
814
+ /**
815
+ * Calculate element center from bounding rect
816
+ */
817
+ /**
818
+ * Normalizes a layout inset for use in CSS custom properties.
819
+ *
820
+ * @param value - Raw inset from `style` (number, px string, or `auto`).
821
+ * @param fallback - Value used when `value` is undefined.
822
+ */
823
+ function formatGlassInsetValue(value, fallback = "auto") {
824
+ return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
825
+ }
826
+
827
+ /**
828
+ * Determines whether the glass should use fixed/sticky layout semantics.
829
+ *
830
+ * @param explicit - Value of the `isFixedOrSticky` prop.
831
+ * @param position - `position` from the consumer `style` object.
832
+ */
833
+ /** Coerces a value to a finite number, returning `fallback` when invalid. */
834
+ function toSafeNumber(value, fallback = 0) {
835
+ return "number" != typeof value || isNaN(value) ? fallback : value;
836
+ }
837
+
838
+ /**
839
+ * Calculates the target frame rate for shader time-animation loops.
840
+ *
841
+ * Balances visual quality against distortion complexity and `animationSpeed`.
842
+ */
843
+ /**
844
+ * Computes per-channel displacement scale for the SVG chromatic-aberration filter.
845
+ */
846
+ function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
847
+ return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
848
+ }
849
+
850
+ /**
851
+ * Get displacement map URL based on mode
852
+ */ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
853
+ switch (mode) {
854
+ case "standard":
855
+ return displacementMap;
856
+
857
+ case "polar":
858
+ return polarDisplacementMap;
859
+
860
+ case "prominent":
861
+ return prominentDisplacementMap;
862
+
863
+ case "shader":
864
+ return shaderMapUrl || displacementMap;
865
+
866
+ default:
867
+ return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
868
+ }
869
+ }, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
870
+ result: "RED_DISPLACED",
871
+ channelResult: "RED_CHANNEL",
872
+ aberrationFactor: 0,
873
+ colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
874
+ }, {
875
+ result: "GREEN_DISPLACED",
876
+ channelResult: "GREEN_CHANNEL",
877
+ aberrationFactor: .02,
878
+ colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
879
+ }, {
880
+ result: "BLUE_DISPLACED",
881
+ channelResult: "BLUE_CHANNEL",
882
+ aberrationFactor: .03,
883
+ colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
884
+ } ], FILTER_SVG_STYLE = {
885
+ position: "absolute",
886
+ width: "100%",
887
+ height: "100%",
888
+ inset: 0
889
+ }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
890
+ style: FILTER_SVG_STYLE,
480
891
  "aria-hidden": "true",
481
892
  children: jsxs("defs", {
482
893
  children: [ jsxs("radialGradient", {
@@ -530,43 +941,21 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
530
941
  dx: "0",
531
942
  dy: "0",
532
943
  result: "CENTER_ORIGINAL"
533
- }), jsx("feDisplacementMap", {
534
- in: "SourceGraphic",
535
- in2: "DISPLACEMENT_MAP",
536
- scale: displacementScale * ("shader" === mode ? 1 : -1),
537
- xChannelSelector: "R",
538
- yChannelSelector: "B",
539
- result: "RED_DISPLACED"
540
- }), jsx("feColorMatrix", {
541
- in: "RED_DISPLACED",
542
- type: "matrix",
543
- values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
544
- result: "RED_CHANNEL"
545
- }), jsx("feDisplacementMap", {
546
- in: "SourceGraphic",
547
- in2: "DISPLACEMENT_MAP",
548
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
549
- xChannelSelector: "R",
550
- yChannelSelector: "B",
551
- result: "GREEN_DISPLACED"
552
- }), jsx("feColorMatrix", {
553
- in: "GREEN_DISPLACED",
554
- type: "matrix",
555
- values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
556
- result: "GREEN_CHANNEL"
557
- }), jsx("feDisplacementMap", {
558
- in: "SourceGraphic",
559
- in2: "DISPLACEMENT_MAP",
560
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
561
- xChannelSelector: "R",
562
- yChannelSelector: "B",
563
- result: "BLUE_DISPLACED"
564
- }), jsx("feColorMatrix", {
565
- in: "BLUE_DISPLACED",
566
- type: "matrix",
567
- values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
568
- result: "BLUE_CHANNEL"
569
- }), jsx("feBlend", {
944
+ }), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
945
+ children: [ jsx("feDisplacementMap", {
946
+ in: "SourceGraphic",
947
+ in2: "DISPLACEMENT_MAP",
948
+ scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
949
+ xChannelSelector: "R",
950
+ yChannelSelector: "B",
951
+ result: channel.result
952
+ }), jsx("feColorMatrix", {
953
+ in: channel.result,
954
+ type: "matrix",
955
+ values: channel.colorMatrix,
956
+ result: channel.channelResult
957
+ }) ]
958
+ }, channel.channelResult))), jsx("feBlend", {
570
959
  in: "GREEN_CHANNEL",
571
960
  in2: "BLUE_CHANNEL",
572
961
  mode: "screen",
@@ -606,20 +995,23 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
606
995
  })
607
996
  });
608
997
 
609
- GlassFilterComponent.displayName = "GlassFilter";
998
+ /**
999
+ * Module-level LRU cache for shader displacement maps.
1000
+ *
1001
+ * Shared across all `AtomixGlassContainer` instances so identical size and
1002
+ * variant combinations are generated once.
1003
+ */ GlassFilterComponent.displayName = "GlassFilter";
610
1004
 
611
- // Memoize component to prevent unnecessary re-renders
1005
+ /** Shallow prop comparison to avoid redundant SVG filter regeneration. */
612
1006
  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 = {
613
1007
  x: 0,
614
1008
  y: 0
615
- }, 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 = {
1009
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
616
1010
  width: 0,
617
1011
  height: 0
618
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
619
- // Phase 1: Animation System props
620
- 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) => {
1012
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1, 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) => {
621
1013
  // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
622
- 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);
1014
+ 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);
623
1015
  // Lazy load shader utilities only when shader mode is needed
624
1016
  useEffect((() => {
625
1017
  "shader" === mode ?
@@ -697,15 +1089,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
697
1089
  shaderGeneratorRef.current = null;
698
1090
  }
699
1091
  };
700
- }), [ mode, glassSize, shaderVariant ]),
701
- // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
702
- useEffect((() => {
1092
+ }), [ mode, glassSize, shaderVariant ]), useEffect((() => {
703
1093
  // Only run animations in shader mode with time animation enabled
704
1094
  if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
705
1095
  // Cancel any existing animation frame
706
1096
  return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
707
1097
  animationFrameRef.current = null));
708
- 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)));
1098
+ const targetFps = function(options) {
1099
+ 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;
1100
+ return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
1101
+ }({
1102
+ distortionQuality: distortionQuality,
1103
+ animationSpeed: animationSpeed,
1104
+ withMultiLayerDistortion: withMultiLayerDistortion,
1105
+ distortionOctaves: distortionOctaves,
1106
+ distortionLacunarity: distortionLacunarity,
1107
+ distortionGain: distortionGain
1108
+ }), frameInterval = 1e3 / targetFps;
709
1109
  let lastUpdate = 0, isCancelled = !1;
710
1110
  const animate = currentTime => {
711
1111
  if (!isCancelled) {
@@ -729,88 +1129,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
729
1129
  };
730
1130
  }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
731
1131
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
732
- const [rectCache, setRectCache] = useState(null);
733
- useEffect((() => {
734
- if (!ref || "function" == typeof ref) return;
735
- const element = ref.current;
736
- if (element) try {
737
- setRectCache(element.getBoundingClientRect());
738
- } catch (error) {
739
- console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
740
- }
741
- }), [ ref, glassSize ]);
742
- const liquidBlur = useMemo((() => {
743
- const defaultBlur = {
744
- baseBlur: blurAmount,
745
- edgeBlur: 1.25 * blurAmount,
746
- centerBlur: 1.1 * blurAmount,
747
- flowBlur: 1.2 * blurAmount
748
- };
749
- // Enhanced validation for liquid blur
750
- if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
1132
+ const containerVars = useMemo((() => {
751
1133
  try {
752
- 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);
753
- // NOTE: hover/active multipliers intentionally omitted here —
754
- // they belong on opacity layers, not the blur filter itself.
755
1134
  return {
756
- baseBlur: clampBlur(baseBlur),
757
- edgeBlur: clampBlur(edgeBlur),
758
- centerBlur: clampBlur(centerBlur),
759
- flowBlur: clampBlur(flowBlur)
760
- };
761
- } catch (error) {
762
- return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
763
- defaultBlur;
764
- }
765
- }), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
766
- try {
767
- 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;
768
- // Validate blur values before using them
769
- return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
770
- 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})`
771
- } : {
772
- 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})`
773
- };
774
- // Single-pass fallback: stronger radius to match perceived blur of multi-pass
775
- } catch (error) {
776
- return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
777
- {
778
- backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
779
- };
780
- }
781
- }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
782
- try {
783
- // Safe extraction of mouse offset values
784
- 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;
785
- return {
786
- "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
787
- "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
788
- "--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",
789
- "--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
790
- // Background and shadow values use design token-aligned RGB values
791
- "--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",
792
- "--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
793
- "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
1135
+ "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
794
1136
  };
795
1137
  } catch (error) {
796
1138
  return console.warn("AtomixGlassContainer: Error generating container variables", error),
797
1139
  {
798
- "--atomix-glass-container-padding": "0 0",
799
- "--atomix-glass-container-radius": "0px",
800
- "--atomix-glass-container-backdrop": "none",
801
- "--atomix-glass-container-shadow": "none",
802
- "--atomix-glass-container-shadow-opacity": 1,
803
- "--atomix-glass-container-bg": "none",
804
- "--atomix-glass-container-text-shadow": "none"
1140
+ "--atomix-glass-container-radius": "0px"
805
1141
  };
806
1142
  }
807
- }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
1143
+ }), [ borderRadius ]);
808
1144
  return jsx("div", {
809
- ref: el => {
810
- // Handle forwarded ref
811
- "function" == typeof ref ? ref(el) : ref && (ref.current = el);
812
- },
813
- className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
1145
+ ref: containerRef,
1146
+ className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
814
1147
  style: {
815
1148
  ...style,
816
1149
  ...containerVars
@@ -828,8 +1161,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
828
1161
  blurAmount: blurAmount,
829
1162
  mode: mode,
830
1163
  id: filterId,
831
- displacementScale: "number" != typeof displacementScale || isNaN(displacementScale) ? 0 : displacementScale,
832
- aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
1164
+ displacementScale: toSafeNumber(displacementScale),
1165
+ aberrationIntensity: toSafeNumber(aberrationIntensity),
833
1166
  shaderMapUrl: shaderMapUrl
834
1167
  }), jsx("div", {
835
1168
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
@@ -851,8 +1184,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
851
1184
  });
852
1185
  }));
853
1186
 
854
- // ─── Blur multiplier constants (module-level, never change at runtime) ────────
855
- AtomixGlassContainer.displayName = "AtomixGlassContainer";
1187
+ /**
1188
+ * Internal glass surface that owns backdrop-filter, SVG distortion, and content.
1189
+ *
1190
+ * Layout and stacking styles are applied via the `style` prop from the parent.
1191
+ * The root wrapper supplies CSS custom properties only.
1192
+ */ AtomixGlassContainer.displayName = "AtomixGlassContainer";
856
1193
 
857
1194
  // Singleton instance
858
1195
  const globalMouseTracker = new
@@ -967,28 +1304,32 @@ class {
967
1304
  */ getSubscriberCount() {
968
1305
  return this.listeners.size;
969
1306
  }
970
- }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
1307
+ }, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
971
1308
  if (!wrapperElement && !containerElement) return;
972
1309
  if (!validateGlassSize(params.glassSize)) return;
973
- 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 = {
1310
+ 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 = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
974
1311
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
975
1312
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
976
1313
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
977
1314
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
978
1315
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
979
1316
  saturationBoost: baseOverLightConfig.saturationBoost
980
- }, 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) => {
981
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
982
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
983
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
984
- })({
985
- x: 0,
986
- y: 0
987
- }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
1317
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
1318
+ /**
1319
+ * Computes tension factor from elastic translation magnitude (0–1).
1320
+ */
1321
+ function(elasticTranslation) {
1322
+ const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
1323
+ return smoothstep(magnitude / 80);
1324
+ }
1325
+ /**
1326
+ * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1327
+ * to avoid React re-renders on mouse movement.
1328
+ */ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
988
1329
  // Calculate mouse influence
989
1330
  // Update Wrapper Styles (glassVars)
990
1331
  if (wrapperElement) {
991
- 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 = {
1332
+ 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 = {
992
1333
  hover1: {
993
1334
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
994
1335
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -1005,28 +1346,55 @@ class {
1005
1346
  x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
1006
1347
  y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
1007
1348
  }, opacityValues = {
1008
- hover1: isHovered || isActive ? .5 : 0,
1009
- hover2: isActive ? .5 : 0,
1010
- hover3: isHovered ? .4 : isActive ? .8 : 0,
1011
- base: isOverLight ? overLightConfig.opacity : 0,
1012
- over: isOverLight ? 1.1 * overLightConfig.opacity : 0
1349
+ // hover-1: ambient highlight glow present on hover and during press
1350
+ hover1: isHovered || isActive ? 1 : 0,
1351
+ // hover-2: press depth shadow only fires on active (mousedown)
1352
+ hover2: isActive ? 1 : 0,
1353
+ // hover-3: global soft-light surface shift half-strength on hover, full on press
1354
+ hover3: isActive ? 1 : isHovered ? .55 : 0,
1355
+ // Dark chrome: faint smoky tint; over-light keeps stronger fill
1356
+ base: isOverLight ? overLightConfig.opacity : .14,
1357
+ over: isOverLight ? 1.1 * overLightConfig.opacity : .1
1013
1358
  }, style = wrapperElement.style;
1014
1359
  style.setProperty("--atomix-glass-transform", transformStyle || "none");
1015
1360
  // Parallax for content (liquid refraction feel)
1016
1361
  const parallaxFactor = .38 + .12 * tensionFactor;
1017
1362
  style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
1018
- style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
1363
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
1019
1364
  // ── Chromatic Rim Lighting ──────────────────────────────────────
1020
- // Layer 1: Core White/Blue highlight
1021
- 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%)`),
1022
- // Layer 2: Subtle Red/Warm highlight (offset angle)
1023
- 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%)`),
1024
- // Hover gradients
1025
- 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}%)`),
1026
- 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}%)`),
1027
- 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}%)`),
1028
- 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})`),
1029
- 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})`),
1365
+ const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
1366
+ if (borderAnimated && !effectiveWithoutEffects) {
1367
+ const borderCssVars =
1368
+ /**
1369
+ * Builds animated chromatic rim CSS variables for border layers 1 and 2.
1370
+ * When empty, SCSS static conic/linear fallbacks apply.
1371
+ */
1372
+ function(params) {
1373
+ 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%)`;
1374
+ return {
1375
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
1376
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
1377
+ };
1378
+ }({
1379
+ mouseOffset: mouseOffset,
1380
+ mouseVelocity: mouseVelocity,
1381
+ elasticVelocity: elasticVelocity,
1382
+ borderOpacity: overLightConfig.borderOpacity,
1383
+ opacityMultiplier: borderOpacityMultiplier,
1384
+ tensionFactor: tensionFactor
1385
+ });
1386
+ style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
1387
+ style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
1388
+ } else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
1389
+ // Hover gradients — cursor-relative radial positions for realistic light tracking.
1390
+ // hover-1: white overlay highlight following cursor (works on both dark + light)
1391
+ 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%)`),
1392
+ // hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
1393
+ 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%)`),
1394
+ // hover-3: full-surface soft-light tint; linear gradient angled with cursor X
1395
+ 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%)`),
1396
+ 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%)`),
1397
+ 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%)`),
1030
1398
  // Opacities
1031
1399
  style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
1032
1400
  style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
@@ -1063,21 +1431,17 @@ class {
1063
1431
  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})`;
1064
1432
  // Container variables
1065
1433
  const style = containerElement.style;
1066
- style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
1434
+ style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
1067
1435
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
1068
1436
  // Shadows
1069
- 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"),
1437
+ 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),
1070
1438
  style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
1071
1439
  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"),
1072
1440
  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)"),
1073
- 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)");
1441
+ style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0 8px 32px rgba(0, 0, 0, 0.32), 0 2px 8px rgba(0, 0, 0, 0.18)");
1074
1442
  }
1075
1443
  };
1076
1444
 
1077
- /**
1078
- * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1079
- * to avoid React re-renders on mouse movement.
1080
- */
1081
1445
  /**
1082
1446
  * Animation System for AtomixGlass Component
1083
1447
  *
@@ -1222,12 +1586,38 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
1222
1586
  * Composable hook for AtomixGlass component logic
1223
1587
  * Manages all state, calculations, and event handlers
1224
1588
  */
1225
- 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:
1589
+ 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, withTimeAnimation:
1226
1590
  // Default priority
1227
1591
  // Phase 1: Animation System Props
1228
1592
  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}) {
1229
1593
  // State
1230
- const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1594
+ const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
1595
+ /**
1596
+ * Resolves `border` and legacy `withBorder` into a single configuration object.
1597
+ */
1598
+ function(border, withBorder) {
1599
+ const legacyDefault = withBorder ?? !0;
1600
+ return void 0 === border ? {
1601
+ enabled: legacyDefault,
1602
+ width: BORDER.DEFAULT_WIDTH,
1603
+ opacityMultiplier: 1,
1604
+ animated: !0
1605
+ } : "boolean" == typeof border ? {
1606
+ enabled: border,
1607
+ width: BORDER.DEFAULT_WIDTH,
1608
+ opacityMultiplier: 1,
1609
+ animated: !0
1610
+ } : {
1611
+ enabled: border.enabled ?? legacyDefault,
1612
+ width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
1613
+ opacityMultiplier: border.opacity ?? 1,
1614
+ animated: !1 !== border.animated
1615
+ };
1616
+ /**
1617
+ * Formats border width for CSS custom properties.
1618
+ */
1619
+ var value;
1620
+ }(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1231
1621
  x: 0,
1232
1622
  y: 0
1233
1623
  }), internalMouseOffsetRef = useRef({
@@ -1522,21 +1912,22 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1522
1912
  isOverLight: isOverLight,
1523
1913
  threshold: .7,
1524
1914
  opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
1525
- contrast: 1.4,
1526
- brightness: .9,
1527
- saturationBoost: 1.3,
1528
- // Fixed value dynamic saturation amplifies perceived displacement
1529
- shadowIntensity: .9,
1530
- borderOpacity: .7
1915
+ // Dark UI (Apple Music): neutral contrast + slight brightness lift
1916
+ contrast: isOverLight ? 1.4 : 1.02,
1917
+ brightness: isOverLight ? .9 : 1.02,
1918
+ saturationBoost: isOverLight ? 1.3 : 1,
1919
+ shadowIntensity: isOverLight ? .9 : 1,
1920
+ borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
1531
1921
  };
1532
1922
  if ("object" == typeof overLight && null !== overLight) {
1533
- 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 = {
1923
+ 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 = {
1534
1924
  ...baseConfig,
1535
1925
  threshold: validatedThreshold,
1536
1926
  opacity: validatedOpacity * hoverIntensity * activeIntensity,
1537
1927
  contrast: validatedContrast,
1538
1928
  brightness: validatedBrightness,
1539
- saturationBoost: validatedSaturationBoost
1929
+ saturationBoost: validatedSaturationBoost,
1930
+ borderOpacity: validatedBorderOpacity
1540
1931
  };
1541
1932
  return "undefined" == typeof process || process.env, finalConfig;
1542
1933
  }
@@ -1634,12 +2025,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1634
2025
  withLiquidBlur: withLiquidBlur,
1635
2026
  blurAmount: blurAmount,
1636
2027
  saturation: saturation,
1637
- padding: padding,
1638
- isFixedOrSticky: isFixedOrSticky
2028
+ isFixedOrSticky: isFixedOrSticky,
2029
+ borderAnimated: resolvedBorder.animated,
2030
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
1639
2031
  }), 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);
1640
2032
  };
1641
2033
  lerpRafRef.current = requestAnimationFrame(tick);
1642
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2034
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
1643
2035
  if (externalGlobalMousePosition && externalMouseOffset) return;
1644
2036
  if (effectiveWithoutEffects) return;
1645
2037
  const container = mouseContainer?.current || glassRef.current;
@@ -1703,9 +2095,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1703
2095
  withLiquidBlur: withLiquidBlur,
1704
2096
  blurAmount: blurAmount,
1705
2097
  saturation: saturation,
1706
- padding: padding
2098
+ borderAnimated: resolvedBorder.animated,
2099
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
1707
2100
  });
1708
- }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
2101
+ }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
1709
2102
  // Event handlers
1710
2103
  const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
1711
2104
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
@@ -1725,6 +2118,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1725
2118
  mouseOffset: mouseOffset,
1726
2119
  // This is now static (refs or props) unless prop changes
1727
2120
  overLightConfig: overLightConfig,
2121
+ resolvedBorder: resolvedBorder,
1728
2122
  transformStyle: transformStyle,
1729
2123
  getShaderTime: getShaderTime,
1730
2124
  applyTimeBasedDistortion: applyTimeBasedDistortion,
@@ -1734,342 +2128,66 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1734
2128
  handleMouseUp: handleMouseUp,
1735
2129
  handleKeyDown: handleKeyDown
1736
2130
  };
1737
- }
1738
-
1739
- /**
1740
- * Default responsive breakpoints configuration
1741
- *
1742
- * These breakpoints are optimized for glass effect performance across device classes:
1743
- * - Mobile: Reduced complexity for 60 FPS target
1744
- * - Tablet: Balanced quality and performance
1745
- * - Desktop: Full fidelity effects
1746
- */ const DEFAULT_BREAKPOINTS = {
1747
- mobile: {
1748
- maxWidth: 640,
1749
- params: {
1750
- distortionOctaves: 3,
1751
- displacementScale: .7,
1752
- blurAmount: .8,
1753
- animationSpeed: .8,
1754
- chromaticIntensity: .5
1755
- }
1756
- },
1757
- tablet: {
1758
- minWidth: 641,
1759
- maxWidth: 1024,
1760
- params: {
1761
- distortionOctaves: 4,
1762
- displacementScale: .85,
1763
- blurAmount: .9,
1764
- animationSpeed: .9,
1765
- chromaticIntensity: .75
1766
- }
1767
- },
1768
- desktop: {
1769
- minWidth: 1025,
1770
- params: {
1771
- distortionOctaves: 5,
1772
- displacementScale: 1,
1773
- blurAmount: 1,
1774
- animationSpeed: 1,
1775
- chromaticIntensity: 1
1776
- }
1777
- }
1778
- };
1779
-
1780
- /**
1781
- * Device performance tier detection
1782
- *
1783
- * Uses Device Memory API and Hardware Concurrency API to classify devices
1784
- * into performance tiers for automatic quality adjustment.
1785
- *
1786
- * @returns Performance tier classification
1787
- */ var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
1788
-
1789
- function getDefaultExportFromCjs(x) {
1790
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
1791
- }
1792
-
1793
- var fails$8 = function(exec) {
1794
- try {
1795
- return !!exec();
1796
- } catch (error) {
1797
- return !0;
1798
- }
1799
- }, functionBindNative = !fails$8((function() {
1800
- // eslint-disable-next-line es/no-function-prototype-bind -- safe
1801
- var test = function() {/* empty */}.bind();
1802
- // eslint-disable-next-line no-prototype-builtins -- safe
1803
- return "function" != typeof test || test.hasOwnProperty("prototype");
1804
- })), NATIVE_BIND$3 = functionBindNative, FunctionPrototype$1 = Function.prototype, call$5 = FunctionPrototype$1.call, uncurryThisWithBind = NATIVE_BIND$3 && FunctionPrototype$1.bind.bind(call$5, call$5), functionUncurryThis = NATIVE_BIND$3 ? uncurryThisWithBind : function(fn) {
1805
- return function() {
1806
- return call$5.apply(fn, arguments);
1807
- };
1808
- }, objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf), check = function(it) {
1809
- return it && it.Math === Math && it;
1810
- }, globalThis_1 =
1811
- // eslint-disable-next-line es/no-global-this -- safe
1812
- check("object" == typeof globalThis && globalThis) || check("object" == typeof window && window) ||
1813
- // eslint-disable-next-line no-restricted-globals -- safe
1814
- check("object" == typeof self && self) || check("object" == typeof commonjsGlobal && commonjsGlobal) || check("object" == typeof commonjsGlobal && commonjsGlobal) ||
1815
- // eslint-disable-next-line no-new-func -- fallback
1816
- function() {
1817
- return this;
1818
- }() || Function("return this")(), NATIVE_BIND$2 = functionBindNative, FunctionPrototype = Function.prototype, apply$1 = FunctionPrototype.apply, call$4 = FunctionPrototype.call, functionApply = "object" == typeof Reflect && Reflect.apply || (NATIVE_BIND$2 ? call$4.bind(apply$1) : function() {
1819
- return call$4.apply(apply$1, arguments);
1820
- }), uncurryThis$7 = functionUncurryThis, toString$3 = uncurryThis$7({}.toString), stringSlice = uncurryThis$7("".slice), classofRaw$2 = function(it) {
1821
- return stringSlice(toString$3(it), 8, -1);
1822
- }, classofRaw$1 = classofRaw$2, uncurryThis$6 = functionUncurryThis, functionUncurryThisClause = function(fn) {
1823
- // Nashorn bug:
1824
- // https://github.com/zloirock/core-js/issues/1128
1825
- // https://github.com/zloirock/core-js/issues/1130
1826
- if ("Function" === classofRaw$1(fn)) return uncurryThis$6(fn);
1827
- }, documentAll = "object" == typeof document && document.all, isCallable$8 = void 0 === documentAll && void 0 !== documentAll ? function(argument) {
1828
- return "function" == typeof argument || argument === documentAll;
1829
- } : function(argument) {
1830
- return "function" == typeof argument;
1831
- }, objectGetOwnPropertyDescriptor = {}, descriptors = !fails$8((function() {
1832
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1833
- return 7 !== Object.defineProperty({}, 1, {
1834
- get: function() {
1835
- return 7;
1836
- }
1837
- })[1];
1838
- })), NATIVE_BIND$1 = functionBindNative, call$3 = Function.prototype.call, functionCall = NATIVE_BIND$1 ? call$3.bind(call$3) : function() {
1839
- return call$3.apply(call$3, arguments);
1840
- }, objectPropertyIsEnumerable = {}, $propertyIsEnumerable = {}.propertyIsEnumerable, getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor, NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({
1841
- 1: 2
1842
- }, 1);
1843
-
1844
- // `Object.prototype.propertyIsEnumerable` method implementation
1845
- // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
1846
- objectPropertyIsEnumerable.f = NASHORN_BUG ? function(V) {
1847
- var descriptor = getOwnPropertyDescriptor$1(this, V);
1848
- return !!descriptor && descriptor.enumerable;
1849
- } : $propertyIsEnumerable;
1850
-
1851
- var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
1852
- return {
1853
- enumerable: !(1 & bitmap),
1854
- configurable: !(2 & bitmap),
1855
- writable: !(4 & bitmap),
1856
- value: value
1857
- };
1858
- }, fails$5 = fails$8, classof$3 = classofRaw$2, $Object$3 = Object, split = functionUncurryThis("".split), indexedObject = fails$5((function() {
1859
- // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
1860
- // eslint-disable-next-line no-prototype-builtins -- safe
1861
- return !$Object$3("z").propertyIsEnumerable(0);
1862
- })) ? function(it) {
1863
- return "String" === classof$3(it) ? split(it, "") : $Object$3(it);
1864
- } : $Object$3, isNullOrUndefined$2 = function(it) {
1865
- return null == it;
1866
- }, isNullOrUndefined$1 = isNullOrUndefined$2, $TypeError$6 = TypeError, requireObjectCoercible$3 = function(it) {
1867
- if (isNullOrUndefined$1(it)) throw new $TypeError$6("Can't call method on " + it);
1868
- return it;
1869
- }, IndexedObject = indexedObject, requireObjectCoercible$2 = requireObjectCoercible$3, toIndexedObject$2 = function(it) {
1870
- return IndexedObject(requireObjectCoercible$2(it));
1871
- }, isCallable$7 = isCallable$8, isObject$5 = function(it) {
1872
- return "object" == typeof it ? null !== it : isCallable$7(it);
1873
- }, path$3 = {}, path$2 = path$3, globalThis$a = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
1874
- return isCallable$6(variable) ? variable : void 0;
1875
- }, navigator$1 = globalThis_1.navigator, userAgent$1 = navigator$1 && navigator$1.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
1876
-
1877
- v8 && (
1878
- // in old Chrome, versions of V8 isn't V8 = Chrome / 10
1879
- // but their correct versions are not interesting for us
1880
- version = (match = v8.split("."))[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1])),
1881
- // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
1882
- // so check `userAgent` even if `.v8` exists, but 0
1883
- !version && userAgent && (!(match = userAgent.match(/Edge\/(\d+)/)) || match[1] >= 74) && (match = userAgent.match(/Chrome\/(\d+)/)) && (version = +match[1]);
1884
-
1885
- var V8_VERSION = version, fails$4 = fails$8, $String$3 = globalThis_1.String, symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$4((function() {
1886
- var symbol = Symbol("symbol detection");
1887
- // Chrome 38 Symbol has incorrect toString conversion
1888
- // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
1889
- // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
1890
- // of course, fail.
1891
- return !$String$3(symbol) || !(Object(symbol) instanceof Symbol) ||
1892
- // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
1893
- !Symbol.sham && V8_VERSION && V8_VERSION < 41;
1894
- })), useSymbolAsUid = symbolConstructorDetection && !Symbol.sham && "symbol" == typeof Symbol.iterator, isCallable$5 = isCallable$8, isPrototypeOf$1 = objectIsPrototypeOf, $Object$2 = Object, isSymbol$2 = useSymbolAsUid ? function(it) {
1895
- return "symbol" == typeof it;
1896
- } : function(it) {
1897
- var $Symbol = function(namespace, method) {
1898
- return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(globalThis$a[namespace]) : path$2[namespace] && path$2[namespace][method] || globalThis$a[namespace] && globalThis$a[namespace][method];
1899
- }("Symbol");
1900
- return isCallable$5($Symbol) && isPrototypeOf$1($Symbol.prototype, $Object$2(it));
1901
- }, $String$2 = String, isCallable$4 = isCallable$8, $TypeError$5 = TypeError, aCallable$2 = function(argument) {
1902
- if (isCallable$4(argument)) return argument;
1903
- throw new $TypeError$5(function(argument) {
1904
- try {
1905
- return $String$2(argument);
1906
- } catch (error) {
1907
- return "Object";
1908
- }
1909
- }(argument) + " is not a function");
1910
- }, aCallable$1 = aCallable$2, isNullOrUndefined = isNullOrUndefined$2, call$2 = functionCall, isCallable$3 = isCallable$8, isObject$4 = isObject$5, $TypeError$4 = TypeError, sharedStore = {
1911
- exports: {}
1912
- }, globalThis$6 = globalThis_1, defineProperty = Object.defineProperty, globalThis$5 = globalThis_1, store$1 = sharedStore.exports = globalThis$5["__core-js_shared__"] || function(key, value) {
1913
- try {
1914
- defineProperty(globalThis$6, key, {
1915
- value: value,
1916
- configurable: !0,
1917
- writable: !0
1918
- });
1919
- } catch (error) {
1920
- globalThis$6[key] = value;
1921
- }
1922
- return value;
1923
- }("__core-js_shared__", {});
1924
-
1925
- /* eslint-disable es/no-symbol -- required for testing */ (store$1.versions || (store$1.versions = [])).push({
1926
- version: "3.43.0",
1927
- mode: "pure",
1928
- copyright: "© 2014-2025 Denis Pushkarev (zloirock.ru)",
1929
- license: "https://github.com/zloirock/core-js/blob/v3.43.0/LICENSE",
1930
- source: "https://github.com/zloirock/core-js"
1931
- });
1932
-
1933
- var key, value, store = sharedStore.exports, requireObjectCoercible$1 = requireObjectCoercible$3, $Object$1 = Object, hasOwnProperty = functionUncurryThis({}.hasOwnProperty), hasOwnProperty_1 = Object.hasOwn || function(it, key) {
1934
- return hasOwnProperty($Object$1(requireObjectCoercible$1(it)), key);
1935
- }, uncurryThis$3 = functionUncurryThis, id = 0, postfix = Math.random(), toString$2 = uncurryThis$3(1.1.toString), hasOwn$2 = hasOwnProperty_1, NATIVE_SYMBOL = symbolConstructorDetection, USE_SYMBOL_AS_UID = useSymbolAsUid, Symbol$1 = globalThis_1.Symbol, WellKnownSymbolsStore = store[key = "wks"] || (store[key] = value || {}), createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1.for || Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || function(key) {
1936
- return "Symbol(" + (void 0 === key ? "" : key) + ")_" + toString$2(++id + postfix, 36);
1937
- }, wellKnownSymbol$5 = function(name) {
1938
- return hasOwn$2(WellKnownSymbolsStore, name) || (WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn$2(Symbol$1, name) ? Symbol$1[name] : createWellKnownSymbol("Symbol." + name)),
1939
- WellKnownSymbolsStore[name];
1940
- }, call$1 = functionCall, isObject$3 = isObject$5, isSymbol$1 = isSymbol$2, $TypeError$3 = TypeError, TO_PRIMITIVE = wellKnownSymbol$5("toPrimitive"), toPrimitive = function(input, pref) {
1941
- if (!isObject$3(input) || isSymbol$1(input)) return input;
1942
- var result, func, exoticToPrim = (func = input[TO_PRIMITIVE], isNullOrUndefined(func) ? void 0 : aCallable$1(func));
1943
- if (exoticToPrim) {
1944
- if (void 0 === pref && (pref = "default"), result = call$1(exoticToPrim, input, pref),
1945
- !isObject$3(result) || isSymbol$1(result)) return result;
1946
- throw new $TypeError$3("Can't convert object to primitive value");
1947
- }
1948
- return void 0 === pref && (pref = "number"), function(input, pref) {
1949
- var fn, val;
1950
- if ("string" === pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1951
- if (isCallable$3(fn = input.valueOf) && !isObject$4(val = call$2(fn, input))) return val;
1952
- if ("string" !== pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1953
- throw new $TypeError$4("Can't convert object to primitive value");
1954
- }(input, pref);
1955
- }, isSymbol = isSymbol$2, toPropertyKey$2 = function(argument) {
1956
- var key = toPrimitive(argument, "string");
1957
- return isSymbol(key) ? key : key + "";
1958
- }, isObject$2 = isObject$5, document$1 = globalThis_1.document, EXISTS = isObject$2(document$1) && isObject$2(document$1.createElement), ie8DomDefine = !descriptors && !fails$8((function() {
1959
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1960
- return 7 !== Object.defineProperty((it = "div", EXISTS ? document$1.createElement(it) : {}), "a", {
1961
- get: function() {
1962
- return 7;
1963
- }
1964
- }).a;
1965
- var it;
1966
- })), DESCRIPTORS$3 = descriptors, call = functionCall, propertyIsEnumerableModule = objectPropertyIsEnumerable, createPropertyDescriptor$1 = createPropertyDescriptor$2, toIndexedObject$1 = toIndexedObject$2, toPropertyKey$1 = toPropertyKey$2, hasOwn$1 = hasOwnProperty_1, IE8_DOM_DEFINE$1 = ie8DomDefine, $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
1967
-
1968
- // `Object.getOwnPropertyDescriptor` method
1969
- // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
1970
- objectGetOwnPropertyDescriptor.f = DESCRIPTORS$3 ? $getOwnPropertyDescriptor$1 : function(O, P) {
1971
- if (O = toIndexedObject$1(O), P = toPropertyKey$1(P), IE8_DOM_DEFINE$1) try {
1972
- return $getOwnPropertyDescriptor$1(O, P);
1973
- } catch (error) {/* empty */}
1974
- if (hasOwn$1(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]);
1975
- };
1976
-
1977
- var fails$2 = fails$8, isCallable$2 = isCallable$8, replacement = /#|\.prototype\./, isForced$1 = function(feature, detection) {
1978
- var value = data[normalize(feature)];
1979
- return value === POLYFILL || value !== NATIVE && (isCallable$2(detection) ? fails$2(detection) : !!detection);
1980
- }, normalize = isForced$1.normalize = function(string) {
1981
- return String(string).replace(replacement, ".").toLowerCase();
1982
- }, data = isForced$1.data = {}, NATIVE = isForced$1.NATIVE = "N", POLYFILL = isForced$1.POLYFILL = "P", isForced_1 = isForced$1, aCallable = aCallable$2, NATIVE_BIND = functionBindNative, bind$1 = functionUncurryThisClause(functionUncurryThisClause.bind), objectDefineProperty = {}, v8PrototypeDefineBug = descriptors && fails$8((function() {
1983
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1984
- return 42 !== Object.defineProperty((function() {/* empty */}), "prototype", {
1985
- value: 42,
1986
- writable: !1
1987
- }).prototype;
1988
- })), isObject$1 = isObject$5, $String$1 = String, $TypeError$2 = TypeError, DESCRIPTORS$1 = descriptors, IE8_DOM_DEFINE = ie8DomDefine, V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug, anObject = function(argument) {
1989
- if (isObject$1(argument)) return argument;
1990
- throw new $TypeError$2($String$1(argument) + " is not an object");
1991
- }, toPropertyKey = toPropertyKey$2, $TypeError$1 = TypeError, $defineProperty = Object.defineProperty, $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1992
-
1993
- // `Object.defineProperty` method
1994
- // https://tc39.es/ecma262/#sec-object.defineproperty
1995
- objectDefineProperty.f = DESCRIPTORS$1 ? V8_PROTOTYPE_DEFINE_BUG ? function(O, P, Attributes) {
1996
- if (anObject(O), P = toPropertyKey(P), anObject(Attributes), "function" == typeof O && "prototype" === P && "value" in Attributes && "writable" in Attributes && !Attributes.writable) {
1997
- var current = $getOwnPropertyDescriptor(O, P);
1998
- current && current.writable && (O[P] = Attributes.value, Attributes = {
1999
- configurable: "configurable" in Attributes ? Attributes.configurable : current.configurable,
2000
- enumerable: "enumerable" in Attributes ? Attributes.enumerable : current.enumerable,
2001
- writable: !1
2002
- });
2003
- }
2004
- return $defineProperty(O, P, Attributes);
2005
- } : $defineProperty : function(O, P, Attributes) {
2006
- if (anObject(O), P = toPropertyKey(P), anObject(Attributes), IE8_DOM_DEFINE) try {
2007
- return $defineProperty(O, P, Attributes);
2008
- } catch (error) {/* empty */}
2009
- if ("get" in Attributes || "set" in Attributes) throw new $TypeError$1("Accessors not supported");
2010
- return "value" in Attributes && (O[P] = Attributes.value), O;
2011
- };
2012
-
2013
- var definePropertyModule = objectDefineProperty, createPropertyDescriptor = createPropertyDescriptor$2, createNonEnumerableProperty$1 = descriptors ? function(object, key, value) {
2014
- return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
2015
- } : function(object, key, value) {
2016
- return object[key] = value, object;
2017
- }, globalThis$2 = globalThis_1, apply = functionApply, uncurryThis$1 = functionUncurryThisClause, isCallable$1 = isCallable$8, getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f, isForced = isForced_1, path$1 = path$3, bind = function(fn, that) {
2018
- return aCallable(fn), void 0 === that ? fn : NATIVE_BIND ? bind$1(fn, that) : function() {
2019
- return fn.apply(that, arguments);
2020
- };
2021
- }, createNonEnumerableProperty = createNonEnumerableProperty$1, hasOwn = hasOwnProperty_1, wrapConstructor = function(NativeConstructor) {
2022
- var Wrapper = function(a, b, c) {
2023
- if (this instanceof Wrapper) {
2024
- switch (arguments.length) {
2025
- case 0:
2026
- return new NativeConstructor;
2027
-
2028
- case 1:
2029
- return new NativeConstructor(a);
2131
+ }
2030
2132
 
2031
- case 2:
2032
- return new NativeConstructor(a, b);
2033
- }
2034
- return new NativeConstructor(a, b, c);
2133
+ /**
2134
+ * Default responsive breakpoints configuration
2135
+ *
2136
+ * These breakpoints are optimized for glass effect performance across device classes:
2137
+ * - Mobile: Reduced complexity for 60 FPS target
2138
+ * - Tablet: Balanced quality and performance
2139
+ * - Desktop: Full fidelity effects
2140
+ */ const DEFAULT_BREAKPOINTS = {
2141
+ mobile: {
2142
+ maxWidth: 640,
2143
+ params: {
2144
+ distortionOctaves: 3,
2145
+ displacementScale: .7,
2146
+ blurAmount: .8,
2147
+ animationSpeed: .8,
2148
+ chromaticIntensity: .5
2035
2149
  }
2036
- return apply(NativeConstructor, this, arguments);
2037
- };
2038
- return Wrapper.prototype = NativeConstructor.prototype, Wrapper;
2039
- }, _export = function(options, source) {
2040
- var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE, key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor, TARGET = options.target, GLOBAL = options.global, STATIC = options.stat, PROTO = options.proto, nativeSource = GLOBAL ? globalThis$2 : STATIC ? globalThis$2[TARGET] : globalThis$2[TARGET] && globalThis$2[TARGET].prototype, target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET], targetPrototype = target.prototype;
2041
- for (key in source)
2042
- // contains in native
2043
- USE_NATIVE = !(FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? "." : "#") + key, options.forced)) && nativeSource && hasOwn(nativeSource, key),
2044
- targetProperty = target[key], USE_NATIVE && (nativeProperty = options.dontCallGetSet ? (descriptor = getOwnPropertyDescriptor(nativeSource, key)) && descriptor.value : nativeSource[key]),
2045
- // export native or implementation
2046
- sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key], (FORCED || PROTO || typeof targetProperty != typeof sourceProperty) && (
2047
- // bind methods to global for calling from export context
2048
- resultProperty = options.bind && USE_NATIVE ? bind(sourceProperty, globalThis$2) : options.wrap && USE_NATIVE ? wrapConstructor(sourceProperty) : PROTO && isCallable$1(sourceProperty) ? uncurryThis$1(sourceProperty) : sourceProperty,
2049
- // add a flag to not completely full polyfills
2050
- (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) && createNonEnumerableProperty(resultProperty, "sham", !0),
2051
- createNonEnumerableProperty(target, key, resultProperty), PROTO && (hasOwn(path$1, VIRTUAL_PROTOTYPE = TARGET + "Prototype") || createNonEnumerableProperty(path$1, VIRTUAL_PROTOTYPE, {}),
2052
- // export virtual prototype methods
2053
- createNonEnumerableProperty(path$1[VIRTUAL_PROTOTYPE], key, sourceProperty),
2054
- // export real prototype methods
2055
- options.real && targetPrototype && (FORCED || !targetPrototype[key]) && createNonEnumerableProperty(targetPrototype, key, sourceProperty)));
2056
- }, ceil = Math.ceil, floor = Math.floor, trunc = Math.trunc || function(x) {
2057
- var n = +x;
2058
- return (n > 0 ? floor : ceil)(n);
2059
- }, toIntegerOrInfinity$2 = function(argument) {
2060
- var number = +argument;
2061
- // eslint-disable-next-line no-self-compare -- NaN check
2062
- return number != number || 0 === number ? 0 : trunc(number);
2063
- }, toIntegerOrInfinity$1 = toIntegerOrInfinity$2, max = Math.max, min$1 = Math.min, toIntegerOrInfinity = toIntegerOrInfinity$2, min = Math.min, toIndexedObject = toIndexedObject$2, lengthOfArrayLike = function(obj) {
2064
- return argument = obj.length, (len = toIntegerOrInfinity(argument)) > 0 ? min(len, 9007199254740991) : 0;
2150
+ },
2151
+ tablet: {
2152
+ minWidth: 641,
2153
+ maxWidth: 1024,
2154
+ params: {
2155
+ distortionOctaves: 4,
2156
+ displacementScale: .85,
2157
+ blurAmount: .9,
2158
+ animationSpeed: .9,
2159
+ chromaticIntensity: .75
2160
+ }
2161
+ },
2162
+ desktop: {
2163
+ minWidth: 1025,
2164
+ params: {
2165
+ distortionOctaves: 5,
2166
+ displacementScale: 1,
2167
+ blurAmount: 1,
2168
+ animationSpeed: 1,
2169
+ chromaticIntensity: 1
2170
+ }
2171
+ }
2172
+ };
2173
+
2174
+ /**
2175
+ * Device performance tier detection
2176
+ *
2177
+ * Uses Device Memory API and Hardware Concurrency API to classify devices
2178
+ * into performance tiers for automatic quality adjustment.
2179
+ *
2180
+ * @returns Performance tier classification
2181
+ */ var toIntegerOrInfinity = toIntegerOrInfinity$2, max = Math.max, min = Math.min, toIndexedObject = toIndexedObject$2, lengthOfArrayLike = function(obj) {
2182
+ return argument = obj.length, (len = toIntegerOrInfinity$1(argument)) > 0 ? min$1(len, 9007199254740991) : 0;
2065
2183
  var argument, len;
2066
2184
  }, createMethod = function(IS_INCLUDES) {
2067
2185
  return function($this, el, fromIndex) {
2068
2186
  var O = toIndexedObject($this), length = lengthOfArrayLike(O);
2069
2187
  if (0 === length) return !IS_INCLUDES && -1;
2070
2188
  var value, index = function(index, length) {
2071
- var integer = toIntegerOrInfinity$1(index);
2072
- return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
2189
+ var integer = toIntegerOrInfinity(index);
2190
+ return integer < 0 ? max(integer + length, 0) : min(integer, length);
2073
2191
  }(fromIndex, length);
2074
2192
  // Array#includes uses SameValueZero equality algorithm
2075
2193
  // eslint-disable-next-line no-self-compare -- NaN check
@@ -2098,12 +2216,7 @@ _export({
2098
2216
  }
2099
2217
  });
2100
2218
 
2101
- var globalThis$1 = globalThis_1, path = path$3, getBuiltInPrototypeMethod$2 = function(CONSTRUCTOR, METHOD) {
2102
- var Namespace = path[CONSTRUCTOR + "Prototype"], pureMethod = Namespace && Namespace[METHOD];
2103
- if (pureMethod) return pureMethod;
2104
- var NativeConstructor = globalThis$1[CONSTRUCTOR], NativePrototype = NativeConstructor && NativeConstructor.prototype;
2105
- return NativePrototype && NativePrototype[METHOD];
2106
- }, includes$4 = getBuiltInPrototypeMethod$2("Array", "includes"), isObject = isObject$5, classof$2 = classofRaw$2, MATCH$1 = wellKnownSymbol$5("match"), $TypeError = TypeError, test = {};
2219
+ var includes$4 = getBuiltInPrototypeMethod$2("Array", "includes"), isObject = isObject$5, classof$2 = classofRaw$2, MATCH$1 = wellKnownSymbol$5("match"), $TypeError = TypeError, test = {};
2107
2220
 
2108
2221
  test[wellKnownSymbol$5("toStringTag")] = "z";
2109
2222
 
@@ -2159,148 +2272,6 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
2159
2272
  /**
2160
2273
  * Get GPU memory info if available (Chrome DevTools only)
2161
2274
  */
2162
- /** Map an FPS value to a semantic color token string. */
2163
- const getQualityColor = quality => {
2164
- switch (quality) {
2165
- case "high":
2166
- return "var(--atomix-color-success, #4ade80)";
2167
-
2168
- case "medium":
2169
- return "var(--atomix-color-warning, #fbbf24)";
2170
-
2171
- case "low":
2172
- return "var(--atomix-color-danger, #ef4444)";
2173
-
2174
- default:
2175
- return "#9ca3af";
2176
- }
2177
- }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
2178
-
2179
- /** Map a quality level string to a semantic color token string. */
2180
- // Inject keyframes once
2181
- if ("undefined" != typeof document) {
2182
- const styleId = "perf-dashboard-keyframes";
2183
- if (!document.getElementById(styleId)) {
2184
- const styleEl = document.createElement("style");
2185
- styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
2186
- document.head.appendChild(styleEl);
2187
- }
2188
- }
2189
-
2190
- /**
2191
- * PerformanceDashboard - Real-time performance monitoring overlay.
2192
- *
2193
- * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
2194
- * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
2195
- */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
2196
- if (!isVisible) return null;
2197
- const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
2198
- var fps;
2199
- const isCritical = metrics.fps < 45;
2200
- return jsxs("div", {
2201
- 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",
2202
- style: {
2203
- zIndex: 9999,
2204
- minWidth: "12.5rem",
2205
- // 200px
2206
- backgroundColor: "rgba(17, 24, 39, 0.95)",
2207
- backdropFilter: "blur(8px)",
2208
- transition: "opacity 0.3s ease"
2209
- },
2210
- children: [ jsxs("div", {
2211
- className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
2212
- children: [ jsx("span", {
2213
- className: "u-text-sm u-font-bold u-text-white",
2214
- children: "Performance Monitor"
2215
- }), onClose && jsx("button", {
2216
- 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",
2217
- onClick: onClose,
2218
- "aria-label": "Close performance dashboard",
2219
- style: {
2220
- transition: "color 0.2s ease"
2221
- },
2222
- children: "×"
2223
- }) ]
2224
- }), jsxs("div", {
2225
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2226
- children: [ jsx("span", {
2227
- className: "u-text-gray-400 u-me-3",
2228
- children: "FPS"
2229
- }), jsx("span", {
2230
- className: "u-font-bold",
2231
- style: {
2232
- color: fpsColor
2233
- },
2234
- children: Math.round(metrics.fps)
2235
- }) ]
2236
- }), jsxs("div", {
2237
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2238
- children: [ jsx("span", {
2239
- className: "u-text-gray-400 u-me-3",
2240
- children: "Frame Time"
2241
- }), jsxs("span", {
2242
- className: "u-font-bold",
2243
- children: [ metrics.frameTime.toFixed(2), "ms" ]
2244
- }) ]
2245
- }), jsxs("div", {
2246
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2247
- children: [ jsx("span", {
2248
- className: "u-text-gray-400 u-me-3",
2249
- children: "Quality"
2250
- }), jsx("span", {
2251
- className: "u-font-bold u-text-uppercase",
2252
- style: {
2253
- fontSize: "0.6875rem",
2254
- // 11px
2255
- color: getQualityColor(metrics.qualityLevel)
2256
- },
2257
- children: metrics.qualityLevel
2258
- }) ]
2259
- }), metrics.gpuMemory && jsxs("div", {
2260
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
2261
- children: [ jsx("span", {
2262
- className: "u-text-gray-400 u-me-3",
2263
- children: "GPU Memory"
2264
- }), jsxs("span", {
2265
- className: "u-font-bold",
2266
- children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
2267
- }) ]
2268
- }), metrics.isAutoScaling && jsx("div", {
2269
- className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
2270
- style: {
2271
- fontSize: "0.625rem",
2272
- // 10px
2273
- color: "#6b7280"
2274
- },
2275
- children: "Auto-scaling active"
2276
- }), jsxs("div", {
2277
- className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
2278
- children: [ jsx("div", {
2279
- className: "u-rounded-full",
2280
- style: {
2281
- width: "0.5rem",
2282
- height: "0.5rem",
2283
- flexShrink: 0,
2284
- backgroundColor: fpsColor,
2285
- ...isCritical && {
2286
- animation: "perf-dashboard-pulse 1s infinite"
2287
- }
2288
- }
2289
- }), jsx("span", {
2290
- className: "u-text-xs",
2291
- style: {
2292
- fontSize: "0.625rem",
2293
- // 10px
2294
- color: fpsColor
2295
- },
2296
- children: getFpsLabel(metrics.fps)
2297
- }) ]
2298
- }) ]
2299
- });
2300
- }));
2301
-
2302
- PerformanceDashboard.displayName = "PerformanceDashboard";
2303
-
2304
2275
  /**
2305
2276
  * Mobile optimization presets
2306
2277
  *
@@ -2420,18 +2391,13 @@ const PERFORMANCE_PRESET = {
2420
2391
  saturation: 70
2421
2392
  }
2422
2393
  }
2423
- }, 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) {
2424
- const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
2425
- // Helper to merge refs
2426
- function(...refs) {
2427
- return node => {
2428
- refs.forEach((ref => {
2429
- "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
2430
- }));
2431
- };
2432
- }
2433
- // Internal implementation with forwardRef
2434
- (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({
2394
+ }, 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) {
2395
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
2396
+ position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
2397
+ var explicit, position;
2398
+ /**
2399
+ * Extracts layout-related properties from a React `CSSProperties` object.
2400
+ */ const {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, resolvedBorder: resolvedBorder} = useAtomixGlass({
2435
2401
  glassRef: glassRef,
2436
2402
  contentRef: contentRef,
2437
2403
  wrapperRef: internalWrapperRef,
@@ -2451,10 +2417,11 @@ const PERFORMANCE_PRESET = {
2451
2417
  blurAmount: blurAmount,
2452
2418
  saturation: saturation,
2453
2419
  withLiquidBlur: withLiquidBlur,
2454
- padding: padding,
2420
+ border: border,
2421
+ withBorder: withBorder,
2422
+ debugBorderRadius: debugBorderRadius,
2455
2423
  style: style,
2456
2424
  isFixedOrSticky: isFixedOrSticky,
2457
- // Phase 1: Animation System props
2458
2425
  withTimeAnimation: withTimeAnimation,
2459
2426
  animationSpeed: animationSpeed,
2460
2427
  withMultiLayerDistortion: withMultiLayerDistortion,
@@ -2463,8 +2430,7 @@ const PERFORMANCE_PRESET = {
2463
2430
  distortionGain: distortionGain,
2464
2431
  distortionQuality: distortionQuality
2465
2432
  });
2466
- // Responsive breakpoint system - automatically adjusts parameters based on viewport
2467
- !
2433
+ (
2468
2434
  /**
2469
2435
  * Responsive Glass Parameters Hook
2470
2436
  *
@@ -2619,7 +2585,7 @@ const PERFORMANCE_PRESET = {
2619
2585
  }), [ enabled ]), useCallback((() => {
2620
2586
  calculateParams();
2621
2587
  }), [ calculateParams ]);
2622
- }({
2588
+ })({
2623
2589
  baseParams: {
2624
2590
  ...useMemo((() =>
2625
2591
  /**
@@ -2653,9 +2619,7 @@ const PERFORMANCE_PRESET = {
2653
2619
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
2654
2620
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
2655
2621
  debug: !1
2656
- });
2657
- // Performance monitoring - tracks FPS, frame time, memory usage
2658
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
2622
+ }),
2659
2623
  /**
2660
2624
  * Performance Monitor Hook
2661
2625
  *
@@ -2690,7 +2654,13 @@ const PERFORMANCE_PRESET = {
2690
2654
  timestamp: 0,
2691
2655
  isAutoScaling: !0,
2692
2656
  lowFpsCount: 0
2693
- }), [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 => {
2657
+ }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
2658
+ // Sync external `enabled` prop changes into internal state
2659
+ useEffect((() => {
2660
+ setIsEnabled(enabled ?? !0);
2661
+ }), [ enabled ]);
2662
+ // Refs for frame tracking
2663
+ 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 => {
2694
2664
  setMetrics((prev => ({
2695
2665
  ...prev,
2696
2666
  ...newMetrics,
@@ -2810,191 +2780,214 @@ const PERFORMANCE_PRESET = {
2810
2780
  /**
2811
2781
  * Reset to auto-scaling mode
2812
2782
  */ var fps, currentQuality;
2813
- return {
2814
- metrics: metrics,
2815
- recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
2816
- isUnderperforming: metrics.fps < minFps,
2817
- setQualityLevel: setQualityLevel,
2818
- resetAutoScaling: resetAutoScaling,
2819
- toggleMonitoring: toggleMonitoring
2820
- };
2783
+ fps = metrics.fps, currentQuality = metrics.qualityLevel, metrics.fps;
2821
2784
  }({
2822
2785
  enabled: debugPerformance,
2823
- // Enable when debugPerformance is true
2824
2786
  debug: !1,
2825
2787
  showOverlay: !1
2826
2788
  });
2827
- // Auto-start performance monitoring when debugPerformance is enabled
2828
- React.useEffect((() => {
2829
- debugPerformance && toggleMonitoring();
2830
- // eslint-disable-next-line react-hooks/exhaustive-deps
2831
- }), [ debugPerformance ]);
2832
- // Re-run when debugPerformance changes
2833
- const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
2834
- if (!isFixedOrSticky) return {};
2835
- const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
2836
- return {
2837
- ...p && {
2838
- position: p
2839
- },
2840
- ...void 0 !== t && {
2841
- top: t
2842
- },
2843
- ...void 0 !== l && {
2844
- left: l
2845
- },
2846
- ...void 0 !== r && {
2847
- right: r
2848
- },
2849
- ...void 0 !== b && {
2850
- bottom: b
2851
- }
2852
- };
2853
- }), [ isFixedOrSticky, restStyle ]);
2854
- // Calculate base style with transforms
2855
- // When layout is hoisted to the root, strip those props from the container
2856
- useMemo((() => {
2857
- if (isFixedOrSticky) {
2858
- const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
2859
- return {
2860
- ...visualStyle
2861
- };
2789
+ const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
2790
+ ...restStyle,
2791
+ ...void 0 !== customZIndex && {
2792
+ zIndex: customZIndex
2862
2793
  }
2794
+ })), [ 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((() =>
2795
+ /**
2796
+ * Returns the internal positioning context for effect layers relative to the root.
2797
+ */
2798
+ function(isFixedOrSticky, restStyle) {
2863
2799
  return {
2864
- ...restStyle
2800
+ position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2801
+ top: 0,
2802
+ left: 0,
2803
+ right: "auto",
2804
+ bottom: "auto"
2865
2805
  };
2866
- }), [ isFixedOrSticky, restStyle ]);
2867
- // Build className with state modifiers
2868
- 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((() => ({
2869
- position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2870
- top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
2871
- left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
2872
- right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
2873
- bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
2874
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
2875
- // Keep a reference to positionStyles to avoid unused-variable lint,
2876
- // but sizing is driven by explicit width/height or measured size.
2877
- positionStyles.position;
2878
- 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;
2806
+ }
2807
+ /**
2808
+ * Computes `--atomix-glass-width` and `--atomix-glass-height` values.
2809
+ *
2810
+ * Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
2811
+ * elements default to `100%`.
2812
+ */ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
2813
+ 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;
2879
2814
  return {
2880
2815
  width: resolveLength(effectiveWidth, glassSize.width),
2881
2816
  height: resolveLength(effectiveHeight, glassSize.height)
2882
2817
  };
2883
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
2884
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
2885
- return {
2886
- borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
2887
- borderStop1: Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER),
2888
- borderStop2: Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER),
2889
- 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 ],
2890
- hoverPositions: {
2891
- hover1: {
2892
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
2893
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
2894
- },
2895
- hover2: {
2896
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
2897
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
2898
- },
2899
- hover3: {
2900
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
2901
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
2902
- }
2903
- },
2904
- basePosition: {
2905
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
2906
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
2907
- },
2908
- mx: mx,
2909
- my: my,
2910
- absMx: absMx,
2911
- absMy: absMy
2912
- };
2913
- }), [ 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((() => ({
2914
- hover1: isHovered || isActive ? .5 : 0,
2915
- hover2: isActive ? .5 : 0,
2916
- hover3: isHovered ? .4 : isActive ? .8 : 0,
2917
- base: isOverLight ? clampedOverLightOpacity || .4 : 0,
2918
- over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
2919
- })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
2920
- 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;
2818
+ }
2819
+ /**
2820
+ * Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
2821
+ *
2822
+ * These variables drive layer geometry, transforms, and stacking offsets. They
2823
+ * must not include layout properties that would interfere with backdrop-filter.
2824
+ */ ({
2825
+ width: width,
2826
+ height: height,
2827
+ restStyle: restStyle,
2828
+ glassSize: glassSize,
2829
+ isFixedOrSticky: isFixedOrSticky
2830
+ })), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
2831
+ 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 =
2832
+ /**
2833
+ * Resolves the `--atomix-glass-position` value for decorative layers.
2834
+ *
2835
+ * Fixed/sticky layers use the same positioning mode as the container; in-flow
2836
+ * layers default to the internal absolute positioning context.
2837
+ */
2838
+ function(isFixedOrSticky, positionStyles, restStyle) {
2839
+ return isFixedOrSticky ? `${function(style) {
2840
+ const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
2841
+ return {
2842
+ ...null != position && {
2843
+ position: position
2844
+ },
2845
+ ...void 0 !== top && {
2846
+ top: top
2847
+ },
2848
+ ...void 0 !== left && {
2849
+ left: left
2850
+ },
2851
+ ...void 0 !== right && {
2852
+ right: right
2853
+ },
2854
+ ...void 0 !== bottom && {
2855
+ bottom: bottom
2856
+ },
2857
+ ...void 0 !== inset && {
2858
+ inset: inset
2859
+ }
2860
+ };
2861
+ }
2862
+ /**
2863
+ * Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
2864
+ *
2865
+ * For fixed and sticky modes, insets mirror the container so sibling layers remain
2866
+ * aligned. In-flow modes, insets follow the consumer `style` when a non-default
2867
+ * `position` is provided.
2868
+ */ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
2869
+ }(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
2870
+ if (isFixedOrSticky) return {
2871
+ top: formatGlassInsetValue(restStyle.top, 0),
2872
+ left: formatGlassInsetValue(restStyle.left, 0),
2873
+ right: formatGlassInsetValue(restStyle.right, "auto"),
2874
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
2875
+ };
2876
+ const position = restStyle.position;
2877
+ return null != position && "static" !== position && "relative" !== position ? {
2878
+ top: formatGlassInsetValue(restStyle.top, 0),
2879
+ left: formatGlassInsetValue(restStyle.left, 0),
2880
+ right: formatGlassInsetValue(restStyle.right, "auto"),
2881
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
2882
+ } : {
2883
+ top: "0px",
2884
+ left: "0px",
2885
+ right: "auto",
2886
+ bottom: "auto"
2887
+ };
2888
+ }(isFixedOrSticky, restStyle);
2921
2889
  return {
2922
2890
  ...void 0 !== customZIndex && {
2923
2891
  "--atomix-glass-base-z-index": customZIndex
2924
2892
  },
2925
2893
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
2926
2894
  "--atomix-glass-transform": transformStyle || "none",
2927
- "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
2928
- "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
2929
- "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
2930
- "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
2931
- "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
2932
- "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
2895
+ "--atomix-glass-container-position": layerPosition,
2896
+ "--atomix-glass-position": layerPosition,
2897
+ "--atomix-glass-top": layerInsets.top,
2898
+ "--atomix-glass-left": layerInsets.left,
2899
+ "--atomix-glass-right": layerInsets.right,
2900
+ "--atomix-glass-bottom": layerInsets.bottom,
2933
2901
  "--atomix-glass-width": adjustedSize.width,
2934
2902
  "--atomix-glass-height": adjustedSize.height,
2935
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
2936
- "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2937
- "--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%)`,
2938
- "--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%)`,
2939
- "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2940
- "--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}%)`,
2941
- "--atomix-glass-hover-2-opacity": opacityValues.hover2,
2942
- "--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}%)`,
2943
- "--atomix-glass-hover-3-opacity": opacityValues.hover3,
2944
- "--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}%)`,
2945
- "--atomix-glass-base-opacity": opacityValues.base,
2946
- "--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})`,
2947
- "--atomix-glass-overlay-opacity": opacityValues.over,
2948
- "--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})`,
2949
- "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
2950
- "--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}%)`
2903
+ // Aliases maintained for backward compatibility and consumer overrides.
2904
+ "--atomix-glass-container-width": adjustedSize.width,
2905
+ "--atomix-glass-container-height": adjustedSize.height,
2906
+ [ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
2907
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
2908
+ };
2909
+ }
2910
+ /**
2911
+ * Applies mode-specific multipliers and accessibility overrides to container effects.
2912
+ */ ({
2913
+ effectiveBorderRadius: effectiveBorderRadius,
2914
+ transformStyle: transformStyle,
2915
+ adjustedSize: adjustedSize,
2916
+ isOverLight: isOverLight,
2917
+ customZIndex: customZIndex,
2918
+ isFixedOrSticky: isFixedOrSticky,
2919
+ positionStyles: positionStyles,
2920
+ restStyle: restStyle,
2921
+ borderWidth: resolvedBorder.width
2922
+ })), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
2923
+ const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
2924
+ x: 0,
2925
+ y: 0
2926
+ }, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
2927
+ if (options.effectiveWithoutEffects) return {
2928
+ displacementScale: 0,
2929
+ blurAmount: 0,
2930
+ saturation: resolveSaturation(),
2931
+ aberrationIntensity: 0,
2932
+ mouseOffset: zeroMouse,
2933
+ globalMousePosition: zeroMouse
2951
2934
  };
2952
- }), [ 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", {
2953
- 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(" ")
2935
+ let resolvedDisplacement = options.displacementScale;
2936
+ "shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
2937
+ let resolvedAberration = options.aberrationIntensity;
2938
+ return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
2939
+ {
2940
+ displacementScale: resolvedDisplacement,
2941
+ blurAmount: options.blurAmount,
2942
+ saturation: resolveSaturation(),
2943
+ aberrationIntensity: resolvedAberration,
2944
+ mouseOffset: options.mouseOffset,
2945
+ globalMousePosition: options.globalMousePosition
2946
+ };
2947
+ }({
2948
+ displacementScale: displacementScale,
2949
+ blurAmount: blurAmount,
2950
+ saturation: saturation,
2951
+ aberrationIntensity: aberrationIntensity,
2952
+ mode: mode,
2953
+ effectiveWithoutEffects: effectiveWithoutEffects,
2954
+ effectiveHighContrast: effectiveHighContrast,
2955
+ isOverLight: isOverLight,
2956
+ saturationBoost: overLightConfig.saturationBoost,
2957
+ mouseOffset: mouseOffset,
2958
+ globalMousePosition: globalMousePosition
2959
+ })), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
2960
+ "aria-hidden": "true",
2961
+ 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)
2954
2962
  });
2955
- // Calculate position and size styles for internal layers
2956
- // When root is fixed/sticky, internal layers use absolute (relative to root)
2957
- return jsxs("div", {
2963
+ return jsxs("div", {
2958
2964
  ...rest,
2959
2965
  ref: mergedRef,
2960
2966
  className: componentClassName,
2961
- style: {
2962
- ...glassVars
2963
- },
2967
+ style: glassVars,
2964
2968
  role: role || (onClick ? "button" : void 0),
2965
2969
  tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
2966
2970
  "aria-label": ariaLabel,
2967
2971
  "aria-describedby": ariaDescribedBy,
2968
2972
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
2969
- "aria-pressed": onClick ? isActive : void 0,
2970
2973
  onKeyDown: onClick ? handleKeyDown : void 0,
2971
2974
  children: [ jsx(AtomixGlassContainer, {
2972
2975
  ref: glassRef,
2973
2976
  contentRef: contentRef,
2974
2977
  className: className,
2975
- style: {
2976
- ...restStyle
2977
- },
2978
+ style: containerStyle,
2978
2979
  borderRadius: effectiveBorderRadius,
2979
- displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
2980
- blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
2981
- saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
2982
- aberrationIntensity: effectiveWithoutEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
2980
+ displacementScale: containerEffects.displacementScale,
2981
+ blurAmount: containerEffects.blurAmount,
2982
+ saturation: containerEffects.saturation,
2983
+ aberrationIntensity: containerEffects.aberrationIntensity,
2983
2984
  glassSize: glassSize,
2984
- padding: padding,
2985
- mouseOffset: effectiveWithoutEffects ? {
2986
- x: 0,
2987
- y: 0
2988
- } : mouseOffset,
2989
- globalMousePosition: effectiveWithoutEffects ? {
2990
- x: 0,
2991
- y: 0
2992
- } : globalMousePosition,
2985
+ mouseOffset: containerEffects.mouseOffset,
2986
+ globalMousePosition: containerEffects.globalMousePosition,
2993
2987
  onMouseEnter: handleMouseEnter,
2994
2988
  onMouseLeave: handleMouseLeave,
2995
2989
  onMouseDown: handleMouseDown,
2996
2990
  onMouseUp: handleMouseUp,
2997
- isHovered: isHovered,
2998
2991
  isActive: isActive,
2999
2992
  overLight: isOverLight,
3000
2993
  overLightConfig: {
@@ -3010,7 +3003,6 @@ const PERFORMANCE_PRESET = {
3010
3003
  shaderVariant: shaderVariant,
3011
3004
  withLiquidBlur: withLiquidBlur,
3012
3005
  isFixedOrSticky: isFixedOrSticky,
3013
- // Phase 1: Animation System props
3014
3006
  shaderTime: getShaderTime(),
3015
3007
  withTimeAnimation: withTimeAnimation,
3016
3008
  animationSpeed: animationSpeed,
@@ -3022,32 +3014,39 @@ const PERFORMANCE_PRESET = {
3022
3014
  children: children
3023
3015
  }), Boolean(onClick) && jsxs(Fragment, {
3024
3016
  children: [ jsx("div", {
3017
+ "aria-hidden": "true",
3025
3018
  className: ATOMIX_GLASS.HOVER_1_CLASS
3026
3019
  }), jsx("div", {
3020
+ "aria-hidden": "true",
3027
3021
  className: ATOMIX_GLASS.HOVER_2_CLASS
3028
3022
  }), jsx("div", {
3023
+ "aria-hidden": "true",
3029
3024
  className: ATOMIX_GLASS.HOVER_3_CLASS
3030
3025
  }) ]
3031
- }), renderBackgroundLayer("dark"), renderBackgroundLayer("black"), shouldRenderOverLightLayers && jsxs(Fragment, {
3026
+ }), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
3027
+ children: renderBackgroundLayer(layerType)
3028
+ }, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
3032
3029
  children: [ jsx("div", {
3030
+ "aria-hidden": "true",
3033
3031
  className: ATOMIX_GLASS.BASE_LAYER_CLASS
3034
3032
  }), jsx("div", {
3033
+ "aria-hidden": "true",
3035
3034
  className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
3036
3035
  }), jsx("div", {
3036
+ "aria-hidden": "true",
3037
3037
  className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
3038
3038
  }) ]
3039
- }), withBorder && jsxs(Fragment, {
3039
+ }), resolvedBorder.enabled && jsxs(Fragment, {
3040
3040
  children: [ jsx("span", {
3041
+ "aria-hidden": "true",
3041
3042
  className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
3042
3043
  }), jsx("span", {
3044
+ "aria-hidden": "true",
3043
3045
  className: ATOMIX_GLASS.BORDER_1_CLASS
3044
3046
  }), jsx("span", {
3047
+ "aria-hidden": "true",
3045
3048
  className: ATOMIX_GLASS.BORDER_2_CLASS
3046
3049
  }) ]
3047
- }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
3048
- metrics: performanceMetrics,
3049
- isVisible: !0,
3050
- onClose: () => {}
3051
3050
  }) ]
3052
3051
  });
3053
3052
  }));
@@ -3057,10 +3056,7 @@ const PERFORMANCE_PRESET = {
3057
3056
  * Default preset for most mobile devices
3058
3057
  */ AtomixGlassInner.displayName = "AtomixGlass";
3059
3058
 
3060
- /**
3061
- * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
3062
- * Ref is forwarded to the root `<div>` element.
3063
- */
3059
+ /** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
3064
3060
  const AtomixGlass = memo(AtomixGlassInner), smoothStep = (a, b, t) => {
3065
3061
  // Add input validation
3066
3062
  if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
@@ -3354,29 +3350,7 @@ const AtomixGlass = memo(AtomixGlassInner), smoothStep = (a, b, t) => {
3354
3350
  liquidGlassWithTime: liquidGlassWithTime
3355
3351
  }, Symbol.toStringTag, {
3356
3352
  value: "Module"
3357
- }));
3358
-
3359
- // Adapted from https://github.com/shuding/liquid-glass
3360
- // Constants
3361
- /**
3362
- * Component Utilities
3363
- *
3364
- * Helper functions for component development with the new customization system
3365
- */
3366
- /**
3367
- * Check if a URL is a YouTube URL
3368
- */
3369
- function isYouTubeUrl(url) {
3370
- return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
3371
- }
3372
-
3373
- /**
3374
- * Extract YouTube video ID from URL
3375
- */
3376
- /**
3377
- * Advanced Video Player Component
3378
- */
3379
- const VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: youtubeId, poster: poster, autoplay: autoplay = !1, loop: loop = !1, muted: muted = !1, controls: controls = !0, preload: preload = "metadata", width: width, height: height, aspectRatio: aspectRatio = "16:9", className: className = "", onPlay: onPlay, onPause: onPause, onEnded: onEnded, onTimeUpdate: onTimeUpdate, onVolumeChange: onVolumeChange, onFullscreenChange: onFullscreenChange, onError: onError, showDownload: showDownload = !1, showShare: showShare = !1, showSettings: showSettings = !0, playbackRates: playbackRates = [ .5, .75, 1, 1.25, 1.5, 2 ], subtitles: subtitles, quality: quality, ambientMode: ambientMode = !1, glass: glass = !1, glassOpacity: glassOpacity = 1, glassContent: glassContent, style: style, ...props}, ref) => {
3353
+ })), VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: youtubeId, poster: poster, autoplay: autoplay = !1, loop: loop = !1, muted: muted = !1, controls: controls = !0, preload: preload = "metadata", width: width, height: height, aspectRatio: aspectRatio = "16:9", className: className = "", onPlay: onPlay, onPause: onPause, onEnded: onEnded, onTimeUpdate: onTimeUpdate, onVolumeChange: onVolumeChange, onFullscreenChange: onFullscreenChange, onError: onError, showDownload: showDownload = !1, showShare: showShare = !1, showSettings: showSettings = !0, playbackRates: playbackRates = [ .5, .75, 1, 1.25, 1.5, 2 ], subtitles: subtitles, quality: quality, ambientMode: ambientMode = !1, glass: glass = !1, glassOpacity: glassOpacity = 1, glassContent: glassContent, style: style, ...props}, ref) => {
3380
3354
  const videoRef = useRef(null), containerRef = useRef(null), canvasRef = useRef(null), iframeRef = useRef(null), [containerBorderRadius, setContainerBorderRadius] = useState(8), isYouTube = "youtube" === type || youtubeId || src && isYouTubeUrl(src), videoId = youtubeId || (isYouTube && src ? function(url) {
3381
3355
  if (!isYouTubeUrl(url)) return null;
3382
3356
  const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
@@ -3554,7 +3528,10 @@ const VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: yo
3554
3528
  getProgressPercentage: getProgressPercentage,
3555
3529
  getBufferedPercentage: getBufferedPercentage
3556
3530
  };
3557
- }({
3531
+ }
3532
+ /**
3533
+ * Advanced Video Player Component
3534
+ */ ({
3558
3535
  videoRef: videoRef,
3559
3536
  containerRef: containerRef,
3560
3537
  onPlay: onPlay,
@@ -4053,6 +4030,8 @@ const VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: yo
4053
4030
  });
4054
4031
  }));
4055
4032
 
4033
+ // Adapted from https://github.com/shuding/liquid-glass
4034
+ // Constants
4056
4035
  VideoPlayer.displayName = "VideoPlayer";
4057
4036
 
4058
4037
  /**
@@ -4307,10 +4286,10 @@ const Badge = memo((({label: label, variant: variant = "primary", size: size =
4307
4286
  if (glass) {
4308
4287
  // Default glass settings for badges
4309
4288
  const defaultGlassProps = {
4310
- displacementScale: 20,
4311
- borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : 16,
4312
- className: "c-badge--glass",
4313
- elasticity: 0
4289
+ ...GLASS_DEFAULTS_BADGE,
4290
+ // Override borderRadius dynamically if the ref is available
4291
+ borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : GLASS_DEFAULTS_BADGE.borderRadius,
4292
+ className: "c-badge--glass"
4314
4293
  }, glassProps = !0 === glass ? defaultGlassProps : {
4315
4294
  ...defaultGlassProps,
4316
4295
  ...glass
@@ -4375,12 +4354,7 @@ const Spinner = memo( forwardRef((({size: size = "md", variant: variant = "prim
4375
4354
  })
4376
4355
  });
4377
4356
  if (glass) {
4378
- const defaultGlassProps = {
4379
- displacementScale: 20,
4380
- blurAmount: 1,
4381
- borderRadius: 999,
4382
- mode: "shader"
4383
- }, glassProps = !0 === glass ? defaultGlassProps : {
4357
+ const defaultGlassProps = GLASS_DEFAULTS_SPINNER, glassProps = !0 === glass ? defaultGlassProps : {
4384
4358
  ...defaultGlassProps,
4385
4359
  ...glass
4386
4360
  };
@@ -4660,11 +4634,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
4660
4634
  // This is a safe fallback for disabled links.
4661
4635
  if (glass) {
4662
4636
  // Default glass props
4663
- const defaultGlassProps = {
4664
- displacementScale: 20,
4665
- blurAmount: 0,
4666
- saturation: 200
4667
- }, glassProps = !0 === glass ? defaultGlassProps : {
4637
+ const defaultGlassProps = GLASS_DEFAULTS_BUTTON, glassProps = !0 === glass ? defaultGlassProps : {
4668
4638
  ...defaultGlassProps,
4669
4639
  ...glass
4670
4640
  };