diff --git a/assets/css/frontend/medal.css b/assets/css/frontend/medal.css
index 465021db..60f2760e 100644
--- a/assets/css/frontend/medal.css
+++ b/assets/css/frontend/medal.css
@@ -7,7 +7,63 @@
* 加载条件与 user-badges.js 一致(badge surface 页面)。
* ============================================================ */
-/* ---------- 分类分组(zibll .medal-cat-box / .medal-cat-name) ---------- */
+/* ---------- 顶部资料卡入口(zibll user-medal-info parity) ---------- */
+.aksrt-medal-entry {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ min-width: 0;
+ margin: 2px 8px 2px 0;
+ padding: 2px 0;
+ border: 0;
+ background: transparent;
+ color: var(--muted-2-color, var(--color-ink-4));
+ font: inherit;
+ font-size: 12px;
+ line-height: 1.4;
+ cursor: pointer;
+ white-space: nowrap;
+ transition: color .15s ease, opacity .15s ease;
+}
+.aksrt-medal-entry:hover,
+.aksrt-medal-entry:focus-visible {
+ color: var(--focus-color);
+ opacity: 1;
+}
+.aksrt-medal-entry:focus-visible {
+ outline: 2px solid var(--focus-color);
+ outline-offset: 2px;
+ border-radius: var(--mini-radius, 6px);
+}
+.aksrt-medal-entry__icons {
+ display: inline-flex;
+ align-items: center;
+ flex: none;
+ min-width: 0;
+}
+.aksrt-medal-entry__icon {
+ width: auto;
+ height: 1.45em;
+ max-width: 2.2em;
+ margin: 0 1px;
+ object-fit: contain;
+ vertical-align: middle;
+}
+.aksrt-medal-entry__icon + .aksrt-medal-entry__icon { margin-left: -1px; }
+.aksrt-medal-entry__fallback {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.6em;
+ height: 1.6em;
+ color: var(--focus-color);
+ background: var(--focus-color-opacity1);
+ border-radius: 50%;
+}
+.aksrt-medal-entry__count { margin-left: 2px; }
+.aksrt-medal-entry__arrow { margin-left: 1px; font-size: .9em; }
+
+
.medal-cat-box {
position: relative;
text-align: center;
diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css
index f320be8e..9e5995e3 100644
--- a/assets/css/frontend/widget-batch5.css
+++ b/assets/css/frontend/widget-batch5.css
@@ -738,8 +738,7 @@
}
.aksrt-author-card__badge img { border-radius: 50%; }
-/* 徽章远程弹窗样式已迁至 assets/css/frontend/medal.css(zibll medal 风格)。 */
-.aksrt-author-hero__badges { margin-top: 8px; }
+/* 徽章入口与弹窗样式统一由 assets/css/frontend/medal.css 提供。 */
/* Forum tab topics (batch6) */
.aksrt-ftab__nav {
diff --git a/inc/helpers/aksrt-identity.php b/inc/helpers/aksrt-identity.php
index 6dde7567..eac33cd5 100644
--- a/inc/helpers/aksrt-identity.php
+++ b/inc/helpers/aksrt-identity.php
@@ -234,6 +234,63 @@ if (!function_exists('aksrt_get_user_name')) {
}
}
+if (!function_exists('aksrt_render_user_medal_entry')) {
+ /**
+ * Render the compact Zibll-style badge overview entry.
+ *
+ * The configured limit controls preview icons only; the count remains
+ * the complete owned badge count returned by the privacy-aware DTO.
+ *
+ * @param int $user_id
+ * @param string $context user-center|user-home
+ * @param bool $can_wear Whether the viewer may initially wear a badge.
+ */
+ function aksrt_render_user_medal_entry(int $user_id, string $context = 'user-home', bool $can_wear = false): string {
+ if ($user_id <= 0 || !class_exists('AKSRT\\User\\Badges') || !class_exists('AKSRT\\Settings\\Settings')) {
+ return '';
+ }
+
+ $settings = \AKSRT\Settings\Settings::get_user_identity_settings();
+ $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : [];
+ if (empty($medal['enabled']) || ($context === 'user-home' && empty($medal['public_display']))) {
+ return '';
+ }
+
+ $data = \AKSRT\User\Badges::list_for_user($user_id);
+ if (empty($data['enabled']) || ($context === 'user-home' && empty($data['public_display']))) {
+ return '';
+ }
+
+ $limit = max(1, min(8, (int) ($medal['limit'] ?? 3)));
+ $icons = [];
+ foreach ((array) ($data['categories'] ?? []) as $category) {
+ foreach ((array) ($category['items'] ?? []) as $item) {
+ if (empty($item['owned'])) {
+ continue;
+ }
+ $icon_url = esc_url((string) ($item['icon_url'] ?? ''));
+ if ($icon_url === '') {
+ continue;
+ }
+ $label = sanitize_text_field((string) ($item['label'] ?? __('徽章', 'aksrt')));
+ $icons[] = '';
+ if (count($icons) >= $limit) {
+ break 2;
+ }
+ }
+ }
+
+ $count = max(0, (int) ($data['count'] ?? 0));
+ $label = $count > 0 ? sprintf(_n('%d枚徽章', '%d枚徽章', $count, 'aksrt'), $count) : __('获取徽章', 'aksrt');
+ $icons_html = implode('', $icons);
+ if ($icons_html === '') {
+ $icons_html = '';
+ }
+ $classes = 'aksrt-medal-entry aksrt-medal-entry--' . sanitize_html_class($context);
+ return '';
+ }
+}
+
if (!function_exists('aksrt_user_has_visible_badges')) {
/**
* Whether a user owns at least one badge that exists in the current catalog.
diff --git a/inc/helpers/user-center-renderers/profile-header.php b/inc/helpers/user-center-renderers/profile-header.php
index 1570b3b1..607a85ca 100644
--- a/inc/helpers/user-center-renderers/profile-header.php
+++ b/inc/helpers/user-center-renderers/profile-header.php
@@ -41,6 +41,9 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_