/* WooCommerce product card ("game key card") v3 — flat, borderless grid item;
   near-square cover art bleeding edge-to-edge with rounded corners, no
   background box behind it (PS Store/Steam-library style). Title/price
   sit below on the page background, no card border/shadow around them.
   Add-to-cart is a bar docked to the image box, hidden until the card is
   hovered (see the .ast-on-card-button rule below). */

/* Fewer columns than before (one less per breakpoint) so each card gets
   noticeably more width — same shared grid the homepage's "جدیدترین بازی‌ها"
   row uses, so both get bigger cards from this one change. */
.woocommerce ul.products,
.woocommerce-page ul.products {
	gap: var(--space-4) !important;
}

/* ---------- Image loading skeleton ----------
   A plain CSS background on the <img> itself, no wrapper markup or JS
   needed for the grid case — browsers paint an element's background
   behind its own content, so the shimmer shows until the image finishes
   decoding and paints over it, then stays hidden permanently (no
   repeated reflow, no timer to clean up). Safe wherever the image is
   guaranteed to fully cover its box — every use below is object-fit:
   cover — since there's no letterboxed gap left exposed once loaded.
   (The single-product gallery uses object-fit:contain instead, since
   real product photos aren't guaranteed square, and needs the different,
   JS-assisted treatment near its own rules further down — a cover image
   naturally hides an endless CSS animation once loaded, but a contained
   one can leave a permanently-visible gap where that same animation
   would just look broken instead of "loading".) */
@keyframes gs-img-shimmer {
	0% { background-position: 200% 0; }
	100% { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
	@keyframes gs-img-shimmer {
		0%, 100% { background-position: 0 0; }
	}
}

@media (min-width: 1400px) {
	.woocommerce ul.products { grid-template-columns: repeat(4, 1fr) !important; }
}

@media (min-width: 768px) and (max-width: 1399px) {
	.woocommerce ul.products { grid-template-columns: repeat(3, 1fr) !important; }
}

@media (max-width: 767px) {
	.woocommerce ul.products { grid-template-columns: repeat(2, 1fr) !important; }
}

.woocommerce ul.products li.product,
.woocommerce-page ul.products li.product {
	display: flex;
	flex-direction: column;
	transition: transform var(--transition-base);
}

.woocommerce ul.products li.product:hover {
	transform: translateY(-4px);
}

/* The photo box: the card's whole visual weight, cover art bleeding
   edge-to-edge (object-fit: cover, below) with no background box behind
   it — just a rounded-corner crop, like a PS Store/Steam library tile. */
.woocommerce ul.products li.product .astra-shop-thumbnail-wrap {
	position: relative;
	aspect-ratio: 1 / 1;
	border-radius: var(--radius-lg);
	overflow: hidden;
	transition: box-shadow var(--transition-base);
}

.woocommerce ul.products li.product:hover .astra-shop-thumbnail-wrap {
	box-shadow: var(--shadow-card-hover);
}

/* Hover-darken overlay on the cover art, gamefa-style — a pseudo-element
   rather than injected markup so no template/hook changes are needed. */
.woocommerce ul.products li.product .astra-shop-thumbnail-wrap::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, .2);
	opacity: 0;
	transition: opacity var(--transition-fast);
	pointer-events: none;
}

.woocommerce ul.products li.product:hover .astra-shop-thumbnail-wrap::after {
	opacity: 1;
}

.woocommerce ul.products li.product a.woocommerce-loop-product__link,
.woocommerce ul.products li.product > a {
	position: relative;
	display: block;
}

.woocommerce ul.products li.product img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 0;
	background-image: linear-gradient(100deg, var(--skeleton-base) 30%, var(--skeleton-highlight) 50%, var(--skeleton-base) 70%);
	background-size: 400% 100%;
	animation: gs-img-shimmer 1.6s ease-in-out infinite;
}

/* max-height (with -webkit-line-clamp below) caps the title at two lines
   without reserving that height for shorter titles — cards size to their
   actual content instead of all matching the tallest possible title. */
/* Astra's own static stylesheet carries a much more specific selector for
   this same element (".woocommerce-page ul.products li.product
   .woocommerce-loop-product__title") that otherwise beats a plain
   ".woocommerce-loop-product__title" override on the shop archive
   (.woocommerce-page is on the body there) — matched here so ours reliably
   wins instead of losing margin-bottom to Astra's .5em default. */
.woocommerce ul.products li.product .woocommerce-loop-product__title,
.woocommerce-page ul.products li.product .woocommerce-loop-product__title {
	/* Same size as the price (.price ins below) on purpose — title and
	   price should read as equally important, not title-as-caption. */
	font-size: var(--font-md);
	font-weight: 600;
	line-height: 1.4;
	color: var(--text-primary);
	margin-block: var(--space-2) var(--space-1);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	max-height: 2.8em;
	transition: color var(--transition-fast);
}

.woocommerce ul.products li.product:hover .woocommerce-loop-product__title {
	color: var(--accent);
}

/* Platform chip row — shared markup (gs_platform_chips_html() in
   functions.php) for both the single-product in-flow row and the shop-loop
   image-corner overlay (.gs-platform-row--card below). */
.gs-platform-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-1);
	margin-block: var(--space-2) var(--space-1);
}

.woocommerce ul.products li.product .price {
	color: var(--text-primary);
	font-weight: 700;
	margin-block: var(--space-1) var(--space-2);
}

/* font-weight: 500, not lighter — IRANSansX's ss02 stylistic set (the
   Persian-style digit glyphs tokens.css turns on for the whole site) has no
   alternates baked in below ~500 on this variable font, so a genuinely thin
   weight here silently fell back to plain Western-style digits while the
   bold current price next to it kept the Persian ones. 500 is the lightest
   weight that still gets the substitution. !important because Astra's own
   compiled CSS (.woocommerce-js div.product p/span.price del) hardcodes 400
   at higher specificity (one more type selector than a plain class match
   can reach). */
.woocommerce ul.products li.product .price del {
	color: var(--text-muted);
	font-weight: 500 !important;
	font-size: var(--font-xs);
	opacity: 1;
	margin-inline-end: var(--space-2);
}

.woocommerce ul.products li.product .price ins {
	color: var(--text-primary);
	font-size: var(--font-md);
	text-decoration: none;
}

/* Add-to-cart bar docked to the bottom of the photo box, reusing Astra's
   own ".ast-on-card-button" element (already the real add-to-cart link,
   already nested inside .astra-shop-thumbnail-wrap) instead of Astra's
   small circular icon treatment. Hidden by default, revealed only on
   hover — Astra's own ".astra-shop-thumbnail-wrap:hover .ast-on-card-button"
   rule already does exactly that (opacity/visibility toggle), so this rule
   deliberately leaves opacity/visibility alone and only restyles position/
   size/color. One rule, so the trigger (":hover") is identical everywhere;
   a touch screen has no hover to trigger, same as any other hover-only UI.
   Text-only (its icon span is hidden below), using the same label Astra
   already renders in ".ast-card-action-tooltip" — no new markup, no
   duplicated "Add to cart"/"Select options" text to keep in sync. Astra's
   own default styling has high enough specificity to need overriding via
   the same selector shape (tag + 2 classes) it already used for the old
   display:none rule. */
.woocommerce ul.products li.product a.add_to_cart_button.ast-on-card-button {
	position: absolute;
	inset-inline: 0;
	inset-block-end: 0;
	left: auto;
	top: auto;
	width: 100%;
	height: 44px;
	margin: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 0;
	background: rgba(10, 11, 13, .85);
	cursor: pointer;
}

.woocommerce ul.products li.product a.add_to_cart_button.ast-on-card-button .ahfb-svg-iconset {
	display: none;
}

.woocommerce ul.products li.product a.add_to_cart_button.ast-on-card-button .ast-card-action-tooltip {
	position: static;
	opacity: 1;
	visibility: visible;
	background: none;
	color: #fff;
	margin: 0;
	padding: 0;
	font-size: var(--font-sm);
	font-weight: 600;
	line-height: 1.4;
	white-space: normal;
}

.woocommerce ul.products li.product a.add_to_cart_button.ast-on-card-button .ast-card-action-tooltip:after {
	display: none;
}

/* Discount badge — a rounded-rect tag in --accent (shared with CTAs, see design-system.md §1),
   text swapped to a real percentage via PHP filter. ".onsale" = classic shop-card style,
   ".ast-on-card-button.ast-onsale-card" = Astra's default "modern" shop-card style. */
.woocommerce span.onsale,
.woocommerce .ast-on-card-button.ast-onsale-card {
	position: absolute;
	inset-block-start: var(--space-3) !important;
	inset-inline-start: var(--space-3) !important;
	inset-inline-end: auto !important;
	margin: 0;
	min-height: 0;
	min-width: 0;
	border-radius: var(--radius-sm);
	background: var(--accent) !important;
	color: #fff !important;
	font-size: var(--font-2xs);
	font-weight: 700;
	line-height: 1.6;
	padding-block: .3em;
	padding-inline: .7em;
	box-shadow: none;
	z-index: 2;
}

/* Instant-delivery chip, image top corner opposite the discount badge. */
.gs-instant-badge {
	position: absolute;
	inset-block-start: var(--space-3);
	inset-inline-end: var(--space-3);
	z-index: 2;
}

/* Platform pills, shop-loop card only — pinned to the image's top-left
   corner (RTL: inset-inline-end), at the same inset-block-start offset as
   the discount badge's opposite corner (.woocommerce span.onsale above) so
   the two sit aligned. Solid surface background (not the transparent-outline
   look .gs-badge--platform normally has) since this row sits on top of the
   cover photo, not the page background. */
.gs-platform-row--card {
	position: absolute;
	inset-block-start: var(--space-3);
	inset-inline-end: var(--space-3);
	inset-inline-start: var(--space-3);
	margin-block: 0;
	justify-content: flex-end;
	z-index: 2;
}

.gs-platform-row--card .gs-badge--platform {
	background: var(--bg-surface);
	box-shadow: var(--shadow-sm);
}

.gs-badge__icon {
	display: inline-flex;
	flex: none;
}

/* Icon xor label, never both — desktop/tablet cards have room to just say
   "پلی‌استیشن" in full; phone-width cards (a 2-column grid card is only
   ~180px wide there) get cramped fast with 2-3 text pills, so those swap to
   icon-only instead. :has() rather than a blanket icon-hide/label-show
   split, because a platform the game-store-options plugin doesn't know an
   icon for (see gs_platform_term_icon()) has no icon span to hide behind —
   it always needs its label, at every width, or it'd render as an empty,
   invisible pill. Scoped to .gs-platform-row--card (shop-loop cards) only —
   the single-product page's in-flow row has room for icon+label together
   at any width and was never part of this ask. */
.gs-platform-row--card .gs-badge--platform:has(.gs-badge__icon) .gs-badge__icon {
	display: none;
}

@media (max-width: 480px) {
	.gs-platform-row--card .gs-badge--platform {
		padding: var(--space-2);
	}

	.gs-platform-row--card .gs-badge--platform:has(.gs-badge__icon) {
		gap: 0;
	}

	.gs-platform-row--card .gs-badge--platform:has(.gs-badge__icon) .gs-badge__icon {
		display: inline-flex;
	}

	.gs-platform-row--card .gs-badge--platform:has(.gs-badge__icon) .gs-badge__label {
		display: none;
	}
}

/* Below-price classic button — hidden unconditionally (no hover/touch
   media-query split, so behavior is identical at every screen width): the
   bar docked on the image is the one add-to-cart affordance everywhere. */
.woocommerce ul.products li.product .button {
	display: none;
}

/* .added_to_cart ("view cart" confirmation after adding) is a genuinely
   different, useful thing — kept visible regardless, as feedback that the
   add actually happened. It lacks the .button class in WooCommerce's own
   markup, so it needs its own block/width/spacing spelled out. */
.woocommerce ul.products li.product .added_to_cart {
	display: block;
	margin-block-start: var(--space-2);
	width: 100%;
	text-align: center;
	border-radius: var(--radius-sm);
	background: var(--success);
	border-color: var(--success);
	color: #fff;
}

/* Low stock notice */
.woocommerce .stock.low-stock,
.woocommerce p.stock.low-stock {
	color: var(--warning);
	font-size: var(--font-xs);
}

.woocommerce .stock.out-of-stock {
	color: var(--danger);
	font-size: var(--font-xs);
}

/* Category / platform quick-nav chips (top of shop page, e.g. above the grid) */
.gs-chip {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding-block: var(--space-2);
	padding-inline: var(--space-4);
	border-radius: var(--radius-full);
	background: var(--bg-elevated);
	border: 1px solid var(--border-subtle);
	color: var(--text-secondary);
	font-size: var(--font-sm);
	font-weight: 600;
	transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.gs-chip:hover,
.gs-chip.is-active {
	background: var(--accent);
	border-color: var(--accent);
	color: #fff;
}

/* ---------- Filter sidebar (new in v2) ---------- */
#secondary.widget-area,
.ast-woo-sidebar-widget {
	background: transparent;
}

.ast-woo-sidebar-widget {
	background: var(--bg-elevated);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-lg);
	padding: var(--space-4);
	margin-block-end: var(--space-4);
}

.ast-woo-sidebar-widget .widget-title {
	font-size: var(--font-sm);
	font-weight: 700;
	color: var(--text-primary);
	margin-block-end: var(--space-3);
}

.ast-woo-sidebar-widget ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* !important beats two separate things at once: Astra's own inline/dynamic
   CSS ("#secondary li { margin-bottom: 0.75em }" — not an exposed
   astra-settings option, checked) stacks a flat 12px under every <li> in
   the sidebar on top of the padding below, nearly doubling the gap between
   filter items; and Astra's WooCommerce-compat stylesheet gives the
   categories widget specifically a smaller, different padding
   (".woocommerce-js ul.product-categories > li{padding:2px 0}") than every
   other widget list here gets, for no reason tied to this design. */
.ast-woo-sidebar-widget ul li {
	padding-block: var(--space-1) !important;
	margin-block-end: 0 !important;
}

.ast-woo-sidebar-widget a {
	color: var(--text-secondary);
}

.ast-woo-sidebar-widget a:hover {
	color: var(--accent);
}

.woocommerce .widget_layered_nav .chosen a::before,
.woocommerce .widget_layered_nav ul li a {
	color: var(--text-secondary);
}

/* "فیلترهای فعال" (Active Filters widget) pills — Astra's compiled CSS
   (woocommerce-grid.min-rtl.css) gives these a hardcoded
   background:rgba(245,245,245,.75), a plain light-gray unrelated to the
   site's palette, while the link's text color separately comes from an
   Astra inline rule pointing at --ast-global-color-3 (-> --text-secondary
   in dark mode). Background never leaves light mode; text does — light
   text on a light pill in dark mode, not just an off-brand color.
   Restyled to match how "chosen" filters are already highlighted
   elsewhere (.woocommerce-widget-layered-nav-list__item--chosen a below):
   accent, not a plain gray tag. #secondary prefix + !important to clear
   Astra's own #secondary-prefixed version of this same selector. */
#secondary .widget_layered_nav_filters ul li.chosen,
.widget_layered_nav_filters ul li.chosen {
	background: var(--accent-soft) !important;
}

.widget_layered_nav_filters ul li.chosen a {
	color: var(--accent) !important;
	font-weight: 600;
}

.woocommerce .price_slider_amount .button,
.woocommerce .price_slider_amount button {
	float: none;
	width: auto;
	margin-inline-start: auto;
	display: block;
}

.woocommerce .ui-slider .ui-slider-range,
.woocommerce .price_slider .ui-slider-range {
	background: var(--accent);
}

.woocommerce .ui-slider .ui-slider-handle {
	background: var(--bg-surface);
	border: 2px solid var(--accent);
}

.woocommerce .woocommerce-widget-layered-nav-list__item--chosen a {
	color: var(--accent);
	font-weight: 600;
}

/* ---------- Single product ---------- */
.single-product div.product .woocommerce-tabs,
.single-product div.product .summary {
	color: var(--text-secondary);
}

.single-product div.product p.price,
.single-product div.product span.price {
	color: var(--text-primary);
	font-size: var(--font-xl);
	font-weight: 700;
}

.single-product div.product .price del {
	color: var(--text-muted);
	font-size: var(--font-md);
	/* see the shop-loop .price del rule above re: ss02 needing >= 500 */
	font-weight: 500 !important;
}

.single-product .gs-platform-row {
	margin-block-end: var(--space-2);
}

.single-product .product_title {
	margin-block-end: var(--space-2);
}

/* Gallery: large main image on top, horizontal thumbnail row below, on a
   light-gray backdrop. Pure CSS restyle of WooCommerce's own flexslider
   gallery markup (.flex-viewport = main slide, .flex-control-nav
   .flex-control-thumbs = the thumbnail list, both generated client-side by
   WooCommerce's own JS) — no gallery plugin needed.

   Single-column grid, main image (grid-area: viewport) stacked above the
   thumbs row (grid-area: thumbs) at every width — a vertical side column of
   thumbnails was tried first and rejected. The thumbnail row itself stays a
   flex row that wraps to the main image's width rather than scrolling, so
   every thumbnail is visible without a horizontal-scroll affordance. Fixed
   pixel thumbnail widths (not percentages) override WooCommerce's own
   thumbnail-row widths (".woocommerce-product-gallery--columns-4
   .flex-control-thumbs li", from Astra's compiled CSS), which are sized for
   a 4-column grid and don't reliably match this layout's image count. */
.single-product .woocommerce-product-gallery {
	display: grid;
	grid-template-areas: "viewport" "thumbs";
	gap: var(--space-3);
}

.single-product .woocommerce-product-gallery .flex-viewport {
	grid-area: viewport;
	width: 100%;
	background: var(--bg-base);
	border-radius: var(--radius-lg);
	overflow: hidden;
}

/* .woocommerce-product-gallery__wrapper (the flexslider track) and each
   .woocommerce-product-gallery__image (one slide) are left alone here —
   flexslider's own JS sets their widths inline (track = N * 100%, each
   slide = 100%/N) and slides between them by animating that track's
   position. Forcing both to width:100% here once broke that math: every
   slide rendered full-width in the same spot, so only the first ever
   showed and the slide transition had nothing to animate. */
.single-product .woocommerce-product-gallery .woocommerce-product-gallery__image img {
	width: 100%;
	height: 100%;
	aspect-ratio: 1 / 1;
	object-fit: contain;
}

/* Shimmer only until assets/js/gallery-skeleton.js marks the image loaded
   (or errored) — see the comment on gs-img-shimmer above for why this one
   needs JS instead of running forever like the grid cards do: contain
   can leave a letterboxed gap even after loading, and an animation stuck
   running behind a permanently-visible gap reads as broken, not
   "loading". Once marked, it just falls back to .flex-viewport's own
   --bg-base showing through, same as it did before this feature existed. */
.single-product .woocommerce-product-gallery .woocommerce-product-gallery__image img:not(.gs-img-loaded) {
	background-image: linear-gradient(100deg, var(--skeleton-base) 30%, var(--skeleton-highlight) 50%, var(--skeleton-base) 70%);
	background-size: 400% 100%;
	animation: gs-img-shimmer 1.6s ease-in-out infinite;
}

.single-product .woocommerce-product-gallery .flex-control-thumbs {
	grid-area: thumbs;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: var(--space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.single-product .woocommerce-product-gallery .flex-control-thumbs li {
	width: 84px !important;
	flex: none;
	margin: 0 !important;
}

.single-product .woocommerce-product-gallery .flex-control-thumbs img {
	display: block;
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: contain;
	background: var(--bg-base);
	border-radius: var(--radius-md);
	border: 2px solid transparent;
	cursor: pointer;
	transition: border-color var(--transition-fast);
}

/* Same shimmer-until-loaded treatment as the main viewport image above. */
.single-product .woocommerce-product-gallery .flex-control-thumbs img:not(.gs-img-loaded) {
	background-image: linear-gradient(100deg, var(--skeleton-base) 30%, var(--skeleton-highlight) 50%, var(--skeleton-base) 70%);
	background-size: 400% 100%;
	animation: gs-img-shimmer 1.6s ease-in-out infinite;
}

.single-product .woocommerce-product-gallery .flex-control-thumbs li.flex-active img {
	border-color: var(--accent);
}

@media (max-width: 781px) {
	.single-product .woocommerce-product-gallery .flex-control-thumbs li {
		width: 64px !important;
	}
}

/* Divider between the short description and the variant choosers, matching
   the reference's visual break at that point. */
.single-product .woocommerce-product-details__short-description {
	padding-block-end: var(--space-4);
	margin-block-end: var(--space-4);
	border-block-end: 1px solid var(--border-subtle);
}

/* Platform / ظرفیت choosers stay real <select> elements with the existing
   cascading JS from game-store-options (includes/frontend.php,
   assets/single-product.js) untouched — this only restyles the table
   WooCommerce renders them in in into a side-by-side layout. */
.single-product .variations {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-4);
	width: 100%;
	margin-block-end: var(--space-4);
	border-collapse: collapse;
}

.single-product .variations tbody {
	display: contents;
}

.single-product .variations tr {
	display: block;
	flex: 1 1 200px;
}

.single-product .variations th.label {
	display: block;
	text-align: start;
	font-weight: 600;
	font-size: var(--font-sm);
	color: var(--text-primary);
	padding-block-end: var(--space-2);
}

.single-product .variations td.value {
	display: block;
}

.single-product .variations select {
	width: 100%;
}

/* WooCommerce toggles .woocommerce-variation (description/price/stock
   status) between an inline display:none and populated content the moment
   a full platform + capacity combination matches a real variation. A flat
   "always reserve the space" fix (min-height, previously here) stops the
   quantity/buy row from jumping, but shows as permanent dead white space
   before anything is selected — worse, not better. Animating max-height
   instead gets both: zero footprint while genuinely empty, and a smooth
   grow-in (not a snap) once WooCommerce fills it in. max-height (a fixed
   number), not grid-template-rows 0fr/1fr, because WooCommerce injects
   description/price/availability as separate sibling divs, not one
   wrapper — the 0fr/1fr trick needs a single child to size against; a
   fixed cap works regardless of how many children there are. !important
   on display: overriding jQuery's inline display:none (no !important of
   its own) is still required so this can be visible *at all* to animate. */
.single-product .woocommerce-variation {
	display: block !important;
	margin: 0 !important;
	max-height: 0;
	overflow: hidden;
	opacity: 0;
	transition: max-height var(--transition-base), opacity var(--transition-base);
}

/* :empty, not a JS-driven class — WooCommerce injects real child elements
   (.woocommerce-variation-description etc.) the moment a variation
   matches, even when their own text content is blank, so this needs no
   extra plugin/JS coordination to know when to reveal. 60px is a safety
   margin over the ~49px this content actually renders at. */
.single-product .woocommerce-variation:not(:empty) {
	max-height: 60px;
	opacity: 1;
}

/* Quantity + buy button as one row — the button already gets its accent
   fill from components.css's generic button rules, no color changes here. */
.single-product .woocommerce-variation-add-to-cart {
	display: flex;
	align-items: stretch;
	flex-wrap: wrap;
	gap: var(--space-3);
}

.single-product .woocommerce-variation-add-to-cart .quantity {
	flex: none;
}

.single-product .woocommerce-variation-add-to-cart .qty {
	height: 100%;
	width: 80px;
	text-align: center;
}

.single-product .single_add_to_cart_button {
	flex: 1;
	min-width: 160px;
}

/* Trust/delivery info box (gs_single_product_info_box() in functions.php) */
.gs-product-info-box {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-lg);
	background: var(--bg-elevated);
	padding: var(--space-4);
	margin-block: var(--space-4);
}

.gs-product-info-box__item {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-size: var(--font-sm);
	color: var(--text-secondary);
}

.gs-product-info-box__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border-radius: var(--radius-full);
	background: var(--accent-soft);
	color: var(--accent);
	flex: none;
}

/* Region / platform notice on single product (manual class .gs-notice, used in product short description when needed) */
.gs-notice {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	background: var(--warning-soft);
	border: 1px solid var(--warning);
	color: var(--warning-text);
	border-radius: var(--radius-md);
	padding: var(--space-3) var(--space-4);
	font-size: var(--font-sm);
	margin-block-end: var(--space-4);
}

/* ---------- Cart / checkout ---------- */
.woocommerce table.shop_table {
	background: var(--bg-elevated);
	border-radius: var(--radius-lg);
	border-color: var(--border-subtle);
}

.woocommerce table.shop_table th,
.woocommerce table.shop_table td {
	border-color: var(--border-subtle);
	color: var(--text-secondary);
}

.woocommerce-checkout #payment,
.woocommerce-cart-form,
.cart-collaterals .cart_totals {
	background: var(--bg-elevated);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-lg);
	padding: var(--space-4);
}

/* ---------- Filter + sort sidebar: zero reserved space when closed ----------
   width:0 + overflow:hidden, not display:none — display can't be animated,
   and this needs to slide open/closed with a real transition. A plain
   Astra left-sidebar layout gives #primary/#secondary fixed inline widths
   (70%/30%) no matter what's actually visible inside #secondary, so hiding
   only the widgets inside it (the earlier approach) still reserved a mostly
   -empty 30% column. Opened by .gs-filter-toggle (now a small icon button
   in the shop toolbar, not inside the sidebar itself — see
   gs_shop_filter_toggle_button() in functions.php) toggling a class on
   #secondary directly; filter-toggle.js also relocates the
   .woocommerce-ordering dropdown into the panel, on top of the filter
   widgets. Scoped to .ast-woo-shop-archive (Astra's own class for the shop/
   category archive templates specifically) — #secondary is the same ID on
   the cart/checkout/my-account pages, which share this sidebar's widgets
   but have no .gs-filter-toggle to ever reopen it, so a bare #secondary
   selector would strand it permanently hidden there. */
/* display:none, not just width:0 — a width:0 block still lays out its
   *content* at that width (overflow:hidden only clips the paint, not the
   box model), and this sidebar's filter widgets reflowed into an
   extremely tall single-word-wide column (six-thousand-plus px) at 0
   width. Floated elements' height affects the page's total scrollable
   height regardless of visibility, which is exactly the "huge empty space
   at the bottom of the page" bug. display:none removes it from layout
   entirely, no reflow-to-tall-column possible; @starting-style +
   transition-behavior:allow-discrete (both widely supported for a while
   now) still let width/opacity animate smoothly across the display flip
   instead of just snapping open/closed. */
.ast-woo-shop-archive #secondary {
	display: none;
	width: 0;
	min-width: 0;
	padding: 0;
	margin: 0;
	opacity: 0;
	overflow: hidden;
	border: 0 !important;
	transition: width var(--transition-base), opacity var(--transition-base), display var(--transition-base) allow-discrete;
}

.ast-woo-shop-archive #secondary.gs-filter-open {
	display: block;
	width: 30%;
	opacity: 1;
	overflow: visible;

	@starting-style {
		width: 0;
		opacity: 0;
	}
}

.ast-woo-shop-archive #primary {
	width: 100%;
	/* Astra's left-sidebar layout gives #primary a border-right marking the
	   column edge (.ast-left-sidebar #primary in its own compiled CSS) —
	   with #secondary collapsed to 0 width that just reads as a stray
	   vertical line with nothing to divide. Only draw it while the panel
	   is actually open. Astra's compiled CSS also gives #primary a
	   permanent padding-right in this same .ast-left-sidebar #primary rule
	   (60px at min-width:993px, 30px at max-width:992px) — a gutter meant
	   to separate it from the sidebar, reserved even while #secondary is
	   display:none and there's nothing to separate from. Zero it here,
	   same as the border, and only restore it (desktop width only — see
	   below) while the panel is open. */
	padding-right: 0 !important;
	border-right: 0 !important;
	transition: width var(--transition-base);
}

.ast-woo-shop-archive:has(#secondary.gs-filter-open) #primary {
	width: 70%;
	border-right: 1px solid var(--border-subtle) !important;
}

@media (min-width: 993px) {
	.ast-woo-shop-archive:has(#secondary.gs-filter-open) #primary {
		padding-right: 60px !important;
	}
}

/* Below Astra's own #primary/#secondary breakpoint (compiled CSS switches
   .ast-container from flex-direction:row to column-reverse at
   max-width:992px — NOT the same breakpoint as the shop grid's own
   grid-template-columns media queries above, a mismatch the previous
   version of this fix assumed away by reusing 781px): a 30/70 side-by-side
   split has no room to breathe, so the open panel instead becomes a
   full-width block. column-reverse is Astra's own mobile default of
   "sidebar renders after main content", which is why opening the panel
   between 782px and 992px visibly jumped to the bottom of the page
   instead of appearing where the toggle button is, AND left #primary's
   game-card grid sitting at its side-by-side 70% width — offset to the
   right, with an empty gap on its left — instead of the full row width a
   stacked layout needs. #secondary is still first in *source* order;
   forcing the container back to plain column (not reversed) makes that
   source order the visual order too, so it appears right below the
   toolbar, above the grid. */
@media (max-width: 992px) {
	/* flex-direction belongs on the flex CONTAINER (.ast-container), not
	   on #primary/#secondary themselves — they're the flex items. :has()
	   scopes this to the specific .ast-container that actually wraps the
	   sidebar, since that class is reused all over the page (header,
	   footer, other sections) for unrelated layout. */
	.ast-woo-shop-archive .ast-container:has(> #secondary) {
		flex-direction: column;
	}

	.ast-woo-shop-archive #secondary.gs-filter-open {
		width: 100%;
		float: none;
		margin-block-end: var(--space-4);
	}

	.ast-woo-shop-archive:has(#secondary.gs-filter-open) #primary {
		width: 100%;
		border-right: 0 !important;
	}
}

.gs-filter-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	float: right;
	width: 40px;
	height: 40px;
	padding: 0;
	background: var(--bg-elevated);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-md);
	color: var(--text-primary);
	cursor: pointer;
	transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.gs-filter-toggle:hover,
.gs-filter-toggle.is-open {
	background: var(--accent);
	border-color: var(--accent);
	color: #fff;
}

.ast-filter-wrap {
	padding: 20px;
}

/* WooCommerce's own ".woocommerce .woocommerce-ordering{float:right;
   margin-bottom:2.5em}" is meant for its normal spot above the grid,
   sitting beside the result count. filter-toggle.js relocates this same
   form to be the first child of .ast-filter-wrap instead (see that file),
   stacked in the vertical filter panel with its select stretched to
   width:100% below — float:right left over from the old context fights
   that: a floated box shrinks to its content width regardless of the
   width:100% on the select inside it, and pulls the next widget up
   alongside it instead of below. */
.ast-filter-wrap .woocommerce-ordering {
	float: none;
	margin-block-end: var(--space-4);
}

.ast-filter-wrap .woocommerce-ordering select {
	width: 100%;
}

/* ---------- Pagination arrow direction (RTL fix) ----------
   WooCommerce's own loop/pagination.php already swaps prev/next to the
   correct RTL glyphs via is_rtl() (prev -> &rarr;, next -> &larr; — "back"
   points toward reading-start/right, "forward" points left). Astra's
   compiled grid-pagination CSS then applies rotateY(180deg) to .prev/.next
   — the ACTUAL rule in effect is the RTL stylesheet's ".rtl
   .woocommerce-pagination .page-numbers li:last-child .next" (one more
   class than a plain ".woocommerce-pagination .page-numbers li:last-child
   .next" can match, since body carries .rtl), re-flipping WooCommerce's
   already-correct glyph and pointing the arrows the wrong way. !important
   because matching that selector's specificity 1:1 is fragile — Astra could
   reorder or add another qualifier on its next compiled-CSS update. */
.woocommerce-pagination .page-numbers li:first-child .prev,
.woocommerce-pagination .page-numbers li:last-child .next {
	transform: none !important;
}

/* ---------- Cart/Checkout blocks: mobile edge-to-edge overflow (RTL) ----------
   Astra's block-layout system gives every alignwide block (an inline rule,
   not a static stylesheet — see .entry-content[data-ast-blocks-layout] >
   .alignwide in the page's <head>) a fixed max-width plus a symmetric
   negative margin-left/margin-right pair meant to bleed it flush to the
   viewport edge below 1200px. With a value on all three of width,
   margin-left and margin-right, the box model is over-constrained; the
   CSS 2.1 spec resolves that by dropping margin-left in RTL (ltr drops
   margin-right instead), so the block re-centers itself by shifting
   entirely toward the physical right edge instead of bleeding evenly.
   Net effect on the WooCommerce Cart/Checkout blocks specifically: content
   (price column, form inputs) sits flush against the screen's right edge
   with zero padding, while the left edge gets double the normal gutter.
   Neutralizing the negative margins keeps these two blocks at their
   normal content width (they were already computing to that width, just
   mis-positioned) without touching alignwide's intended edge-to-edge
   bleed for any other block on the site. !important because the rule
   we're beating is inline and CSS-var driven, not a stylesheet we can
   out-specificity in the normal cascade. */
@media (max-width: 1200px) {
	.wp-block-woocommerce-cart.alignwide,
	.wp-block-woocommerce-checkout.alignwide {
		margin-left: 0 !important;
		margin-right: 0 !important;
	}
}

/* ---------- WooCommerce default components: dark-mode gaps ----------
   These three ship with hardcoded light-only colors from WooCommerce/Astra
   compiled CSS (not astra-settings options — checked) that the theme's
   dark-mode tokens never reached because nothing here targeted them
   before. Using the existing --bg-elevated/--text-primary tokens (rather
   than a separate dark-only override block) means they keep tracking
   in both directions if tokens.css' dark palette changes.

   1) My Account nav: current-tab background is a literal
      rgb(251,251,251) (Astra inline CSS) — invisible seam in light mode,
      a glaring white tile in dark mode.
   2) WooCommerce notice boxes (.woocommerce-message/-info/-error — "no
      orders found", "confirm your email", etc.) keep a hardcoded light
      card background regardless of theme.
   3) Address book card headers (.woocommerce-Address-title, e.g. "آدرس
      ارسال"): background is hardcoded rgb(251,251,251) while the h2
      inside already follows the dark-mode text token via Astra's heading
      color slot — so in dark mode this was light text on a near-white
      box, an actual contrast failure, not just a mismatch. */
body .woocommerce-MyAccount-navigation-link.is-active a {
	background-color: var(--bg-elevated) !important;
}

.woocommerce-error,
.woocommerce-info,
.woocommerce-message {
	background-color: var(--bg-elevated) !important;
	color: var(--text-primary) !important;
}

.woocommerce-Address-title {
	background-color: var(--bg-elevated) !important;
}
