The top-nav publish chip and open-membership chip carried an AKSRT-only
class layer (navbar-cta / navbar-cta-text / navbar-newposts /
navbar-vip-hover) plus a matching set of CSS overrides that replaced the
legacy .but geometry: margin 0.4em -> 0, an extra min-height and flex gap,
an FA5 pencil glyph that is not the reference pencil, and label text
wrapped in a span. The VIP hover card also had its own positioning
override instead of the reference static position.
Drop that layer and emit the reference class combination verbatim so the
already byte-identical legacy stylesheet owns the geometry again:
- publish chip renders newadd-btns but nowave <skin> [radius] btn-newadd
with the label echoed as saved (no injected icon, no span)
- VIP chip renders pay-vip|signin-loader but jb-red radius payvip-icon
with the vip_1 SVG at em12 mr3, inside span.hover-show.inline-block
- user-card CTA uses the vip_1 SVG (em12 mr6) instead of fa-gem and drops
vip-level, matching zib_get_header_payvip_icon()
- both buttons now honour Settings::close_sign(), matching the reference
zib_is_close_sign() gate and the floating publish button
- header-userbox.css keeps one rule that restores the hover wrapper to a
plain block container so .sub-vip-card takes its reference static
position; every other override is gone
- nav_newposts_text default drops the duplicated fas and uses the FA5
spelling of the reference pencil (fa-pencil-alt, not fa-pen)
Dead code removed: aksrt_normalize_header_cta_label(), the unreachable
multi-type dropdown branch of aksrt_render_new_add_btns() (only 'post' is
supported and only ['post'] is ever passed), and the
newadd-btns__toggle / newadd-btns__item / drop-newadd markup it emitted.
ml10 is no longer set on the VIP anchor: .aksrt-navbar-actions already
supplies the 10px gap the reference gets from ml10, and keeping both
would double it to 20px.
No migration for sites that already stored the old nav_newposts_text.
Verified: node --test across tests/ (603 passing), php -l on the changed
PHP files, and a stubbed render of every publish/VIP branch.
The two large hero avatar frames go back to their legacy rounded-square look: the user center profile header keeps 6px and the public user home hero keeps var(--radius). Both declare an explicit radius because the global avatar primitive (img.avatar, 0,1,1) ties them on specificity and only the later route rule wins the cascade.
Everything else stays: the primitive still circles the bare avatar-mini in the ban and report modals, the VIP modal avatar and the post-card meta avatar, the friends page avatar is circular, and the VIP icon still leads the badge row. The contract test now guards the two hero frames as rounded-square so the primitive cannot silently re-circularize them.
Make --radius-avatar the single source of truth for frontend user avatar shape. A new primitive in components-ext.css (img.avatar / avatar-mini / avatar-md / avatar-lg / .avatar-img img) forces a circle on every avatar image, which covers the bare avatar-mini in the ban and report modals, the classless img inside the VIP modal's .avatar-img, and the post-card meta avatar that previously depended on post-card.css being enqueued. The user center header frame, the public user home hero and the friends page avatar switch to the same token because route CSS loads after the public bundle and would otherwise override the primitive.
The VIP icon no longer rides the avatar corner. The user card widget, the after-article author card and the sign-in modal stop opting into aksrt_get_avatar_box()'s corner badge, and the icon renders first in the badge/level row instead, since aksrt_get_user_name already orders name -> VIP -> auth -> medal -> level. The sign-in modal appends it after the display name and keeps the legacy precedence where a ban badge takes the VIP slot. The user card widget name row now shrinks its display name so the extra icon cannot overflow a narrow sidebar.
Verified with the new frontend-avatar-shape-contract test plus post-visual, user-card-runtime, circular-button-icon-margin, user-features and page-display contracts, and php -l on every changed PHP file. The public bundle was rebuilt with tools/build-public-assets.mjs.
The posts/favorites tabs turn the article list into a 2-column grid at
>=992px. The AJAX pagination skeleton .post_ajax_loader is a direct
child of that grid, so with no grid-column it was laid out as a single
half-width card and the whole placeholder stack collapsed into one
column while paging or switching tabs.
Span the loader across every column and, while loading, give it the
same 2-column template the real cards use so placeholders line up with
them. The skeleton shape now follows the resolved render mode instead
of a hardcoded 'list', so card mode no longer renders list blocks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>