@mundogamernetwork/shared-ui 1.0.0 → 1.0.1

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.
@@ -12,23 +12,36 @@ const walls = ref<any[]>([]);
12
12
 
13
13
  const userId = computed(() => kit.value?.user_id);
14
14
  const streamer = computed(() => kit.value?.streamer ?? {});
15
- const stats = computed(() => kit.value?.stats ?? {});
15
+ const stats = computed(() => kit.value?.stats ?? null);
16
16
  const topGames = computed(() => kit.value?.top_games ?? []);
17
- const period = computed(() => kit.value?.period ?? {});
18
- const mediaKitWall = computed(() => {
19
- return walls.value.find((w: any) => w.show_on_media_kit) ?? null;
17
+ const rateCards = computed(() => kit.value?.rate_cards ?? []);
18
+ const bundles = computed(() => kit.value?.rate_card_bundles ?? []);
19
+ const schedule = computed(() => kit.value?.schedule ?? []);
20
+ const demographics = computed(() => kit.value?.demographics ?? null);
21
+ const styles = computed(() => kit.value?.content_styles ?? []);
22
+ const brands = computed(() => kit.value?.brands ?? []);
23
+ const period = computed(() => kit.value?.period ?? null);
24
+ const tpl = computed(() => kit.value?.theme || null);
25
+ const mediaKitWall = computed(() => walls.value.find((w: any) => w.show_on_media_kit) ?? null);
26
+
27
+ const socials = computed(() => {
28
+ const s = streamer.value?.social_links || {};
29
+ return Object.entries(s).filter(([, v]) => v).map(([k, v]) => ({ platform: k, url: v as string }));
30
+ });
31
+
32
+ const DOW = ['kit.media.sun', 'kit.media.mon', 'kit.media.tue', 'kit.media.wed', 'kit.media.thu', 'kit.media.fri', 'kit.media.sat'];
33
+ const scheduleByDay = computed(() => {
34
+ const map: Record<number, any> = {};
35
+ for (const s of schedule.value) map[s.day_of_week] = s;
36
+ return [0, 1, 2, 3, 4, 5, 6].map((d) => ({ d, key: DOW[d], slot: map[d] || null }));
20
37
  });
21
38
 
22
39
  onMounted(async () => {
23
40
  try {
24
41
  const { data } = await fetchPublicMediaKit(slug.value);
25
42
  kit.value = data?.data || data;
26
-
27
43
  if (kit.value?.user_id) {
28
- trackMediaKitEvent(kit.value.user_id, {
29
- type: 'view',
30
- referrer: document.referrer || undefined,
31
- }).catch(() => {});
44
+ trackMediaKitEvent(kit.value.user_id, { type: 'view', referrer: document.referrer || undefined }).catch(() => {});
32
45
  }
33
46
  } catch {
34
47
  error.value = true;
@@ -42,584 +55,261 @@ watch(userId, async (id) => {
42
55
  try {
43
56
  const res = await fetchStreamerActiveWalls(id);
44
57
  walls.value = res.data?.data ?? res.data ?? [];
45
- } catch {
46
- walls.value = [];
47
- }
58
+ } catch { walls.value = []; }
48
59
  }, { immediate: true });
49
60
 
50
- function formatNumber(num: number) {
51
- if (!num) return '0';
52
- if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;
53
- if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;
54
- return num.toLocaleString();
61
+ function fmt(n: number) {
62
+ if (!n) return '0';
63
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
64
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
65
+ return n.toLocaleString();
55
66
  }
56
-
57
- function handleContact() {
58
- if (userId.value) {
59
- trackMediaKitEvent(userId.value, { type: 'contact' });
60
- }
67
+ function track(type: 'click' | 'download' | 'contact') {
68
+ if (userId.value) trackMediaKitEvent(userId.value, { type });
61
69
  }
62
-
63
- function handleDownload() {
64
- if (userId.value) {
65
- trackMediaKitEvent(userId.value, { type: 'download' });
66
- }
70
+ function onDownload() {
71
+ track('download');
67
72
  if (import.meta.client) window.print();
68
73
  }
69
74
  </script>
70
75
 
71
76
  <template>
72
- <div id="public-media-kit">
73
- <div class="mk-inner">
74
- <div v-if="loading" class="loading-state">
75
- <i class="fa-solid fa-spinner fa-spin" />
76
- </div>
77
-
78
- <div v-else-if="error" class="error-state">
79
- <i class="fa-solid fa-circle-exclamation" />
80
- <p>{{ $t("tv.media_kit.not_available") }}</p>
81
- </div>
77
+ <div class="kit-media" :data-tpl="tpl">
78
+ <div v-if="loading" class="kit-state">{{ $t('kit.loading') }}</div>
79
+ <div v-else-if="error || !kit" class="kit-state"><p>{{ $t('kit.media.not_available') }}</p></div>
82
80
 
83
- <template v-else-if="kit">
84
- <!-- Header -->
81
+ <template v-else>
82
+ <div class="mk-cover" />
83
+ <div class="kit-wrap">
85
84
  <header class="mk-header">
86
- <div class="mk-header-content">
87
- <img
88
- v-if="streamer.avatar"
89
- :src="streamer.avatar"
90
- width="80"
91
- height="80"
92
- class="mk-avatar"
93
- />
94
- <div class="mk-header-info">
95
- <h1 class="mk-name">{{ streamer.name }}</h1>
96
- <div class="mk-meta">
97
- <span v-if="streamer.platform" class="mk-platform">
98
- <i :class="streamer.platform === 'twitch' ? 'fa-brands fa-twitch' : 'fa-brands fa-youtube'" />
99
- {{ streamer.platform }}
100
- </span>
101
- <span v-if="streamer.tier && streamer.tier !== 'free'" class="mk-tier">
102
- {{ streamer.tier.toUpperCase() }}
103
- </span>
104
- </div>
105
- <p v-if="streamer.bio" class="mk-bio">{{ streamer.bio }}</p>
85
+ <img v-if="streamer.avatar" class="mk-avatar" :src="streamer.avatar" :alt="streamer.name" />
86
+ <div v-else class="mk-avatar mk-avatar-ph" />
87
+ <div class="mk-hid">
88
+ <h1>{{ streamer.name }}</h1>
89
+ <div class="mk-badges">
90
+ <span v-if="streamer.platform" class="mk-badge plat">{{ streamer.platform }}</span>
91
+ <span v-if="streamer.tier && streamer.tier !== 'free'" class="mk-badge tier">{{ String(streamer.tier).toUpperCase() }}</span>
106
92
  </div>
93
+ <p v-if="streamer.bio" class="mk-bio">{{ streamer.bio }}</p>
107
94
  </div>
108
- <div class="mk-header-actions no-print">
109
- <button class="btn-mk-download" @click="handleDownload">
110
- <i class="fa-solid fa-download" />
111
- {{ $t("tv.media_kit.download_pdf") }}
112
- </button>
113
- <button v-if="streamer.social_links?.website" class="btn-mk-contact" @click="handleContact">
114
- <a :href="streamer.social_links.website" target="_blank" rel="noopener noreferrer">
115
- <i class="fa-solid fa-envelope" />
116
- {{ $t("tv.media_kit.contact") }}
117
- </a>
118
- </button>
95
+ <div class="mk-actions no-print">
96
+ <a class="kit-btn kit-btn-primary" @click="onDownload">{{ $t('kit.media.download_pdf') }}</a>
97
+ <a v-if="streamer.contact_email" class="kit-btn kit-btn-ghost" :href="`mailto:${streamer.contact_email}`" @click="track('contact')">{{ $t('kit.media.contact') }}</a>
119
98
  </div>
120
99
  </header>
121
100
 
122
- <!-- Key Metrics -->
123
- <section class="mk-section">
124
- <h2 class="mk-section-title">{{ $t("tv.media_kit.key_metrics") }}</h2>
125
- <p class="mk-period">{{ $t("tv.media_kit.last_days", { days: period.days }) }} ({{ period.start }} — {{ period.end }})</p>
126
- <div class="mk-metrics-grid">
127
- <div class="mk-metric-card">
128
- <span class="mk-metric-value">{{ formatNumber(stats.total_followers) }}</span>
129
- <span class="mk-metric-label">{{ $t("tv.media_kit.followers") }}</span>
130
- </div>
131
- <div class="mk-metric-card">
132
- <span class="mk-metric-value">{{ formatNumber(stats.avg_viewers) }}</span>
133
- <span class="mk-metric-label">{{ $t("tv.media_kit.avg_viewers") }}</span>
134
- </div>
135
- <div class="mk-metric-card">
136
- <span class="mk-metric-value">{{ formatNumber(stats.peak_viewers) }}</span>
137
- <span class="mk-metric-label">{{ $t("tv.media_kit.peak_viewers") }}</span>
138
- </div>
139
- <div class="mk-metric-card">
140
- <span class="mk-metric-value">{{ stats.streams_per_week }}</span>
141
- <span class="mk-metric-label">{{ $t("tv.media_kit.streams_week") }}</span>
101
+ <section v-if="stats" class="kit-block">
102
+ <h2>{{ $t('kit.media.key_metrics') }}</h2>
103
+ <p v-if="period" class="mk-period">{{ $t('kit.media.last_days', { days: period.days }) }} · {{ period.start }} — {{ period.end }}</p>
104
+ <div class="mk-metrics">
105
+ <div class="mk-metric"><div class="val accent">{{ fmt(stats.total_followers) }}</div><div class="lab">{{ $t('kit.media.followers') }}</div></div>
106
+ <div class="mk-metric"><div class="val">{{ fmt(stats.avg_viewers) }}</div><div class="lab">{{ $t('kit.media.avg_viewers') }}</div></div>
107
+ <div class="mk-metric"><div class="val">{{ fmt(stats.peak_viewers) }}</div><div class="lab">{{ $t('kit.media.peak_viewers') }}</div></div>
108
+ <div class="mk-metric"><div class="val">{{ stats.streams_per_week }}</div><div class="lab">{{ $t('kit.media.streams_week') }}</div></div>
109
+ <div class="mk-metric"><div class="val">{{ fmt(stats.total_streams_90d) }}</div><div class="lab">{{ $t('kit.media.total_streams') }}</div></div>
110
+ <div class="mk-metric"><div class="val">{{ stats.total_hours_90d }}h</div><div class="lab">{{ $t('kit.media.hours') }}</div></div>
111
+ <div class="mk-metric"><div class="val accent">+{{ fmt(stats.new_followers_90d) }}</div><div class="lab">{{ $t('kit.media.new_followers') }}</div></div>
112
+ <div class="mk-metric"><div class="val">{{ fmt(stats.total_chat_messages) }}</div><div class="lab">{{ $t('kit.media.chat') }}</div></div>
113
+ </div>
114
+ </section>
115
+
116
+ <section v-if="demographics" class="kit-block">
117
+ <h2>{{ $t('kit.media.audience') }}</h2>
118
+ <div class="mk-cols2">
119
+ <div class="kit-card mk-pad" v-if="demographics.age_ranges?.length">
120
+ <h3>{{ $t('kit.media.age') }}</h3>
121
+ <div v-for="a in demographics.age_ranges" :key="a.label" class="mk-bar">
122
+ <div class="top"><span>{{ a.label }}</span><b>{{ a.percent }}%</b></div>
123
+ <div class="track"><div class="fill" :style="{ width: a.percent + '%' }" /></div>
124
+ </div>
142
125
  </div>
143
- <div class="mk-metric-card">
144
- <span class="mk-metric-value">{{ formatNumber(stats.total_streams_90d) }}</span>
145
- <span class="mk-metric-label">{{ $t("tv.media_kit.total_streams") }}</span>
126
+ <div class="kit-card mk-pad" v-if="demographics.gender">
127
+ <h3>{{ $t('kit.media.gender_regions') }}</h3>
128
+ <div class="mk-gender">
129
+ <div v-for="(v, k) in demographics.gender" :key="k" class="g"><div class="pct">{{ v }}%</div><div class="lb">{{ k }}</div></div>
130
+ </div>
146
131
  </div>
147
- <div class="mk-metric-card">
148
- <span class="mk-metric-value">{{ stats.total_hours_90d }}h</span>
149
- <span class="mk-metric-label">{{ $t("tv.media_kit.hours_streamed") }}</span>
132
+ </div>
133
+ </section>
134
+
135
+ <section v-if="styles.length" class="kit-block">
136
+ <h2>{{ $t('kit.media.styles') }}</h2>
137
+ <div class="mk-tags"><span v-for="(s, i) in styles" :key="i" class="mk-tag">{{ s }}</span></div>
138
+ </section>
139
+
140
+ <section v-if="topGames.length" class="kit-block">
141
+ <h2>{{ $t('kit.media.top_games') }}</h2>
142
+ <div class="mk-games">
143
+ <div v-for="g in topGames" :key="g.game" class="mk-game">
144
+ <span class="nm">{{ g.game }}</span>
145
+ <span class="st"><span>{{ g.hours }}h</span><span>{{ g.avg_viewers }} {{ $t('kit.media.avg_short') }}</span></span>
150
146
  </div>
151
- <div class="mk-metric-card">
152
- <span class="mk-metric-value">+{{ formatNumber(stats.new_followers_90d) }}</span>
153
- <span class="mk-metric-label">{{ $t("tv.media_kit.new_followers") }}</span>
147
+ </div>
148
+ </section>
149
+
150
+ <section v-if="rateCards.length || bundles.length" class="kit-block">
151
+ <h2>{{ $t('kit.media.rates') }}</h2>
152
+ <div v-if="rateCards.length" class="mk-rates">
153
+ <div v-for="(r, i) in rateCards" :key="i" class="mk-rate">
154
+ <div class="fmt">{{ r.content_format || r.ad_channel }}</div>
155
+ <div class="lb">{{ r.label }}</div>
156
+ <div class="price">{{ r.currency }} {{ r.price_min }}<span v-if="r.price_max">–{{ r.price_max }}</span></div>
157
+ <div v-if="r.delivery_time_days" class="dl">{{ $t('kit.media.delivery', { d: r.delivery_time_days }) }}</div>
154
158
  </div>
155
- <div class="mk-metric-card">
156
- <span class="mk-metric-value">{{ formatNumber(stats.total_chat_messages) }}</span>
157
- <span class="mk-metric-label">{{ $t("tv.media_kit.chat_messages") }}</span>
159
+ </div>
160
+ <div v-if="bundles.length" class="mk-bundles">
161
+ <div v-for="(b, i) in bundles" :key="i" class="mk-bundle">
162
+ <span v-if="b.discount_percent" class="off">-{{ b.discount_percent }}%</span>
163
+ <div class="bn">{{ b.name }}</div>
164
+ <div v-if="b.description" class="bd">{{ b.description }}</div>
165
+ <div class="bp">{{ b.currency }} {{ b.bundle_price }} <s v-if="b.original_price">{{ b.original_price }}</s></div>
158
166
  </div>
159
167
  </div>
160
168
  </section>
161
169
 
162
- <!-- Top Games -->
163
- <section v-if="topGames.length" class="mk-section">
164
- <h2 class="mk-section-title">{{ $t("tv.media_kit.top_games") }}</h2>
165
- <div class="mk-games-list">
166
- <div v-for="game in topGames" :key="game.game" class="mk-game-item">
167
- <span class="mk-game-name">{{ game.game }}</span>
168
- <div class="mk-game-stats">
169
- <span>{{ game.hours }}h {{ $t("tv.media_kit.played") }}</span>
170
- <span>{{ game.avg_viewers }} {{ $t("tv.media_kit.avg_viewers_short") }}</span>
171
- </div>
170
+ <section v-if="brands.length" class="kit-block">
171
+ <h2>{{ $t('kit.media.brands') }}</h2>
172
+ <div class="mk-brands"><div v-for="(b, i) in brands" :key="i" class="mk-brand">{{ b.name || b }}</div></div>
173
+ </section>
174
+
175
+ <section v-if="schedule.length" class="kit-block">
176
+ <h2>{{ $t('kit.media.schedule') }}</h2>
177
+ <div class="mk-schedule">
178
+ <div v-for="d in scheduleByDay" :key="d.d" class="mk-day" :class="{ on: d.slot }">
179
+ <div class="dn">{{ $t(d.key) }}</div>
180
+ <div v-if="d.slot" class="hr">{{ d.slot.start_time }}</div>
181
+ <div v-else class="off">—</div>
172
182
  </div>
173
183
  </div>
174
184
  </section>
175
185
 
176
- <!-- Social Links -->
177
- <section v-if="streamer.social_links && Object.values(streamer.social_links).some(Boolean)" class="mk-section no-print">
178
- <h2 class="mk-section-title">{{ $t("tv.media_kit.connect") }}</h2>
179
- <div class="mk-social-links">
180
- <a
181
- v-for="(url, platform) in streamer.social_links"
182
- v-show="url"
183
- :key="platform"
184
- :href="url"
185
- target="_blank"
186
- rel="noopener noreferrer"
187
- class="mk-social-link"
188
- @click="() => userId && trackMediaKitEvent(userId, { type: 'click' })"
189
- >
190
- <i :class="{
191
- 'fa-brands fa-x-twitter': platform === 'twitter',
192
- 'fa-brands fa-instagram': platform === 'instagram',
193
- 'fa-brands fa-discord': platform === 'discord',
194
- 'fa-brands fa-tiktok': platform === 'tiktok',
195
- 'fa-solid fa-globe': platform === 'website',
196
- }" />
197
- <span>{{ platform }}</span>
198
- </a>
186
+ <section v-if="socials.length" class="kit-block no-print">
187
+ <h2>{{ $t('kit.media.connect') }}</h2>
188
+ <div class="mk-socials">
189
+ <a v-for="s in socials" :key="s.platform" class="mk-soc" :href="s.url" target="_blank" rel="noopener" @click="track('click')">{{ s.platform }}</a>
199
190
  </div>
200
191
  </section>
201
192
 
202
- <!-- IndieWall section (shown only if creator has a media-kit wall) -->
203
- <section v-if="mediaKitWall" class="mk-section mk-indiewall">
204
- <h2 class="mk-section-title">{{ $t("tv.media_kit.indiewall_title") }}</h2>
205
- <div class="mk-indiewall-card">
206
- <div class="mk-indiewall-info">
207
- <h3 class="mk-indiewall-name">{{ mediaKitWall.name }}</h3>
208
- <p v-if="mediaKitWall.description" class="mk-indiewall-desc">{{ mediaKitWall.description }}</p>
209
- <div class="mk-indiewall-stats">
210
- <div class="mk-indiewall-stat">
211
- <span class="mk-indiewall-stat-label">{{ $t("tv.media_kit.indiewall_raised") }}</span>
212
- <span class="mk-indiewall-stat-value">{{ mediaKitWall.currency }} {{ Number(mediaKitWall.raised_amount || 0).toFixed(2) }}</span>
213
- </div>
214
- <div class="mk-indiewall-stat">
215
- <span class="mk-indiewall-stat-label">{{ $t("tv.media_kit.indiewall_supporters") }}</span>
216
- <span class="mk-indiewall-stat-value">{{ mediaKitWall.supporters_count ?? 0 }}</span>
217
- </div>
218
- <div class="mk-indiewall-stat">
219
- <span class="mk-indiewall-stat-label">{{ $t("tv.media_kit.indiewall_pixels") }}</span>
220
- <span class="mk-indiewall-stat-value">{{ mediaKitWall.used_pixels ?? 0 }} / {{ mediaKitWall.total_pixels ?? 0 }}</span>
221
- </div>
193
+ <section v-if="mediaKitWall" class="kit-block">
194
+ <h2>{{ $t('kit.media.support') }}</h2>
195
+ <div class="mk-indiewall">
196
+ <div>
197
+ <div class="iw-name">{{ mediaKitWall.name }}</div>
198
+ <div v-if="mediaKitWall.description" class="iw-desc">{{ mediaKitWall.description }}</div>
199
+ <div class="iw-stats">
200
+ <div class="s"><div class="v">{{ mediaKitWall.currency }} {{ Number(mediaKitWall.raised_amount || 0).toFixed(2) }}</div><div class="l">{{ $t('kit.media.raised') }}</div></div>
201
+ <div class="s"><div class="v">{{ mediaKitWall.supporters_count ?? 0 }}</div><div class="l">{{ $t('kit.media.supporters') }}</div></div>
222
202
  </div>
223
203
  </div>
224
- <a :href="mediaKitWall.mural_url" target="_blank" rel="noopener" class="mk-indiewall-cta">
225
- {{ $t("tv.media_kit.indiewall_cta") }}
226
- </a>
204
+ <a :href="mediaKitWall.mural_url" target="_blank" rel="noopener" class="kit-btn kit-btn-primary">{{ $t('kit.media.view_wall') }}</a>
227
205
  </div>
228
206
  </section>
229
207
 
230
- <!-- Footer -->
231
- <footer class="mk-footer">
232
- <p>{{ $t("tv.media_kit.powered_by") }} <strong>Mundo Gamer TV</strong></p>
233
- <p class="mk-generated">{{ $t("tv.media_kit.generated") }} {{ kit.generated_at?.slice(0, 10) }}</p>
234
- </footer>
235
- </template>
236
- </div>
208
+ <footer class="mk-footer">{{ $t('kit.media.generated') }} {{ kit.generated_at?.slice(0, 10) }}</footer>
209
+ </div>
210
+ </template>
237
211
  </div>
238
212
  </template>
239
213
 
240
214
  <style lang="scss" scoped>
241
- #public-media-kit {
242
- min-height: 100vh;
243
- background: #0a0a0a;
244
- color: #fff;
245
- font-family: "Roboto", sans-serif;
246
-
247
- .mk-inner {
248
- max-width: 800px;
249
- margin: 0 auto;
250
- padding: 40px 24px;
251
- }
252
-
253
- .loading-state,
254
- .error-state {
255
- display: flex;
256
- flex-direction: column;
257
- align-items: center;
258
- justify-content: center;
259
- min-height: 60vh;
260
- gap: 16px;
261
- color: #878a99;
262
- font-size: 16px;
263
-
264
- i {
265
- font-size: 32px;
266
- color: #d297ff;
267
- }
268
- }
269
-
270
- .mk-header {
271
- display: flex;
272
- align-items: flex-start;
273
- justify-content: space-between;
274
- gap: 24px;
275
- margin-bottom: 48px;
276
- padding-bottom: 32px;
277
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
278
-
279
- .mk-header-content {
280
- display: flex;
281
- gap: 20px;
282
- align-items: flex-start;
283
- }
284
-
285
- .mk-avatar {
286
- border: 2px solid #6b15ac;
287
- flex-shrink: 0;
288
- }
289
-
290
- .mk-header-info {
291
- display: flex;
292
- flex-direction: column;
293
- gap: 6px;
294
- }
295
-
296
- .mk-name {
297
- font: 700 28px/36px "Roboto", sans-serif;
298
- color: #fff;
299
- }
300
-
301
- .mk-meta {
302
- display: flex;
303
- align-items: center;
304
- gap: 12px;
305
- }
306
-
307
- .mk-platform {
308
- color: #878a99;
309
- font-size: 14px;
310
- text-transform: capitalize;
311
-
312
- i {
313
- margin-right: 4px;
314
- }
315
- }
316
-
317
- .mk-tier {
318
- background: rgba(107, 21, 172, 0.2);
319
- color: #a855f7;
320
- font-size: 10px;
321
- font-weight: 700;
322
- padding: 2px 8px;
323
- letter-spacing: 0.05em;
324
- }
325
-
326
- .mk-bio {
327
- color: #aaa;
328
- font: 400 14px/20px "Roboto", sans-serif;
329
- margin-top: 8px;
330
- max-width: 480px;
331
- }
332
-
333
- .mk-header-actions {
334
- display: flex;
335
- gap: 8px;
336
- flex-shrink: 0;
337
- }
338
-
339
- .btn-mk-download,
340
- .btn-mk-contact {
341
- display: flex;
342
- align-items: center;
343
- gap: 6px;
344
- padding: 8px 16px;
345
- font: 400 13px/20px "Roboto", sans-serif;
346
- cursor: pointer;
347
- transition: all 0.15s ease-in-out;
348
- }
349
-
350
- .btn-mk-download {
351
- background: transparent;
352
- border: 1px solid #6b15ac;
353
- color: #d297ff;
354
-
355
- &:hover {
356
- background: rgba(107, 21, 172, 0.15);
357
- }
358
- }
359
-
360
- .btn-mk-contact {
361
- background: #6b15ac;
362
- border: 1px solid #6b15ac;
363
- color: #fff;
364
-
365
- a {
366
- color: inherit;
367
- text-decoration: none;
368
- display: flex;
369
- align-items: center;
370
- gap: 6px;
371
- }
372
-
373
- &:hover {
374
- background: #460279;
375
- }
376
- }
377
- }
378
-
379
- .mk-section {
380
- margin-bottom: 40px;
381
-
382
- .mk-section-title {
383
- font: 600 20px/28px "Roboto", sans-serif;
384
- color: #fff;
385
- margin-bottom: 8px;
386
- }
387
-
388
- .mk-period {
389
- color: #878a99;
390
- font: 400 13px/18px "Roboto", sans-serif;
391
- margin-bottom: 20px;
392
- }
393
- }
394
-
395
- .mk-metrics-grid {
396
- display: grid;
397
- grid-template-columns: repeat(4, 1fr);
398
- gap: 12px;
399
-
400
- .mk-metric-card {
401
- background: rgba(255, 255, 255, 0.04);
402
- border: 1px solid rgba(255, 255, 255, 0.08);
403
- padding: 20px 16px;
404
- text-align: center;
405
-
406
- .mk-metric-value {
407
- display: block;
408
- font: 700 24px/32px "Roboto", sans-serif;
409
- color: #d297ff;
410
- margin-bottom: 4px;
411
- }
412
-
413
- .mk-metric-label {
414
- display: block;
415
- font: 400 12px/16px "Roboto", sans-serif;
416
- color: #878a99;
417
- text-transform: uppercase;
418
- letter-spacing: 0.5px;
419
- }
420
- }
421
- }
422
-
423
- .mk-games-list {
424
- display: flex;
425
- flex-direction: column;
426
- gap: 8px;
427
-
428
- .mk-game-item {
429
- display: flex;
430
- align-items: center;
431
- justify-content: space-between;
432
- padding: 12px 16px;
433
- background: rgba(255, 255, 255, 0.04);
434
- border: 1px solid rgba(255, 255, 255, 0.08);
435
-
436
- .mk-game-name {
437
- font: 500 14px/20px "Roboto", sans-serif;
438
- color: #fff;
439
- }
440
-
441
- .mk-game-stats {
442
- display: flex;
443
- gap: 20px;
444
- color: #878a99;
445
- font: 400 13px/18px "Roboto", sans-serif;
446
- }
447
- }
448
- }
449
-
450
- .mk-social-links {
451
- display: flex;
452
- gap: 12px;
453
- flex-wrap: wrap;
454
-
455
- .mk-social-link {
456
- display: flex;
457
- align-items: center;
458
- gap: 6px;
459
- padding: 8px 16px;
460
- background: rgba(255, 255, 255, 0.04);
461
- border: 1px solid rgba(255, 255, 255, 0.08);
462
- color: #d297ff;
463
- text-decoration: none;
464
- font: 400 13px/18px "Roboto", sans-serif;
465
- text-transform: capitalize;
466
- transition: all 0.15s ease-in-out;
467
-
468
- &:hover {
469
- background: rgba(107, 21, 172, 0.15);
470
- }
471
- }
472
- }
473
-
474
- .mk-indiewall {
475
- .mk-indiewall-card {
476
- background: rgba(107, 21, 172, 0.08);
477
- border: 1px solid rgba(107, 21, 172, 0.3);
478
- padding: 24px;
479
- display: flex;
480
- flex-wrap: wrap;
481
- align-items: center;
482
- justify-content: space-between;
483
- gap: 20px;
484
- }
485
-
486
- .mk-indiewall-name {
487
- font: 700 18px/24px "Roboto", sans-serif;
488
- color: #fff;
489
- margin: 0 0 6px;
490
- }
491
-
492
- .mk-indiewall-desc {
493
- font: 400 13px/20px "Roboto", sans-serif;
494
- color: #aaa;
495
- margin: 0 0 16px;
496
- }
497
-
498
- .mk-indiewall-stats {
499
- display: flex;
500
- flex-wrap: wrap;
501
- gap: 20px;
502
- }
503
-
504
- .mk-indiewall-stat {
505
- display: flex;
506
- flex-direction: column;
507
- gap: 2px;
508
- }
509
-
510
- .mk-indiewall-stat-label {
511
- font: 400 10px/14px "Roboto", sans-serif;
512
- color: #888;
513
- text-transform: uppercase;
514
- letter-spacing: 0.04em;
515
- }
516
-
517
- .mk-indiewall-stat-value {
518
- font: 700 15px/20px "Roboto", sans-serif;
519
- color: #d297ff;
520
- }
521
-
522
- .mk-indiewall-cta {
523
- display: inline-block;
524
- background: #6b15ac;
525
- color: #fff;
526
- padding: 10px 20px;
527
- font: 600 13px/18px "Roboto", sans-serif;
528
- text-decoration: none;
529
- white-space: nowrap;
530
-
531
- &:hover {
532
- background: #7d1bc8;
533
- }
534
- }
535
- }
536
-
537
- .mk-footer {
538
- margin-top: 60px;
539
- padding-top: 24px;
540
- border-top: 1px solid rgba(255, 255, 255, 0.1);
541
- text-align: center;
542
- color: #878a99;
543
- font: 400 13px/18px "Roboto", sans-serif;
544
-
545
- strong {
546
- color: #d297ff;
547
- }
548
-
549
- .mk-generated {
550
- margin-top: 4px;
551
- font-size: 11px;
552
- }
553
- }
554
-
555
- @media screen and (max-width: 767px) {
556
- .mk-inner {
557
- padding: 24px 16px;
558
- }
559
-
560
- .mk-header {
561
- flex-direction: column;
562
-
563
- .mk-header-content {
564
- flex-direction: column;
565
- align-items: center;
566
- text-align: center;
567
- }
568
-
569
- .mk-header-info {
570
- align-items: center;
571
- }
572
-
573
- .mk-meta {
574
- justify-content: center;
575
- }
576
-
577
- .mk-header-actions {
578
- width: 100%;
579
- justify-content: center;
580
- }
581
- }
582
-
583
- .mk-metrics-grid {
584
- grid-template-columns: repeat(2, 1fr);
585
- }
586
-
587
- .mk-games-list .mk-game-item {
588
- flex-direction: column;
589
- align-items: flex-start;
590
- gap: 4px;
591
- }
592
- }
593
-
594
- @media print {
595
- background: #fff;
596
- color: #000;
597
-
598
- .no-print {
599
- display: none !important;
600
- }
601
-
602
- .mk-name {
603
- color: #000;
604
- }
605
-
606
- .mk-metric-value {
607
- color: #6b15ac !important;
608
- }
609
-
610
- .mk-metric-card,
611
- .mk-game-item {
612
- border-color: #ddd !important;
613
- background: #f9f9f9 !important;
614
- }
615
-
616
- .mk-section-title {
617
- color: #000;
618
- }
619
-
620
- .mk-footer strong {
621
- color: #6b15ac;
622
- }
623
- }
215
+ .kit-media { background: var(--kit-bg); color: var(--kit-text); min-height: 100vh; font-family: 'Inter', system-ui, sans-serif; }
216
+ .kit-state { display: flex; align-items: center; justify-content: center; min-height: 60vh; color: var(--kit-muted); }
217
+ .kit-wrap { max-width: 1100px; margin: 0 auto; padding: 0 24px 60px; }
218
+ .mk-cover { height: 200px; background: linear-gradient(120deg, var(--kit-accent), #2a0e4e 60%, var(--kit-bg)); }
219
+
220
+ .mk-header { margin-top: -70px; position: relative; z-index: 2; display: flex; gap: 24px; align-items: flex-end; flex-wrap: wrap; }
221
+ .mk-avatar { width: 140px; height: 140px; border: 3px solid var(--kit-accent); object-fit: cover; flex-shrink: 0; background: var(--kit-surface-2); }
222
+ .mk-avatar-ph { background: linear-gradient(135deg, var(--kit-surface-2), var(--kit-accent)); }
223
+ .mk-hid { flex: 1; min-width: 260px; padding-bottom: 6px; }
224
+ .mk-hid h1 { font-family: 'Rajdhani'; font-size: 40px; line-height: 1.05; }
225
+ .mk-badges { display: flex; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
226
+ .mk-badge { font-family: 'Rajdhani'; font-weight: 700; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; padding: 4px 10px; }
227
+ .mk-badge.plat { background: var(--kit-surface-2); border: 1px solid var(--kit-line); }
228
+ .mk-badge.tier { background: var(--kit-accent); color: var(--kit-accent-ink); }
229
+ .mk-bio { color: #c4c4d2; font-size: 15px; max-width: 60ch; margin-top: 6px; }
230
+ .mk-actions { display: flex; gap: 10px; padding-bottom: 8px; }
231
+
232
+ .kit-btn { display: inline-flex; align-items: center; gap: 8px; font-family: 'Rajdhani'; font-weight: 700; font-size: 14px; padding: 11px 20px; cursor: pointer; border: 1px solid transparent; text-transform: uppercase; text-decoration: none; }
233
+ .kit-btn-primary { background: var(--kit-accent); color: var(--kit-accent-ink); }
234
+ .kit-btn-ghost { background: rgba(255,255,255,.04); border-color: var(--kit-line); color: var(--kit-text); }
235
+
236
+ .kit-block { margin-top: 44px; }
237
+ .kit-block > h2 { font-size: 13px; letter-spacing: 3px; text-transform: uppercase; color: var(--kit-muted); font-weight: 700; margin-bottom: 16px; display: flex; align-items: center; gap: 12px; }
238
+ .kit-block > h2::after { content: ""; flex: 1; height: 1px; background: var(--kit-line); }
239
+ .mk-period { color: var(--kit-muted); font-size: 13px; margin: -8px 0 16px; }
240
+
241
+ .mk-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
242
+ .mk-metric { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 20px 16px; text-align: center; position: relative; }
243
+ .mk-metric::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: var(--kit-accent); }
244
+ .mk-metric .val { font-family: 'Rajdhani'; font-weight: 700; font-size: 30px; line-height: 1; }
245
+ .mk-metric .val.accent { color: var(--kit-accent); }
246
+ .mk-metric .lab { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); margin-top: 8px; }
247
+
248
+ .mk-cols2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
249
+ .kit-card { background: var(--kit-surface); border: 1px solid var(--kit-line); }
250
+ .mk-pad { padding: 20px; }
251
+ .mk-pad h3 { font-size: 14px; font-weight: 700; margin-bottom: 14px; }
252
+ .mk-bar { margin-bottom: 12px; }
253
+ .mk-bar .top { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 5px; }
254
+ .mk-bar .top b { color: var(--kit-accent); }
255
+ .mk-bar .track { height: 8px; background: var(--kit-surface-2); }
256
+ .mk-bar .fill { height: 100%; background: var(--kit-accent); }
257
+ .mk-gender { display: flex; gap: 16px; }
258
+ .mk-gender .g { flex: 1; text-align: center; background: var(--kit-surface-2); border: 1px solid var(--kit-line); padding: 14px; }
259
+ .mk-gender .pct { font-family: 'Rajdhani'; font-weight: 700; font-size: 26px; color: var(--kit-accent); }
260
+ .mk-gender .lb { font-size: 12px; color: var(--kit-muted); text-transform: uppercase; }
261
+
262
+ .mk-tags { display: flex; flex-wrap: wrap; gap: 8px; }
263
+ .mk-tag { background: var(--kit-surface-2); border: 1px solid var(--kit-line); padding: 6px 13px; font-size: 13px; }
264
+
265
+ .mk-games { display: flex; flex-direction: column; gap: 8px; }
266
+ .mk-game { display: flex; align-items: center; justify-content: space-between; background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 12px 16px; }
267
+ .mk-game .nm { font-weight: 600; }
268
+ .mk-game .st { display: flex; gap: 18px; color: var(--kit-muted); font-size: 13px; }
269
+
270
+ .mk-rates { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
271
+ .mk-rate { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 18px; }
272
+ .mk-rate .fmt { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-accent); font-weight: 700; }
273
+ .mk-rate .lb { font-weight: 600; font-size: 16px; margin: 6px 0 10px; font-family: 'Rajdhani'; }
274
+ .mk-rate .price { font-family: 'Rajdhani'; font-weight: 700; font-size: 22px; }
275
+ .mk-rate .dl { font-size: 12px; color: var(--kit-muted); margin-top: 6px; }
276
+ .mk-bundles { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
277
+ .mk-bundle { background: linear-gradient(135deg, var(--kit-surface), var(--kit-surface-2)); border: 1px solid var(--kit-accent); padding: 18px; position: relative; }
278
+ .mk-bundle .off { position: absolute; top: 14px; right: 14px; background: var(--kit-accent); color: var(--kit-accent-ink); font-size: 11px; font-weight: 700; padding: 3px 9px; font-family: 'Rajdhani'; }
279
+ .mk-bundle .bn { font-weight: 700; font-size: 17px; font-family: 'Rajdhani'; }
280
+ .mk-bundle .bd { font-size: 13px; color: var(--kit-muted); margin: 4px 0 10px; }
281
+ .mk-bundle .bp { font-family: 'Rajdhani'; font-weight: 700; font-size: 24px; color: var(--kit-accent); }
282
+ .mk-bundle .bp s { color: var(--kit-muted); font-size: 15px; font-weight: 500; margin-left: 8px; }
283
+
284
+ .mk-brands { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
285
+ .mk-brand { aspect-ratio: 5/2; background: var(--kit-surface-2); border: 1px solid var(--kit-line); display: flex; align-items: center; justify-content: center; color: var(--kit-muted); font-family: 'Rajdhani'; font-weight: 700; font-size: 14px; }
286
+
287
+ .mk-schedule { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
288
+ .mk-day { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 12px 8px; text-align: center; }
289
+ .mk-day.on { border-color: var(--kit-accent); }
290
+ .mk-day .dn { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); }
291
+ .mk-day.on .dn { color: var(--kit-accent); }
292
+ .mk-day .hr { font-family: 'Rajdhani'; font-weight: 700; margin-top: 6px; font-size: 14px; }
293
+ .mk-day .off { color: var(--kit-muted); opacity: .4; margin-top: 6px; }
294
+
295
+ .mk-socials { display: flex; flex-wrap: wrap; gap: 10px; }
296
+ .mk-soc { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 9px 16px; font-size: 14px; text-transform: capitalize; }
297
+
298
+ .mk-indiewall { background: var(--kit-surface); border: 1px solid var(--kit-accent); padding: 24px; display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap; }
299
+ .mk-indiewall .iw-name { font-family: 'Rajdhani'; font-weight: 700; font-size: 19px; }
300
+ .mk-indiewall .iw-desc { color: #b4b4c2; font-size: 13px; margin-top: 4px; }
301
+ .mk-indiewall .iw-stats { display: flex; gap: 26px; margin-top: 10px; }
302
+ .mk-indiewall .iw-stats .v { font-family: 'Rajdhani'; font-weight: 700; font-size: 20px; color: var(--kit-accent); }
303
+ .mk-indiewall .iw-stats .l { font-size: 11px; text-transform: uppercase; color: var(--kit-muted); }
304
+
305
+ .mk-footer { border-top: 1px solid var(--kit-line); margin-top: 48px; padding: 24px 0; text-align: center; color: var(--kit-muted); font-size: 13px; }
306
+
307
+ @media (max-width: 840px) {
308
+ .mk-metrics { grid-template-columns: repeat(2, 1fr); }
309
+ .mk-cols2, .mk-rates, .mk-bundles { grid-template-columns: 1fr; }
310
+ .mk-brands { grid-template-columns: repeat(3, 1fr); }
311
+ .mk-schedule { grid-template-columns: repeat(4, 1fr); }
312
+ .mk-header { flex-direction: column; align-items: flex-start; }
624
313
  }
314
+ @media print { .no-print { display: none !important; } }
625
315
  </style>