@mundogamernetwork/shared-ui 1.0.0 → 1.0.2

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,45 @@ 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
+ // Layout emphasis template (premium): creator (default) / performance / commercial / audience
26
+ const template = computed(() => kit.value?.template || 'creator');
27
+ const platforms = computed(() => kit.value?.platforms ?? []);
28
+ const totalFollowers = computed(() => kit.value?.total_followers ?? 0);
29
+ const mediaKitWall = computed(() => walls.value.find((w: any) => w.show_on_media_kit) ?? null);
30
+
31
+ const PLATFORM_LABEL: Record<string, string> = {
32
+ instagram: 'Instagram', tiktok: 'TikTok', youtube: 'YouTube', twitch: 'Twitch', x: 'X',
33
+ facebook: 'Facebook', kick: 'Kick', discord: 'Discord', telegram: 'Telegram', linkedin: 'LinkedIn', bluesky: 'Bluesky',
34
+ };
35
+
36
+ const socials = computed(() => {
37
+ const s = streamer.value?.social_links || {};
38
+ return Object.entries(s).filter(([, v]) => v).map(([k, v]) => ({ platform: k, url: v as string }));
39
+ });
40
+
41
+ const DOW = ['kit.media.sun', 'kit.media.mon', 'kit.media.tue', 'kit.media.wed', 'kit.media.thu', 'kit.media.fri', 'kit.media.sat'];
42
+ const scheduleByDay = computed(() => {
43
+ const map: Record<number, any> = {};
44
+ for (const s of schedule.value) map[s.day_of_week] = s;
45
+ return [0, 1, 2, 3, 4, 5, 6].map((d) => ({ d, key: DOW[d], slot: map[d] || null }));
20
46
  });
21
47
 
22
48
  onMounted(async () => {
23
49
  try {
24
50
  const { data } = await fetchPublicMediaKit(slug.value);
25
51
  kit.value = data?.data || data;
26
-
27
52
  if (kit.value?.user_id) {
28
- trackMediaKitEvent(kit.value.user_id, {
29
- type: 'view',
30
- referrer: document.referrer || undefined,
31
- }).catch(() => {});
53
+ trackMediaKitEvent(kit.value.user_id, { type: 'view', referrer: document.referrer || undefined }).catch(() => {});
32
54
  }
33
55
  } catch {
34
56
  error.value = true;
@@ -42,584 +64,321 @@ watch(userId, async (id) => {
42
64
  try {
43
65
  const res = await fetchStreamerActiveWalls(id);
44
66
  walls.value = res.data?.data ?? res.data ?? [];
45
- } catch {
46
- walls.value = [];
47
- }
67
+ } catch { walls.value = []; }
48
68
  }, { immediate: true });
49
69
 
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();
70
+ function fmt(n: number) {
71
+ if (!n) return '0';
72
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
73
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
74
+ return n.toLocaleString();
55
75
  }
56
-
57
- function handleContact() {
58
- if (userId.value) {
59
- trackMediaKitEvent(userId.value, { type: 'contact' });
60
- }
76
+ function track(type: 'click' | 'download' | 'contact') {
77
+ if (userId.value) trackMediaKitEvent(userId.value, { type });
61
78
  }
62
-
63
- function handleDownload() {
64
- if (userId.value) {
65
- trackMediaKitEvent(userId.value, { type: 'download' });
66
- }
79
+ function onDownload() {
80
+ track('download');
67
81
  if (import.meta.client) window.print();
68
82
  }
69
83
  </script>
70
84
 
71
85
  <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>
86
+ <div class="kit-media" :data-tpl="tpl" :data-template="template">
87
+ <div v-if="loading" class="kit-state">{{ $t('kit.loading') }}</div>
88
+ <div v-else-if="error || !kit" class="kit-state"><p>{{ $t('kit.media.not_available') }}</p></div>
82
89
 
83
- <template v-else-if="kit">
84
- <!-- Header -->
90
+ <template v-else>
91
+ <div class="mk-cover" />
92
+ <div class="kit-wrap mk-sections">
85
93
  <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>
94
+ <img v-if="streamer.avatar" class="mk-avatar" :src="streamer.avatar" :alt="streamer.name" />
95
+ <div v-else class="mk-avatar mk-avatar-ph" />
96
+ <div class="mk-hid">
97
+ <h1>{{ streamer.name }}</h1>
98
+ <div class="mk-badges">
99
+ <span v-if="streamer.platform" class="mk-badge plat">{{ streamer.platform }}</span>
100
+ <span v-if="streamer.tier && streamer.tier !== 'free'" class="mk-badge tier">{{ String(streamer.tier).toUpperCase() }}</span>
106
101
  </div>
102
+ <p v-if="streamer.bio" class="mk-bio">{{ streamer.bio }}</p>
107
103
  </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>
104
+ <div class="mk-actions no-print">
105
+ <a class="kit-btn kit-btn-primary" @click="onDownload">{{ $t('kit.media.download_pdf') }}</a>
106
+ <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
107
  </div>
120
108
  </header>
121
109
 
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>
110
+ <section v-if="platforms.length" class="kit-block" data-sec="reach">
111
+ <h2>{{ $t('kit.media.reach') }}</h2>
112
+ <p v-if="totalFollowers" class="mk-total-reach">{{ fmt(totalFollowers) }} <span>{{ $t('kit.media.total_reach') }}</span></p>
113
+ <div class="mk-platforms">
114
+ <a v-for="p in platforms" :key="p.platform" class="mk-platform" :href="p.url || undefined" target="_blank" rel="noopener" @click="track('click')">
115
+ <div class="pl-head">
116
+ <span class="pl-name">{{ PLATFORM_LABEL[p.platform] || p.platform }}</span>
117
+ <span v-if="p.verified" class="pl-verified" :title="$t('kit.media.verified')">✓</span>
118
+ </div>
119
+ <div class="pl-followers">{{ fmt(p.followers) }}</div>
120
+ <div class="pl-meta">
121
+ <span v-if="p.engagement_rate != null">{{ p.engagement_rate }}% {{ $t('kit.media.eng_short') }}</span>
122
+ <span v-if="p.avg_views != null">{{ fmt(p.avg_views) }} {{ $t('kit.media.views_short') }}</span>
123
+ </div>
124
+ </a>
125
+ </div>
126
+ </section>
127
+
128
+ <section v-if="stats" class="kit-block" data-sec="metrics">
129
+ <h2>{{ $t('kit.media.key_metrics') }}</h2>
130
+ <p v-if="period" class="mk-period">{{ $t('kit.media.last_days', { days: period.days }) }} · {{ period.start }} — {{ period.end }}</p>
131
+ <div class="mk-metrics">
132
+ <div class="mk-metric"><div class="val accent">{{ fmt(stats.total_followers) }}</div><div class="lab">{{ $t('kit.media.followers') }}</div></div>
133
+ <div class="mk-metric"><div class="val">{{ fmt(stats.avg_viewers) }}</div><div class="lab">{{ $t('kit.media.avg_viewers') }}</div></div>
134
+ <div class="mk-metric"><div class="val">{{ fmt(stats.peak_viewers) }}</div><div class="lab">{{ $t('kit.media.peak_viewers') }}</div></div>
135
+ <div class="mk-metric"><div class="val">{{ stats.streams_per_week }}</div><div class="lab">{{ $t('kit.media.streams_week') }}</div></div>
136
+ <div class="mk-metric"><div class="val">{{ fmt(stats.total_streams_90d) }}</div><div class="lab">{{ $t('kit.media.total_streams') }}</div></div>
137
+ <div class="mk-metric"><div class="val">{{ stats.total_hours_90d }}h</div><div class="lab">{{ $t('kit.media.hours') }}</div></div>
138
+ <div class="mk-metric"><div class="val accent">+{{ fmt(stats.new_followers_90d) }}</div><div class="lab">{{ $t('kit.media.new_followers') }}</div></div>
139
+ <div class="mk-metric"><div class="val">{{ fmt(stats.total_chat_messages) }}</div><div class="lab">{{ $t('kit.media.chat') }}</div></div>
140
+ </div>
141
+ </section>
142
+
143
+ <section v-if="demographics" data-sec="audience" class="kit-block">
144
+ <h2>{{ $t('kit.media.audience') }}</h2>
145
+ <div class="mk-cols2">
146
+ <div class="kit-card mk-pad" v-if="demographics.age_ranges?.length">
147
+ <h3>{{ $t('kit.media.age') }}</h3>
148
+ <div v-for="a in demographics.age_ranges" :key="a.label" class="mk-bar">
149
+ <div class="top"><span>{{ a.label }}</span><b>{{ a.percent }}%</b></div>
150
+ <div class="track"><div class="fill" :style="{ width: a.percent + '%' }" /></div>
151
+ </div>
142
152
  </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>
153
+ <div class="kit-card mk-pad" v-if="demographics.gender">
154
+ <h3>{{ $t('kit.media.gender_regions') }}</h3>
155
+ <div class="mk-gender">
156
+ <div v-for="(v, k) in demographics.gender" :key="k" class="g"><div class="pct">{{ v }}%</div><div class="lb">{{ k }}</div></div>
157
+ </div>
146
158
  </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>
159
+ </div>
160
+ </section>
161
+
162
+ <section v-if="styles.length" data-sec="styles" class="kit-block">
163
+ <h2>{{ $t('kit.media.styles') }}</h2>
164
+ <div class="mk-tags"><span v-for="(s, i) in styles" :key="i" class="mk-tag">{{ s }}</span></div>
165
+ </section>
166
+
167
+ <section v-if="topGames.length" data-sec="games" class="kit-block">
168
+ <h2>{{ $t('kit.media.top_games') }}</h2>
169
+ <div class="mk-games">
170
+ <div v-for="g in topGames" :key="g.game" class="mk-game">
171
+ <span class="nm">{{ g.game }}</span>
172
+ <span class="st"><span>{{ g.hours }}h</span><span>{{ g.avg_viewers }} {{ $t('kit.media.avg_short') }}</span></span>
150
173
  </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>
174
+ </div>
175
+ </section>
176
+
177
+ <section v-if="rateCards.length || bundles.length" data-sec="rates" class="kit-block">
178
+ <h2>{{ $t('kit.media.rates') }}</h2>
179
+ <div v-if="rateCards.length" class="mk-rates">
180
+ <div v-for="(r, i) in rateCards" :key="i" class="mk-rate">
181
+ <div class="fmt">{{ r.content_format || r.ad_channel }}</div>
182
+ <div class="lb">{{ r.label }}</div>
183
+ <div class="price">{{ r.currency }} {{ r.price_min }}<span v-if="r.price_max">–{{ r.price_max }}</span></div>
184
+ <div v-if="r.delivery_time_days" class="dl">{{ $t('kit.media.delivery', { d: r.delivery_time_days }) }}</div>
154
185
  </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>
186
+ </div>
187
+ <div v-if="bundles.length" class="mk-bundles">
188
+ <div v-for="(b, i) in bundles" :key="i" class="mk-bundle">
189
+ <span v-if="b.discount_percent" class="off">-{{ b.discount_percent }}%</span>
190
+ <div class="bn">{{ b.name }}</div>
191
+ <div v-if="b.description" class="bd">{{ b.description }}</div>
192
+ <ul v-if="b.rate_cards?.length" class="bundle-items">
193
+ <li v-for="(it, j) in b.rate_cards" :key="j"><b>{{ it.quantity || 1 }}×</b> {{ it.label }}</li>
194
+ </ul>
195
+ <div class="bp">{{ b.currency }} {{ b.bundle_price }} <s v-if="b.original_price">{{ b.original_price }}</s></div>
158
196
  </div>
159
197
  </div>
160
198
  </section>
161
199
 
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>
200
+ <section v-if="brands.length" data-sec="brands" class="kit-block">
201
+ <h2>{{ $t('kit.media.brands') }}</h2>
202
+ <div class="mk-brands"><div v-for="(b, i) in brands" :key="i" class="mk-brand">{{ b.name || b }}</div></div>
203
+ </section>
204
+
205
+ <section v-if="schedule.length" data-sec="schedule" class="kit-block">
206
+ <h2>{{ $t('kit.media.schedule') }}</h2>
207
+ <div class="mk-schedule">
208
+ <div v-for="d in scheduleByDay" :key="d.d" class="mk-day" :class="{ on: d.slot }">
209
+ <div class="dn">{{ $t(d.key) }}</div>
210
+ <div v-if="d.slot" class="hr">{{ d.slot.start_time }}</div>
211
+ <div v-else class="off">—</div>
172
212
  </div>
173
213
  </div>
174
214
  </section>
175
215
 
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>
216
+ <section v-if="socials.length" data-sec="connect" class="kit-block no-print">
217
+ <h2>{{ $t('kit.media.connect') }}</h2>
218
+ <div class="mk-socials">
219
+ <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
220
  </div>
200
221
  </section>
201
222
 
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>
223
+ <section v-if="mediaKitWall" data-sec="support" class="kit-block">
224
+ <h2>{{ $t('kit.media.support') }}</h2>
225
+ <div class="mk-indiewall">
226
+ <div>
227
+ <div class="iw-name">{{ mediaKitWall.name }}</div>
228
+ <div v-if="mediaKitWall.description" class="iw-desc">{{ mediaKitWall.description }}</div>
229
+ <div class="iw-stats">
230
+ <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>
231
+ <div class="s"><div class="v">{{ mediaKitWall.supporters_count ?? 0 }}</div><div class="l">{{ $t('kit.media.supporters') }}</div></div>
222
232
  </div>
223
233
  </div>
224
- <a :href="mediaKitWall.mural_url" target="_blank" rel="noopener" class="mk-indiewall-cta">
225
- {{ $t("tv.media_kit.indiewall_cta") }}
226
- </a>
234
+ <a :href="mediaKitWall.mural_url" target="_blank" rel="noopener" class="kit-btn kit-btn-primary">{{ $t('kit.media.view_wall') }}</a>
227
235
  </div>
228
236
  </section>
229
237
 
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>
238
+ <footer class="mk-footer">{{ $t('kit.media.generated') }} {{ kit.generated_at?.slice(0, 10) }}</footer>
239
+ </div>
240
+ </template>
237
241
  </div>
238
242
  </template>
239
243
 
240
244
  <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
- }
245
+ .kit-media { background: var(--kit-bg); color: var(--kit-text); min-height: 100vh; font-family: 'Inter', system-ui, sans-serif; }
246
+ .kit-state { display: flex; align-items: center; justify-content: center; min-height: 60vh; color: var(--kit-muted); }
247
+ .kit-wrap { max-width: 1100px; margin: 0 auto; padding: 0 24px 60px; }
248
+ .mk-cover { height: 200px; background: linear-gradient(120deg, var(--kit-accent), #2a0e4e 60%, var(--kit-bg)); }
249
+
250
+ .mk-header { margin-top: -70px; position: relative; z-index: 2; display: flex; gap: 24px; align-items: flex-end; flex-wrap: wrap; }
251
+ .mk-avatar { width: 140px; height: 140px; border: 3px solid var(--kit-accent); object-fit: cover; flex-shrink: 0; background: var(--kit-surface-2); }
252
+ .mk-avatar-ph { background: linear-gradient(135deg, var(--kit-surface-2), var(--kit-accent)); }
253
+ .mk-hid { flex: 1; min-width: 260px; padding-bottom: 6px; }
254
+ .mk-hid h1 { font-family: 'Rajdhani'; font-size: 40px; line-height: 1.05; }
255
+ .mk-badges { display: flex; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
256
+ .mk-badge { font-family: 'Rajdhani'; font-weight: 700; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; padding: 4px 10px; }
257
+ .mk-badge.plat { background: var(--kit-surface-2); border: 1px solid var(--kit-line); }
258
+ .mk-badge.tier { background: var(--kit-accent); color: var(--kit-accent-ink); }
259
+ .mk-bio { color: #c4c4d2; font-size: 15px; max-width: 60ch; margin-top: 6px; }
260
+ .mk-actions { display: flex; gap: 10px; padding-bottom: 8px; }
261
+
262
+ .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; }
263
+ .kit-btn-primary { background: var(--kit-accent); color: var(--kit-accent-ink); }
264
+ .kit-btn-ghost { background: rgba(255,255,255,.04); border-color: var(--kit-line); color: var(--kit-text); }
265
+
266
+ .kit-block { margin-top: 44px; }
267
+ .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; }
268
+ .kit-block > h2::after { content: ""; flex: 1; height: 1px; background: var(--kit-line); }
269
+ .mk-period { color: var(--kit-muted); font-size: 13px; margin: -8px 0 16px; }
270
+
271
+ .mk-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
272
+ .mk-metric { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 20px 16px; text-align: center; position: relative; }
273
+ .mk-metric::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: var(--kit-accent); }
274
+ .mk-metric .val { font-family: 'Rajdhani'; font-weight: 700; font-size: 30px; line-height: 1; }
275
+ .mk-metric .val.accent { color: var(--kit-accent); }
276
+ .mk-metric .lab { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); margin-top: 8px; }
277
+
278
+ .mk-cols2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
279
+ .kit-card { background: var(--kit-surface); border: 1px solid var(--kit-line); }
280
+ .mk-pad { padding: 20px; }
281
+ .mk-pad h3 { font-size: 14px; font-weight: 700; margin-bottom: 14px; }
282
+ .mk-bar { margin-bottom: 12px; }
283
+ .mk-bar .top { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 5px; }
284
+ .mk-bar .top b { color: var(--kit-accent); }
285
+ .mk-bar .track { height: 8px; background: var(--kit-surface-2); }
286
+ .mk-bar .fill { height: 100%; background: var(--kit-accent); }
287
+ .mk-gender { display: flex; gap: 16px; }
288
+ .mk-gender .g { flex: 1; text-align: center; background: var(--kit-surface-2); border: 1px solid var(--kit-line); padding: 14px; }
289
+ .mk-gender .pct { font-family: 'Rajdhani'; font-weight: 700; font-size: 26px; color: var(--kit-accent); }
290
+ .mk-gender .lb { font-size: 12px; color: var(--kit-muted); text-transform: uppercase; }
291
+
292
+ .mk-tags { display: flex; flex-wrap: wrap; gap: 8px; }
293
+ .mk-tag { background: var(--kit-surface-2); border: 1px solid var(--kit-line); padding: 6px 13px; font-size: 13px; }
294
+
295
+ .mk-games { display: flex; flex-direction: column; gap: 8px; }
296
+ .mk-game { display: flex; align-items: center; justify-content: space-between; background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 12px 16px; }
297
+ .mk-game .nm { font-weight: 600; }
298
+ .mk-game .st { display: flex; gap: 18px; color: var(--kit-muted); font-size: 13px; }
299
+
300
+ .mk-rates { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
301
+ .mk-rate { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 18px; }
302
+ .mk-rate .fmt { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-accent); font-weight: 700; }
303
+ .mk-rate .lb { font-weight: 600; font-size: 16px; margin: 6px 0 10px; font-family: 'Rajdhani'; }
304
+ .mk-rate .price { font-family: 'Rajdhani'; font-weight: 700; font-size: 22px; }
305
+ .mk-rate .dl { font-size: 12px; color: var(--kit-muted); margin-top: 6px; }
306
+ .mk-bundles { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
307
+ .mk-bundle { background: linear-gradient(135deg, var(--kit-surface), var(--kit-surface-2)); border: 1px solid var(--kit-accent); padding: 18px; position: relative; }
308
+ .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'; }
309
+ .mk-bundle .bn { font-weight: 700; font-size: 17px; font-family: 'Rajdhani'; }
310
+ .mk-bundle .bd { font-size: 13px; color: var(--kit-muted); margin: 4px 0 10px; }
311
+ .mk-bundle .bp { font-family: 'Rajdhani'; font-weight: 700; font-size: 24px; color: var(--kit-accent); }
312
+ .mk-bundle .bp s { color: var(--kit-muted); font-size: 15px; font-weight: 500; margin-left: 8px; }
313
+ .mk-bundle .bundle-items { list-style: none; padding: 0; margin: 0 0 12px; display: flex; flex-direction: column; gap: 4px; }
314
+ .mk-bundle .bundle-items li { font-size: 13px; color: #c4c4d2; }
315
+ .mk-bundle .bundle-items li b { color: var(--kit-accent); font-family: 'Rajdhani'; }
316
+
317
+ .mk-brands { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
318
+ .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; }
319
+
320
+ .mk-schedule { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
321
+ .mk-day { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 12px 8px; text-align: center; }
322
+ .mk-day.on { border-color: var(--kit-accent); }
323
+ .mk-day .dn { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); }
324
+ .mk-day.on .dn { color: var(--kit-accent); }
325
+ .mk-day .hr { font-family: 'Rajdhani'; font-weight: 700; margin-top: 6px; font-size: 14px; }
326
+ .mk-day .off { color: var(--kit-muted); opacity: .4; margin-top: 6px; }
327
+
328
+ .mk-socials { display: flex; flex-wrap: wrap; gap: 10px; }
329
+ .mk-soc { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 9px 16px; font-size: 14px; text-transform: capitalize; }
330
+
331
+ .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; }
332
+ .mk-indiewall .iw-name { font-family: 'Rajdhani'; font-weight: 700; font-size: 19px; }
333
+ .mk-indiewall .iw-desc { color: #b4b4c2; font-size: 13px; margin-top: 4px; }
334
+ .mk-indiewall .iw-stats { display: flex; gap: 26px; margin-top: 10px; }
335
+ .mk-indiewall .iw-stats .v { font-family: 'Rajdhani'; font-weight: 700; font-size: 20px; color: var(--kit-accent); }
336
+ .mk-indiewall .iw-stats .l { font-size: 11px; text-transform: uppercase; color: var(--kit-muted); }
337
+
338
+ .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; }
339
+
340
+ @media (max-width: 840px) {
341
+ .mk-metrics { grid-template-columns: repeat(2, 1fr); }
342
+ .mk-cols2, .mk-rates, .mk-bundles { grid-template-columns: 1fr; }
343
+ .mk-brands { grid-template-columns: repeat(3, 1fr); }
344
+ .mk-schedule { grid-template-columns: repeat(4, 1fr); }
345
+ .mk-header { flex-direction: column; align-items: flex-start; }
624
346
  }
347
+ @media print { .no-print { display: none !important; } }
348
+
349
+ /* Reach / platform breakdown */
350
+ .mk-total-reach { font-family: 'Rajdhani'; font-weight: 700; font-size: 28px; color: var(--kit-accent); margin: -8px 0 16px; }
351
+ .mk-total-reach span { font-family: 'Inter'; font-size: 13px; color: var(--kit-muted); font-weight: 500; text-transform: uppercase; letter-spacing: 1px; }
352
+ .mk-platforms { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
353
+ .mk-platform { background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 16px; text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 6px; }
354
+ .mk-platform:hover { border-color: var(--kit-accent); }
355
+ .mk-platform .pl-head { display: flex; align-items: center; justify-content: space-between; }
356
+ .mk-platform .pl-name { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); }
357
+ .mk-platform .pl-verified { color: #27ae60; font-weight: 700; }
358
+ .mk-platform .pl-followers { font-family: 'Rajdhani'; font-weight: 700; font-size: 24px; }
359
+ .mk-platform .pl-meta { display: flex; gap: 12px; font-size: 12px; color: var(--kit-muted); flex-wrap: wrap; }
360
+
361
+ /* Template = layout emphasis (section order). Default DOM order = Creator. */
362
+ .mk-sections { display: flex; flex-direction: column; }
363
+ .mk-sections > .mk-header { order: 0; }
364
+ .mk-sections > .mk-footer { order: 100; }
365
+ .mk-sections > [data-sec="reach"]{order:1} .mk-sections > [data-sec="metrics"]{order:2}
366
+ .mk-sections > [data-sec="audience"]{order:3} .mk-sections > [data-sec="styles"]{order:4}
367
+ .mk-sections > [data-sec="games"]{order:5} .mk-sections > [data-sec="rates"]{order:6}
368
+ .mk-sections > [data-sec="brands"]{order:7} .mk-sections > [data-sec="schedule"]{order:8}
369
+ .mk-sections > [data-sec="connect"]{order:9} .mk-sections > [data-sec="support"]{order:10}
370
+
371
+ [data-template="performance"] .mk-sections > [data-sec="metrics"]{order:1}
372
+ [data-template="performance"] .mk-sections > [data-sec="reach"]{order:2}
373
+ [data-template="performance"] .mk-sections > [data-sec="games"]{order:3}
374
+
375
+ [data-template="commercial"] .mk-sections > [data-sec="reach"]{order:1}
376
+ [data-template="commercial"] .mk-sections > [data-sec="rates"]{order:2}
377
+ [data-template="commercial"] .mk-sections > [data-sec="brands"]{order:3}
378
+ [data-template="commercial"] .mk-sections > [data-sec="metrics"]{order:4}
379
+
380
+ [data-template="audience"] .mk-sections > [data-sec="reach"]{order:1}
381
+ [data-template="audience"] .mk-sections > [data-sec="audience"]{order:2}
382
+ [data-template="audience"] .mk-sections > [data-sec="styles"]{order:3}
383
+ [data-template="audience"] .mk-sections > [data-sec="metrics"]{order:4}
625
384
  </style>