@ibgib/space-gib 0.0.5 → 0.0.7

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 (58) hide show
  1. package/README.md +20 -0
  2. package/dist/client/bootstrap.mjs +31 -31
  3. package/dist/client/bootstrap.mjs.map +3 -3
  4. package/dist/client/chunk-RXFIBFRK.mjs +42 -0
  5. package/dist/client/chunk-RXFIBFRK.mjs.map +7 -0
  6. package/dist/client/chunk-ULFNE26Y.mjs +2216 -0
  7. package/dist/client/chunk-ULFNE26Y.mjs.map +7 -0
  8. package/dist/client/index.html +35 -14
  9. package/dist/client/index.mjs +1 -1
  10. package/dist/client/script.mjs +1 -1
  11. package/dist/client/style.css +29 -5
  12. package/dist/server/server.mjs +1447 -270
  13. package/dist/server/server.mjs.map +4 -4
  14. package/package.json +5 -5
  15. package/space-gib.localhost-1783713259760.log +45 -0
  16. package/src/client/AUTO-GENERATED-version.mts +1 -1
  17. package/src/client/bootstrap.mts +9 -0
  18. package/src/client/components/identity-header/identity-header.css +40 -2
  19. package/src/client/components/identity-header/identity-header.html +3 -2
  20. package/src/client/components/identity-header/identity-header.mts +127 -49
  21. package/src/client/components/identity-manager/identity-manager.css +57 -353
  22. package/src/client/components/identity-manager/identity-manager.html +0 -94
  23. package/src/client/components/identity-manager/identity-manager.mts +356 -484
  24. package/src/client/components/keystone-creator/keystone-creator.mts +90 -13
  25. package/src/client/components/keystone-details/keystone-details.css +472 -0
  26. package/src/client/components/keystone-details/keystone-details.html +99 -0
  27. package/src/client/components/keystone-details/keystone-details.mts +821 -0
  28. package/src/client/components/keystone-scrubber/SCRUBBER_IMPLEMENTATION.md +33 -0
  29. package/src/client/components/keystone-scrubber/keystone-scrubber.css +46 -0
  30. package/src/client/components/keystone-scrubber/keystone-scrubber.html +15 -0
  31. package/src/client/components/keystone-scrubber/keystone-scrubber.mts +356 -0
  32. package/src/client/dev-tools/common.mts +505 -10
  33. package/src/client/dev-tools/phase-4-1.mts +19 -4
  34. package/src/client/dev-tools/phase-4-10.mts +77 -305
  35. package/src/client/dev-tools/phase-4-2.mts +46 -212
  36. package/src/client/dev-tools/phase-4-3.mts +57 -198
  37. package/src/client/dev-tools/phase-4-4.mts +57 -170
  38. package/src/client/dev-tools/phase-4-5.mts +48 -204
  39. package/src/client/dev-tools/phase-4-6.mts +37 -103
  40. package/src/client/dev-tools/phase-4-7.mts +44 -228
  41. package/src/client/dev-tools/phase-4-8.mts +33 -136
  42. package/src/client/dev-tools/phase-4-9.mts +33 -137
  43. package/src/client/dev-tools/phase-4.mts +30 -6
  44. package/src/client/dev-tools.mts +18 -0
  45. package/src/client/index.html +35 -14
  46. package/src/client/style.css +29 -5
  47. package/src/client/types.mts +4 -1
  48. package/src/client/ui/shell/space-gib-shell-service.mts +4 -0
  49. package/src/server/path-constants.mts +12 -0
  50. package/src/server/serve-gib/handlers/api/keystone/sso-config.handler.mts +66 -0
  51. package/src/server/serve-gib/handlers/api/keystone/sso-link.handler.mts +119 -0
  52. package/src/server/serve-gib/handlers/api/keystone/sso-login.handler.mts +189 -0
  53. package/src/server/server.mts +6 -0
  54. package/dist/client/chunk-ANGVYAEK.mjs +0 -42
  55. package/dist/client/chunk-ANGVYAEK.mjs.map +0 -7
  56. package/dist/client/chunk-IRGFDQRD.mjs +0 -1920
  57. package/dist/client/chunk-IRGFDQRD.mjs.map +0 -7
  58. package/dist/respec-gib.node.mjs +0 -5
@@ -2,7 +2,7 @@ import thisCss from "./keystone-creator.css";
2
2
  import thisHtml from "./keystone-creator.html";
3
3
  import styleCss from "../../style.css";
4
4
 
5
- import { delay, extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
5
+ import { delay, extractErrorMsg, hash } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
6
6
  import { HashAlgorithm } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
7
7
  import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
8
8
  import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
@@ -32,7 +32,8 @@ import { SettingsType } from "@ibgib/web-gib/dist/common/settings/settings-const
32
32
  import { SettingsIbGib_V1 } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
33
33
  import { updateSpecialIndex, mut8Timeline } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
34
34
  import { toDto } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
35
- import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
35
+ import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP, KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
36
+ import { deriveDelegateSecret } from "@ibgib/core-gib/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs";
36
37
  import { EVENT_IBGIB_IDENTITY_REQUEST_CHANGE } from "@ibgib/web-gib/dist/ui/ui-constants.mjs";
37
38
 
38
39
  export const KEYSTONE_CREATOR_COMPONENT_NAME = 'ibgib-keystone-creator';
@@ -247,12 +248,13 @@ export class KeystoneCreatorComponentInstance
247
248
  loadingText: 'Generating...'
248
249
  });
249
250
 
250
- // 1. Prepare Keystone Configs using the test behavior profile (with username and description)
251
- const builder = KeystoneProfileBuilder.buildKeystone('test')
251
+ // 1. Prepare Primary/Domain Keystone Configs
252
+ const builder = KeystoneProfileBuilder.buildKeystone('domain')
252
253
  .withUsername(username)
253
254
  .withDescription(description)
254
255
  .withDetails({
255
256
  client: 'space-gib-web',
257
+ role: 'domain-identity'
256
258
  });
257
259
  const configs = await builder.compileConfigs();
258
260
 
@@ -274,26 +276,73 @@ export class KeystoneCreatorComponentInstance
274
276
  configs,
275
277
  metaspace,
276
278
  space,
277
- frameDetails: builder.getFrameDetails()
279
+ frameDetails: builder.getFrameDetails(),
280
+ isPrimary: true
278
281
  });
279
282
 
280
283
  const addr = getIbGibAddr({ ibGib: keystoneIbGib });
281
284
  console.log(`${lc} [NAG][ibgib-paradigm] local genesis complete: ${addr}`);
282
285
  await delay(humanEyeDelay); // for human eyes, not needed for functionality
283
- this.setStatus("Local genesis complete. Syncing to server...", "info");
286
+ this.setStatus("Local genesis complete. Creating sync delegate...", "info");
284
287
  devLog(`✓ Local genesis complete: ${addr}`);
285
288
 
286
- // Expose for dev tools
287
- (window as any).dev_domainI = keystoneIbGib;
288
- (window as any).dev_domainIMasterSecret = masterSecret;
289
+ // Automatically generate Sync Delegate Keystone
290
+ this.showBusy({
291
+ isBusy: true,
292
+ title: 'Creating Sync Delegate...',
293
+ msg: 'Generating cryptographic sync delegate keys...',
294
+ animationEmoji: '🔑'
295
+ });
296
+
297
+ const delegateSecret = await deriveDelegateSecret({ masterSecret });
298
+ const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
299
+ .withUsername(`${username}-sync`)
300
+ .withDescription(`Sync Delegate for ${username}`)
301
+ .withDetails({
302
+ client: 'space-gib-web',
303
+ role: 'sync-delegate'
304
+ });
305
+ const delegateConfigs = await delegateBuilder.compileConfigs();
306
+
307
+ const delegateKeystoneIbGib = await keystoneService.genesis({
308
+ masterSecret: delegateSecret,
309
+ configs: delegateConfigs,
310
+ metaspace,
311
+ space,
312
+ frameDetails: delegateBuilder.getFrameDetails()
313
+ });
314
+
315
+ const delegateAddr = getIbGibAddr({ ibGib: delegateKeystoneIbGib });
316
+ console.log(`${lc} sync delegate genesis complete: ${delegateAddr}`);
317
+ await delay(humanEyeDelay);
318
+
319
+ // Register delegate on parent
320
+ this.setStatus("Registering delegate on parent...", "info");
321
+ this.showBusy({
322
+ isBusy: true,
323
+ title: 'Registering Delegate...',
324
+ msg: 'Evolving domain identity to register delegate...',
325
+ animationEmoji: '📝'
326
+ });
327
+ const evolvedParentKeystoneIbGib = await keystoneService.registerDelegate({
328
+ parentKeystone: keystoneIbGib,
329
+ delegateKeystone: delegateKeystoneIbGib,
330
+ masterSecret,
331
+ metaspace,
332
+ space,
333
+ allowedVerbs: [KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT]
334
+ });
335
+ const evolvedParentAddr = getIbGibAddr({ ibGib: evolvedParentKeystoneIbGib });
336
+ console.log(`${lc} delegate registered. evolved parent address: ${evolvedParentAddr}`);
337
+ await delay(humanEyeDelay);
289
338
 
290
339
  // 4. Post to Server
291
340
  devLog(`Posting genesis keystone to server...`);
341
+ this.setStatus("Syncing genesis to server...", "info");
292
342
  this.showBusy({
293
343
  isBusy: true,
294
344
  title: 'Syncing to Server...',
295
345
  msg: [
296
- 'Local genesis complete!',
297
346
  'Posting genesis keystone to server sync node...',
298
347
  '(may take awhile, depending on strength of keystone...)',
299
348
  ].join('\n'),
@@ -306,6 +355,25 @@ export class KeystoneCreatorComponentInstance
306
355
  return; /* <<<< returns early */
307
356
  }
308
357
 
358
+ // Post evolved keystone + delegate keystone
359
+ this.setStatus("Syncing delegate registration to server...", "info");
360
+ this.showBusy({
361
+ isBusy: true,
362
+ title: 'Syncing Delegate...',
363
+ msg: 'Posting evolved domain identity and sync delegate to server...',
364
+ animationEmoji: '🔄'
365
+ });
366
+ const resEvolve = await spaceGibApiBridge.putEvolveKeystone(
367
+ addr,
368
+ evolvedParentKeystoneIbGib,
369
+ [delegateKeystoneIbGib]
370
+ );
371
+ if (!resEvolve.success) {
372
+ this.setStatus(`Delegate registration sync failed: ${resEvolve.message}`, "error");
373
+ devLog(`✗ Server rejected delegate registration: ${resEvolve.message}`);
374
+ return; /* <<<< returns early */
375
+ }
376
+
309
377
  // 5. Register with the keystones special index
310
378
  this.showBusy({
311
379
  isBusy: true,
@@ -319,25 +387,34 @@ export class KeystoneCreatorComponentInstance
319
387
  rel8nInfos: [
320
388
  {
321
389
  rel8nName: "keystone",
322
- ibGibs: [toDto({ ibGib: keystoneIbGib })],
390
+ ibGibs: [
391
+ toDto({ ibGib: evolvedParentKeystoneIbGib }),
392
+ toDto({ ibGib: delegateKeystoneIbGib })
393
+ ],
323
394
  },
324
395
  ],
325
396
  metaspace,
326
397
  space,
327
398
  });
328
399
 
400
+ // Expose for dev tools
401
+ (window as any).dev_domainI = evolvedParentKeystoneIbGib;
402
+ (window as any).dev_domainIMasterSecret = masterSecret;
403
+ (window as any).dev_syncDelegate = delegateKeystoneIbGib;
404
+ (window as any).dev_syncDelegateSecret = delegateSecret;
405
+
329
406
  // 6. Request to make the new identity active if the checkbox is checked
330
407
  const makeActive = this.elements!.checkboxMakeActive?.checked;
331
408
  if (makeActive) {
332
409
  window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
333
- detail: { activeIdentityAddr: addr },
410
+ detail: { activeIdentityAddr: evolvedParentAddr },
334
411
  bubbles: true,
335
412
  composed: true
336
413
  }));
337
414
  }
338
415
 
339
416
  // 7. Success
340
- this.elements!.keystoneAddrEl.textContent = addr;
417
+ this.elements!.keystoneAddrEl.textContent = evolvedParentAddr;
341
418
  this.elements!.statusArea.classList.remove('hidden');
342
419
  this.setStatus("Keystone successfully created and synced!", "success");
343
420
  await delay(humanEyeDelay); // for human eyes, not needed for functionality
@@ -0,0 +1,472 @@
1
+ :host {
2
+ display: block;
3
+ width: 100%;
4
+ max-width: 100%;
5
+ font-family: var(--font-family-base, inherit);
6
+ font-size: var(--font-size-base, 1rem);
7
+ color: var(--text-color-base, var(--clr-text-primary, #ffffff));
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ .details-view {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 1.5rem;
15
+ }
16
+
17
+ .card {
18
+ padding: 1.5rem;
19
+ background: rgba(255, 255, 255, 0.02);
20
+ border: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.05));
21
+ border-radius: var(--radius-md, 8px);
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: 1rem;
25
+ }
26
+
27
+ .card h3 {
28
+ margin: 0;
29
+ font-size: var(--h3-font-size, 1.15rem);
30
+ font-weight: var(--h3-font-weight, 500);
31
+ color: var(--clr-accent, #50fa7b);
32
+ }
33
+
34
+ /* Key-Value Details Grid Layout */
35
+ .kv-grid {
36
+ display: grid;
37
+ grid-template-columns: minmax(140px, 180px) 1fr;
38
+ gap: 0.75rem 1.5rem;
39
+ align-items: baseline;
40
+ margin-top: 1rem;
41
+ margin-bottom: 1.5rem;
42
+ }
43
+
44
+ .kv-label {
45
+ font-family: var(--font-sans);
46
+ font-size: 0.75rem;
47
+ font-weight: 600;
48
+ text-transform: uppercase;
49
+ letter-spacing: 0.05em;
50
+ color: var(--clr-text-secondary, #8fa08f);
51
+ user-select: none;
52
+ }
53
+
54
+ .kv-value {
55
+ font-size: 0.9375rem;
56
+ color: var(--clr-text-primary, #ffffff);
57
+ word-break: break-all;
58
+ }
59
+
60
+ .kv-pre {
61
+ margin: 0;
62
+ padding: 0.6rem 0.8rem;
63
+ background: rgba(0, 0, 0, 0.3);
64
+ border: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.05));
65
+ border-radius: var(--radius-sm, 6px);
66
+ font-family: var(--font-mono, monospace);
67
+ font-size: 0.8rem;
68
+ color: var(--clr-accent, #50fa7b);
69
+ max-height: 150px;
70
+ overflow: auto;
71
+ white-space: pre;
72
+ word-break: normal;
73
+ }
74
+
75
+ /* Accordion raw styles */
76
+ .accordion {
77
+ padding: 0;
78
+ overflow: hidden;
79
+ }
80
+
81
+ .accordion-header {
82
+ padding: 1.25rem 1.5rem;
83
+ display: flex;
84
+ justify-content: space-between;
85
+ align-items: center;
86
+ cursor: pointer;
87
+ background: rgba(255, 255, 255, 0.01);
88
+ transition: background 0.2s ease-in-out;
89
+ }
90
+
91
+ .accordion-header:hover {
92
+ background: rgba(255, 255, 255, 0.03);
93
+ }
94
+
95
+ .accordion-header .chevron {
96
+ transition: transform 0.2s ease-in-out;
97
+ font-size: 0.8rem;
98
+ color: var(--clr-text-secondary, #b3b3b3);
99
+ }
100
+
101
+ .accordion-header.expanded .chevron {
102
+ transform: rotate(180deg);
103
+ }
104
+
105
+ .accordion-content {
106
+ max-height: 0;
107
+ transition: max-height 0.3s cubic-bezier(0, 1, 0, 1);
108
+ background: rgba(0, 0, 0, 0.15);
109
+ border-top: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.03));
110
+ }
111
+
112
+ .accordion-content.expanded {
113
+ max-height: 5000px;
114
+ overflow-y: visible;
115
+ transition: max-height 0.3s cubic-bezier(1, 0, 1, 0);
116
+ }
117
+
118
+ .json-code {
119
+ margin: 0;
120
+ padding: 1.25rem;
121
+ font-family: var(--font-mono, monospace);
122
+ font-size: 0.8rem;
123
+ color: var(--clr-accent, #50fa7b);
124
+ background: transparent;
125
+ overflow: auto;
126
+ max-height: 70dvh;
127
+ white-space: pre-wrap;
128
+ word-break: break-all;
129
+ }
130
+
131
+ .description {
132
+ font-size: 0.85rem;
133
+ color: var(--clr-text-secondary, #b3b3b3);
134
+ margin: 0;
135
+ }
136
+
137
+ .hidden {
138
+ display: none !important;
139
+ }
140
+
141
+ .pools-container {
142
+ display: flex;
143
+ flex-direction: column;
144
+ gap: 1rem;
145
+ }
146
+
147
+ .pool-card {
148
+ padding: 1rem;
149
+ background: rgba(0, 0, 0, 0.25);
150
+ border: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.05));
151
+ border-radius: 6px;
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.75rem;
155
+ }
156
+
157
+ .pool-header {
158
+ display: flex;
159
+ justify-content: space-between;
160
+ align-items: center;
161
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
162
+ padding-bottom: 0.5rem;
163
+ }
164
+
165
+ .pool-title {
166
+ font-size: 0.95rem;
167
+ font-weight: 600;
168
+ color: var(--clr-accent, #50fa7b);
169
+ }
170
+
171
+ .pool-tag {
172
+ font-size: 0.7rem;
173
+ padding: 0.15rem 0.4rem;
174
+ border-radius: 4px;
175
+ font-weight: bold;
176
+ text-transform: uppercase;
177
+ }
178
+
179
+ .pool-tag.foreign {
180
+ background: rgba(255, 184, 108, 0.15);
181
+ border: 1px solid rgba(255, 184, 108, 0.3);
182
+ color: #ffb86c;
183
+ }
184
+
185
+ .pool-tag.native {
186
+ background: rgba(80, 250, 123, 0.1);
187
+ border: 1px solid rgba(80, 250, 123, 0.2);
188
+ color: #50fa7b;
189
+ }
190
+
191
+ .pool-grid {
192
+ display: grid;
193
+ grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
194
+ gap: 0.75rem;
195
+ font-size: 0.85rem;
196
+ }
197
+
198
+ .pool-field {
199
+ display: flex;
200
+ flex-direction: column;
201
+ gap: 0.2rem;
202
+ }
203
+
204
+ .pool-field label {
205
+ font-size: 0.7rem;
206
+ color: var(--clr-text-secondary, #b3b3b3);
207
+ text-transform: uppercase;
208
+ letter-spacing: 0.03em;
209
+ }
210
+
211
+ .pool-field span {
212
+ color: #ffffff;
213
+ font-weight: 500;
214
+ word-break: break-all;
215
+ }
216
+
217
+ /* Pool Details & Challenges/Binding Map styling */
218
+ .pool-details {
219
+ margin-top: 0.75rem;
220
+ border-top: 1px solid rgba(255, 255, 255, 0.05);
221
+ padding-top: 0.5rem;
222
+ }
223
+
224
+ .pool-details-summary {
225
+ font-size: 0.8rem;
226
+ font-weight: 600;
227
+ color: var(--clr-text-secondary, #8fa08f);
228
+ cursor: pointer;
229
+ user-select: none;
230
+ outline: none;
231
+ padding: 0.25rem 0;
232
+ display: flex;
233
+ align-items: center;
234
+ gap: 0.25rem;
235
+ transition: color var(--t-fast, 120ms ease);
236
+ }
237
+
238
+ .pool-details-summary:hover {
239
+ color: var(--clr-accent, #78f87e);
240
+ }
241
+
242
+ .pool-challenges-list {
243
+ margin-top: 0.5rem;
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 0.4rem;
247
+ max-height: 180px;
248
+ overflow-y: auto;
249
+ padding-right: 0.25rem;
250
+ border: 1px solid rgba(255, 255, 255, 0.05);
251
+ background: rgba(0, 0, 0, 0.15);
252
+ border-radius: 4px;
253
+ padding: 0.5rem;
254
+ }
255
+
256
+ .pool-challenge-item {
257
+ display: flex;
258
+ justify-content: space-between;
259
+ align-items: center;
260
+ background: rgba(255, 255, 255, 0.02);
261
+ border: 1px solid rgba(255, 255, 255, 0.03);
262
+ border-radius: 4px;
263
+ padding: 0.35rem 0.5rem;
264
+ font-size: 0.75rem;
265
+ font-family: var(--font-mono, monospace);
266
+ }
267
+
268
+ .challenge-id {
269
+ color: var(--clr-text-secondary, #8fa08f);
270
+ font-weight: 500;
271
+ }
272
+
273
+ .challenge-hash {
274
+ color: var(--clr-accent, #78f87e);
275
+ word-break: break-all;
276
+ margin-left: 1rem;
277
+ text-align: right;
278
+ }
279
+
280
+ /* Delegates Table styling */
281
+ .delegates-table {
282
+ width: 100%;
283
+ border-collapse: collapse;
284
+ margin-top: 1rem;
285
+ font-size: 0.9rem;
286
+ background: rgba(0, 0, 0, 0.2);
287
+ border-radius: var(--radius-sm, 6px);
288
+ overflow: hidden;
289
+ }
290
+
291
+ .delegates-table th,
292
+ .delegates-table td {
293
+ padding: 0.75rem 1rem;
294
+ text-align: left;
295
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
296
+ }
297
+
298
+ .delegates-table th {
299
+ font-family: var(--font-sans);
300
+ font-size: 0.75rem;
301
+ font-weight: 600;
302
+ text-transform: uppercase;
303
+ letter-spacing: 0.05em;
304
+ color: var(--clr-text-secondary, #8fa08f);
305
+ background: rgba(255, 255, 255, 0.02);
306
+ }
307
+
308
+ .delegates-table td {
309
+ font-family: var(--font-mono, monospace);
310
+ font-size: 0.8rem;
311
+ color: var(--clr-text-primary, #ffffff);
312
+ word-break: break-all;
313
+ }
314
+
315
+ .delegates-table tbody tr:hover {
316
+ background: rgba(255, 255, 255, 0.02);
317
+ }
318
+
319
+ .action-row {
320
+ display: flex;
321
+ gap: 1rem;
322
+ margin-top: 1rem;
323
+ }
324
+
325
+ .action-btn {
326
+ padding: 0.6rem 1.2rem;
327
+ background: var(--clr-accent, #50fa7b);
328
+ border: none;
329
+ border-radius: var(--radius-sm, 4px);
330
+ color: #1a1a24;
331
+ font-weight: 600;
332
+ cursor: pointer;
333
+ transition: all 0.2s ease-in-out;
334
+ }
335
+
336
+ .action-btn:hover {
337
+ background: #40c767;
338
+ }
339
+
340
+ .action-btn.secondary {
341
+ background: transparent;
342
+ border: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.1));
343
+ color: #ffffff;
344
+ }
345
+
346
+ .action-btn.secondary:hover {
347
+ background: rgba(255, 255, 255, 0.05);
348
+ }
349
+
350
+ .action-btn.small {
351
+ padding: 0.2rem 0.5rem;
352
+ font-size: var(--font-size-xs, 0.75rem);
353
+ border-radius: 3px;
354
+ }
355
+
356
+ .action-btn.active-primary {
357
+ background: rgba(80, 250, 123, 0.2);
358
+ border: 1px solid rgba(80, 250, 123, 0.4);
359
+ color: var(--clr-accent, #50fa7b);
360
+ cursor: default;
361
+ }
362
+
363
+ .address-code {
364
+ display: inline-block;
365
+ padding: 0.2rem 0.4rem;
366
+ background: rgba(0, 0, 0, 0.3);
367
+ border: 1px solid var(--border-color-base, rgba(255, 255, 255, 0.05));
368
+ border-radius: var(--radius-sm, 4px);
369
+ font-family: var(--font-mono, monospace);
370
+ font-size: 0.8rem;
371
+ color: var(--clr-accent, #50fa7b);
372
+ word-break: break-all;
373
+ }
374
+
375
+ .status-msg {
376
+ margin-top: 1rem;
377
+ padding: 0.75rem 1rem;
378
+ border-radius: var(--radius-sm, 4px);
379
+ font-size: 0.9rem;
380
+ }
381
+
382
+ .status-msg.info {
383
+ background: rgba(139, 233, 253, 0.1);
384
+ border: 1px solid rgba(139, 233, 253, 0.3);
385
+ color: #8be9fd;
386
+ }
387
+
388
+ .status-msg.success {
389
+ background: rgba(80, 250, 123, 0.1);
390
+ border: 1px solid rgba(80, 250, 123, 0.3);
391
+ color: #50fa7b;
392
+ }
393
+
394
+ .status-msg.error {
395
+ background: rgba(255, 85, 85, 0.1);
396
+ border: 1px solid rgba(255, 85, 85, 0.3);
397
+ color: #ff5555;
398
+ }
399
+
400
+ /* Warning styles for viewing historical frames */
401
+ #container.is-historical {
402
+ border: 3px dashed var(--clr-warning, #ffb86c);
403
+ border-radius: var(--radius-md, 8px);
404
+ padding: 1.5rem;
405
+ position: relative;
406
+ background: rgba(255, 184, 108, 0.01);
407
+ }
408
+
409
+ .warning-banner {
410
+ background: rgba(255, 184, 108, 0.1);
411
+ border: 1.5px solid rgba(255, 184, 108, 0.35);
412
+ color: var(--clr-warning, #ffb86c);
413
+ padding: 0.8rem 1.2rem;
414
+ border-radius: var(--radius-md, 8px);
415
+ font-weight: 600;
416
+ font-size: 1rem;
417
+ margin-bottom: 1.5rem;
418
+ display: flex;
419
+ align-items: center;
420
+ gap: 0.5rem;
421
+ box-shadow: 0 4px 12px rgba(255, 184, 108, 0.05);
422
+ animation: pulse-border 2s infinite alternate;
423
+ }
424
+
425
+ @keyframes pulse-border {
426
+ 0% {
427
+ border-color: rgba(255, 184, 108, 0.2);
428
+ box-shadow: 0 4px 12px rgba(255, 184, 108, 0.02);
429
+ }
430
+ 100% {
431
+ border-color: rgba(255, 184, 108, 0.5);
432
+ box-shadow: 0 4px 16px rgba(255, 184, 108, 0.08);
433
+ }
434
+ }
435
+
436
+ .sso-actions {
437
+ display: flex;
438
+ gap: 1rem;
439
+ margin-top: 1rem;
440
+ flex-wrap: wrap;
441
+ }
442
+
443
+ .sso-btn {
444
+ flex: 1;
445
+ min-width: 200px;
446
+ display: inline-flex;
447
+ justify-content: center;
448
+ align-items: center;
449
+ gap: 0.5rem;
450
+ padding: 0.75rem 1.25rem;
451
+ font-weight: 600;
452
+ }
453
+
454
+ .sso-btn.google {
455
+ background: #4285F4;
456
+ border-color: #4285F4;
457
+ color: #ffffff;
458
+ }
459
+
460
+ .sso-btn.google:hover {
461
+ background: #357ae8;
462
+ }
463
+
464
+ .sso-btn.github {
465
+ background: #333333;
466
+ border-color: #444444;
467
+ color: #ffffff;
468
+ }
469
+
470
+ .sso-btn.github:hover {
471
+ background: #444444;
472
+ }