- delivery-information, product-actions, product-description,
product-gallery, product-information, related-products,
variant-selector: normalize hardcoded hex colors to design tokens
(--text-primary, --text-secondary, --border-color, --bg-primary/
--bg-secondary, --primary-color/--primary-hover); stock status and
discount badge now use semantic --success-color/--warning-color/
--error-color instead of near-duplicate literal hex
- product-actions: add aria-pressed to wishlist/compare toggle
buttons; add hover/active/disabled states to action buttons
- product-gallery: add aria-current + aria-label to active thumbnail
button; add focus-visible ring and hover state on thumbnails and
toolbar buttons
- variant-selector: add aria-pressed to colour/size option buttons;
add a visible checkmark glyph on the selected colour swatch so
selection isn't color-only; add hover states
- product-tabs: add role="tab"/aria-selected to tab buttons
- star-selector: add per-star aria-label (new starsLabel i18n key
added to en/hy/ru + translations.ts interface)
- question-list: add aria-expanded to the ask-question disclosure
toggle; swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager buttons
- review-list: swap plain empty-state <p> for app-empty-state; add
hover/disabled states to pager and load-more buttons
- question-card, question-form, review-form: normalize accepted/
success/error colors to semantic tokens; add focus-visible and
hover/disabled states to inputs and submit buttons
- compare-table: add scope="col"/scope="row" to table headers; make
header row and attribute column sticky for easier comparison on
long tables
- compare-page: add hover/focus states to the remove-from-compare
chip button
Build verified green via `npm run build`.
Out of scope / skipped:
- src/app/pages/item-detail/* is dead code (not referenced by any
route or component) - left untouched
- wishlist page and product-details-container were already fully
composed with shared skeleton/empty-state/button components from
the RC-Visual-02 pass - no changes needed
- stars.component display-only rating glyphs use a light gray not an
exact token match - left as-is to avoid an unintended visual shift
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace hand-rolled loading/error/empty markup with shared app-skeleton,
app-empty-state, and app-button across catalog, product details, cart,
compare, wishlist, and the public static-page renderer
- Fix hardcoded hex colors that bypassed theme CSS variables (catalog,
product details), restoring multi-tenant theme correctness
- Remove ~1100 lines of dead "alt" cart theme CSS (never applied by the
template) from cart.component.scss, bringing it back under the 40kB
build budget (89.49kB -> 59.39kB cart-component chunk)
- Swap legacy global .btn/.btn-ghost/.btn-primary classes for app-button
in compare and wishlist empty/toolbar actions
Mechanical, value-preserving: font-weight: 400/500/600/700 -> var(--font-weight-normal/medium/semibold/bold, <same value>) across src/app.
Note: cart.component.scss now sits ~771 bytes over its per-file budget
in angular.json due to longer var() strings; non-fatal build warning,
noted in docs/UI-DESIGN-REVIEW.md as a follow-up (either bump the
component style budget slightly or accept the warning).
Mechanical sweep for border-radius: 4px/8px/12px/13px/999px replaced
with var(--radius-xs/sm/md/lg/full, <same value>) across src/app.
Only exact matches to existing token values were touched (20px, 16px,
10px, 6px, 3px, 2px etc. were left as-is since no token maps to them
without a visible size change on at least one tenant theme — see
docs/UI-DESIGN-REVIEW.md).
Mechanical, value-preserving substitution: every literal font-size
declaration across src/app (89 files) that matched one of the 9
typography scale steps introduced earlier (--font-size-xs..4xl) was
replaced with var(--font-size-STEP, <same-or-nearest-step-value>).
Values within ~0.03rem/1px of a scale step were snapped to that step
(e.g. 0.85rem and 0.8rem both -> --font-size-sm/0.8125rem; 0.9rem and
0.875rem -> --font-size-base/0.875rem) to consolidate roughly 15
near-duplicate sizes down to the 9-step scale, per the RC design-system
finalization brief. This eliminates most of the font-size fragmentation
found across the app (previously: 0.7/0.72/0.75/0.78/0.8/0.8125/0.85/
0.875/0.9/0.9375/0.95/1/1.05/1.1/1.125/1.15/1.2/1.25/1.3/1.35/1.4/1.5/
1.75/2rem all in live use simultaneously).
Not touched (deliberately, see docs/UI-DESIGN-REVIEW.md): 3rem+ display
sizes (too large a jump to any existing step, would need a --font-size-5xl
addition), font-size values expressed via clamp()/calc(), and any
component listed as intentionally distinct (code-editor syntax tokens,
theme brand colors).
Add role=status/alert + aria-live to loading/error sections (matching
the pattern already applied to home/search/catalog).
Add missing :focus-visible states to the buying-flow controls that had
none: add-to-cart/buy-now/wishlist/compare/share buttons, variant
colour-swatch and size-chip pickers, and the star rating selector.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
P0-5: some catalog listings (live backend data, proxied third-party
marketplace via novo.market) carry HTML-entity-encoded markup in
their description field, e.g. '<attention>...</attention>'
and '"AppStops"' — rendered verbatim as visible text on
search-result cards and the PDP description tab.
Added a pure cleanDescription() util (item.utils.ts) that decodes
the common HTML entities and strips any resulting tag-like markup,
then wired it into ProductCardComponent (covers Home/Catalog/Search/
Wishlist/Compare/PDP-similar) and ProductDescriptionComponent (PDP
description tab). Output stays a plain string rendered via text
interpolation (never innerHTML), so this only cleans up display —
it introduces no HTML-rendering/XSS surface.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Unify product details modules behind config-driven contracts so teams can
extend UX without changing runtime architecture or bootstrap flow.
Keep backward compatibility with existing product payloads by treating new
media/specification/variant/related structures as optional extensions.
Improve conversion and content discoverability with reusable actions,
typed media rendering, grouped specifications, dynamic variants, and
multi-collection related products.