@latchprotocol/widgets 0.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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +649 -0
  3. package/dist/adapters/binDistribution.d.ts +19 -0
  4. package/dist/adapters/binDistribution.d.ts.map +1 -0
  5. package/dist/adapters/protocol.d.ts +409 -0
  6. package/dist/adapters/protocol.d.ts.map +1 -0
  7. package/dist/adapters/sale.d.ts +142 -0
  8. package/dist/adapters/sale.d.ts.map +1 -0
  9. package/dist/adapters/viem.d.ts +89 -0
  10. package/dist/adapters/viem.d.ts.map +1 -0
  11. package/dist/callpath/constants.d.ts +218 -0
  12. package/dist/callpath/constants.d.ts.map +1 -0
  13. package/dist/callpath/launch.d.ts +1979 -0
  14. package/dist/callpath/launch.d.ts.map +1 -0
  15. package/dist/callpath/liquidity.d.ts +103 -0
  16. package/dist/callpath/liquidity.d.ts.map +1 -0
  17. package/dist/callpath/plan.d.ts +34 -0
  18. package/dist/callpath/plan.d.ts.map +1 -0
  19. package/dist/callpath/swap.d.ts +129 -0
  20. package/dist/callpath/swap.d.ts.map +1 -0
  21. package/dist/chunks/SwapWidget-DgyHAVc8.js +2404 -0
  22. package/dist/chunks/SwapWidget-DgyHAVc8.js.map +1 -0
  23. package/dist/chunks/scan-Dhu7f4Nl.js +2497 -0
  24. package/dist/chunks/scan-Dhu7f4Nl.js.map +1 -0
  25. package/dist/chunks/useLocker-D1c_NTk-.js +1613 -0
  26. package/dist/chunks/useLocker-D1c_NTk-.js.map +1 -0
  27. package/dist/components/LaunchWidget.d.ts +117 -0
  28. package/dist/components/LaunchWidget.d.ts.map +1 -0
  29. package/dist/components/LiquidityWidget.d.ts +33 -0
  30. package/dist/components/LiquidityWidget.d.ts.map +1 -0
  31. package/dist/components/LockerWidget.d.ts +51 -0
  32. package/dist/components/LockerWidget.d.ts.map +1 -0
  33. package/dist/components/LocksWidgets.d.ts +61 -0
  34. package/dist/components/LocksWidgets.d.ts.map +1 -0
  35. package/dist/components/SwapWidget.d.ts +165 -0
  36. package/dist/components/SwapWidget.d.ts.map +1 -0
  37. package/dist/components/TokenTrustPanel.d.ts +32 -0
  38. package/dist/components/TokenTrustPanel.d.ts.map +1 -0
  39. package/dist/components/lockCharts.d.ts +29 -0
  40. package/dist/components/lockCharts.d.ts.map +1 -0
  41. package/dist/components/portal.d.ts +10 -0
  42. package/dist/components/portal.d.ts.map +1 -0
  43. package/dist/components/primitives.d.ts +139 -0
  44. package/dist/components/primitives.d.ts.map +1 -0
  45. package/dist/components/swap/SwapSettings.d.ts +12 -0
  46. package/dist/components/swap/SwapSettings.d.ts.map +1 -0
  47. package/dist/components/swap/TokenSelect.d.ts +61 -0
  48. package/dist/components/swap/TokenSelect.d.ts.map +1 -0
  49. package/dist/components/swap/state.d.ts +208 -0
  50. package/dist/components/swap/state.d.ts.map +1 -0
  51. package/dist/config/chain.d.ts +163 -0
  52. package/dist/config/chain.d.ts.map +1 -0
  53. package/dist/config/integrator.d.ts +121 -0
  54. package/dist/config/integrator.d.ts.map +1 -0
  55. package/dist/context/WidgetProvider.d.ts +78 -0
  56. package/dist/context/WidgetProvider.d.ts.map +1 -0
  57. package/dist/core/clMath.d.ts +98 -0
  58. package/dist/core/clMath.d.ts.map +1 -0
  59. package/dist/core/errors.d.ts +18 -0
  60. package/dist/core/errors.d.ts.map +1 -0
  61. package/dist/core/format.d.ts +47 -0
  62. package/dist/core/format.d.ts.map +1 -0
  63. package/dist/core/liquidityGuards.d.ts +53 -0
  64. package/dist/core/liquidityGuards.d.ts.map +1 -0
  65. package/dist/core/liquidityRefresh.d.ts +35 -0
  66. package/dist/core/liquidityRefresh.d.ts.map +1 -0
  67. package/dist/core/math.d.ts +129 -0
  68. package/dist/core/math.d.ts.map +1 -0
  69. package/dist/core/pool.d.ts +33 -0
  70. package/dist/core/pool.d.ts.map +1 -0
  71. package/dist/core/tokenLists.d.ts +46 -0
  72. package/dist/core/tokenLists.d.ts.map +1 -0
  73. package/dist/embed/iframe.d.ts +185 -0
  74. package/dist/embed/iframe.d.ts.map +1 -0
  75. package/dist/embed/lockBadge.d.ts +55 -0
  76. package/dist/embed/lockBadge.d.ts.map +1 -0
  77. package/dist/embed/webComponent.d.ts +83 -0
  78. package/dist/embed/webComponent.d.ts.map +1 -0
  79. package/dist/embed.d.ts +25 -0
  80. package/dist/embed.d.ts.map +1 -0
  81. package/dist/embed.js +543 -0
  82. package/dist/embed.js.map +1 -0
  83. package/dist/headless.d.ts +60 -0
  84. package/dist/headless.d.ts.map +1 -0
  85. package/dist/headless.js +223 -0
  86. package/dist/headless.js.map +1 -0
  87. package/dist/hooks/useAsyncResource.d.ts +38 -0
  88. package/dist/hooks/useAsyncResource.d.ts.map +1 -0
  89. package/dist/hooks/useLaunch.d.ts +140 -0
  90. package/dist/hooks/useLaunch.d.ts.map +1 -0
  91. package/dist/hooks/useLiquidity.d.ts +91 -0
  92. package/dist/hooks/useLiquidity.d.ts.map +1 -0
  93. package/dist/hooks/useLocker.d.ts +77 -0
  94. package/dist/hooks/useLocker.d.ts.map +1 -0
  95. package/dist/hooks/useLocks.d.ts +33 -0
  96. package/dist/hooks/useLocks.d.ts.map +1 -0
  97. package/dist/hooks/useSwapExecute.d.ts +46 -0
  98. package/dist/hooks/useSwapExecute.d.ts.map +1 -0
  99. package/dist/hooks/useSwapQuote.d.ts +51 -0
  100. package/dist/hooks/useSwapQuote.d.ts.map +1 -0
  101. package/dist/hooks/useTokenLists.d.ts +26 -0
  102. package/dist/hooks/useTokenLists.d.ts.map +1 -0
  103. package/dist/hooks/useTokenTrust.d.ts +40 -0
  104. package/dist/hooks/useTokenTrust.d.ts.map +1 -0
  105. package/dist/hooks/useTokens.d.ts +15 -0
  106. package/dist/hooks/useTokens.d.ts.map +1 -0
  107. package/dist/index.d.ts +59 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +1052 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/latch-embed.d.ts +19 -0
  112. package/dist/latch-embed.d.ts.map +1 -0
  113. package/dist/latch-embed.js +950 -0
  114. package/dist/latch-embed.js.map +1 -0
  115. package/dist/latch-embed.mjs +13162 -0
  116. package/dist/latch-embed.mjs.map +1 -0
  117. package/dist/locker/model.d.ts +73 -0
  118. package/dist/locker/model.d.ts.map +1 -0
  119. package/dist/locks/embedModel.d.ts +22 -0
  120. package/dist/locks/embedModel.d.ts.map +1 -0
  121. package/dist/locks/fetch.d.ts +60 -0
  122. package/dist/locks/fetch.d.ts.map +1 -0
  123. package/dist/locks/model.d.ts +143 -0
  124. package/dist/locks/model.d.ts.map +1 -0
  125. package/dist/locks/scan.d.ts +25 -0
  126. package/dist/locks/scan.d.ts.map +1 -0
  127. package/dist/styles/css.d.ts +32 -0
  128. package/dist/styles/css.d.ts.map +1 -0
  129. package/dist/styles.css +895 -0
  130. package/dist/trust/model.d.ts +48 -0
  131. package/dist/trust/model.d.ts.map +1 -0
  132. package/package.json +102 -0
@@ -0,0 +1,895 @@
1
+ /* Generated from src/styles/css.ts by scripts/emit-css.mjs. Do not edit. */
2
+ .latch-widget {
3
+ /* Palette */
4
+ --latch-bg: #ffffff;
5
+ --latch-bg-elevated: #f6f7f9;
6
+ --latch-bg-sunken: #eceef2;
7
+ --latch-border: #dfe3e8;
8
+ --latch-border-strong: #c4cad3;
9
+ --latch-text: #10131a;
10
+ --latch-text-muted: #5c6472;
11
+ --latch-text-inverted: #ffffff;
12
+ --latch-accent: #3b5bdb;
13
+ --latch-accent-hover: #2f49b2;
14
+ --latch-accent-text: #ffffff;
15
+ --latch-success: #157347;
16
+ --latch-warning: #9a6700;
17
+ --latch-warning-bg: #fff8e1;
18
+ --latch-danger: #b42318;
19
+ --latch-danger-bg: #fef3f2;
20
+ --latch-focus: #3b5bdb;
21
+ /* The compact swap's Buy side: the CVD-safe "up" colour, with a dark label (6:1). */
22
+ --latch-buy: #1f9e89;
23
+ --latch-buy-hover: #23b39b;
24
+ --latch-buy-text: #04060c;
25
+
26
+ /* Shape and type */
27
+ --latch-radius: 14px;
28
+ --latch-radius-sm: 9px;
29
+ --latch-font: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
30
+ --latch-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
31
+ --latch-font-size: 14px;
32
+ --latch-font-size-sm: 12px;
33
+ --latch-font-size-lg: 22px;
34
+ --latch-gap: 12px;
35
+ --latch-padding: 16px;
36
+ --latch-control-height: 44px;
37
+ --latch-shadow: 0 1px 2px rgba(16, 19, 26, 0.06), 0 8px 24px rgba(16, 19, 26, 0.06);
38
+
39
+ box-sizing: border-box;
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: var(--latch-gap);
43
+ width: 100%;
44
+ min-width: 0;
45
+ max-width: 480px;
46
+ padding: var(--latch-padding);
47
+ background: var(--latch-bg);
48
+ color: var(--latch-text);
49
+ border: 1px solid var(--latch-border);
50
+ border-radius: var(--latch-radius);
51
+ box-shadow: var(--latch-shadow);
52
+ font-family: var(--latch-font);
53
+ font-size: var(--latch-font-size);
54
+ line-height: 1.45;
55
+ }
56
+
57
+ .latch-widget *,
58
+ .latch-widget *::before,
59
+ .latch-widget *::after {
60
+ box-sizing: inherit;
61
+ }
62
+
63
+ /* Text takes the WIDGET's ink, not the host page's. A host rule such as
64
+ \`h2 { color: var(--ink) }\` otherwise beats inheritance: a dark-themed widget
65
+ on a light page drew its title in the page's near-black on the widget's
66
+ near-black (1.1:1, axe, the locker embed 2026-09-26). Specificity (0,1,0)
67
+ beats any element selector; every widget class rule below comes later and
68
+ still sets its own colour. A host's own content in a slot is left alone. */
69
+ .latch-widget :where(h1, h2, h3, h4, h5, h6, p, label, legend, dt, dd, li, th, td, figcaption, caption):where(:not(.latch-slot *)) {
70
+ color: inherit;
71
+ }
72
+
73
+ .latch-widget[data-latch-theme="dark"] {
74
+ --latch-bg: #14161b;
75
+ --latch-bg-elevated: #1c1f26;
76
+ --latch-bg-sunken: #23262f;
77
+ --latch-border: #2b2f38;
78
+ --latch-border-strong: #3d4350;
79
+ --latch-text: #f2f4f8;
80
+ --latch-text-muted: #98a1b1;
81
+ --latch-text-inverted: #14161b;
82
+ --latch-accent: #6b8afd;
83
+ --latch-accent-hover: #849dff;
84
+ --latch-accent-text: #0b0d12;
85
+ --latch-success: #4ade80;
86
+ --latch-warning: #fbbf5c;
87
+ --latch-warning-bg: #33280f;
88
+ --latch-danger: #ff8a80;
89
+ --latch-danger-bg: #3a1a17;
90
+ --latch-focus: #849dff;
91
+ --latch-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
92
+ }
93
+
94
+ @media (prefers-color-scheme: dark) {
95
+ .latch-widget[data-latch-theme="system"] {
96
+ --latch-bg: #14161b;
97
+ --latch-bg-elevated: #1c1f26;
98
+ --latch-bg-sunken: #23262f;
99
+ --latch-border: #2b2f38;
100
+ --latch-border-strong: #3d4350;
101
+ --latch-text: #f2f4f8;
102
+ --latch-text-muted: #98a1b1;
103
+ --latch-text-inverted: #14161b;
104
+ --latch-accent: #6b8afd;
105
+ --latch-accent-hover: #849dff;
106
+ --latch-accent-text: #0b0d12;
107
+ --latch-success: #4ade80;
108
+ --latch-warning: #fbbf5c;
109
+ --latch-warning-bg: #33280f;
110
+ --latch-danger: #ff8a80;
111
+ --latch-danger-bg: #3a1a17;
112
+ --latch-focus: #849dff;
113
+ --latch-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
114
+ }
115
+ }
116
+
117
+ .latch-header {
118
+ display: flex;
119
+ align-items: baseline;
120
+ justify-content: space-between;
121
+ gap: 8px;
122
+ flex-wrap: wrap;
123
+ }
124
+
125
+ .latch-title {
126
+ margin: 0;
127
+ font-size: 16px;
128
+ font-weight: 650;
129
+ }
130
+
131
+ .latch-subtitle {
132
+ margin: 0;
133
+ color: var(--latch-text-muted);
134
+ font-size: var(--latch-font-size-sm);
135
+ }
136
+
137
+ .latch-mock-banner {
138
+ display: flex;
139
+ gap: 8px;
140
+ align-items: flex-start;
141
+ padding: 10px 12px;
142
+ border: 1px solid var(--latch-warning);
143
+ border-radius: var(--latch-radius-sm);
144
+ background: var(--latch-warning-bg);
145
+ color: var(--latch-warning);
146
+ font-size: var(--latch-font-size-sm);
147
+ font-weight: 600;
148
+ }
149
+
150
+ .latch-mock-banner span {
151
+ font-weight: 500;
152
+ }
153
+
154
+ .latch-field {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 6px;
158
+ padding: 12px;
159
+ background: var(--latch-bg-elevated);
160
+ border: 1px solid var(--latch-border);
161
+ border-radius: var(--latch-radius-sm);
162
+ }
163
+
164
+ .latch-field-row {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: 8px;
168
+ flex-wrap: wrap;
169
+ }
170
+
171
+ .latch-label {
172
+ display: block;
173
+ color: var(--latch-text-muted);
174
+ font-size: var(--latch-font-size-sm);
175
+ font-weight: 600;
176
+ letter-spacing: 0.01em;
177
+ }
178
+
179
+ .latch-amount-input {
180
+ flex: 1 1 120px;
181
+ min-width: 0;
182
+ padding: 0;
183
+ border: 0;
184
+ background: transparent;
185
+ color: var(--latch-text);
186
+ font-family: var(--latch-font);
187
+ font-size: var(--latch-font-size-lg);
188
+ font-weight: 600;
189
+ line-height: 1.2;
190
+ }
191
+
192
+ .latch-amount-input::placeholder {
193
+ color: var(--latch-text-muted);
194
+ font-weight: 500;
195
+ }
196
+
197
+ .latch-amount-input:focus-visible,
198
+ .latch-select:focus-visible,
199
+ .latch-button:focus-visible,
200
+ .latch-icon-button:focus-visible,
201
+ .latch-slider:focus-visible,
202
+ .latch-chip:focus-visible {
203
+ outline: 2px solid var(--latch-focus);
204
+ outline-offset: 2px;
205
+ border-radius: 4px;
206
+ }
207
+
208
+ .latch-select {
209
+ flex: 0 1 auto;
210
+ max-width: 100%;
211
+ height: 34px;
212
+ padding: 0 8px;
213
+ background: var(--latch-bg);
214
+ color: var(--latch-text);
215
+ border: 1px solid var(--latch-border-strong);
216
+ border-radius: 999px;
217
+ font-family: inherit;
218
+ font-size: var(--latch-font-size);
219
+ font-weight: 600;
220
+ cursor: pointer;
221
+ }
222
+
223
+ .latch-meta {
224
+ display: flex;
225
+ justify-content: space-between;
226
+ gap: 8px;
227
+ color: var(--latch-text-muted);
228
+ font-size: var(--latch-font-size-sm);
229
+ }
230
+
231
+ .latch-meta-value {
232
+ font-variant-numeric: tabular-nums;
233
+ }
234
+
235
+ .latch-switch-row {
236
+ display: flex;
237
+ justify-content: center;
238
+ margin: -6px 0;
239
+ }
240
+
241
+ .latch-icon-button {
242
+ display: inline-flex;
243
+ align-items: center;
244
+ justify-content: center;
245
+ width: 32px;
246
+ height: 32px;
247
+ padding: 0;
248
+ background: var(--latch-bg);
249
+ color: var(--latch-text);
250
+ border: 1px solid var(--latch-border-strong);
251
+ border-radius: 999px;
252
+ cursor: pointer;
253
+ font-size: 15px;
254
+ line-height: 1;
255
+ }
256
+
257
+ .latch-icon-button:hover {
258
+ background: var(--latch-bg-sunken);
259
+ }
260
+
261
+ .latch-summary {
262
+ display: flex;
263
+ flex-direction: column;
264
+ gap: 6px;
265
+ padding: 12px;
266
+ background: var(--latch-bg-sunken);
267
+ border-radius: var(--latch-radius-sm);
268
+ font-size: var(--latch-font-size-sm);
269
+ }
270
+
271
+ .latch-summary dl {
272
+ display: flex;
273
+ flex-direction: column;
274
+ gap: 6px;
275
+ margin: 0;
276
+ }
277
+
278
+ .latch-summary-row {
279
+ display: flex;
280
+ align-items: baseline;
281
+ justify-content: space-between;
282
+ gap: 10px;
283
+ }
284
+
285
+ .latch-summary-row dt {
286
+ color: var(--latch-text-muted);
287
+ min-width: 0;
288
+ }
289
+
290
+ .latch-summary-row dd {
291
+ margin: 0;
292
+ text-align: right;
293
+ font-variant-numeric: tabular-nums;
294
+ overflow-wrap: anywhere;
295
+ }
296
+
297
+ .latch-summary-row[data-latch-emphasis="fee"] dd {
298
+ color: var(--latch-accent);
299
+ font-weight: 650;
300
+ }
301
+
302
+ .latch-summary-row[data-latch-severity="high"] dd,
303
+ .latch-summary-row[data-latch-severity="severe"] dd {
304
+ color: var(--latch-danger);
305
+ font-weight: 650;
306
+ }
307
+
308
+ .latch-route {
309
+ display: flex;
310
+ flex-wrap: wrap;
311
+ align-items: center;
312
+ gap: 4px;
313
+ font-size: var(--latch-font-size-sm);
314
+ color: var(--latch-text-muted);
315
+ }
316
+
317
+ .latch-route-token {
318
+ padding: 2px 8px;
319
+ background: var(--latch-bg);
320
+ border: 1px solid var(--latch-border);
321
+ border-radius: 999px;
322
+ color: var(--latch-text);
323
+ font-weight: 600;
324
+ }
325
+
326
+ .latch-button {
327
+ display: inline-flex;
328
+ align-items: center;
329
+ justify-content: center;
330
+ gap: 8px;
331
+ width: 100%;
332
+ min-height: var(--latch-control-height);
333
+ padding: 0 16px;
334
+ background: var(--latch-accent);
335
+ color: var(--latch-accent-text);
336
+ border: 1px solid transparent;
337
+ border-radius: var(--latch-radius-sm);
338
+ font-family: inherit;
339
+ font-size: 15px;
340
+ font-weight: 650;
341
+ cursor: pointer;
342
+ }
343
+
344
+ .latch-button:hover:not(:disabled) {
345
+ background: var(--latch-accent-hover);
346
+ }
347
+
348
+ .latch-button:disabled {
349
+ opacity: 0.55;
350
+ cursor: not-allowed;
351
+ }
352
+
353
+ .latch-button[data-latch-variant="secondary"] {
354
+ background: var(--latch-bg-elevated);
355
+ color: var(--latch-text);
356
+ border-color: var(--latch-border-strong);
357
+ }
358
+
359
+ .latch-button[data-latch-variant="danger"] {
360
+ background: var(--latch-danger);
361
+ color: var(--latch-text-inverted);
362
+ }
363
+
364
+ .latch-status {
365
+ min-height: 18px;
366
+ margin: 0;
367
+ font-size: var(--latch-font-size-sm);
368
+ color: var(--latch-text-muted);
369
+ }
370
+
371
+ .latch-status[data-latch-tone="error"] {
372
+ color: var(--latch-danger);
373
+ }
374
+
375
+ .latch-status[data-latch-tone="success"] {
376
+ color: var(--latch-success);
377
+ }
378
+
379
+ .latch-error {
380
+ padding: 10px 12px;
381
+ background: var(--latch-danger-bg);
382
+ border: 1px solid var(--latch-danger);
383
+ border-radius: var(--latch-radius-sm);
384
+ color: var(--latch-danger);
385
+ font-size: var(--latch-font-size-sm);
386
+ overflow-wrap: anywhere;
387
+ }
388
+
389
+ .latch-tabs {
390
+ display: flex;
391
+ gap: 4px;
392
+ padding: 3px;
393
+ background: var(--latch-bg-sunken);
394
+ border-radius: 999px;
395
+ }
396
+
397
+ .latch-chip {
398
+ flex: 1 1 0;
399
+ min-width: 0;
400
+ padding: 7px 10px;
401
+ background: transparent;
402
+ color: var(--latch-text-muted);
403
+ border: 0;
404
+ border-radius: 999px;
405
+ font-family: inherit;
406
+ font-size: var(--latch-font-size-sm);
407
+ font-weight: 650;
408
+ cursor: pointer;
409
+ white-space: nowrap;
410
+ overflow: hidden;
411
+ text-overflow: ellipsis;
412
+ }
413
+
414
+ .latch-chip[aria-selected="true"],
415
+ .latch-chip[aria-pressed="true"] {
416
+ background: var(--latch-bg);
417
+ color: var(--latch-text);
418
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
419
+ }
420
+
421
+ .latch-progress {
422
+ height: 8px;
423
+ background: var(--latch-bg-sunken);
424
+ border-radius: 999px;
425
+ overflow: hidden;
426
+ }
427
+
428
+ .latch-progress-fill {
429
+ height: 100%;
430
+ background: var(--latch-accent);
431
+ border-radius: 999px;
432
+ transition: width 200ms ease;
433
+ }
434
+
435
+ .latch-slider {
436
+ width: 100%;
437
+ accent-color: var(--latch-accent);
438
+ }
439
+
440
+ .latch-range-grid {
441
+ display: grid;
442
+ grid-template-columns: repeat(2, minmax(0, 1fr));
443
+ gap: 8px;
444
+ }
445
+
446
+ .latch-range-grid input {
447
+ width: 100%;
448
+ min-width: 0;
449
+ height: 36px;
450
+ padding: 0 10px;
451
+ background: var(--latch-bg);
452
+ color: var(--latch-text);
453
+ border: 1px solid var(--latch-border-strong);
454
+ border-radius: var(--latch-radius-sm);
455
+ font-family: var(--latch-font-mono);
456
+ font-size: var(--latch-font-size);
457
+ }
458
+
459
+ .latch-curve {
460
+ display: block;
461
+ width: 100%;
462
+ height: auto;
463
+ border-radius: var(--latch-radius-sm);
464
+ background: var(--latch-bg-sunken);
465
+ }
466
+
467
+ .latch-visually-hidden {
468
+ position: absolute;
469
+ width: 1px;
470
+ height: 1px;
471
+ margin: -1px;
472
+ padding: 0;
473
+ border: 0;
474
+ clip: rect(0 0 0 0);
475
+ clip-path: inset(50%);
476
+ overflow: hidden;
477
+ white-space: nowrap;
478
+ }
479
+
480
+ .latch-footer {
481
+ display: flex;
482
+ justify-content: space-between;
483
+ gap: 8px;
484
+ color: var(--latch-text-muted);
485
+ font-size: 11px;
486
+ }
487
+
488
+ .latch-footer a {
489
+ color: inherit;
490
+ }
491
+
492
+ .latch-launch-legs {
493
+ display: grid;
494
+ gap: 16px;
495
+ }
496
+
497
+ .latch-empty {
498
+ margin: 0;
499
+ color: var(--latch-text-muted);
500
+ font-size: 13px;
501
+ line-height: 1.5;
502
+ }
503
+
504
+ @media (max-width: 380px) {
505
+ .latch-widget {
506
+ --latch-padding: 12px;
507
+ --latch-font-size-lg: 20px;
508
+ }
509
+
510
+ .latch-range-grid {
511
+ grid-template-columns: minmax(0, 1fr);
512
+ }
513
+ }
514
+
515
+ @media (prefers-reduced-motion: reduce) {
516
+ .latch-progress-fill {
517
+ transition: none;
518
+ }
519
+ }
520
+
521
+ /* ============================================================================
522
+ Swap surface (SwapWidget): panels, big inputs, token buttons, dialog,
523
+ popover, CTA, details. Every colour is a --latch-* token above.
524
+ ============================================================================ */
525
+
526
+ .latch-swap { max-width: 480px; }
527
+ .latch-swap__form { display: flex; flex-direction: column; gap: 4px; }
528
+
529
+ .latch-panel {
530
+ background: var(--latch-bg-elevated);
531
+ border: 1px solid transparent;
532
+ border-radius: var(--latch-radius);
533
+ padding: 14px 16px 12px;
534
+ transition: border-color 120ms ease, background 120ms ease;
535
+ }
536
+ .latch-panel:focus-within { border-color: var(--latch-border-strong); background: var(--latch-bg); }
537
+ /* The amount field draws no outline of its own (it is the panel's big number), so the PANEL carries
538
+ the keyboard focus ring; the border-strong change alone was invisible on a dark theme (WCAG 2.4.7). */
539
+ .latch-panel:has(.latch-big-input:focus-visible) { border-color: var(--latch-focus); box-shadow: 0 0 0 1px var(--latch-focus); }
540
+ .latch-panel__top { display: flex; justify-content: space-between; align-items: center; min-height: 18px; }
541
+ .latch-panel__balance { font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); display: inline-flex; gap: 8px; align-items: center; }
542
+ /* Quick amounts under "You pay": real fractions of the balance just read, one row of equal chips. */
543
+ .latch-portions { display: grid; grid-template-columns: repeat(auto-fit, minmax(52px, 1fr)); gap: 8px; margin-top: 12px; }
544
+ .latch-portion {
545
+ font: inherit; font-size: var(--latch-font-size-sm); font-weight: 600; min-height: 36px; padding: 0 8px; border-radius: var(--latch-radius-sm);
546
+ border: 1px solid var(--latch-border); background: var(--latch-bg); color: var(--latch-text); cursor: pointer;
547
+ transition: border-color 120ms, color 120ms;
548
+ }
549
+ .latch-portion:hover { border-color: var(--latch-accent); color: var(--latch-accent); }
550
+ .latch-portion:focus-visible { outline: 2px solid var(--latch-focus); outline-offset: 2px; }
551
+
552
+ /* The compact variant's Buy / Sell pill, in the header where the title was. */
553
+ .latch-sides {
554
+ flex: 1 1 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px; min-width: 0;
555
+ border: 1px solid var(--latch-border); border-radius: 999px; background: var(--latch-bg-sunken);
556
+ }
557
+ .latch-sides__btn {
558
+ min-height: 40px; border: 0; border-radius: 999px; background: transparent; color: var(--latch-text);
559
+ font: inherit; font-weight: 600; cursor: pointer; transition: background 120ms, color 120ms;
560
+ }
561
+ .latch-sides__btn:hover { background: var(--latch-bg-elevated); }
562
+ .latch-sides__btn:focus-visible { outline: 2px solid var(--latch-focus); outline-offset: 2px; }
563
+ .latch-sides__btn[data-latch-side="buy"][aria-pressed="true"] { background: var(--latch-buy); color: var(--latch-buy-text); }
564
+ .latch-sides__btn[data-latch-side="sell"][aria-pressed="true"] { background: var(--latch-accent); color: var(--latch-accent-text); }
565
+ .latch-swap .latch-header:has(.latch-sides) { align-items: center; flex-wrap: nowrap; }
566
+
567
+ /* The compact variant's lines, always visible above the button, one fee per line. */
568
+ .latch-lines { margin: 8px 0 0; padding: 4px 4px 0; display: grid; gap: 8px; }
569
+ .latch-lines .latch-details__row { font-size: 13px; }
570
+ .latch-lines output { font: inherit; transition: opacity 150ms; }
571
+ .latch-lines output.is-refreshing { opacity: 0.55; }
572
+ .latch-swap__form[data-latch-variant="compact"][data-latch-swap-side="buy"] .latch-cta { background: var(--latch-buy); color: var(--latch-buy-text); }
573
+ .latch-swap__form[data-latch-variant="compact"][data-latch-swap-side="buy"] .latch-cta:hover:not(:disabled) { background: var(--latch-buy-hover); }
574
+ .latch-panel__main { display: flex; align-items: center; gap: 12px; margin-top: 6px; }
575
+ .latch-big-input {
576
+ flex: 1 1 auto; min-width: 0; width: 100%;
577
+ font-family: var(--latch-font); font-size: 32px; font-weight: 500; letter-spacing: -0.01em;
578
+ background: transparent; border: 0; color: var(--latch-text); padding: 4px 0; outline: none;
579
+ }
580
+ .latch-big-input::placeholder, .latch-big-input__placeholder { color: var(--latch-text-muted); opacity: 0.7; }
581
+ .latch-big-input--out { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: opacity 150ms; }
582
+ .latch-big-input--out.is-refreshing { opacity: 0.55; }
583
+ .latch-panel__error { margin: 6px 0 0; font-size: var(--latch-font-size-sm); color: var(--latch-danger); }
584
+ .latch-panel__note { margin: 6px 0 0; font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); }
585
+
586
+ .latch-token-button {
587
+ flex: 0 0 auto; display: inline-flex; align-items: center; gap: 8px;
588
+ padding: 6px 10px 6px 6px; border-radius: 999px; font: inherit; font-weight: 650; cursor: pointer;
589
+ background: var(--latch-bg); color: var(--latch-text); border: 1px solid var(--latch-border);
590
+ box-shadow: 0 1px 2px rgba(0,0,0,0.06); transition: border-color 120ms, transform 80ms;
591
+ }
592
+ .latch-token-button:hover { border-color: var(--latch-border-strong); }
593
+ .latch-token-button:active { transform: scale(0.98); }
594
+ .latch-token-button__chevron { color: var(--latch-text-muted); font-size: 12px; }
595
+ .latch-token-button--locked { cursor: default; box-shadow: none; background: var(--latch-bg-sunken); }
596
+ .latch-token-button--locked:hover { border-color: var(--latch-border); }
597
+ .latch-slot { display: block; }
598
+ .latch-slot--header { margin-top: -4px; }
599
+ .latch-token-logo { border-radius: 50%; object-fit: cover; flex-shrink: 0; background: var(--latch-bg-sunken); }
600
+ .latch-token-logo--initials {
601
+ display: inline-flex; align-items: center; justify-content: center; font-weight: 700;
602
+ color: #fff; letter-spacing: 0.01em; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
603
+ background: linear-gradient(140deg, hsl(var(--latch-mono-hue, 215) 62% 52%), hsl(calc(var(--latch-mono-hue, 215) + 28) 58% 34%));
604
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
605
+ }
606
+
607
+ .latch-flip { display: flex; justify-content: center; height: 0; position: relative; z-index: 1; }
608
+ .latch-flip__button {
609
+ position: relative; top: -16px; width: 36px; height: 36px; border-radius: 12px; cursor: pointer;
610
+ background: var(--latch-bg); border: 4px solid var(--latch-bg); color: var(--latch-text);
611
+ box-shadow: 0 0 0 1px var(--latch-border); font-size: 16px; line-height: 1;
612
+ display: inline-flex; align-items: center; justify-content: center; transition: transform 160ms ease, background 120ms;
613
+ }
614
+ .latch-flip__button:hover { background: var(--latch-bg-sunken); transform: rotate(180deg); }
615
+
616
+ .latch-cta {
617
+ margin-top: 8px; width: 100%; height: 52px; border: 0; border-radius: var(--latch-radius);
618
+ background: var(--latch-accent); color: var(--latch-accent-text); font: inherit; font-size: 17px; font-weight: 700;
619
+ cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 10px;
620
+ transition: background 120ms, transform 80ms, opacity 120ms;
621
+ }
622
+ .latch-cta:hover:not(:disabled) { background: var(--latch-accent-hover); }
623
+ .latch-cta:active:not(:disabled) { transform: scale(0.995); }
624
+ .latch-cta:disabled { background: var(--latch-bg-sunken); color: var(--latch-text-muted); cursor: not-allowed; }
625
+ .latch-cta[data-latch-busy="true"] { opacity: 0.85; cursor: progress; }
626
+ .latch-spinner {
627
+ width: 16px; height: 16px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent;
628
+ animation: latch-spin 0.8s linear infinite;
629
+ }
630
+ @keyframes latch-spin { to { transform: rotate(360deg); } }
631
+
632
+ .latch-ack {
633
+ display: flex; gap: 10px; align-items: flex-start; margin-top: 6px; padding: 10px 12px;
634
+ border-radius: var(--latch-radius-sm); background: var(--latch-warning-bg); color: var(--latch-text); font-size: var(--latch-font-size-sm);
635
+ }
636
+ .latch-ack input { margin-top: 2px; }
637
+
638
+ .latch-details { margin-top: 8px; border: 1px solid var(--latch-border); border-radius: var(--latch-radius-sm); overflow: hidden; }
639
+ .latch-details__toggle {
640
+ width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 8px;
641
+ padding: 10px 12px; background: transparent; border: 0; font: inherit; color: var(--latch-text); cursor: pointer; text-align: left;
642
+ }
643
+ .latch-details__toggle:hover { background: var(--latch-bg-elevated); }
644
+ .latch-details__rate { font-weight: 600; cursor: pointer; }
645
+ .latch-details__hint { display: inline-flex; gap: 10px; align-items: center; color: var(--latch-text-muted); font-size: var(--latch-font-size-sm); }
646
+ .latch-details__list { margin: 0; padding: 4px 12px 10px; display: grid; gap: 6px; border-top: 1px solid var(--latch-border); }
647
+ .latch-details__row { display: flex; justify-content: space-between; gap: 12px; font-size: var(--latch-font-size-sm); }
648
+ .latch-details__row dt { color: var(--latch-text-muted); }
649
+ .latch-details__row dd { margin: 0; text-align: right; color: var(--latch-text); overflow-wrap: anywhere; }
650
+ [data-latch-severity="high"] { color: var(--latch-danger) !important; }
651
+ [data-latch-severity="medium"] { color: var(--latch-warning) !important; }
652
+
653
+ .latch-settings-trigger { display: inline-flex; align-items: center; gap: 6px; width: auto; padding: 0 10px; border-radius: 999px; }
654
+ .latch-settings-trigger__value { font-size: var(--latch-font-size-sm); font-weight: 600; }
655
+
656
+ /* Overlays. Portalled into .latch-widget, so they inherit the tokens. */
657
+ .latch-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(2px); animation: latch-fade 120ms ease; z-index: 50; }
658
+ .latch-dialog {
659
+ position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 51;
660
+ width: min(420px, calc(100vw - 32px)); max-height: min(640px, calc(100vh - 32px));
661
+ display: flex; flex-direction: column; gap: 10px;
662
+ background: var(--latch-bg); color: var(--latch-text); border: 1px solid var(--latch-border);
663
+ border-radius: var(--latch-radius); box-shadow: var(--latch-shadow); padding: 14px 14px 8px;
664
+ font-family: var(--latch-font); font-size: var(--latch-font-size); animation: latch-pop 140ms ease;
665
+ }
666
+ @keyframes latch-fade { from { opacity: 0; } }
667
+ @keyframes latch-pop { from { opacity: 0; transform: translate(-50%, -48%) scale(0.98); } }
668
+ .latch-dialog__head { display: flex; justify-content: space-between; align-items: center; }
669
+ .latch-dialog__title { margin: 0; font-size: 17px; font-weight: 700; display: inline-flex; align-items: center; gap: 8px; }
670
+ .latch-dialog__count {
671
+ font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; font-variant-numeric: tabular-nums;
672
+ color: var(--latch-text-muted); background: var(--latch-bg-elevated); border: 1px solid var(--latch-border);
673
+ }
674
+ .latch-search-wrap { position: relative; display: flex; align-items: center; }
675
+ .latch-search-wrap__icon { position: absolute; left: 14px; color: var(--latch-text-muted); pointer-events: none; }
676
+ .latch-search-wrap__clear {
677
+ position: absolute; right: 8px; width: 28px; height: 28px; border-radius: 999px; border: 0; cursor: pointer;
678
+ background: var(--latch-bg-sunken); color: var(--latch-text-muted); font-size: 16px; line-height: 1;
679
+ }
680
+ .latch-search-wrap__clear:hover { color: var(--latch-text); }
681
+ .latch-search {
682
+ width: 100%; font: inherit; font-size: 16px; padding: 12px 40px; border-radius: 999px;
683
+ border: 1px solid var(--latch-border); background: var(--latch-bg-elevated); color: var(--latch-text); outline: none;
684
+ transition: border-color 120ms, box-shadow 120ms;
685
+ }
686
+ .latch-search:focus { border-color: var(--latch-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--latch-accent) 22%, transparent); }
687
+ .latch-common { display: flex; flex-wrap: wrap; gap: 8px; padding-bottom: 4px; }
688
+ .latch-chip--token {
689
+ flex: 0 0 auto; display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 0 14px 0 6px;
690
+ border-radius: 999px; border: 1px solid var(--latch-border); background: var(--latch-bg-elevated); color: var(--latch-text);
691
+ font-weight: 600; transition: border-color 120ms, background 120ms;
692
+ }
693
+ .latch-chip--token:hover { border-color: color-mix(in srgb, var(--latch-accent) 55%, var(--latch-border)); }
694
+ .latch-chip--token[aria-pressed="true"] { border-color: var(--latch-accent); background: color-mix(in srgb, var(--latch-accent) 14%, var(--latch-bg-elevated)); }
695
+ .latch-token-list { list-style: none; margin: 0 -14px; padding: 6px 8px 8px; overflow-y: auto; border-top: 1px solid var(--latch-border); }
696
+ .latch-token-row {
697
+ width: 100%; display: flex; align-items: center; gap: 12px; padding: 10px; min-height: 56px; background: transparent; border: 0;
698
+ border-radius: 12px; font: inherit; color: var(--latch-text); cursor: pointer; text-align: left; transition: background 100ms;
699
+ }
700
+ .latch-token-row:hover:not(:disabled), .latch-token-row:focus-visible { background: var(--latch-bg-elevated); outline: none; }
701
+ .latch-token-row:focus-visible { box-shadow: inset 0 0 0 2px var(--latch-accent); }
702
+ .latch-token-row[aria-selected="true"] { background: color-mix(in srgb, var(--latch-accent) 10%, transparent); }
703
+ .latch-token-row:disabled { opacity: 0.4; cursor: not-allowed; }
704
+ .latch-token-row--note { color: var(--latch-text-muted); font-size: var(--latch-font-size-sm); cursor: default; min-height: 0; }
705
+ .latch-token-row--empty { justify-content: center; text-align: center; padding: 28px 16px; }
706
+ .latch-token-row__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
707
+ .latch-token-row__symbol { font-weight: 650; font-size: 15px; display: inline-flex; align-items: center; flex-wrap: wrap; }
708
+ .latch-token-row__name { font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
709
+ .latch-token-row__balance { display: flex; flex-direction: column; align-items: flex-end; font-variant-numeric: tabular-nums; color: var(--latch-text); font-weight: 600; }
710
+ .latch-token-row__balance-sym { font-size: 11px; font-weight: 500; color: var(--latch-text-muted); }
711
+ .latch-token-row__check { color: var(--latch-accent); font-weight: 700; font-size: 15px; margin-left: 4px; }
712
+ @media (prefers-reduced-motion: reduce) {
713
+ .latch-token-row, .latch-chip--token, .latch-search { transition: none; }
714
+ }
715
+ .latch-token-row--unlisted { background: color-mix(in srgb, var(--latch-warning) 8%, transparent); }
716
+ .latch-token-row__badges { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 8px; vertical-align: middle; }
717
+ .latch-badge {
718
+ display: inline-block; padding: 1px 6px; border-radius: 999px; font-size: 11px; font-weight: 600; line-height: 16px; letter-spacing: 0.01em;
719
+ border: 1px solid var(--latch-border); background: var(--latch-bg-elevated); color: var(--latch-text-muted); white-space: nowrap;
720
+ }
721
+ .latch-badge[data-latch-tone="info"] { color: var(--latch-accent); border-color: color-mix(in srgb, var(--latch-accent) 35%, transparent); }
722
+ .latch-badge[data-latch-tone="warn"] { color: var(--latch-warning); border-color: color-mix(in srgb, var(--latch-warning) 45%, transparent); }
723
+ .latch-token-group { list-style: none; }
724
+ .latch-token-group__label {
725
+ display: block; padding: 8px 14px 4px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
726
+ color: var(--latch-text-muted); border-top: 1px solid var(--latch-border);
727
+ }
728
+ .latch-token-group:first-child .latch-token-group__label { border-top: 0; }
729
+ .latch-token-group__list { list-style: none; margin: 0; padding: 0; }
730
+
731
+ .latch-popover {
732
+ z-index: 51; width: min(320px, calc(100vw - 32px)); background: var(--latch-bg); color: var(--latch-text);
733
+ border: 1px solid var(--latch-border); border-radius: var(--latch-radius); box-shadow: var(--latch-shadow); padding: 12px;
734
+ display: flex; flex-direction: column; gap: 8px; font-family: var(--latch-font); font-size: var(--latch-font-size); animation: latch-fade 120ms ease;
735
+ }
736
+ .latch-popover__row { display: flex; justify-content: space-between; align-items: center; }
737
+ .latch-popover__value { font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); }
738
+ .latch-custom-slippage { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
739
+ .latch-custom-slippage input {
740
+ width: 56px; font: inherit; font-size: var(--latch-font-size-sm); padding: 6px 8px; border-radius: 999px;
741
+ border: 1px solid var(--latch-border); background: var(--latch-bg); color: var(--latch-text); text-align: right; outline: none;
742
+ }
743
+ .latch-custom-slippage input:focus { border-color: var(--latch-accent); }
744
+ .latch-note { margin: 0; font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); }
745
+ .latch-note--warn { color: var(--latch-warning); }
746
+ .latch-footer--brand { justify-content: center; color: var(--latch-text-muted); font-size: 11px; }
747
+ .latch-footer a { color: var(--latch-accent); text-decoration: none; }
748
+
749
+ /* ============================================================================
750
+ Locks (LocksBadge, LocksPanel): the locked share and a countdown. Every
751
+ colour is a --latch-* token above.
752
+ ============================================================================ */
753
+ .latch-locks { gap: 6px; }
754
+ .latch-locks--badge { display: inline-flex; flex-direction: column; width: auto; max-width: 100%; padding: 10px 14px; box-shadow: none; border-radius: var(--latch-radius-sm); }
755
+ .latch-locks--panel { max-width: none; }
756
+ .latch-locks__headline { margin: 0; display: flex; align-items: baseline; gap: 8px; font-weight: 600; overflow-wrap: anywhere; }
757
+ .latch-locks__headline--muted { color: var(--latch-text-muted); font-weight: 500; }
758
+ .latch-locks__headline--error { color: var(--latch-danger); font-weight: 500; }
759
+ .latch-locks__dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--latch-text-muted); transform: translateY(-1px); }
760
+ .latch-locks__dot--locked { background: var(--latch-success); }
761
+ .latch-locks__dot--open { background: var(--latch-warning); }
762
+ .latch-locks__dot--none { background: var(--latch-border-strong); }
763
+ .latch-locks__countdown { margin: 0; font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); overflow-wrap: anywhere; }
764
+ .latch-locks__timer { font-family: var(--latch-font-mono); font-variant-numeric: tabular-nums; color: var(--latch-text); }
765
+ .latch-locks__link { font-size: var(--latch-font-size-sm); color: var(--latch-accent); text-decoration: none; font-weight: 600; }
766
+ .latch-locks__link:hover { text-decoration: underline; }
767
+ .latch-locks__link:focus-visible { outline: 2px solid var(--latch-focus); outline-offset: 2px; border-radius: 4px; }
768
+ .latch-locks__list { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 8px; }
769
+ .latch-locks__item { display: grid; gap: 6px; padding: 10px 12px; border: 1px solid var(--latch-border); border-radius: var(--latch-radius-sm); background: var(--latch-bg-elevated); min-width: 0; }
770
+ .latch-locks__item[data-status="withdrawn"], .latch-locks__item[data-status="claimed"] { opacity: 0.72; }
771
+ .latch-locks__row { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
772
+ .latch-locks__status { flex: 0 0 auto; padding: 1px 8px; border: 1px solid currentColor; border-radius: 999px; font-size: 11px; font-weight: 650; white-space: nowrap; }
773
+ .latch-locks__status--locked, .latch-locks__status--cliff, .latch-locks__status--vesting { color: var(--latch-success); }
774
+ .latch-locks__status--unlockable, .latch-locks__status--vested { color: var(--latch-warning); }
775
+ .latch-locks__status--withdrawn, .latch-locks__status--claimed { color: var(--latch-text-muted); }
776
+ .latch-locks__status--permanent { color: var(--latch-accent, var(--latch-success)); }
777
+ .latch-locks__facts { margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 6px 12px; font-size: var(--latch-font-size-sm); }
778
+ .latch-locks__facts div { min-width: 0; }
779
+ .latch-locks__facts dt { color: var(--latch-text-muted); }
780
+ .latch-locks__facts dd { margin: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
781
+
782
+ /* Lock charts (lockCharts.tsx): a locked-share bar that grows in, and a release
783
+ schedule that draws on. Motion off under prefers-reduced-motion. */
784
+ .latch-sharebar { display: grid; gap: 6px; min-width: 0; }
785
+ .latch-locks--badge .latch-sharebar { min-width: 180px; }
786
+ .latch-sharebar__track { height: 8px; border-radius: 999px; overflow: hidden; background: var(--latch-bg-sunken); }
787
+ .latch-sharebar__grow { display: flex; height: 100%; transform-origin: left center; animation: latch-grow 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; }
788
+ .latch-sharebar__part { flex: 0 0 auto; height: 100%; }
789
+ .latch-sharebar__part + .latch-sharebar__part { box-shadow: inset 2px 0 0 var(--latch-bg); }
790
+ .latch-sharebar__part--permanent, .latch-sharebar__part--lp { background: var(--latch-success); }
791
+ .latch-sharebar__part--time, .latch-sharebar__part--unvested { background: var(--latch-accent); }
792
+ .latch-sharebar__part--vested { background: var(--latch-accent); opacity: 0.45; }
793
+ .latch-sharebar__key { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 2px 12px; font-size: 11px; color: var(--latch-text-muted); font-variant-numeric: tabular-nums; }
794
+ .latch-sharebar__key li { display: inline-flex; align-items: center; gap: 5px; }
795
+ .latch-sharebar__sw { display: inline-block; width: 8px; height: 8px; border-radius: 2px; }
796
+ .latch-spark { margin: 2px 0 0; display: grid; gap: 4px; }
797
+ .latch-spark__svg { display: block; width: 100%; height: 44px; overflow: visible; cursor: crosshair; border-radius: 4px; }
798
+ .latch-spark__svg:focus-visible { outline: 2px solid var(--latch-focus); outline-offset: 2px; }
799
+ .latch-spark__base { stroke: var(--latch-border); stroke-width: 1; }
800
+ .latch-spark__line { stroke: var(--latch-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; stroke-dasharray: 2000; animation: latch-draw 1.3s cubic-bezier(0.22, 1, 0.36, 1) both; }
801
+ .latch-spark__now { stroke: var(--latch-text-muted); stroke-width: 1; stroke-dasharray: 3 3; }
802
+ .latch-spark__cross { stroke: var(--latch-accent); stroke-width: 1; opacity: 0.6; }
803
+ .latch-spark__cap { font-size: 11px; color: var(--latch-text-muted); overflow-wrap: anywhere; }
804
+ .latch-locks .latch-progress-fill, .latch-locker .latch-progress-fill { transform-origin: left center; animation: latch-grow 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; }
805
+ @keyframes latch-grow { from { transform: scaleX(0.02); } to { transform: scaleX(1); } }
806
+ @keyframes latch-draw { from { stroke-dashoffset: 2000; } to { stroke-dashoffset: 0; } }
807
+ @media (prefers-reduced-motion: reduce) {
808
+ .latch-sharebar__grow, .latch-spark__line, .latch-locks .latch-progress-fill, .latch-locker .latch-progress-fill { animation: none; transform: none; stroke-dashoffset: 0; }
809
+ }
810
+
811
+ /* ============================================================================
812
+ Token trust (TokenTrustPanel): labelled rows, each with its source.
813
+ ============================================================================ */
814
+ .latch-trust { max-width: none; gap: 8px; }
815
+ .latch-trust__list { margin: 0; display: grid; gap: 0; }
816
+ .latch-trust__row { display: grid; grid-template-columns: minmax(120px, 180px) 1fr; gap: 4px 14px; padding: 9px 0; border-top: 1px solid var(--latch-border); min-width: 0; }
817
+ .latch-trust__row:first-child { border-top: 0; }
818
+ @media (max-width: 520px) { .latch-trust__row { grid-template-columns: 1fr; } }
819
+ .latch-trust__label { color: var(--latch-text-muted); font-size: var(--latch-font-size-sm); font-weight: 600; }
820
+ .latch-trust__value { margin: 0; min-width: 0; display: grid; gap: 3px; }
821
+ .latch-trust__headline { margin: 0; display: flex; align-items: baseline; gap: 8px; font-weight: 600; overflow-wrap: anywhere; }
822
+ .latch-trust__detail { margin: 0; font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); overflow-wrap: anywhere; }
823
+ .latch-trust__source { margin: 0; display: flex; flex-wrap: wrap; gap: 2px 10px; font-family: var(--latch-font-mono); font-size: 11px; color: var(--latch-text-muted); overflow-wrap: anywhere; }
824
+ .latch-trust__source a { color: inherit; text-decoration: underline; text-decoration-color: var(--latch-border-strong); }
825
+ .latch-trust__source a:hover { color: var(--latch-accent); }
826
+ .latch-trust__dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--latch-border-strong); transform: translateY(-1px); }
827
+ .latch-trust__dot--locked { background: var(--latch-success); }
828
+ .latch-trust__dot--neutral { background: var(--latch-text-muted); }
829
+ .latch-trust__dot--caution { background: var(--latch-warning); }
830
+ .latch-trust__dot--flagged, .latch-trust__dot--error { background: var(--latch-danger); }
831
+ .latch-trust__row[data-tone="flagged"] .latch-trust__headline, .latch-trust__row[data-tone="error"] .latch-trust__headline { color: var(--latch-danger); }
832
+ .latch-trust__subhead { margin: 6px 0 0; font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--latch-text-muted); }
833
+ .latch-trust__pool { display: grid; gap: 4px; padding: 10px 12px; border: 1px solid var(--latch-border); border-radius: var(--latch-radius-sm); background: var(--latch-bg-elevated); min-width: 0; }
834
+ .latch-trust__pool-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
835
+ .latch-trust__pool-head code { font-family: var(--latch-font-mono); font-size: 11px; color: var(--latch-text-muted); }
836
+ .latch-trust__found { margin: 0; font-size: 11px; color: var(--latch-text-muted); }
837
+ .latch-trust__link { font-size: var(--latch-font-size-sm); color: var(--latch-accent); text-decoration: none; font-weight: 600; margin-left: auto; }
838
+ .latch-trust__link:hover { text-decoration: underline; }
839
+ .latch-trust__state { margin: 0; color: var(--latch-text-muted); }
840
+ .latch-trust__state--error { color: var(--latch-danger); }
841
+ .latch-trust__retry { font: inherit; background: none; border: 0; padding: 0; color: var(--latch-accent); cursor: pointer; text-decoration: underline; }
842
+
843
+ /* ============================================================================
844
+ Locker (LockerWidget): lock a position, lock or vest tokens, manage locks.
845
+ ============================================================================ */
846
+ .latch-locker { gap: 10px; }
847
+ .latch-locker__tabs { display: flex; gap: 4px; padding: 3px; border-radius: 999px; background: var(--latch-bg-sunken); }
848
+ .latch-locker__tab { flex: 1; font: inherit; font-size: var(--latch-font-size-sm); font-weight: 600; padding: 7px 10px; border: 0; border-radius: 999px; background: transparent; color: var(--latch-text-muted); cursor: pointer; }
849
+ .latch-locker__tab[aria-selected="true"] { background: var(--latch-bg); color: var(--latch-text); box-shadow: var(--latch-shadow); }
850
+ .latch-locker__field { display: grid; gap: 4px; font-size: var(--latch-font-size-sm); }
851
+ .latch-locker__field > span { color: var(--latch-text-muted); font-weight: 600; }
852
+ .latch-locker__input { width: 100%; font: inherit; padding: 10px 12px; border-radius: var(--latch-radius-sm); border: 1px solid var(--latch-border); background: var(--latch-bg-elevated); color: var(--latch-text); outline: none; min-width: 0; }
853
+ .latch-locker__input:focus { border-color: var(--latch-accent); }
854
+ .latch-locker__row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
855
+ @media (max-width: 420px) { .latch-locker__row2 { grid-template-columns: 1fr; } }
856
+ .latch-locker__issues { margin: 0; padding-left: 18px; color: var(--latch-danger); font-size: var(--latch-font-size-sm); }
857
+ .latch-locker__fee { margin: 0; padding: 8px 10px; border-radius: var(--latch-radius-sm); background: var(--latch-bg-elevated); font-size: var(--latch-font-size-sm); display: grid; gap: 2px; }
858
+ .latch-locker__fee strong { font-variant-numeric: tabular-nums; }
859
+ .latch-locker__steps { margin: 0; padding-left: 18px; display: grid; gap: 2px; font-size: var(--latch-font-size-sm); color: var(--latch-text-muted); }
860
+ .latch-locker__steps li[data-state="done"] { color: var(--latch-success); }
861
+ .latch-locker__steps li[data-state="active"] { color: var(--latch-text); font-weight: 600; }
862
+ .latch-locker__status { margin: 0; font-size: var(--latch-font-size-sm); overflow-wrap: anywhere; }
863
+ .latch-locker__status[data-kind="error"] { color: var(--latch-danger); }
864
+ .latch-locker__status[data-kind="success"] { color: var(--latch-success); }
865
+ .latch-locker__actions { display: flex; flex-wrap: wrap; gap: 6px; }
866
+ .latch-locker__btn { font: inherit; font-size: var(--latch-font-size-sm); font-weight: 600; padding: 6px 12px; border-radius: 999px; border: 1px solid var(--latch-border-strong); background: var(--latch-bg); color: var(--latch-text); cursor: pointer; }
867
+ .latch-locker__btn:hover:not(:disabled) { border-color: var(--latch-accent); color: var(--latch-accent); }
868
+ .latch-locker__btn:disabled { opacity: 0.5; cursor: not-allowed; }
869
+ .latch-locker__choice { display: flex; gap: 12px; flex-wrap: wrap; font-size: var(--latch-font-size-sm); }
870
+ .latch-locker__choice label { display: inline-flex; gap: 6px; align-items: center; cursor: pointer; }
871
+
872
+ /* ============================================================================
873
+ The Latch mark (brand kit masters/latch-mark.svg, loaded as shipped, never
874
+ redrawn). 24 px wide is the kit's minimum; the margin is its clear space
875
+ (the height of the hook's eye at this size).
876
+ ============================================================================ */
877
+ .latch-brand { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 11px; color: var(--latch-text-muted); }
878
+ .latch-brand__mark { flex: 0 0 auto; width: 24px; height: auto; margin: 4px; display: block; }
879
+ .latch-brand__spacer { flex: 1; }
880
+
881
+
882
+ /* ============================================================================
883
+ Touch (pointer: coarse): 44px targets, and inputs at 16px so iOS Safari does
884
+ not zoom the host page when a field is focused.
885
+ ============================================================================ */
886
+ @media (pointer: coarse) {
887
+ .latch-widget input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
888
+ .latch-widget select,
889
+ .latch-widget textarea,
890
+ .latch-locker input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
891
+ .latch-locker select { font-size: max(16px, 1em); }
892
+ .latch-portion, .latch-chip, .latch-select, .latch-settings-trigger, .latch-icon-button,
893
+ .latch-locker__tab, .latch-locker__input, .latch-locker__btn, .latch-button, .latch-token-button { min-height: 44px; }
894
+ .latch-locker__choice label { min-height: 44px; }
895
+ }