@koehler8/cms-ext-crypto 1.0.0-beta.4

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/components/CommunityStrip.vue +655 -0
  4. package/components/CuriosityTeaser.vue +842 -0
  5. package/components/HeaderWalletAction.vue +398 -0
  6. package/components/HeroPresale.vue +778 -0
  7. package/components/PercentDoughnut.vue +249 -0
  8. package/components/Presale.vue +507 -0
  9. package/components/PresaleAdmin.vue +1259 -0
  10. package/components/PresaleFaq.vue +95 -0
  11. package/components/ProgressFomo.vue +766 -0
  12. package/components/SocialProofFeed.vue +585 -0
  13. package/components/Tokenomics.vue +617 -0
  14. package/components/Trust.vue +123 -0
  15. package/components/TrustBar.vue +619 -0
  16. package/components/presale/BonusIncentive.vue +476 -0
  17. package/components/presale/Buy.vue +5388 -0
  18. package/components/presale/CountdownTimer.vue +326 -0
  19. package/components/presale/FirstTimeOnboarding.vue +443 -0
  20. package/components/presale/FuseMeter.vue +276 -0
  21. package/components/presale/HoldersBenefits.vue +135 -0
  22. package/components/presale/MomentumCard.vue +163 -0
  23. package/components/presale/PresaleFaqContent.vue +393 -0
  24. package/components/presale/PriceTimeline.vue +143 -0
  25. package/components/presale/Stake.vue +1415 -0
  26. package/components/presale/Status.vue +1113 -0
  27. package/components/presale/StatusMetric.vue +336 -0
  28. package/components/presale/StatusProgressBar.vue +98 -0
  29. package/components/presale/TrustSignals.vue +595 -0
  30. package/components/presale/buyAnalytics.js +58 -0
  31. package/components/presale/buyAssets.js +75 -0
  32. package/components/presale/buyTextHelpers.js +582 -0
  33. package/components/presale/priceSnapshotCache.js +72 -0
  34. package/components/presale/useBuyContentConfig.js +643 -0
  35. package/components/presale/useBuyOnboarding.js +338 -0
  36. package/components/presale/useBuyTransaction.js +464 -0
  37. package/components/presale/useBuyWallet.js +509 -0
  38. package/components/presale/useFomoProgress.js +578 -0
  39. package/components/presale/walletBalanceHelper.js +47 -0
  40. package/composables/usePresaleContext.js +24 -0
  41. package/content.defaults.json +171 -0
  42. package/extension.config.json +116 -0
  43. package/index.js +8 -0
  44. package/package.json +47 -0
  45. package/plugins/appKit.js +261 -0
  46. package/setup.js +29 -0
  47. package/stores/presale.js +70 -0
  48. package/utils/presaleContracts.js +69 -0
  49. package/utils/scrollToPresale.js +21 -0
  50. package/utils/tokenFormat.js +21 -0
  51. package/utils/walletTracking.js +175 -0
@@ -0,0 +1,842 @@
1
+ <template>
2
+ <section
3
+ v-if="isEnabled"
4
+ class="curiosity-teaser"
5
+ :aria-labelledby="headingId"
6
+ data-analytics-section="curiosity_teaser"
7
+ >
8
+ <SbCard class="curiosity-teaser__card">
9
+ <p v-if="eyebrow" class="curiosity-teaser__eyebrow">{{ eyebrow }}</p>
10
+ <h2 class="curiosity-teaser__headline" :id="headingId">
11
+ {{ headline }}
12
+ </h2>
13
+ <p v-if="description" class="curiosity-teaser__description">
14
+ {{ description }}
15
+ </p>
16
+ <p
17
+ v-if="disclaimer"
18
+ class="curiosity-teaser__disclaimer"
19
+ :id="disclaimerId"
20
+ >
21
+ {{ disclaimer }}
22
+ </p>
23
+ <div class="curiosity-teaser__actions">
24
+ <button
25
+ v-if="ctaMode === 'modal'"
26
+ type="button"
27
+ class="curiosity-teaser__cta curiosity-teaser__cta--secondary"
28
+ @click="openModal"
29
+ :aria-controls="dialogId"
30
+ :aria-expanded="isModalOpen"
31
+ :aria-describedby="disclaimer ? disclaimerId : undefined"
32
+ >
33
+ {{ ctaText }}
34
+ </button>
35
+ <a
36
+ v-else-if="ctaMode === 'link' && ctaHref"
37
+ class="curiosity-teaser__cta curiosity-teaser__cta--secondary curiosity-teaser__cta--link"
38
+ :href="ctaHref"
39
+ :target="ctaTarget"
40
+ rel="noopener"
41
+ @click="handlePrimaryLinkClick"
42
+ >
43
+ {{ ctaText }}
44
+ </a>
45
+ </div>
46
+ <div v-if="communityLinks.length" class="curiosity-teaser__community">
47
+ <p v-if="communityTitle" class="curiosity-teaser__community-title">
48
+ {{ communityTitle }}
49
+ </p>
50
+ <ul class="curiosity-teaser__community-list">
51
+ <li
52
+ v-for="link in communityLinks"
53
+ :key="link.id"
54
+ class="curiosity-teaser__community-item"
55
+ >
56
+ <a
57
+ :href="link.href"
58
+ class="curiosity-teaser__community-link"
59
+ :target="link.external ? '_blank' : undefined"
60
+ :rel="link.external ? 'noopener noreferrer' : undefined"
61
+ :aria-label="link.ariaLabel"
62
+ @click="handleCommunityLinkClick(link)"
63
+ >
64
+ <span
65
+ v-if="link.icon"
66
+ class="curiosity-teaser__community-icon"
67
+ aria-hidden="true"
68
+ >
69
+ {{ link.icon }}
70
+ </span>
71
+ <span class="curiosity-teaser__community-text">
72
+ {{ link.text }}
73
+ </span>
74
+ <span v-if="link.external" class="sr-only">
75
+ (opens in a new tab)
76
+ </span>
77
+ </a>
78
+ </li>
79
+ </ul>
80
+ </div>
81
+ </SbCard>
82
+
83
+ <teleport to="body">
84
+ <div
85
+ v-if="ctaMode === 'modal' && isModalOpen"
86
+ class="curiosity-modal"
87
+ @keydown.esc.prevent.stop="closeModal"
88
+ >
89
+ <div class="curiosity-modal__backdrop" @click.self="closeModal">
90
+ <div
91
+ class="curiosity-modal__dialog"
92
+ role="dialog"
93
+ aria-modal="true"
94
+ :aria-labelledby="dialogTitleId"
95
+ :aria-describedby="modalLead ? dialogDescriptionId : undefined"
96
+ :id="dialogId"
97
+ tabindex="-1"
98
+ ref="dialogRef"
99
+ >
100
+ <button
101
+ type="button"
102
+ class="curiosity-modal__close"
103
+ @click="closeModal"
104
+ aria-label="Close teaser details"
105
+ >
106
+ <span aria-hidden="true">&times;</span>
107
+ </button>
108
+ <h3 class="curiosity-modal__title" :id="dialogTitleId">
109
+ {{ modalTitle }}
110
+ </h3>
111
+ <p
112
+ v-if="modalLead"
113
+ class="curiosity-modal__lead"
114
+ :id="dialogDescriptionId"
115
+ >
116
+ {{ modalLead }}
117
+ </p>
118
+ <ul v-if="modalHighlights.length" class="curiosity-modal__list">
119
+ <li
120
+ v-for="item in modalHighlights"
121
+ :key="item.id"
122
+ class="curiosity-modal__item"
123
+ >
124
+ <span
125
+ v-if="item.icon"
126
+ class="curiosity-modal__item-icon"
127
+ aria-hidden="true"
128
+ >
129
+ {{ item.icon }}
130
+ </span>
131
+ <div class="curiosity-modal__item-copy">
132
+ <p class="curiosity-modal__item-title">{{ item.title }}</p>
133
+ <p v-if="item.body" class="curiosity-modal__item-body">
134
+ {{ item.body }}
135
+ </p>
136
+ </div>
137
+ </li>
138
+ </ul>
139
+ <div v-if="rewardCode" class="curiosity-modal__code">
140
+ <span class="curiosity-modal__code-label">{{ rewardCode.label }}</span>
141
+ <code class="curiosity-modal__code-value">{{ rewardCode.value }}</code>
142
+ <p v-if="rewardCode.description" class="curiosity-modal__code-note">
143
+ {{ rewardCode.description }}
144
+ </p>
145
+ </div>
146
+ <p v-if="modalFootnote" class="curiosity-modal__footnote">
147
+ {{ modalFootnote }}
148
+ </p>
149
+ <a
150
+ v-if="modalCta.href && modalCta.text"
151
+ :href="modalCta.href"
152
+ class="curiosity-modal__cta"
153
+ :target="modalCta.external ? '_blank' : undefined"
154
+ rel="noopener"
155
+ @click="handleModalCtaClick"
156
+ >
157
+ {{ modalCta.text }}
158
+ </a>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ </teleport>
163
+ </section>
164
+ </template>
165
+
166
+ <script setup>
167
+ import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
168
+ import { trackEvent, trackFunnelEvent } from '@koehler8/cms/utils/analytics';
169
+ import SbCard from '@koehler8/cms/components/ui/SbCard.vue';
170
+
171
+ const pageContent = inject('pageContent', ref({}));
172
+
173
+ const uniqueId = `curiosity-${Math.random().toString(36).slice(2, 9)}`;
174
+
175
+ const rawConfig = computed(() => pageContent.value?.curiosityTeaser || {});
176
+
177
+ const sanitizeCopy = (value) => {
178
+ if (typeof value !== 'string') return '';
179
+ return value.trim();
180
+ };
181
+
182
+ const isEnabled = computed(() => rawConfig.value?.enabled !== false && hasMeaningfulContent(rawConfig.value));
183
+ const eyebrow = computed(() => sanitizeCopy(rawConfig.value?.eyebrow));
184
+ const headline = computed(() => sanitizeCopy(rawConfig.value?.headline) || "Curious about what's next?");
185
+ const description = computed(() => sanitizeCopy(rawConfig.value?.description));
186
+ const disclaimer = computed(() => sanitizeCopy(rawConfig.value?.disclaimer));
187
+
188
+ const ctaText = computed(() => sanitizeCopy(rawConfig.value?.cta?.text) || 'Peek behind the curtain');
189
+ const ctaMode = computed(() => {
190
+ const mode = sanitizeCopy(rawConfig.value?.cta?.mode).toLowerCase();
191
+ if (mode === 'link' && sanitizeCopy(rawConfig.value?.cta?.href)) {
192
+ return 'link';
193
+ }
194
+ if (rawConfig.value?.modal) {
195
+ return 'modal';
196
+ }
197
+ if (sanitizeCopy(rawConfig.value?.cta?.href)) {
198
+ return 'link';
199
+ }
200
+ return 'modal';
201
+ });
202
+ const ctaHref = computed(() => {
203
+ if (ctaMode.value !== 'link') return '';
204
+ const href = sanitizeCopy(rawConfig.value?.cta?.href);
205
+ return href || '';
206
+ });
207
+ const ctaTarget = computed(() => (rawConfig.value?.cta?.external ? '_blank' : undefined));
208
+ const communityTitle = computed(() => sanitizeCopy(rawConfig.value?.community?.title));
209
+ const communityLinks = computed(() => normalizeCommunityLinks(rawConfig.value?.community?.links));
210
+
211
+ const modalTitle = computed(() => sanitizeCopy(rawConfig.value?.modal?.title) || headline.value);
212
+ const modalLead = computed(() => sanitizeCopy(rawConfig.value?.modal?.lead || rawConfig.value?.modal?.description));
213
+ const modalFootnote = computed(() => sanitizeCopy(rawConfig.value?.modal?.footnote));
214
+ const modalHighlights = computed(() => normalizeHighlights(rawConfig.value?.modal?.highlights));
215
+ const rewardCode = computed(() => normalizeReward(rawConfig.value?.modal?.rewardCode));
216
+ const modalCta = computed(() => normalizeModalCta(rawConfig.value?.modal?.cta));
217
+
218
+ const headingId = `${uniqueId}-heading`;
219
+ const disclaimerId = `${uniqueId}-note`;
220
+ const dialogId = `${uniqueId}-dialog`;
221
+ const dialogTitleId = `${uniqueId}-dialog-title`;
222
+ const dialogDescriptionId = `${uniqueId}-dialog-description`;
223
+
224
+ const isModalOpen = ref(false);
225
+ const dialogRef = ref(null);
226
+ const focusableSelector =
227
+ 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])';
228
+
229
+ function trackSecretDropInteraction(trigger) {
230
+ trackFunnelEvent('secret_drop_peek', {
231
+ source: 'curiosity_teaser',
232
+ trigger,
233
+ mode: ctaMode.value,
234
+ cta_text: ctaText.value,
235
+ });
236
+ }
237
+
238
+ function handlePrimaryLinkClick() {
239
+ trackSecretDropInteraction('link_click');
240
+ const href = ctaHref.value || '';
241
+ const text = ctaText.value || '';
242
+ const hrefLower = href.toLowerCase();
243
+ const textLower = text.toLowerCase();
244
+ if (hrefLower.includes('playbook') || textLower.includes('playbook')) {
245
+ trackFunnelEvent('playbook_view', {
246
+ source: 'curiosity_primary_cta',
247
+ href,
248
+ label: text,
249
+ });
250
+ }
251
+ }
252
+
253
+ function handleCommunityLinkClick(link) {
254
+ const href = link?.href || '';
255
+ trackEvent('curiosity_teaser_community_click', {
256
+ id: link?.id || '',
257
+ href,
258
+ });
259
+ const hrefLower = href.toLowerCase();
260
+ if (hrefLower.includes('t.me') || hrefLower.includes('telegram')) {
261
+ trackFunnelEvent('social_telegram_click', {
262
+ source: 'curiosity_teaser',
263
+ href,
264
+ label: link?.text || '',
265
+ });
266
+ } else if (hrefLower.includes('twitter') || hrefLower.includes('x.com')) {
267
+ trackFunnelEvent('social_twitter_click', {
268
+ source: 'curiosity_teaser',
269
+ href,
270
+ label: link?.text || '',
271
+ });
272
+ }
273
+ }
274
+
275
+ function handleModalCtaClick() {
276
+ const href = modalCta.value?.href || '';
277
+ const text = modalCta.value?.text || '';
278
+ if (!href && !text) return;
279
+ trackEvent('curiosity_modal_cta_click', {
280
+ href,
281
+ label: text,
282
+ });
283
+ const hrefLower = href.toLowerCase();
284
+ const textLower = text.toLowerCase();
285
+ if (hrefLower.includes('playbook') || textLower.includes('playbook')) {
286
+ trackFunnelEvent('playbook_view', {
287
+ source: 'curiosity_modal_cta',
288
+ href,
289
+ label: text,
290
+ });
291
+ }
292
+ }
293
+
294
+ function hasMeaningfulContent(config) {
295
+ if (!config || typeof config !== 'object') return false;
296
+ return Boolean(sanitizeCopy(config.headline) || sanitizeCopy(config.description) || sanitizeCopy(config.cta?.text));
297
+ }
298
+
299
+ function normalizeHighlights(entries) {
300
+ const items = Array.isArray(entries) ? entries : [];
301
+ return items
302
+ .map((entry, index) => {
303
+ if (!entry || typeof entry !== 'object') return null;
304
+ const title = sanitizeCopy(entry.title);
305
+ const body = sanitizeCopy(entry.body);
306
+ const icon = sanitizeCopy(entry.icon);
307
+ if (!title && !body) return null;
308
+ return {
309
+ id: entry.id || `highlight-${index}`,
310
+ title: title || body,
311
+ body,
312
+ icon: icon || '',
313
+ };
314
+ })
315
+ .filter(Boolean);
316
+ }
317
+
318
+ function normalizeReward(rawReward) {
319
+ if (!rawReward || typeof rawReward !== 'object') return null;
320
+ const value = sanitizeCopy(rawReward.value);
321
+ if (!value) return null;
322
+ return {
323
+ label: sanitizeCopy(rawReward.label) || 'Whisper code',
324
+ value,
325
+ description: sanitizeCopy(rawReward.description),
326
+ };
327
+ }
328
+
329
+ function normalizeModalCta(rawCta) {
330
+ if (!rawCta || typeof rawCta !== 'object') return { text: '', href: '' };
331
+ const text = sanitizeCopy(rawCta.text);
332
+ const href = sanitizeCopy(rawCta.href);
333
+ if (!text || !href) {
334
+ return { text: '', href: '' };
335
+ }
336
+ return {
337
+ text,
338
+ href,
339
+ external: Boolean(rawCta.external),
340
+ };
341
+ }
342
+
343
+ function normalizeCommunityLinks(rawLinks) {
344
+ const links = Array.isArray(rawLinks) ? rawLinks : [];
345
+ return links
346
+ .map((entry, index) => {
347
+ if (!entry || typeof entry !== 'object') return null;
348
+ const text = sanitizeCopy(entry.text || entry.label);
349
+ const href = sanitizeCopy(entry.href);
350
+ if (!text || !href) return null;
351
+
352
+ const icon = sanitizeCopy(entry.icon);
353
+ const ariaLabel =
354
+ sanitizeCopy(entry.ariaLabel) ||
355
+ (entry.external !== false ? `${text} (opens in a new tab)` : text);
356
+
357
+ return {
358
+ id: sanitizeCopy(entry.id) || `community-link-${index}`,
359
+ text,
360
+ href,
361
+ icon,
362
+ external: entry.external !== false,
363
+ ariaLabel,
364
+ };
365
+ })
366
+ .filter(Boolean);
367
+ }
368
+
369
+ function openModal() {
370
+ if (ctaMode.value !== 'modal') return;
371
+ trackSecretDropInteraction('modal_open');
372
+ isModalOpen.value = true;
373
+ }
374
+
375
+ function closeModal() {
376
+ isModalOpen.value = false;
377
+ }
378
+
379
+ const trapFocus = (event) => {
380
+ if (!isModalOpen.value) return;
381
+ if (event.key !== 'Tab') return;
382
+ const dialogEl = dialogRef.value;
383
+ if (!dialogEl) return;
384
+ const focusable = dialogEl.querySelectorAll(focusableSelector);
385
+ if (focusable.length === 0) {
386
+ event.preventDefault();
387
+ return;
388
+ }
389
+ const first = focusable[0];
390
+ const last = focusable[focusable.length - 1];
391
+ const active = document.activeElement;
392
+ if (event.shiftKey) {
393
+ if (active === first || !dialogEl.contains(active)) {
394
+ event.preventDefault();
395
+ last.focus();
396
+ }
397
+ } else if (active === last) {
398
+ event.preventDefault();
399
+ first.focus();
400
+ }
401
+ };
402
+
403
+ watch(isModalOpen, (open) => {
404
+ if (typeof document === 'undefined') return;
405
+ if (open) {
406
+ document.addEventListener('keydown', trapFocus);
407
+ if (typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function') {
408
+ window.requestAnimationFrame(() => {
409
+ dialogRef.value?.focus();
410
+ });
411
+ } else {
412
+ dialogRef.value?.focus();
413
+ }
414
+ } else {
415
+ document.removeEventListener('keydown', trapFocus);
416
+ }
417
+ });
418
+
419
+ onMounted(() => {
420
+ if (typeof document === 'undefined') return;
421
+ if (isModalOpen.value) {
422
+ document.addEventListener('keydown', trapFocus);
423
+ }
424
+ });
425
+
426
+ onBeforeUnmount(() => {
427
+ if (typeof document === 'undefined') return;
428
+ document.removeEventListener('keydown', trapFocus);
429
+ });
430
+
431
+ watch(ctaMode, (mode) => {
432
+ if (mode !== 'modal') {
433
+ isModalOpen.value = false;
434
+ }
435
+ });
436
+ </script>
437
+
438
+ <style scoped>
439
+ .curiosity-teaser {
440
+ margin: 3.5rem auto 3rem;
441
+ padding: 3rem 1.5rem 0;
442
+ max-width: 58rem;
443
+ border-top: 1px solid color-mix(in srgb, var(--brand-fg-300, #a798b0) 18%, transparent);
444
+ }
445
+
446
+ @media (min-width: 992px) {
447
+ .curiosity-teaser {
448
+ margin: 4.5rem auto 4rem;
449
+ padding: 4rem 2rem 0;
450
+ }
451
+ }
452
+
453
+ .curiosity-teaser__card {
454
+ position: relative;
455
+ overflow: hidden;
456
+ color: #fdf5ff;
457
+ background: color-mix(in srgb, var(--brand-bg-900, #0a0a0d) 88%, transparent);
458
+ border: 1px solid rgba(255, 255, 255, 0.06);
459
+ border-radius: var(--brand-card-radius, 24px);
460
+ box-shadow: 0 16px 36px rgba(10, 8, 14, 0.46);
461
+ }
462
+
463
+ .curiosity-teaser__card::before {
464
+ content: '';
465
+ position: absolute;
466
+ inset: 0;
467
+ background:
468
+ radial-gradient(circle at top right, rgba(255, 120, 216, 0.12), transparent 45%),
469
+ linear-gradient(145deg, rgba(39, 243, 255, 0.05), transparent 55%);
470
+ pointer-events: none;
471
+ }
472
+
473
+ .curiosity-teaser__card > * {
474
+ position: relative;
475
+ z-index: 1;
476
+ }
477
+
478
+ .curiosity-teaser__eyebrow {
479
+ margin: 0 0 0.75rem;
480
+ font-size: 0.8125rem;
481
+ font-weight: 600;
482
+ letter-spacing: 0.12em;
483
+ text-transform: uppercase;
484
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
485
+ color: rgba(255, 255, 255, 0.72);
486
+ }
487
+
488
+ .curiosity-teaser__headline {
489
+ margin: 0 0 1rem;
490
+ font-family: 'Space Grotesk', 'Inter', sans-serif;
491
+ font-size: clamp(2.25rem, 4vw, 3.5rem);
492
+ line-height: 1.1;
493
+ font-weight: 700;
494
+ }
495
+
496
+ .curiosity-teaser__description {
497
+ margin: 0 0 1.25rem;
498
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
499
+ font-size: clamp(1rem, 2.4vw, 1.125rem);
500
+ line-height: 1.5;
501
+ color: rgba(255, 255, 255, 0.82);
502
+ }
503
+
504
+ .curiosity-teaser__disclaimer {
505
+ margin: 0 0 1.5rem;
506
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
507
+ font-size: clamp(0.875rem, 2vw, 0.95rem);
508
+ color: rgba(255, 255, 255, 0.65);
509
+ }
510
+
511
+ .curiosity-teaser__actions {
512
+ display: flex;
513
+ flex-wrap: wrap;
514
+ gap: 1rem;
515
+ justify-content: flex-start;
516
+ }
517
+
518
+ .curiosity-teaser__community {
519
+ margin-top: 2.25rem;
520
+ padding-top: 1.75rem;
521
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
522
+ }
523
+
524
+ .curiosity-teaser__community-title {
525
+ margin: 0 0 1rem;
526
+ font-family: 'Space Grotesk', 'Inter', sans-serif;
527
+ font-size: clamp(1.05rem, 2.4vw, 1.25rem);
528
+ letter-spacing: 0.14em;
529
+ text-transform: uppercase;
530
+ color: rgba(255, 255, 255, 0.68);
531
+ }
532
+
533
+ .curiosity-teaser__community-list {
534
+ display: flex;
535
+ flex-wrap: wrap;
536
+ gap: 0.75rem;
537
+ margin: 0;
538
+ padding: 0;
539
+ list-style: none;
540
+ }
541
+
542
+ .curiosity-teaser__community-item {
543
+ margin: 0;
544
+ }
545
+
546
+ .curiosity-teaser__community-link {
547
+ display: inline-flex;
548
+ align-items: center;
549
+ gap: 0.5rem;
550
+ padding: 0.25rem 0;
551
+ border-radius: 0;
552
+ background: transparent;
553
+ color: rgba(255, 255, 255, 0.72);
554
+ font-weight: 500;
555
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
556
+ text-decoration: none;
557
+ transition: color 0.2s ease, text-decoration-color 0.2s ease;
558
+ }
559
+
560
+ .curiosity-teaser__community-link:hover,
561
+ .curiosity-teaser__community-link:focus {
562
+ color: var(--brand-electric-blue, #27f3ff);
563
+ text-decoration: underline;
564
+ text-decoration-color: rgba(39, 243, 255, 0.4);
565
+ }
566
+
567
+ .curiosity-teaser__community-link:focus {
568
+ outline: 2px solid rgba(39, 243, 255, 0.35);
569
+ outline-offset: 3px;
570
+ }
571
+
572
+ .curiosity-teaser__community-icon {
573
+ display: inline-flex;
574
+ font-size: 1.1rem;
575
+ }
576
+
577
+ .curiosity-teaser__community-text {
578
+ font-size: 0.95rem;
579
+ letter-spacing: 0.04em;
580
+ }
581
+
582
+ .sr-only {
583
+ position: absolute;
584
+ width: 1px;
585
+ height: 1px;
586
+ padding: 0;
587
+ margin: -1px;
588
+ overflow: hidden;
589
+ clip: rect(0, 0, 0, 0);
590
+ border: 0;
591
+ }
592
+
593
+ .curiosity-teaser__cta {
594
+ display: inline-flex;
595
+ align-items: center;
596
+ justify-content: center;
597
+ min-width: 10.5rem;
598
+ padding: 0.75rem 1.65rem;
599
+ border-radius: var(--brand-button-radius, 14px);
600
+ border: 1px solid rgba(154, 46, 255, 0.32);
601
+ background: color-mix(in srgb, var(--brand-bg-900, #0a0a0d) 78%, transparent);
602
+ color: color-mix(in srgb, var(--brand-electric-blue, #27f3ff) 78%, #ffffff 12%);
603
+ font-weight: 600;
604
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
605
+ letter-spacing: 0.1em;
606
+ text-transform: uppercase;
607
+ box-shadow: none;
608
+ cursor: pointer;
609
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
610
+ text-decoration: none;
611
+ }
612
+
613
+ .curiosity-teaser__cta:hover,
614
+ .curiosity-teaser__cta:focus {
615
+ transform: translateY(-1px);
616
+ background: color-mix(in srgb, var(--brand-electric-blue, #27f3ff) 12%, transparent);
617
+ box-shadow: 0 14px 28px rgba(39, 243, 255, 0.18);
618
+ }
619
+
620
+ .curiosity-teaser__cta--link {
621
+ border-color: rgba(154, 46, 255, 0.24);
622
+ background: transparent;
623
+ color: rgba(255, 255, 255, 0.78);
624
+ }
625
+
626
+ .curiosity-teaser__cta--link:hover,
627
+ .curiosity-teaser__cta--link:focus {
628
+ color: var(--brand-electric-blue, #27f3ff);
629
+ border-color: rgba(39, 243, 255, 0.45);
630
+ }
631
+
632
+ .curiosity-teaser__cta--link:focus-visible {
633
+ outline: 2px solid rgba(39, 243, 255, 0.4);
634
+ outline-offset: 3px;
635
+ }
636
+
637
+ .curiosity-teaser__cta--secondary {
638
+ color: rgba(255, 255, 255, 0.82);
639
+ }
640
+
641
+ .curiosity-teaser__cta:focus-visible {
642
+ outline: 2px solid rgba(39, 243, 255, 0.35);
643
+ outline-offset: 3px;
644
+ }
645
+
646
+ .curiosity-modal {
647
+ position: fixed;
648
+ inset: 0;
649
+ z-index: 10000;
650
+ }
651
+
652
+ .curiosity-modal__backdrop {
653
+ display: flex;
654
+ align-items: center;
655
+ justify-content: center;
656
+ width: 100%;
657
+ height: 100%;
658
+ background: rgba(7, 5, 12, 0.75);
659
+ padding: 1.25rem;
660
+ }
661
+
662
+ .curiosity-modal__dialog {
663
+ position: relative;
664
+ max-width: 34rem;
665
+ width: 100%;
666
+ padding: 2.5rem 2rem 2rem;
667
+ border-radius: var(--brand-modal-radius, 24px);
668
+ background: linear-gradient(150deg, rgba(10, 10, 13, 0.96), rgba(20, 18, 22, 0.9));
669
+ color: rgba(240, 234, 243, 0.95);
670
+ box-shadow: var(--brand-modal-shadow, 0 8px 24px rgba(217, 22, 75, 0.18));
671
+ outline: none;
672
+ }
673
+
674
+ .curiosity-modal__close {
675
+ position: absolute;
676
+ top: 1rem;
677
+ right: 1rem;
678
+ background: transparent;
679
+ border: none;
680
+ color: rgba(255, 255, 255, 0.72);
681
+ font-size: 1.5rem;
682
+ cursor: pointer;
683
+ line-height: 1;
684
+ }
685
+
686
+ .curiosity-modal__close:hover,
687
+ .curiosity-modal__close:focus {
688
+ color: var(--brand-neon-pink, #ff2d86);
689
+ }
690
+
691
+ .curiosity-modal__title {
692
+ margin: 0 0 1rem;
693
+ font-family: 'Space Grotesk', 'Inter', sans-serif;
694
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
695
+ line-height: 1.1;
696
+ font-weight: 700;
697
+ }
698
+
699
+ .curiosity-modal__lead {
700
+ margin: 0 0 1.5rem;
701
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
702
+ font-size: clamp(0.95rem, 2.3vw, 1.05rem);
703
+ color: rgba(255, 255, 255, 0.78);
704
+ }
705
+
706
+ .curiosity-modal__list {
707
+ margin: 0 0 1.75rem;
708
+ padding: 0;
709
+ list-style: none;
710
+ display: grid;
711
+ gap: 1rem;
712
+ }
713
+
714
+ .curiosity-modal__item {
715
+ display: grid;
716
+ grid-template-columns: auto 1fr;
717
+ gap: 0.75rem;
718
+ align-items: flex-start;
719
+ padding: 1rem;
720
+ border-radius: var(--brand-radius-md, 14px);
721
+ background: rgba(255, 255, 255, 0.05);
722
+ }
723
+
724
+ .curiosity-modal__item-icon {
725
+ font-size: 1.5rem;
726
+ }
727
+
728
+ .curiosity-modal__item-title {
729
+ margin: 0 0 0.35rem;
730
+ font-size: 1.0625rem;
731
+ font-family: 'Space Grotesk', 'Inter', sans-serif;
732
+ font-weight: 600;
733
+ }
734
+
735
+ .curiosity-modal__item-body {
736
+ margin: 0;
737
+ font-size: clamp(0.9rem, 2.1vw, 0.98rem);
738
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
739
+ color: rgba(255, 255, 255, 0.75);
740
+ }
741
+
742
+ .curiosity-modal__code {
743
+ margin: 0 0 1.5rem;
744
+ padding: 1.25rem;
745
+ border-radius: var(--brand-radius-md, 14px);
746
+ border: 1px dashed rgba(39, 243, 255, 0.35);
747
+ background: rgba(39, 243, 255, 0.08);
748
+ }
749
+
750
+ .curiosity-modal__code-label {
751
+ display: block;
752
+ margin-bottom: 0.5rem;
753
+ font-size: 0.875rem;
754
+ text-transform: uppercase;
755
+ letter-spacing: 0.08em;
756
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
757
+ color: rgba(201, 191, 208, 0.85);
758
+ }
759
+
760
+ .curiosity-modal__code-value {
761
+ display: inline-block;
762
+ padding: 0.35rem 0.75rem;
763
+ border-radius: 999px;
764
+ background: rgba(255, 45, 134, 0.18);
765
+ font-size: 1.125rem;
766
+ font-weight: 700;
767
+ font-family: 'Space Grotesk', 'Inter', sans-serif;
768
+ letter-spacing: 0.04em;
769
+ }
770
+
771
+ .curiosity-modal__code-note {
772
+ margin: 0.75rem 0 0;
773
+ font-size: clamp(0.875rem, 2.1vw, 0.95rem);
774
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
775
+ color: rgba(255, 255, 255, 0.72);
776
+ }
777
+
778
+ .curiosity-modal__footnote {
779
+ margin: 0 0 1.5rem;
780
+ font-size: clamp(0.85rem, 2vw, 0.95rem);
781
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
782
+ color: rgba(255, 255, 255, 0.65);
783
+ }
784
+
785
+ .curiosity-modal__cta {
786
+ display: inline-flex;
787
+ align-items: center;
788
+ justify-content: center;
789
+ padding: 0.9rem 1.75rem;
790
+ border-radius: var(--brand-button-radius, 14px);
791
+ background: var(
792
+ --brand-primary-cta-gradient,
793
+ linear-gradient(135deg, #ff2d86 0%, #9a2eff 55%, #27f3ff 100%)
794
+ );
795
+ color: var(--brand-primary-cta-text, #0a0a0d);
796
+ font-weight: 700;
797
+ font-family: 'Inter', 'Helvetica Neue', sans-serif;
798
+ text-decoration: none;
799
+ box-shadow: var(--brand-primary-cta-shadow, 0 18px 40px rgba(255, 45, 134, 0.45));
800
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
801
+ }
802
+
803
+ .curiosity-modal__cta:hover,
804
+ .curiosity-modal__cta:focus {
805
+ transform: translateY(-1px);
806
+ box-shadow: var(--brand-primary-cta-hover-shadow, 0 20px 44px rgba(255, 45, 134, 0.55));
807
+ }
808
+
809
+ @media (max-width: 640px) {
810
+ .curiosity-teaser {
811
+ padding: 2.5rem 1rem;
812
+ }
813
+
814
+ .curiosity-teaser__card {
815
+ padding: 1.75rem;
816
+ }
817
+
818
+ .curiosity-teaser__actions {
819
+ flex-direction: column;
820
+ align-items: stretch;
821
+ }
822
+
823
+ .curiosity-teaser__community-list {
824
+ flex-direction: column;
825
+ }
826
+
827
+ .curiosity-teaser__community-link {
828
+ justify-content: center;
829
+ }
830
+
831
+ .curiosity-modal__dialog {
832
+ padding: 2rem 1.5rem 1.5rem;
833
+ }
834
+ }
835
+
836
+ @media (prefers-reduced-motion: reduce) {
837
+ .curiosity-teaser__cta,
838
+ .curiosity-modal__cta {
839
+ transition: none;
840
+ }
841
+ }
842
+ </style>