@salmexio/ui 0.4.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +52 -3
  2. package/dist/dialogs/ContextMenu/ContextMenu.svelte +97 -94
  3. package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts +3 -2
  4. package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts.map +1 -1
  5. package/dist/dialogs/Modal/Modal.svelte +112 -116
  6. package/dist/dialogs/Modal/Modal.svelte.d.ts +1 -1
  7. package/dist/feedback/Alert/Alert.svelte +119 -220
  8. package/dist/feedback/Alert/Alert.svelte.d.ts +1 -1
  9. package/dist/feedback/ProgressBar/ProgressBar.svelte +265 -0
  10. package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts +40 -0
  11. package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts.map +1 -0
  12. package/dist/feedback/ProgressBar/index.d.ts +2 -0
  13. package/dist/feedback/ProgressBar/index.d.ts.map +1 -0
  14. package/dist/feedback/ProgressBar/index.js +1 -0
  15. package/dist/feedback/Skeleton/Skeleton.svelte +157 -0
  16. package/dist/feedback/Skeleton/Skeleton.svelte.d.ts +37 -0
  17. package/dist/feedback/Skeleton/Skeleton.svelte.d.ts.map +1 -0
  18. package/dist/feedback/Skeleton/index.d.ts +2 -0
  19. package/dist/feedback/Skeleton/index.d.ts.map +1 -0
  20. package/dist/feedback/Skeleton/index.js +1 -0
  21. package/dist/feedback/Spinner/Spinner.svelte +86 -151
  22. package/dist/feedback/Spinner/Spinner.svelte.d.ts +5 -3
  23. package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -1
  24. package/dist/feedback/Toast/Toaster.svelte +431 -0
  25. package/dist/feedback/Toast/Toaster.svelte.d.ts +22 -0
  26. package/dist/feedback/Toast/Toaster.svelte.d.ts.map +1 -0
  27. package/dist/feedback/Toast/index.d.ts +4 -0
  28. package/dist/feedback/Toast/index.d.ts.map +1 -0
  29. package/dist/feedback/Toast/index.js +2 -0
  30. package/dist/feedback/Toast/toastStore.d.ts +34 -0
  31. package/dist/feedback/Toast/toastStore.d.ts.map +1 -0
  32. package/dist/feedback/Toast/toastStore.js +43 -0
  33. package/dist/feedback/index.d.ts +4 -0
  34. package/dist/feedback/index.d.ts.map +1 -1
  35. package/dist/feedback/index.js +3 -0
  36. package/dist/forms/Checkbox/Checkbox.svelte +87 -104
  37. package/dist/forms/Checkbox/Checkbox.svelte.d.ts +1 -1
  38. package/dist/forms/Select/Select.svelte +137 -179
  39. package/dist/forms/Select/Select.svelte.d.ts +1 -1
  40. package/dist/forms/Slider/Slider.svelte +356 -0
  41. package/dist/forms/Slider/Slider.svelte.d.ts +50 -0
  42. package/dist/forms/Slider/Slider.svelte.d.ts.map +1 -0
  43. package/dist/forms/Slider/index.d.ts +2 -0
  44. package/dist/forms/Slider/index.d.ts.map +1 -0
  45. package/dist/forms/Slider/index.js +1 -0
  46. package/dist/forms/TextInput/TextInput.svelte +161 -167
  47. package/dist/forms/TextInput/TextInput.svelte.d.ts +1 -1
  48. package/dist/forms/Textarea/Textarea.svelte +615 -0
  49. package/dist/forms/Textarea/Textarea.svelte.d.ts +47 -0
  50. package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -0
  51. package/dist/forms/Textarea/index.d.ts +2 -0
  52. package/dist/forms/Textarea/index.d.ts.map +1 -0
  53. package/dist/forms/Textarea/index.js +1 -0
  54. package/dist/forms/Toggle/Toggle.svelte +239 -0
  55. package/dist/forms/Toggle/Toggle.svelte.d.ts +39 -0
  56. package/dist/forms/Toggle/Toggle.svelte.d.ts.map +1 -0
  57. package/dist/forms/Toggle/index.d.ts +2 -0
  58. package/dist/forms/Toggle/index.d.ts.map +1 -0
  59. package/dist/forms/Toggle/index.js +1 -0
  60. package/dist/forms/index.d.ts +3 -0
  61. package/dist/forms/index.d.ts.map +1 -1
  62. package/dist/forms/index.js +3 -0
  63. package/dist/index.d.ts +0 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +0 -1
  66. package/dist/layout/Card/Card.svelte +66 -39
  67. package/dist/layout/Card/Card.svelte.d.ts +1 -1
  68. package/dist/layout/Card/Card.svelte.d.ts.map +1 -1
  69. package/dist/layout/Container/Container.svelte +71 -71
  70. package/dist/layout/Container/Container.svelte.d.ts +2 -2
  71. package/dist/layout/ThermalBackground/ThermalBackground.svelte +313 -0
  72. package/dist/layout/ThermalBackground/ThermalBackground.svelte.d.ts +16 -0
  73. package/dist/layout/ThermalBackground/ThermalBackground.svelte.d.ts.map +1 -0
  74. package/dist/layout/ThermalBackground/index.d.ts +2 -0
  75. package/dist/layout/ThermalBackground/index.d.ts.map +1 -0
  76. package/dist/layout/ThermalBackground/index.js +1 -0
  77. package/dist/layout/index.d.ts +1 -0
  78. package/dist/layout/index.d.ts.map +1 -1
  79. package/dist/layout/index.js +1 -0
  80. package/dist/navigation/CommandPalette/CommandPalette.svelte +407 -189
  81. package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts +8 -3
  82. package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts.map +1 -1
  83. package/dist/navigation/Tabs/Tabs.svelte +139 -192
  84. package/dist/navigation/Tabs/Tabs.svelte.d.ts +2 -2
  85. package/dist/primitives/Badge/Badge.svelte +85 -220
  86. package/dist/primitives/Badge/Badge.svelte.d.ts +2 -2
  87. package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
  88. package/dist/primitives/Button/Button.svelte +214 -194
  89. package/dist/primitives/Button/Button.svelte.d.ts +3 -3
  90. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
  91. package/dist/primitives/Tooltip/Tooltip.svelte +260 -0
  92. package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +36 -0
  93. package/dist/primitives/Tooltip/Tooltip.svelte.d.ts.map +1 -0
  94. package/dist/primitives/Tooltip/index.d.ts +2 -0
  95. package/dist/primitives/Tooltip/index.d.ts.map +1 -0
  96. package/dist/primitives/Tooltip/index.js +1 -0
  97. package/dist/primitives/index.d.ts +1 -0
  98. package/dist/primitives/index.d.ts.map +1 -1
  99. package/dist/primitives/index.js +1 -0
  100. package/dist/styles/tokens.css +329 -260
  101. package/package.json +5 -5
  102. package/dist/windowing/Window/Window.svelte +0 -637
  103. package/dist/windowing/Window/Window.svelte.d.ts +0 -65
  104. package/dist/windowing/Window/Window.svelte.d.ts.map +0 -1
  105. package/dist/windowing/Window/index.d.ts +0 -2
  106. package/dist/windowing/Window/index.d.ts.map +0 -1
  107. package/dist/windowing/Window/index.js +0 -1
  108. package/dist/windowing/WindowManager/WindowManager.svelte +0 -425
  109. package/dist/windowing/WindowManager/WindowManager.svelte.d.ts +0 -38
  110. package/dist/windowing/WindowManager/WindowManager.svelte.d.ts.map +0 -1
  111. package/dist/windowing/WindowManager/index.d.ts +0 -2
  112. package/dist/windowing/WindowManager/index.d.ts.map +0 -1
  113. package/dist/windowing/WindowManager/index.js +0 -1
  114. package/dist/windowing/index.d.ts +0 -5
  115. package/dist/windowing/index.d.ts.map +0 -1
  116. package/dist/windowing/index.js +0 -3
  117. package/dist/windowing/windowStore.svelte.d.ts +0 -49
  118. package/dist/windowing/windowStore.svelte.d.ts.map +0 -1
  119. package/dist/windowing/windowStore.svelte.js +0 -170
@@ -1,8 +1,8 @@
1
1
  <!--
2
2
  @component Container
3
3
 
4
- Win2K × Basquiat — Responsive layout wrapper. Max-width, padding, optional centering.
5
- Sharp edges, no rounded corners; supports semantic elements.
4
+ INFRARED — Responsive layout wrapper. Max-width, padding, optional centering.
5
+ Pure layout utility; supports semantic elements.
6
6
  -->
7
7
  <script lang="ts">
8
8
  import type { Snippet } from 'svelte';
@@ -45,11 +45,11 @@ const resolvedPaddingY = $derived(paddingY ?? 'none');
45
45
  this={as}
46
46
  {id}
47
47
  class={cn(
48
- 'salmex-container',
49
- `salmex-container-${size}`,
50
- `salmex-container-px-${resolvedPaddingX}`,
51
- `salmex-container-py-${resolvedPaddingY}`,
52
- centered && 'salmex-container-centered',
48
+ 'sx-container',
49
+ `sx-container-${size}`,
50
+ `sx-container-px-${resolvedPaddingX}`,
51
+ `sx-container-py-${resolvedPaddingY}`,
52
+ centered && 'sx-container-centered',
53
53
  className
54
54
  )}
55
55
  {...restProps}
@@ -60,143 +60,143 @@ const resolvedPaddingY = $derived(paddingY ?? 'none');
60
60
  </svelte:element>
61
61
 
62
62
  <style>
63
- .salmex-container {
63
+ .sx-container {
64
64
  width: 100%;
65
65
  }
66
66
 
67
- .salmex-container-centered {
67
+ .sx-container-centered {
68
68
  margin-left: auto;
69
69
  margin-right: auto;
70
70
  }
71
71
 
72
- .salmex-container-xs {
72
+ .sx-container-xs {
73
73
  max-width: 20rem;
74
74
  }
75
75
 
76
- .salmex-container-sm {
76
+ .sx-container-sm {
77
77
  max-width: 42rem;
78
78
  }
79
79
 
80
- .salmex-container-md {
80
+ .sx-container-md {
81
81
  max-width: 56rem;
82
82
  }
83
83
 
84
- .salmex-container-lg {
84
+ .sx-container-lg {
85
85
  max-width: 64rem;
86
86
  }
87
87
 
88
- .salmex-container-xl {
88
+ .sx-container-xl {
89
89
  max-width: 72rem;
90
90
  }
91
91
 
92
- .salmex-container-2xl {
92
+ .sx-container-2xl {
93
93
  max-width: 80rem;
94
94
  }
95
95
 
96
- .salmex-container-prose {
96
+ .sx-container-prose {
97
97
  max-width: 65ch;
98
98
  }
99
99
 
100
- .salmex-container-full {
100
+ .sx-container-full {
101
101
  max-width: 100%;
102
102
  }
103
103
 
104
- .salmex-container-px-none {
104
+ .sx-container-px-none {
105
105
  padding-left: 0;
106
106
  padding-right: 0;
107
107
  }
108
108
 
109
- .salmex-container-px-sm {
110
- padding-left: var(--salmex-space-4);
111
- padding-right: var(--salmex-space-4);
109
+ .sx-container-px-sm {
110
+ padding-left: var(--sx-space-4);
111
+ padding-right: var(--sx-space-4);
112
112
  }
113
113
 
114
- .salmex-container-px-md {
115
- padding-left: var(--salmex-space-6);
116
- padding-right: var(--salmex-space-6);
114
+ .sx-container-px-md {
115
+ padding-left: var(--sx-space-6);
116
+ padding-right: var(--sx-space-6);
117
117
  }
118
118
 
119
- .salmex-container-px-lg {
120
- padding-left: var(--salmex-space-8);
121
- padding-right: var(--salmex-space-8);
119
+ .sx-container-px-lg {
120
+ padding-left: var(--sx-space-8);
121
+ padding-right: var(--sx-space-8);
122
122
  }
123
123
 
124
- .salmex-container-px-xl {
125
- padding-left: var(--salmex-space-10);
126
- padding-right: var(--salmex-space-10);
124
+ .sx-container-px-xl {
125
+ padding-left: var(--sx-space-10);
126
+ padding-right: var(--sx-space-10);
127
127
  }
128
128
 
129
129
  @media (min-width: 640px) {
130
- .salmex-container-px-sm {
131
- padding-left: var(--salmex-space-6);
132
- padding-right: var(--salmex-space-6);
130
+ .sx-container-px-sm {
131
+ padding-left: var(--sx-space-6);
132
+ padding-right: var(--sx-space-6);
133
133
  }
134
- .salmex-container-px-md {
135
- padding-left: var(--salmex-space-8);
136
- padding-right: var(--salmex-space-8);
134
+ .sx-container-px-md {
135
+ padding-left: var(--sx-space-8);
136
+ padding-right: var(--sx-space-8);
137
137
  }
138
- .salmex-container-px-lg {
139
- padding-left: var(--salmex-space-10);
140
- padding-right: var(--salmex-space-10);
138
+ .sx-container-px-lg {
139
+ padding-left: var(--sx-space-10);
140
+ padding-right: var(--sx-space-10);
141
141
  }
142
- .salmex-container-px-xl {
143
- padding-left: var(--salmex-space-12);
144
- padding-right: var(--salmex-space-12);
142
+ .sx-container-px-xl {
143
+ padding-left: var(--sx-space-12);
144
+ padding-right: var(--sx-space-12);
145
145
  }
146
146
  }
147
147
 
148
148
  @media (min-width: 1024px) {
149
- .salmex-container-px-md {
150
- padding-left: var(--salmex-space-10);
151
- padding-right: var(--salmex-space-10);
149
+ .sx-container-px-md {
150
+ padding-left: var(--sx-space-10);
151
+ padding-right: var(--sx-space-10);
152
152
  }
153
- .salmex-container-px-lg {
154
- padding-left: var(--salmex-space-12);
155
- padding-right: var(--salmex-space-12);
153
+ .sx-container-px-lg {
154
+ padding-left: var(--sx-space-12);
155
+ padding-right: var(--sx-space-12);
156
156
  }
157
- .salmex-container-px-xl {
157
+ .sx-container-px-xl {
158
158
  padding-left: 42px;
159
159
  padding-right: 42px;
160
160
  }
161
161
  }
162
162
 
163
- .salmex-container-py-none {
163
+ .sx-container-py-none {
164
164
  padding-top: 0;
165
165
  padding-bottom: 0;
166
166
  }
167
167
 
168
- .salmex-container-py-sm {
169
- padding-top: var(--salmex-space-4);
170
- padding-bottom: var(--salmex-space-4);
168
+ .sx-container-py-sm {
169
+ padding-top: var(--sx-space-4);
170
+ padding-bottom: var(--sx-space-4);
171
171
  }
172
172
 
173
- .salmex-container-py-md {
174
- padding-top: var(--salmex-space-6);
175
- padding-bottom: var(--salmex-space-6);
173
+ .sx-container-py-md {
174
+ padding-top: var(--sx-space-6);
175
+ padding-bottom: var(--sx-space-6);
176
176
  }
177
177
 
178
- .salmex-container-py-lg {
179
- padding-top: var(--salmex-space-8);
180
- padding-bottom: var(--salmex-space-8);
178
+ .sx-container-py-lg {
179
+ padding-top: var(--sx-space-8);
180
+ padding-bottom: var(--sx-space-8);
181
181
  }
182
182
 
183
- .salmex-container-py-xl {
184
- padding-top: var(--salmex-space-10);
185
- padding-bottom: var(--salmex-space-10);
183
+ .sx-container-py-xl {
184
+ padding-top: var(--sx-space-10);
185
+ padding-bottom: var(--sx-space-10);
186
186
  }
187
187
 
188
188
  @media (min-width: 640px) {
189
- .salmex-container-py-md {
190
- padding-top: var(--salmex-space-8);
191
- padding-bottom: var(--salmex-space-8);
189
+ .sx-container-py-md {
190
+ padding-top: var(--sx-space-8);
191
+ padding-bottom: var(--sx-space-8);
192
192
  }
193
- .salmex-container-py-lg {
194
- padding-top: var(--salmex-space-10);
195
- padding-bottom: var(--salmex-space-10);
193
+ .sx-container-py-lg {
194
+ padding-top: var(--sx-space-10);
195
+ padding-bottom: var(--sx-space-10);
196
196
  }
197
- .salmex-container-py-xl {
198
- padding-top: var(--salmex-space-12);
199
- padding-bottom: var(--salmex-space-12);
197
+ .sx-container-py-xl {
198
+ padding-top: var(--sx-space-12);
199
+ padding-bottom: var(--sx-space-12);
200
200
  }
201
201
  }
202
202
  </style>
@@ -16,8 +16,8 @@ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'class'> {
16
16
  /**
17
17
  * Container
18
18
  *
19
- * Win2K × Basquiat — Responsive layout wrapper. Max-width, padding, optional centering.
20
- * Sharp edges, no rounded corners; supports semantic elements.
19
+ * INFRARED — Responsive layout wrapper. Max-width, padding, optional centering.
20
+ * Pure layout utility; supports semantic elements.
21
21
  */
22
22
  declare const Container: import("svelte").Component<Props, {}, "">;
23
23
  type Container = ReturnType<typeof Container>;
@@ -0,0 +1,313 @@
1
+ <!--
2
+ ThermalBackground — Dynamic INFRARED background
3
+
4
+ Layered ambient background with thermal blob drift, radar sweep,
5
+ and film grain. Pure CSS — zero JS runtime cost.
6
+
7
+ Usage:
8
+ <ThermalBackground /> — default (all layers)
9
+ <ThermalBackground grain={false} /> — no grain overlay
10
+ <ThermalBackground sweep={false} /> — no radar sweep
11
+ <ThermalBackground intensity="low" /> — subtler blobs
12
+ -->
13
+
14
+ <script lang="ts">
15
+ interface Props {
16
+ /** Show film grain overlay */
17
+ grain?: boolean;
18
+ /** Show radar sweep line */
19
+ sweep?: boolean;
20
+ /** Blob intensity: low = barely visible, default = subtle, high = pronounced */
21
+ intensity?: 'low' | 'default' | 'high';
22
+ /** Additional CSS class */
23
+ class?: string;
24
+ /** Test ID */
25
+ testId?: string;
26
+ }
27
+
28
+ let {
29
+ grain = true,
30
+ sweep = true,
31
+ intensity = 'default',
32
+ class: className = '',
33
+ testId = undefined,
34
+ }: Props = $props();
35
+ </script>
36
+
37
+ <div
38
+ class="sx-thermal-bg sx-thermal-{intensity} {className}"
39
+ aria-hidden="true"
40
+ data-testid={testId}
41
+ >
42
+ <!-- Layer 1: Thermal blobs — large diffuse orbs drifting independently -->
43
+ <div class="sx-thermal-blobs">
44
+ <div class="sx-thermal-blob sx-thermal-blob-1"></div>
45
+ <div class="sx-thermal-blob sx-thermal-blob-2"></div>
46
+ <div class="sx-thermal-blob sx-thermal-blob-3"></div>
47
+ <div class="sx-thermal-blob sx-thermal-blob-4"></div>
48
+ </div>
49
+
50
+ <!-- Layer 2: Radar/thermal sweep — horizontal scan line -->
51
+ {#if sweep}
52
+ <div class="sx-thermal-sweep"></div>
53
+ {/if}
54
+
55
+ <!-- Layer 3: Animated film grain -->
56
+ {#if grain}
57
+ <div class="sx-thermal-grain"></div>
58
+ {/if}
59
+ </div>
60
+
61
+ <style>
62
+ /* ========================================
63
+ ROOT CONTAINER — fixed fullscreen backdrop
64
+ ======================================== */
65
+
66
+ .sx-thermal-bg {
67
+ position: fixed;
68
+ inset: 0;
69
+ z-index: 0;
70
+ overflow: hidden;
71
+ pointer-events: none;
72
+ background: var(--sx-color-base);
73
+ }
74
+
75
+ /* ========================================
76
+ THERMAL BLOBS — Drifting infrared orbs
77
+ Large, soft radial gradients that move on
78
+ independent orbits. Each has a unique size,
79
+ color, speed, and path.
80
+ ======================================== */
81
+
82
+ .sx-thermal-blobs {
83
+ position: absolute;
84
+ inset: -50%;
85
+ width: 200%;
86
+ height: 200%;
87
+ }
88
+
89
+ .sx-thermal-blob {
90
+ position: absolute;
91
+ border-radius: 50%;
92
+ filter: blur(80px);
93
+ will-change: transform;
94
+ }
95
+
96
+ /* Blob 1 — Vermilion/primary — largest, slowest */
97
+ .sx-thermal-blob-1 {
98
+ width: 45vmax;
99
+ height: 45vmax;
100
+ top: 10%;
101
+ left: 15%;
102
+ background: radial-gradient(
103
+ circle,
104
+ rgba(255, 107, 53, 0.08) 0%,
105
+ rgba(255, 107, 53, 0.02) 50%,
106
+ transparent 70%
107
+ );
108
+ animation: sx-thermal-drift-1 35s ease-in-out infinite;
109
+ }
110
+
111
+ /* Blob 2 — Brass/secondary — medium, offset orbit */
112
+ .sx-thermal-blob-2 {
113
+ width: 35vmax;
114
+ height: 35vmax;
115
+ top: 55%;
116
+ right: 10%;
117
+ background: radial-gradient(
118
+ circle,
119
+ rgba(200, 168, 78, 0.06) 0%,
120
+ rgba(200, 168, 78, 0.015) 50%,
121
+ transparent 70%
122
+ );
123
+ animation: sx-thermal-drift-2 42s ease-in-out infinite;
124
+ }
125
+
126
+ /* Blob 3 — Teal — smallest, fastest, cool counterpoint */
127
+ .sx-thermal-blob-3 {
128
+ width: 30vmax;
129
+ height: 30vmax;
130
+ bottom: 15%;
131
+ left: 40%;
132
+ background: radial-gradient(
133
+ circle,
134
+ rgba(61, 139, 139, 0.06) 0%,
135
+ rgba(61, 139, 139, 0.015) 50%,
136
+ transparent 70%
137
+ );
138
+ animation: sx-thermal-drift-3 28s ease-in-out infinite;
139
+ }
140
+
141
+ /* Blob 4 — Deep vermilion — secondary heat signature */
142
+ .sx-thermal-blob-4 {
143
+ width: 38vmax;
144
+ height: 38vmax;
145
+ top: 40%;
146
+ left: 60%;
147
+ background: radial-gradient(
148
+ circle,
149
+ rgba(224, 85, 32, 0.05) 0%,
150
+ rgba(224, 85, 32, 0.01) 50%,
151
+ transparent 70%
152
+ );
153
+ animation: sx-thermal-drift-4 50s ease-in-out infinite;
154
+ }
155
+
156
+ /* ========================================
157
+ BLOB DRIFT ORBITS
158
+ Each blob traces a unique Lissajous-like path
159
+ using translate transforms. Different durations
160
+ ensure they never sync up, creating organic motion.
161
+ ======================================== */
162
+
163
+ @keyframes sx-thermal-drift-1 {
164
+ 0% { transform: translate(0%, 0%) scale(1); }
165
+ 25% { transform: translate(12%, -8%) scale(1.05); }
166
+ 50% { transform: translate(-5%, 15%) scale(0.95); }
167
+ 75% { transform: translate(-15%, -5%) scale(1.08); }
168
+ 100% { transform: translate(0%, 0%) scale(1); }
169
+ }
170
+
171
+ @keyframes sx-thermal-drift-2 {
172
+ 0% { transform: translate(0%, 0%) scale(1); }
173
+ 20% { transform: translate(-18%, 8%) scale(1.1); }
174
+ 40% { transform: translate(8%, -12%) scale(0.9); }
175
+ 60% { transform: translate(-8%, -18%) scale(1.05); }
176
+ 80% { transform: translate(15%, 5%) scale(0.95); }
177
+ 100% { transform: translate(0%, 0%) scale(1); }
178
+ }
179
+
180
+ @keyframes sx-thermal-drift-3 {
181
+ 0% { transform: translate(0%, 0%) rotate(0deg) scale(1); }
182
+ 33% { transform: translate(20%, -15%) rotate(5deg) scale(1.1); }
183
+ 66% { transform: translate(-15%, 10%) rotate(-3deg) scale(0.92); }
184
+ 100% { transform: translate(0%, 0%) rotate(0deg) scale(1); }
185
+ }
186
+
187
+ @keyframes sx-thermal-drift-4 {
188
+ 0% { transform: translate(0%, 0%) scale(1); }
189
+ 30% { transform: translate(-10%, 12%) scale(1.06); }
190
+ 60% { transform: translate(15%, -8%) scale(0.94); }
191
+ 100% { transform: translate(0%, 0%) scale(1); }
192
+ }
193
+
194
+ /* ========================================
195
+ INTENSITY VARIANTS
196
+ Control blob visibility without changing motion
197
+ ======================================== */
198
+
199
+ .sx-thermal-low .sx-thermal-blobs {
200
+ opacity: 0.5;
201
+ }
202
+
203
+ .sx-thermal-default .sx-thermal-blobs {
204
+ opacity: 1;
205
+ }
206
+
207
+ .sx-thermal-high .sx-thermal-blobs {
208
+ opacity: 1.5;
209
+ }
210
+
211
+ .sx-thermal-high .sx-thermal-blob-1 {
212
+ background: radial-gradient(
213
+ circle,
214
+ rgba(255, 107, 53, 0.14) 0%,
215
+ rgba(255, 107, 53, 0.04) 50%,
216
+ transparent 70%
217
+ );
218
+ }
219
+
220
+ .sx-thermal-high .sx-thermal-blob-2 {
221
+ background: radial-gradient(
222
+ circle,
223
+ rgba(200, 168, 78, 0.10) 0%,
224
+ rgba(200, 168, 78, 0.03) 50%,
225
+ transparent 70%
226
+ );
227
+ }
228
+
229
+ .sx-thermal-high .sx-thermal-blob-3 {
230
+ background: radial-gradient(
231
+ circle,
232
+ rgba(61, 139, 139, 0.10) 0%,
233
+ rgba(61, 139, 139, 0.03) 50%,
234
+ transparent 70%
235
+ );
236
+ }
237
+
238
+ .sx-thermal-high .sx-thermal-blob-4 {
239
+ background: radial-gradient(
240
+ circle,
241
+ rgba(224, 85, 32, 0.09) 0%,
242
+ rgba(224, 85, 32, 0.02) 50%,
243
+ transparent 70%
244
+ );
245
+ }
246
+
247
+ /* ========================================
248
+ RADAR SWEEP — Horizontal scan line
249
+ A faint horizontal gradient that sweeps
250
+ top to bottom like a thermal scanner or
251
+ radar display. Very subtle.
252
+ ======================================== */
253
+
254
+ .sx-thermal-sweep {
255
+ position: absolute;
256
+ inset: 0;
257
+ background: linear-gradient(
258
+ 180deg,
259
+ transparent 0%,
260
+ rgba(255, 107, 53, 0.015) 48%,
261
+ rgba(255, 107, 53, 0.04) 50%,
262
+ rgba(255, 107, 53, 0.015) 52%,
263
+ transparent 100%
264
+ );
265
+ background-size: 100% 300%;
266
+ animation: sx-thermal-scan 8s linear infinite;
267
+ opacity: 0.7;
268
+ }
269
+
270
+ @keyframes sx-thermal-scan {
271
+ 0% { background-position: 0% 0%; }
272
+ 100% { background-position: 0% 100%; }
273
+ }
274
+
275
+ /* ========================================
276
+ FILM GRAIN — Animated noise texture
277
+ SVG feTurbulence noise with subtle position
278
+ stepping for a living grain effect.
279
+ ======================================== */
280
+
281
+ .sx-thermal-grain {
282
+ position: absolute;
283
+ inset: -50%;
284
+ width: 300%;
285
+ height: 300%;
286
+ opacity: 0.03;
287
+ mix-blend-mode: overlay;
288
+ pointer-events: none;
289
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
290
+ background-size: 256px 256px;
291
+ animation: sx-thermal-grain-drift 0.4s steps(4) infinite;
292
+ }
293
+
294
+ @keyframes sx-thermal-grain-drift {
295
+ 0% { transform: translate(0, 0); }
296
+ 25% { transform: translate(-5%, -5%); }
297
+ 50% { transform: translate(3%, -8%); }
298
+ 75% { transform: translate(-8%, 2%); }
299
+ 100% { transform: translate(0, 0); }
300
+ }
301
+
302
+ /* ========================================
303
+ REDUCED MOTION — Static fallback
304
+ ======================================== */
305
+
306
+ @media (prefers-reduced-motion: reduce) {
307
+ .sx-thermal-blob,
308
+ .sx-thermal-sweep,
309
+ .sx-thermal-grain {
310
+ animation: none !important;
311
+ }
312
+ }
313
+ </style>
@@ -0,0 +1,16 @@
1
+ interface Props {
2
+ /** Show film grain overlay */
3
+ grain?: boolean;
4
+ /** Show radar sweep line */
5
+ sweep?: boolean;
6
+ /** Blob intensity: low = barely visible, default = subtle, high = pronounced */
7
+ intensity?: 'low' | 'default' | 'high';
8
+ /** Additional CSS class */
9
+ class?: string;
10
+ /** Test ID */
11
+ testId?: string;
12
+ }
13
+ declare const ThermalBackground: import("svelte").Component<Props, {}, "">;
14
+ type ThermalBackground = ReturnType<typeof ThermalBackground>;
15
+ export default ThermalBackground;
16
+ //# sourceMappingURL=ThermalBackground.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThermalBackground.svelte.d.ts","sourceRoot":"","sources":["../../../src/layout/ThermalBackground/ThermalBackground.svelte.ts"],"names":[],"mappings":"AAGC,UAAU,KAAK;IACd,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gFAAgF;IAChF,SAAS,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAuCF,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as ThermalBackground } from './ThermalBackground.svelte';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/layout/ThermalBackground/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as ThermalBackground } from './ThermalBackground.svelte';
@@ -1,3 +1,4 @@
1
1
  export { Card } from './Card/index.js';
2
2
  export { Container } from './Container/index.js';
3
+ export { ThermalBackground } from './ThermalBackground/index.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export { Card } from './Card/index.js';
2
2
  export { Container } from './Container/index.js';
3
+ export { ThermalBackground } from './ThermalBackground/index.js';