diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css
index a51c6701..ded92c65 100644
--- a/assets/css/frontend/widget-batch5.css
+++ b/assets/css/frontend/widget-batch5.css
@@ -1432,3 +1432,273 @@
.aksrt-product-widget--oneline .aksrt-product-widget__grid {
/* legacy flex fallback if swiper unavailable */
}
+
+/* ===== Batch13: oneline posts swiper-scroll + user minicards + term graphic ===== */
+
+.widget-main-post.aksrt-oneline-posts {
+ margin-bottom: 16px;
+}
+.aksrt-oneline-swiper {
+ position: relative;
+ overflow: hidden;
+ padding: 0 28px 4px;
+}
+.aksrt-oneline-swiper .swiper-wrapper {
+ display: flex;
+ align-items: stretch;
+}
+.aksrt-oneline-swiper .swiper-slide {
+ width: auto;
+ max-width: 46%;
+ min-width: 160px;
+ height: auto;
+}
+.widget-main-post.style-mini .aksrt-oneline-swiper .swiper-slide {
+ max-width: 280px;
+ min-width: 220px;
+}
+.widget-main-post.style-list .aksrt-oneline-swiper .swiper-slide {
+ max-width: 320px;
+ min-width: 240px;
+}
+.aksrt-oneline-swiper .posts-item,
+.aksrt-oneline-swiper .posts-mini {
+ height: 100%;
+ margin: 0 8px 0 0;
+}
+.aksrt-oneline-swiper .swiper-button-prev,
+.aksrt-oneline-swiper .swiper-button-next {
+ width: 28px;
+ height: 28px;
+ margin-top: 0;
+ top: 42%;
+ border-radius: 50%;
+ background: var(--surface-1, #fff);
+ border: 1px solid var(--color-line, #e5e7eb);
+ color: var(--color-ink, #111);
+ box-shadow: 0 2px 8px rgba(0,0,0,.06);
+}
+.aksrt-oneline-swiper .swiper-button-prev:after,
+.aksrt-oneline-swiper .swiper-button-next:after {
+ font-size: 12px;
+ font-weight: 700;
+}
+.aksrt-oneline-swiper .swiper-button-prev { left: 0; }
+.aksrt-oneline-swiper .swiper-button-next { right: 0; }
+
+/* User lists → author-minicard */
+.aksrt-user-lists .user_lists {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ text-align: left;
+}
+.aksrt-user-lists .author-minicard {
+ display: block;
+ padding: 12px 14px;
+ border-radius: 8px;
+ background: var(--surface-1, #fff);
+ border: 1px solid var(--color-line, #e5e7eb);
+ overflow: hidden;
+}
+.aksrt-user-lists.is-bare .author-minicard {
+ background: transparent;
+}
+.aksrt-user-lists .author-minicard > ul.list-inline {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.aksrt-user-lists .author-minicard > ul.list-inline > li {
+ margin: 0;
+ list-style: none;
+}
+.aksrt-user-lists .author-minicard .avatar-img img.avatar {
+ width: 42px;
+ height: 42px;
+ border-radius: 50%;
+ object-fit: cover;
+ display: block;
+}
+.aksrt-user-lists .author-minicard dl {
+ margin: 0;
+ min-width: 0;
+}
+.aksrt-user-lists .author-minicard dt.flex {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 4px;
+}
+.aksrt-user-lists .author-minicard dd {
+ margin: 0;
+ max-width: 100%;
+}
+.aksrt-user-lists .author-minicard .abs-blur-bg {
+ position: absolute;
+ inset: 0;
+ overflow: hidden;
+ z-index: 0;
+ opacity: .18;
+ pointer-events: none;
+}
+.aksrt-user-lists .author-minicard .abs-blur-bg img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ filter: blur(18px);
+ transform: scale(1.2);
+}
+.aksrt-user-lists .author-minicard .relative {
+ position: relative;
+ z-index: 1;
+}
+
+/* Graphic card polish */
+.graphic {
+ background: var(--surface-2, #f3f4f6);
+}
+.graphic .graphic-mask {
+ position: absolute;
+ inset: 0;
+ background: #000;
+ pointer-events: none;
+ z-index: 1;
+}
+.graphic .graphic-text,
+.graphic .abs-center {
+ z-index: 2;
+ padding: 10px 12px;
+}
+.graphic .title-h-center {
+ font-size: 16px;
+ font-weight: 700;
+}
+.graphic badge.b-black,
+.graphic .img-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 2px 8px;
+ border-radius: 4px;
+ background: rgba(0,0,0,.55);
+ color: #fff;
+ font-size: 12px;
+ line-height: 1.4;
+}
+.graphic video.fit-cover {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+.hover-zoom-img .graphic img.fit-cover,
+.hover-zoom-img.graphic img.fit-cover {
+ transition: transform .45s ease;
+}
+.hover-zoom-img:hover .graphic img.fit-cover,
+.hover-zoom-img.graphic:hover img.fit-cover {
+ transform: scale(1.06);
+}
+.aksrt-term-cards .row.gutters-5 {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0 -4px;
+}
+.aksrt-term-cards .row.gutters-5 > [class*="col-"] {
+ padding: 0 4px;
+ box-sizing: border-box;
+}
+.aksrt-term-cards .col-sm-12 { width: 100%; }
+.aksrt-term-cards .col-sm-6 { width: 50%; }
+.aksrt-term-cards .col-sm-4 { width: 33.333%; }
+.aksrt-term-cards .col-sm-3 { width: 25%; }
+.aksrt-term-cards .col-sm-2 { width: 16.666%; }
+@media (max-width: 767px) {
+ .aksrt-term-cards .col-xs-12 { width: 100%; }
+ .aksrt-term-cards .col-xs-6 { width: 50%; }
+ .aksrt-term-cards .col-xs-4 { width: 33.333%; }
+}
+
+/* Term aggregation (zibll term-aggregation) */
+.term-aggregation.aksrt-term-agg__card,
+.zib-widget.term-aggregation {
+ padding: 14px;
+ border-radius: 10px;
+ background: var(--surface-1, #fff);
+ border: 1px solid var(--color-line, #e5e7eb);
+ margin-bottom: 12px;
+}
+.aksrt-term-agg {
+ display: grid;
+ gap: 12px;
+ grid-template-columns: repeat(var(--aksrt-ta-cols, 1), minmax(0, 1fr));
+}
+.term-aggregation .hover-zoom-img.flex {
+ display: flex;
+ align-items: stretch;
+ gap: 0;
+}
+.term-aggregation .term-img {
+ width: 38%;
+ max-width: 180px;
+ min-width: 110px;
+}
+.term-aggregation .term-img .graphic {
+ margin: 0;
+ border-radius: 8px;
+}
+.term-aggregation .term-title {
+ min-width: 0;
+ padding-left: 4px;
+}
+.term-aggregation .term-title > a {
+ font-weight: 700;
+ text-decoration: none;
+ color: inherit;
+}
+.term-aggregation .term-meta {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 8px;
+ margin-top: 6px;
+}
+.term-aggregation .icon-circle {
+ position: relative;
+ padding-left: 14px;
+ color: inherit;
+ text-decoration: none;
+}
+.term-aggregation .icon-circle:before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--theme-color, var(--focus-color, #f04494));
+ transform: translateY(-50%);
+}
+.term-aggregation .but.c-blue {
+ display: inline-flex;
+ align-items: center;
+ gap: 2px;
+ border-radius: 999px;
+ padding: 2px 10px;
+ font-size: 12px;
+ background: rgba(59,130,246,.1);
+ color: #2563eb;
+ text-decoration: none;
+}
+@media (max-width: 640px) {
+ .aksrt-term-agg { grid-template-columns: 1fr; }
+ .term-aggregation .term-img { max-width: 120px; min-width: 88px; width: 34%; }
+ .term-aggregation .hide-sm { display: none !important; }
+ .aksrt-oneline-swiper .swiper-slide { max-width: 72%; min-width: 140px; }
+}
diff --git a/inc/bootstrap.php b/inc/bootstrap.php
index aa2e6c2d..b19a0bea 100644
--- a/inc/bootstrap.php
+++ b/inc/bootstrap.php
@@ -48,6 +48,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-header-userbox.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-header-menu-buttons.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-runtime-win.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-identity.php';
+require_once AKSRT_DIR . '/inc/helpers/aksrt-graphic-card.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-user-card.php';
require_once AKSRT_DIR . '/inc/helpers/aksrt-rewards.php';
require_once AKSRT_DIR . '/inc/helpers/menu-decoration.php';
diff --git a/inc/helpers/aksrt-graphic-card.php b/inc/helpers/aksrt-graphic-card.php
new file mode 100644
index 00000000..93952de6
--- /dev/null
+++ b/inc/helpers/aksrt-graphic-card.php
@@ -0,0 +1,276 @@
+ $args {
+ * @type string $type style-1|style-2|style-3|style-4|''.
+ * @type string $class Extra classes on .graphic.
+ * @type string $img Image URL.
+ * @type string $video Optional video URL (desktop).
+ * @type string $alt Image alt.
+ * @type array{url?:string,target?:string}|string $link Link.
+ * @type string $text1 Primary text.
+ * @type string $text2 Secondary text.
+ * @type string $text3 Tertiary / badge text (HTML allowed for icon+count).
+ * @type string $more Extra absolute HTML (badge etc).
+ * @type bool $lazy Use aksrt-lazy data-src.
+ * @type int|float $height_scale Padding-bottom % (0 = default CSS).
+ * @type int|float $mask_opacity 0–100 overlay opacity.
+ * @type string $hide pc|m|'' hide on device.
+ * }
+ * @param bool $echo Echo instead of return.
+ */
+ function aksrt_graphic_card(array $args = [], bool $echo = false): string {
+ $defaults = [
+ 'type' => '',
+ 'hide' => '',
+ 'class' => 'mb10',
+ 'img' => '',
+ 'video' => '',
+ 'alt' => __('图片', 'aksrt'),
+ 'link' => [
+ 'url' => '',
+ 'target' => '',
+ ],
+ 'text1' => '',
+ 'text2' => '',
+ 'text3' => '',
+ 'more' => '',
+ 'lazy' => true,
+ 'height_scale' => 0,
+ 'mask_opacity' => 0,
+ ];
+ $args = wp_parse_args($args, $defaults);
+
+ $img_url = trim((string) $args['img']);
+ $video_url = trim((string) $args['video']);
+ if ($img_url === '' && $video_url === '') {
+ return '';
+ }
+
+ // Device visibility.
+ $hide = sanitize_key((string) $args['hide']);
+ if ($hide === 'pc' || $hide === 'm') {
+ $is_mobile = function_exists('wp_is_mobile') ? wp_is_mobile() : false;
+ if ((!$is_mobile && $hide === 'pc') || ($is_mobile && $hide === 'm')) {
+ return '';
+ }
+ }
+
+ $type = sanitize_key((string) $args['type']);
+ if ($type !== '' && !in_array($type, ['style-1', 'style-2', 'style-3', 'style-4'], true)) {
+ // Accept bare "1"–"4".
+ if (preg_match('/^[1-4]$/', $type)) {
+ $type = 'style-' . $type;
+ } else {
+ $type = '';
+ }
+ }
+
+ $link = $args['link'];
+ if (is_string($link)) {
+ $link = ['url' => $link, 'target' => ''];
+ }
+ if (!is_array($link)) {
+ $link = ['url' => '', 'target' => ''];
+ }
+ $link_url = esc_url(trim((string) ($link['url'] ?? '')));
+ $link_target = sanitize_text_field((string) ($link['target'] ?? ''));
+
+ $lazy = !empty($args['lazy']);
+ $placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg';
+ $media = '';
+ if ($video_url !== '' && !(function_exists('wp_is_mobile') && wp_is_mobile())) {
+ $poster = $img_url !== '' ? ' poster="' . esc_url($img_url) . '"' : '';
+ if ($lazy) {
+ $media = '';
+ } else {
+ $media = '';
+ }
+ } elseif ($img_url !== '') {
+ $alt = (string) ($args['alt'] !== '' ? $args['alt'] : __('图片', 'aksrt'));
+ if ($lazy) {
+ $media = '';
+ } else {
+ $media = '
';
+ }
+ }
+ if ($media === '') {
+ return '';
+ }
+
+ $mask_opacity = max(0, min(100, (int) $args['mask_opacity']));
+ $mask = $mask_opacity > 0
+ ? '
@@ -156,6 +215,11 @@ class WidgetOnelinePosts extends \WP_Widget {
$new_instance
+ * @param array