@taskon/widget-react 0.0.1-beta.5 → 0.0.1-beta.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 (65) hide show
  1. package/README.md +61 -47
  2. package/dist/CommunityTaskList.css +9 -1
  3. package/dist/EligibilityInfo.css +48 -75
  4. package/dist/LeaderboardWidget.css +73 -71
  5. package/dist/PageBuilder.css +5 -0
  6. package/dist/Quest.css +18 -14
  7. package/dist/TaskOnProvider.css +289 -0
  8. package/dist/ThemeProvider.css +227 -0
  9. package/dist/UserCenterWidget.css +6 -6
  10. package/dist/UserCenterWidget2.css +1388 -1621
  11. package/dist/{dynamic-import-helper.css → WidgetShell.css} +0 -227
  12. package/dist/chunks/{CommunityTaskList-CrMvOB8w.js → CommunityTaskList-D0uVD8wD.js} +393 -208
  13. package/dist/chunks/{EligibilityInfo-Beww12QX.js → EligibilityInfo-Cf6hx9-a.js} +459 -679
  14. package/dist/chunks/{LeaderboardWidget-DwuSpVl0.js → LeaderboardWidget-DyoiiNS6.js} +274 -252
  15. package/dist/chunks/{PageBuilder-DsX6Tv0N.js → PageBuilder-DoAFPm6-.js} +5 -5
  16. package/dist/chunks/{Quest-CuD2LElS.js → Quest-ySZlYd4u.js} +74 -57
  17. package/dist/chunks/TaskOnProvider-CxtFIs3n.js +2072 -0
  18. package/dist/chunks/{dynamic-import-helper-WmIF58Sb.js → ThemeProvider-CulHkqqY.js} +1282 -555
  19. package/dist/chunks/UserCenterWidget-BJsc_GSZ.js +3246 -0
  20. package/dist/chunks/{UserCenterWidget-CvU6K4AC.js → UserCenterWidget-STq8kpV4.js} +1174 -1386
  21. package/dist/chunks/WidgetShell-8xn-Jivw.js +659 -0
  22. package/dist/chunks/communitytask-es-CBNnS4o2.js +521 -0
  23. package/dist/chunks/communitytask-ja-GRf9cbdx.js +521 -0
  24. package/dist/chunks/communitytask-ko-Bf24PQKI.js +521 -0
  25. package/dist/chunks/{communitytask-ru-DhySaZL8.js → communitytask-ru-CZm2CPoV.js} +211 -1
  26. package/dist/chunks/leaderboardwidget-es-vKjrjQaz.js +146 -0
  27. package/dist/chunks/leaderboardwidget-ja-Q6u0HxKG.js +146 -0
  28. package/dist/chunks/leaderboardwidget-ko-CG6SWgxf.js +146 -0
  29. package/dist/chunks/leaderboardwidget-ru-DCcHcJGz.js +146 -0
  30. package/dist/chunks/{quest-es-D-b5xcme.js → quest-es-Dyyy0zaw.js} +8 -93
  31. package/dist/chunks/{quest-ja-Dxd2vqBF.js → quest-ja-Depog33y.js} +8 -93
  32. package/dist/chunks/{quest-ko-CSmRWgK_.js → quest-ko-BMu3uRQJ.js} +8 -93
  33. package/dist/chunks/{quest-ru-CkEKv1_F.js → quest-ru-xne814Rw.js} +8 -93
  34. package/dist/chunks/useIsMobile-D6Ybur-6.js +30 -0
  35. package/dist/chunks/useToast-BGJhd3BX.js +93 -0
  36. package/dist/chunks/usercenter-es-Dz3Wp2vV.js +512 -0
  37. package/dist/chunks/usercenter-ja-CKE4DJC6.js +512 -0
  38. package/dist/chunks/usercenter-ko-Dtpkn2qb.js +512 -0
  39. package/dist/chunks/usercenter-ru-DnBGee45.js +512 -0
  40. package/dist/community-task.d.ts +0 -390
  41. package/dist/community-task.js +2 -7
  42. package/dist/core.d.ts +38 -20
  43. package/dist/core.js +9 -10
  44. package/dist/index.d.ts +86 -709
  45. package/dist/index.js +22 -28
  46. package/dist/leaderboard.d.ts +0 -498
  47. package/dist/leaderboard.js +2 -16
  48. package/dist/page-builder.js +1 -1
  49. package/dist/quest.d.ts +0 -971
  50. package/dist/quest.js +2 -7
  51. package/dist/user-center.d.ts +0 -1610
  52. package/dist/user-center.js +2 -494
  53. package/package.json +2 -2
  54. package/dist/chunks/TaskOnProvider-xUeP2Nro.js +0 -1243
  55. package/dist/chunks/ThemeProvider-Bt4UZ33y.js +0 -1334
  56. package/dist/chunks/UserCenterWidget-CB0hnj-L.js +0 -3230
  57. package/dist/chunks/communitytask-es-1zawvXEX.js +0 -311
  58. package/dist/chunks/communitytask-ja-CmW6nP-L.js +0 -311
  59. package/dist/chunks/communitytask-ko-BD0hzQSi.js +0 -311
  60. package/dist/chunks/createLocaleLoader-BameiEhU.js +0 -65
  61. package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +0 -119
  62. package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +0 -119
  63. package/dist/chunks/useToast-CaRkylKe.js +0 -304
  64. package/dist/chunks/usercenter-ja-B2465c1O.js +0 -326
  65. package/dist/chunks/usercenter-ko-xAEYxqLg.js +0 -326
package/README.md CHANGED
@@ -23,7 +23,7 @@ import { QuestWidget } from "@taskon/widget-react/quest";
23
23
  const App = () => (
24
24
  <TaskOnProvider
25
25
  config={{
26
- apiKey: "your-api-key",
26
+ clientId: "your-client-id",
27
27
  }}
28
28
  >
29
29
  <YourApp />
@@ -62,7 +62,7 @@ import { QuestWidget } from "@taskon/widget-react/quest";
62
62
  const App = () => (
63
63
  <TaskOnProvider
64
64
  config={{
65
- apiKey: "your-api-key",
65
+ clientId: "your-client-id",
66
66
  }}
67
67
  >
68
68
  <YourApp />
@@ -103,7 +103,7 @@ const YourApp = () => {
103
103
 
104
104
  ```
105
105
  ┌─ TaskOnProvider ─────────────────────────────────────────┐
106
- │ config: { apiKey } │
106
+ │ config: { clientId } │
107
107
  │ Purpose: Authentication only │
108
108
  │ │
109
109
  │ ┌─ Mode A: Cloud Config ──────────────────────────────┐ │
@@ -128,12 +128,12 @@ const YourApp = () => {
128
128
 
129
129
  ## Security
130
130
 
131
- TaskOn uses **API Key** authentication to verify that widget requests come from authorized projects.
131
+ TaskOn uses **Client ID** authentication to verify that widget requests come from authorized projects.
132
132
 
133
- ### Step 1: Get API Key from TaskOn Dashboard
133
+ ### Step 1: Get Client ID from TaskOn Dashboard
134
134
 
135
135
  ```
136
- API Key: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)
136
+ Client ID: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)
137
137
  ```
138
138
 
139
139
  ### Step 2: Configure TaskOnProvider
@@ -141,7 +141,7 @@ API Key: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)
141
141
  ```tsx
142
142
  <TaskOnProvider
143
143
  config={{
144
- apiKey: "your-api-key",
144
+ clientId: "your-client-id",
145
145
  }}
146
146
  >
147
147
  <YourApp />
@@ -153,13 +153,13 @@ API Key: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)
153
153
  All API requests include:
154
154
 
155
155
  ```
156
- X-API-Key: your-api-key # Project authorization
156
+ X-API-Key: your-client-id # Project authorization
157
157
  Authorization: Bearer xxx # User authorization (after login)
158
158
  ```
159
159
 
160
160
  ### Security Best Practices
161
161
 
162
- 1. **Keep API Key secure** - Don't expose in public repositories
162
+ 1. **Keep Client ID secure** - Don't expose in public repositories
163
163
  2. **Use HTTPS** - All communication must be encrypted
164
164
 
165
165
  ## TaskOnProvider
@@ -177,8 +177,8 @@ The root provider component for authentication. Must wrap your application.
177
177
 
178
178
  ```typescript
179
179
  interface TaskOnProviderConfig {
180
- // Required: API Key for authentication (X-API-Key header)
181
- apiKey: string;
180
+ // Required: Client ID for authentication (X-API-Key header)
181
+ clientId: string;
182
182
 
183
183
  // Locale setting
184
184
  locale?: "en" | "ko" | "ja" | "ru" | "es"; // default: auto-detect
@@ -187,10 +187,13 @@ interface TaskOnProviderConfig {
187
187
  walletConfig?: {
188
188
  evmAdapter?: WalletAdapter; // Custom EVM wallet adapter
189
189
  solanaAdapter?: WalletAdapter; // Custom Solana wallet adapter
190
- disableAutoDetect?: boolean; // Disable auto-detection
191
190
  };
192
191
 
193
- // WalletConnect Project ID (required for WalletConnect support)
192
+ // WalletConnect Project ID
193
+ // Only needed when you design Web3 wallet login or wallet-based rewards
194
+ // (wallet binding, on-chain verification, NFT/token claiming, etc.)
195
+ // Optional; SDK has a built-in default project ID
196
+ // For production, strongly recommended to use your own project ID
194
197
  // Get your project ID at https://cloud.walletconnect.com
195
198
  walletConnectProjectId?: string;
196
199
 
@@ -216,7 +219,7 @@ interface TaskOnProviderConfig {
216
219
  ```tsx
217
220
  <TaskOnProvider
218
221
  config={{
219
- apiKey: "your-api-key",
222
+ clientId: "your-client-id",
220
223
  locale: "ko",
221
224
  }}
222
225
  >
@@ -233,7 +236,7 @@ const App = () => {
233
236
  const [locale, setLocale] = useState("en");
234
237
 
235
238
  return (
236
- <TaskOnProvider config={{ apiKey: "your-api-key", locale }}>
239
+ <TaskOnProvider config={{ clientId: "your-client-id", locale }}>
237
240
  <select value={locale} onChange={(e) => setLocale(e.target.value)}>
238
241
  <option value="en">English</option>
239
242
  <option value="ko">한국어</option>
@@ -379,7 +382,7 @@ light/dark.map > light/dark.seed (derived) > map > seed (derived) > default
379
382
  Nested ThemeProviders inherit from parent and can override specific values:
380
383
 
381
384
  ```tsx
382
- <TaskOnProvider config={{ apiKey: "your-api-key" }}>
385
+ <TaskOnProvider config={{ clientId: "your-client-id" }}>
383
386
  <ThemeProvider theme={{ mode: "light", seed: { colorPrimary: "#6366f1" } }}>
384
387
  <Header /> {/* light + primary #6366f1 */}
385
388
  <ThemeProvider theme={{ mode: "dark" }}>
@@ -521,13 +524,13 @@ Each widget documents its available parts in its own API reference.
521
524
 
522
525
  ```tsx
523
526
  // Example 1: Using cloud config (theme from Dashboard)
524
- <TaskOnProvider config={{ apiKey: 'your-api-key' }}>
527
+ <TaskOnProvider config={{ clientId: 'your-client-id' }}>
525
528
  <QuestWidget widgetId={123} />
526
529
  <TaskWidget widgetId={456} />
527
530
  </TaskOnProvider>
528
531
 
529
532
  // Example 2: Using local theme (no cloud config)
530
- <TaskOnProvider config={{ apiKey: 'your-api-key' }}>
533
+ <TaskOnProvider config={{ clientId: 'your-client-id' }}>
531
534
  <ThemeProvider theme={{ mode: 'dark', seed: { colorPrimary: '#6366f1' } }}>
532
535
  <QuestWidget />
533
536
  <TaskWidget />
@@ -535,7 +538,7 @@ Each widget documents its available parts in its own API reference.
535
538
  </TaskOnProvider>
536
539
 
537
540
  // Example 3: Different local themes for different areas
538
- <TaskOnProvider config={{ apiKey: 'your-api-key' }}>
541
+ <TaskOnProvider config={{ clientId: 'your-client-id' }}>
539
542
  <ThemeProvider theme={{ mode: 'light' }}>
540
543
  <TaskWidget />
541
544
  </ThemeProvider>
@@ -546,7 +549,7 @@ Each widget documents its available parts in its own API reference.
546
549
  </TaskOnProvider>
547
550
 
548
551
  // Example 4: Mixed - some with cloud config, some with local theme
549
- <TaskOnProvider config={{ apiKey: 'your-api-key' }}>
552
+ <TaskOnProvider config={{ clientId: 'your-client-id' }}>
550
553
  {/* Cloud config */}
551
554
  <QuestWidget widgetId={123} />
552
555
 
@@ -626,34 +629,44 @@ TaskOn provides flexible wallet integration options:
626
629
  | Setup | Behavior |
627
630
  | -------------- | ------------------------------------- |
628
631
  | Custom adapter | Uses your provided `WalletAdapter` |
629
- | Default | Uses built-in window.ethereum adapter |
632
+ | Default | Uses built-in wallet picker adapter |
630
633
 
631
634
  ### Custom Wallet Adapter (Recommended)
632
635
 
633
636
  If you want full control over wallet connection (e.g., using RainbowKit, Web3Modal), provide a custom adapter:
634
637
 
635
638
  ```tsx
639
+ import { useMemo } from "react";
636
640
  import { createWalletAdapter } from "./my-wallet-adapter";
637
641
 
638
- <TaskOnProvider
639
- config={{
640
- apiKey: "your-api-key",
641
- walletConfig: {
642
- evmAdapter: createWalletAdapter(),
643
- },
644
- }}
645
- >
646
- <App />
647
- </TaskOnProvider>;
642
+ const App = () => {
643
+ const evmAdapter = useMemo(() => createWalletAdapter(), []);
644
+
645
+ return (
646
+ <TaskOnProvider
647
+ config={{
648
+ clientId: "your-client-id",
649
+ walletConfig: {
650
+ evmAdapter,
651
+ },
652
+ }}
653
+ >
654
+ <MainContent />
655
+ </TaskOnProvider>
656
+ );
657
+ };
648
658
  ```
649
659
 
660
+ Note: keep `evmAdapter` reference stable (for example via `useMemo`) to avoid
661
+ re-creating adapters and resetting wallet state on every render.
662
+
650
663
  ### Built-in Wallet Support
651
664
 
652
- If no custom adapter is provided, TaskOn automatically uses `window.ethereum` to connect to browser wallets like MetaMask:
665
+ If no custom adapter is provided, TaskOn automatically uses built-in wallet picker flow:
653
666
 
654
667
  ```tsx
655
- // No wallet config needed - uses window.ethereum by default
656
- <TaskOnProvider config={{ apiKey: "your-api-key" }}>
668
+ // No wallet config needed
669
+ <TaskOnProvider config={{ clientId: "your-client-id" }}>
657
670
  <App />
658
671
  </TaskOnProvider>
659
672
  ```
@@ -664,23 +677,25 @@ When tasks require wallet binding (e.g., on-chain verification), TaskOn shows a
664
677
 
665
678
  **Desktop (without adapter):**
666
679
  - MetaMask
667
- - ONTO Wallet
668
680
  - Bitget Wallet
669
681
  - OKX Wallet
670
- - WalletConnect (requires `walletConnectProjectId`)
682
+ - WalletConnect (uses SDK default project ID if not configured; not recommended for production)
671
683
 
672
684
  **Mobile (non-Dapp browser):**
673
- - WalletConnect only (requires `walletConnectProjectId`)
685
+ - WalletConnect only (uses SDK default project ID if not configured; not recommended for production)
674
686
 
675
687
  **Mobile (Dapp browser / wallet app):**
676
688
  - Uses injected provider directly
677
689
 
690
+ Only configure `walletConnectProjectId` when your product needs Web3 wallet login
691
+ or wallet-based rewards (wallet binding, on-chain verification, NFT/token claiming).
692
+
678
693
  To enable WalletConnect in the dialog:
679
694
 
680
695
  ```tsx
681
696
  <TaskOnProvider
682
697
  config={{
683
- apiKey: "your-api-key",
698
+ clientId: "your-client-id",
684
699
  walletConnectProjectId: "your-project-id", // Get from cloud.walletconnect.com
685
700
  }}
686
701
  >
@@ -690,10 +705,10 @@ To enable WalletConnect in the dialog:
690
705
 
691
706
  ### Built-in Wallet Management
692
707
 
693
- If no external provider is detected, the widget uses its built-in wallet management. No configuration needed:
708
+ If no external adapter is provided, the widget uses built-in wallet management. No configuration needed:
694
709
 
695
710
  ```tsx
696
- <TaskOnProvider config={{ apiKey: "your-api-key" }}>
711
+ <TaskOnProvider config={{ clientId: "your-client-id" }}>
697
712
  <App /> {/* Widget handles wallet connection internally */}
698
713
  </TaskOnProvider>
699
714
  ```
@@ -707,9 +722,6 @@ interface WalletConfig {
707
722
 
708
723
  // Solana wallet adapter (highest priority)
709
724
  solanaAdapter?: WalletAdapter;
710
-
711
- // Disable auto-detection of external providers
712
- disableAutoDetect?: boolean;
713
725
  }
714
726
  ```
715
727
 
@@ -748,7 +760,7 @@ const App = () => {
748
760
  return (
749
761
  <TaskOnProvider
750
762
  config={{
751
- apiKey: "your-api-key",
763
+ clientId: "your-client-id",
752
764
  walletConfig: { evmAdapter },
753
765
  }}
754
766
  >
@@ -763,7 +775,7 @@ const App = () => {
763
775
  When multiple options are available:
764
776
 
765
777
  1. **Custom Adapter** - `walletConfig.evmAdapter` / `solanaAdapter` (highest)
766
- 2. **Built-in Adapter** - window.ethereum adapter for EVM wallets (lowest)
778
+ 2. **Built-in Adapter** - SDK wallet picker adapter for EVM wallets (fallback)
767
779
 
768
780
  ## Hooks
769
781
 
@@ -1068,6 +1080,7 @@ Works with:
1068
1080
 
1069
1081
  ### Optional Peer Dependencies
1070
1082
 
1083
+ Install these only when you need Web3 wallet login or wallet-based reward flows.
1071
1084
  For WalletConnect support in the built-in wallet binding dialog:
1072
1085
 
1073
1086
  ```bash
@@ -1079,7 +1092,7 @@ Then configure your project ID:
1079
1092
  ```tsx
1080
1093
  <TaskOnProvider
1081
1094
  config={{
1082
- apiKey: "your-api-key",
1095
+ clientId: "your-client-id",
1083
1096
  walletConnectProjectId: "your-walletconnect-project-id",
1084
1097
  }}
1085
1098
  >
@@ -1089,7 +1102,8 @@ Then configure your project ID:
1089
1102
 
1090
1103
  Get your WalletConnect Project ID at https://cloud.walletconnect.com
1091
1104
 
1092
- If not configured, the WalletConnect option will be disabled in the wallet binding dialog.
1105
+ If not configured, the SDK will use a built-in default WalletConnect project ID.
1106
+ For production use, strongly recommend configuring your own `walletConnectProjectId`.
1093
1107
 
1094
1108
  ## Limitations
1095
1109
 
@@ -3330,6 +3330,8 @@
3330
3330
  margin-top: 8px;
3331
3331
  font-size: 14px;
3332
3332
  color: var(--taskon-color-text-secondary);
3333
+ overflow-wrap: anywhere;
3334
+ word-break: break-word;
3333
3335
  }
3334
3336
  /**
3335
3337
  * SectorItem 组件样式
@@ -4183,7 +4185,9 @@
4183
4185
  line-height: 1.43;
4184
4186
  letter-spacing: 0.04em;
4185
4187
  text-align: left;
4186
- white-space: nowrap;
4188
+ white-space: normal;
4189
+ overflow-wrap: anywhere;
4190
+ word-break: break-word;
4187
4191
  }
4188
4192
 
4189
4193
  /* ==================== 提交按钮 ==================== */
@@ -4392,6 +4396,8 @@
4392
4396
  font-size: var(--taskon-font-size);
4393
4397
  line-height: 1.5;
4394
4398
  max-width: 300px;
4399
+ overflow-wrap: anywhere;
4400
+ word-break: break-word;
4395
4401
  }
4396
4402
 
4397
4403
  .taskon-dialog-error-retry {
@@ -4733,6 +4739,8 @@
4733
4739
  text-align: center;
4734
4740
  color: var(--taskon-color-error);
4735
4741
  font-size: var(--taskon-font-size-lg);
4742
+ overflow-wrap: anywhere;
4743
+ word-break: break-word;
4736
4744
  }
4737
4745
 
4738
4746
  /* 空状态 */
@@ -2,9 +2,8 @@
2
2
  * ConfirmNoticeDialog styles
3
3
  *
4
4
  * @description
5
- * Reproduces the visual rhythm of taskon-website ConfirmNotice:
6
- * icon -> title -> description -> actions,
7
- * while intentionally removing the glow background layer.
5
+ * Keep only content-specific layout/typography and rely on Dialog
6
+ * for container surface, radius and body spacing.
8
7
  */
9
8
 
10
9
  /*
@@ -20,24 +19,10 @@
20
19
  * 2) Keep viewport media query as fallback
21
20
  */
22
21
 
23
- /* Narrow the default dialog body padding for this notice layout */
24
-
25
- .taskon-confirm-notice-dialog .taskon-dialog-body {
26
- padding: 0;
27
- }
28
-
29
22
  /* ConfirmNotice content root */
30
23
 
31
24
  .taskon-confirm-notice {
32
- position: relative;
33
- width: auto;
34
- max-width: none;
35
- padding: var(--taskon-spacing-xl) var(--taskon-spacing-lg) var(--taskon-spacing-lg);
36
- background: var(--taskon-color-bg-floating);
37
- color: var(--taskon-color-text);
38
- border-radius: var(--taskon-border-radius-lg);
39
25
  text-align: center;
40
- box-sizing: border-box;
41
26
  }
42
27
 
43
28
  /* Status icon */
@@ -136,12 +121,6 @@
136
121
 
137
122
  @supports (container-type: inline-size) {
138
123
  @container (min-width: 751px) {
139
- .taskon-confirm-notice {
140
- width: 100%;
141
- max-width: 470px;
142
- padding: 40px 55px;
143
- }
144
-
145
124
  .taskon-confirm-notice-buttons {
146
125
  flex-direction: row;
147
126
  align-items: center;
@@ -156,12 +135,6 @@
156
135
 
157
136
  @supports not (container-type: inline-size) {
158
137
  @media (min-width: 751px) {
159
- .taskon-confirm-notice {
160
- width: 100%;
161
- max-width: 470px;
162
- padding: 40px 55px;
163
- }
164
-
165
138
  .taskon-confirm-notice-buttons {
166
139
  flex-direction: row;
167
140
  align-items: center;
@@ -804,10 +777,6 @@
804
777
  * 2) Keep viewport media query as fallback
805
778
  */
806
779
 
807
- .taskon-task-verify-failed-dialog .taskon-dialog-body {
808
- padding: 0;
809
- }
810
-
811
780
  .taskon-task-verify-failed-dialog-message {
812
781
  margin-top: var(--taskon-spacing-sm);
813
782
  font-size: var(--taskon-font-size-lg);
@@ -1027,6 +996,8 @@
1027
996
  margin-top: 10px;
1028
997
  font-size: var(--taskon-font-size);
1029
998
  color: var(--taskon-color-error);
999
+ overflow-wrap: anywhere;
1000
+ word-break: break-word;
1030
1001
  }
1031
1002
 
1032
1003
  /* ============================================
@@ -1373,6 +1344,8 @@
1373
1344
  .taskon-outer-point-api-dialog-error {
1374
1345
  font-size: var(--taskon-font-size-sm);
1375
1346
  color: var(--taskon-color-error);
1347
+ overflow-wrap: anywhere;
1348
+ word-break: break-word;
1376
1349
  }
1377
1350
 
1378
1351
  /* Action buttons */
@@ -2205,17 +2178,29 @@
2205
2178
  container-type: inline-size;
2206
2179
  position: relative;
2207
2180
  width: min(520px, 92vw);
2181
+ min-height: 500px;
2182
+ padding: 24px var(--taskon-spacing-lg) 40px;
2183
+ display: flex;
2184
+ flex-direction: column;
2185
+ align-items: center;
2208
2186
  overflow: hidden;
2209
- padding-top: var(--taskon-spacing-lg);
2210
2187
  }
2211
2188
 
2212
2189
  .taskon-quest-blindbox-dialog-title {
2213
- margin: 0 0 var(--taskon-spacing-md);
2214
- padding: 0 var(--taskon-spacing-lg);
2215
- font-size: var(--taskon-font-size-xxl);
2190
+ margin: 0;
2191
+ font-size: 32px;
2216
2192
  font-weight: 600;
2217
- line-height: 1.4;
2193
+ line-height: 1.25;
2218
2194
  color: #fff;
2195
+ text-align: center;
2196
+ }
2197
+
2198
+ .taskon-quest-blindbox-dialog-subtitle {
2199
+ margin: 12px 0 20px;
2200
+ font-size: var(--taskon-font-size-lg);
2201
+ line-height: 1.5;
2202
+ color: rgba(255, 255, 255, 0.7);
2203
+ text-align: center;
2219
2204
  }
2220
2205
 
2221
2206
  /* Stage container - centered square area for animation */
@@ -2227,7 +2212,7 @@
2227
2212
  justify-content: center;
2228
2213
  width: 100%;
2229
2214
  max-width: 420px;
2230
- margin: 0 auto;
2215
+ margin: 0 auto auto;
2231
2216
  aspect-ratio: 1;
2232
2217
  overflow: visible;
2233
2218
  border-radius: 32px;
@@ -2335,35 +2320,17 @@
2335
2320
  .taskon-quest-blindbox-reward {
2336
2321
  container-type: inline-size;
2337
2322
  position: relative;
2338
- width: 510px;
2339
- max-width: 92vw;
2340
- padding: 48px var(--taskon-spacing-lg);
2323
+ width: min(520px, 92vw);
2324
+ min-height: 500px;
2325
+ padding: 24px var(--taskon-spacing-lg) 40px;
2326
+ display: flex;
2327
+ flex-direction: column;
2328
+ align-items: center;
2341
2329
  text-align: center;
2342
2330
  color: #fff;
2343
2331
  overflow: hidden;
2344
2332
  }
2345
2333
 
2346
- /* Light background effect */
2347
-
2348
- .taskon-quest-blindbox-reward-light {
2349
- position: absolute;
2350
- top: 0;
2351
- left: 50%;
2352
- width: 120%;
2353
- max-width: none;
2354
- transform: translateX(-50%);
2355
- object-fit: contain;
2356
- pointer-events: none;
2357
- opacity: 0;
2358
- animation: taskon-blindbox-light-appear 2s ease-out forwards;
2359
- }
2360
-
2361
- @keyframes taskon-blindbox-light-appear {
2362
- to {
2363
- opacity: 1;
2364
- }
2365
- }
2366
-
2367
2334
  /* Title */
2368
2335
 
2369
2336
  .taskon-quest-blindbox-reward-title {
@@ -2377,6 +2344,7 @@
2377
2344
 
2378
2345
  .taskon-quest-blindbox-reward-subtitle {
2379
2346
  margin-top: 12px;
2347
+ margin-bottom: 0;
2380
2348
  font-size: var(--taskon-font-size-lg);
2381
2349
  line-height: 1.5;
2382
2350
  color: rgba(255, 255, 255, 0.7);
@@ -2389,7 +2357,7 @@
2389
2357
  flex-wrap: wrap;
2390
2358
  justify-content: center;
2391
2359
  align-items: center;
2392
- margin-top: var(--taskon-spacing-lg);
2360
+ margin-top: 20px;
2393
2361
  gap: var(--taskon-spacing-sm);
2394
2362
  padding: 12px var(--taskon-spacing-md);
2395
2363
  border-radius: var(--taskon-border-radius);
@@ -2445,7 +2413,8 @@
2445
2413
  .taskon-quest-blindbox-reward-btn-wrap {
2446
2414
  display: flex;
2447
2415
  justify-content: center;
2448
- margin-top: 40px;
2416
+ margin-top: auto;
2417
+ padding-top: 40px;
2449
2418
  }
2450
2419
 
2451
2420
  /* Back button - matches Vue g-button--light-border */
@@ -2510,19 +2479,21 @@
2510
2479
  @supports (container-type: inline-size) {
2511
2480
  @container (min-width: 751px) {
2512
2481
  .taskon-quest-blindbox-dialog {
2513
- padding-top: 40px;
2482
+ min-height: 540px;
2483
+ padding: 32px 40px 48px;
2514
2484
  }
2515
2485
 
2516
- .taskon-quest-blindbox-dialog-title {
2517
- padding: 0 40px;
2486
+ .taskon-quest-blindbox-dialog-subtitle {
2487
+ margin-bottom: 28px;
2518
2488
  }
2519
2489
 
2520
2490
  .taskon-quest-blindbox-reward {
2521
- padding: 64px 40px;
2491
+ min-height: 540px;
2492
+ padding: 32px 40px 48px;
2522
2493
  }
2523
2494
 
2524
2495
  .taskon-quest-blindbox-reward-btn-wrap {
2525
- margin-top: 60px;
2496
+ padding-top: 56px;
2526
2497
  }
2527
2498
  }
2528
2499
  }
@@ -2530,19 +2501,21 @@
2530
2501
  @supports not (container-type: inline-size) {
2531
2502
  @media (min-width: 751px) {
2532
2503
  .taskon-quest-blindbox-dialog {
2533
- padding-top: 40px;
2504
+ min-height: 540px;
2505
+ padding: 32px 40px 48px;
2534
2506
  }
2535
2507
 
2536
- .taskon-quest-blindbox-dialog-title {
2537
- padding: 0 40px;
2508
+ .taskon-quest-blindbox-dialog-subtitle {
2509
+ margin-bottom: 28px;
2538
2510
  }
2539
2511
 
2540
2512
  .taskon-quest-blindbox-reward {
2541
- padding: 64px 40px;
2513
+ min-height: 540px;
2514
+ padding: 32px 40px 48px;
2542
2515
  }
2543
2516
 
2544
2517
  .taskon-quest-blindbox-reward-btn-wrap {
2545
- margin-top: 60px;
2518
+ padding-top: 56px;
2546
2519
  }
2547
2520
  }
2548
2521
  }