/*
 Theme Name:   Woodmart Child
 Description:  Woodmart Child Theme
 Author:       XTemos
 Author URI:   http://xtemos.com
 Template:     woodmart
 Version:      1.0.0
 Text Domain:  woodmart
*/

/* Start Malkesh */
#home-Prod figcaption.elementor-image-carousel-caption {
    position: absolute;
    bottom: 10px;
    left: 10px;
    right: 10px;
    height: 48px;
	transition: height 1s ease;
}
#home-Prod .swiper-slide-inner {
	overflow: hidden;
}
#home-Prod .swiper-slide-inner .swiper-slide-image {
	transition: transform .5s cubic-bezier(0, 0, 0.44, 1.18);
}
#home-Prod .swiper-slide-inner:hover figcaption.elementor-image-carousel-caption {
    height: auto;
}
#home-Prod .swiper-slide-inner:hover .swiper-slide-image {
	transform: scale3d(1.1, 1.1, 1);
}
/* End Malkesh */
/* ------------------------------------------------------------------
   Mega menu columns — fit every top-level group on one row.

   Woodmart sizes each mega-menu column with `flex: 0 0 var(--wd-f-basis)`,
   default 200px, inside a boxed dropdown 1192px wide with a 20px gap.
   "All Products" has six groups: 6*200 + 5*20 = 1300px, which overflows,
   so the sixth wrapped onto a second row. A flex row is as tall as its
   tallest column (Hardware Components, 8 links), which stranded that
   sixth group under ~300px of empty space.

   Flexbox picks line breaks from each item's HYPOTHETICAL main size
   (flex-basis clamped by min/max), not its size after shrinking, so
   allowing shrink would NOT have prevented the wrap — the basis itself
   has to come down. 180px is the widest value that still fits six
   columns plus gaps (6*180 + 5*20 = 1180 <= 1192).

   Setting the theme's own variable keeps every column a uniform width,
   including menus that legitimately wrap (Brands has ten groups and now
   lays out 6 + 4, all the same width). An earlier attempt using
   `flex: 1 1 150px` let the first row grow to seven narrow columns while
   the second row kept 200px ones, which looked worse than the bug.

   The selector deliberately mirrors and extends Woodmart's own rule in
   css/parts/base-deferred.css:

     .wd-dropdown-menu:is(.wd-design-sized,.wd-design-full-width,
       .wd-design-full-height)>.container>.wd-grid-f-inline{--wd-f-basis:200px}

   That rule is specificity (0,4,0) — identical to the obvious override —
   and base-deferred.css loads after this child stylesheet is inlined, so
   an equal-specificity rule loses on source order. Adding .wd-dropdown and
   .wd-sub-menu takes this to (0,6,0) and wins on specificity instead,
   which avoids !important.
   ------------------------------------------------------------------ */
.wd-dropdown-menu.wd-dropdown:is(.wd-design-sized, .wd-design-full-width, .wd-design-full-height) > .container > .wd-sub-menu.wd-grid-f-inline {
	--wd-f-basis: 180px;
}

/* ------------------------------------------------------------------
   Elementor core widgets: follow Woodmart's palette, not Elementor's.

   The Elementor kit (46499) has no saved settings, so Elementor emits its
   FACTORY defaults — #6EC1E4 headings in Roboto 600 and #7A7A7A body copy —
   from post-46499.css, which is linked on every Elementor page. That paints
   131 core `heading` widgets and 30 `text-editor` widgets in a palette that
   belongs to no one: not Porto, not Woodmart, not Hankerz.

   The theme already publishes the right values. `body.global-color-scheme-light`
   resolves `--wd-title-color` to #FFF and `--wd-text-color` to
   rgba(255,255,255,.8) via the `[class*=color-scheme-light]` rule, so pointing
   Elementor at those variables makes these widgets track the theme's colour
   scheme automatically — including any future light-background section.

   Specificity note: Elementor's own rule is
     .elementor-widget-heading .elementor-heading-title   (0,2,0)
   and it ships in the per-post CSS, which loads AFTER this stylesheet is
   inlined — so an equal-specificity override would lose on source order.
   Prefixing with .elementor takes these to (0,3,0) / (0,2,0) and wins on
   specificity instead, which avoids !important.

   This is deliberately page-scoped styling rather than an edit to kit 46499:
   the kit is shared by every Elementor page and changing it is a wider blast
   radius than this needs.
   ------------------------------------------------------------------ */
.elementor .elementor-widget-heading .elementor-heading-title {
	color: var(--wd-title-color);
	font-family: var(--wd-title-font);
	font-weight: var(--wd-title-font-weight);
}

.elementor .elementor-widget-text-editor {
	color: var(--wd-text-color);
}

/* Core Elementor buttons: Woodmart's primary, not Elementor's factory green.
   Elementor paints `.elementor-widget-button .elementor-button` with
   --e-global-color-accent (#61CE70) from the unsaved kit — same root cause as
   the headings above. (0,3,0) beats Elementor's (0,2,0) without !important. */
.elementor .elementor-widget-button .elementor-button {
	background-color: var(--wd-primary-color);
	font-family: var(--wd-text-font);
}

/* Porto-era dead markup on the Team page: 14 `.game-list-container` blocks
   holding 71 `<li class="game-item">`. No stylesheet anywhere under wp-content
   defines either class — whatever drew them died with Porto. 40 of the items
   are literally empty; the other 31 hold a 128x128 `<svg>` with no shapes
   inside it, so they paint nothing either. Every item and every container has
   zero text content, which is why they rendered as ~71 stray bullets.

   Hiding the container rather than the items: `:empty` cannot match the 31
   whitespace/SVG-bearing ones, and the block conveys nothing as a whole. */
.elementor .game-list-container {
	display: none;
}

/* ------------------------------------------------------------------
   Shop page hero.

   Porto rendered this from `banner_block` postmeta pointing at porto_builder
   post 2071. Woodmart ignores that meta, so /shop lost its hero. Page 207 is
   the WooCommerce archive — no Elementor data — so the markup lives in
   post_content and WooCommerce prints it above the loop via
   woocommerce_product_archive_description() (page 1 only).

   The artwork is Hankerz's own attachment 2072; the Porto block hardcoded an
   external Porto-demo CDN URL for the same file, so this also removes a
   third-party hotlink. (Hostname omitted here on purpose: this comment is
   inlined into every page, and naming it would defeat audit greps for it.)

   Text is dark here on purpose. The banner sits on its own light backdrop
   (#77e1ff plus artwork measuring 207/255 where the copy sits), not on the
   page's rgb(16,16,16) — so the page-level white-text tokens would be
   unreadable. This mirrors Porto's own `heading-dark` / `btn-dark`.
   ------------------------------------------------------------------ */
.hz-shop-banner {
	display: block;
	padding: 3.25rem 30px;
	margin-bottom: 30px;
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
	color: #242424;
}

/* Keep every text element inside the flat left-hand area of the artwork.
   The right-hand third is the product photograph — dark copy laid over it is
   unreadable, which is where "Exclusive Products" / "Best Prices" landed. */
.hz-shop-banner-main,
.hz-shop-banner-aside {
	max-width: 58%;
}

.hz-shop-banner .hz-shop-banner-title {
	margin: 0 0 .75rem;
	font-size: 3rem;
	line-height: 1;
	text-transform: uppercase;
	color: #242424;
}

.hz-shop-banner .hz-shop-banner-sm { font-size: .8rem; line-height: 1.6; }
.hz-shop-banner .hz-shop-banner-lg { font-size: 1rem; line-height: 1.4; margin-bottom: 1rem; }

/* Woodmart only enqueues css/parts/el-button.css when one of its button
   widgets renders, and the shop archive has none — so .btn-color-black's
   --btn-* custom properties are undefined here and the base rule falls back to
   #F3F3F3 (a near-white button on a light banner). Set the colours outright
   rather than depending on a stylesheet that is not guaranteed to load. */
.hz-shop-banner .hz-shop-banner-btn {
	display: inline-block;
	padding: 12px 26px;
	background-color: #212121;
	color: #fff;
	font-weight: 600;
	line-height: 1;
	border-radius: 0;
}

@media (max-width: 768.98px) {
	.hz-shop-banner { padding: 2.5rem 20px; }
	.hz-shop-banner-main,
	.hz-shop-banner-aside { max-width: 100%; }
	.hz-shop-banner .hz-shop-banner-title { font-size: 2rem; }
}

/* ------------------------------------------------------------------
   Porto info-box icons on the Contact Us / About Us tiles.

   These are icon-FONT elements — Font Awesome (`far fa-envelope`,
   `fas fa-mobile-alt`, `far fa-calendar-alt`) and Simple Line Icons
   (`Simple-Line-Icons-pointer`) — and Porto's icon fonts are not loaded under
   Woodmart. Three of the four collapse to zero height, but Woodmart ships a
   partial Font Awesome subset, so `fa-envelope` resolves far enough to paint
   the browser's missing-glyph box: a broken-looking square that also pushed
   its heading 72px out of line with its three neighbours.
   Hiding the wrapper (not the <i>) is what makes the row uniform.

   Hiding the icon element makes the row uniform. Woodmart's own wd_infobox
   takes an image attachment rather than an icon font, so restoring icons here
   means supplying image assets — a content task, not a styling one.
   ------------------------------------------------------------------ */
.porto-sicon-box .porto-just-icon-wrapper {
	display: none;
}

/* ------------------------------------------------------------------
   Porto FAQ list: suppress Woodmart's blog post-meta.

   [porto_faqs] runs a WP_Query over the `faq` post type, and Woodmart's blog
   templates then decorate each result with its author and dates — so the FAQ
   reads "Posted by Magento1 Team / January 10, 2022 / On September 11, 2020"
   above every answer. Porto never showed that.

   Scoped to the FAQ wrapper so real blog posts keep their meta.
   ------------------------------------------------------------------ */
.porto-faqs .wd-post-meta,
.porto-faqs .wd-post-author,
.porto-faqs .wd-post-date,
.porto-faqs .entry-meta {
	display: none;
}

/* FAQ archive: the answers are shown in full (see functions.php), so the
   "Continue reading" link has nothing left to reveal. Woodmart's blog templates
   emit it unconditionally via woodmart_render_read_more_btn(); the theme option
   that controls it is global, and the real blog still wants it — so it is
   suppressed here on the faq archive only.

   The author/date meta is hidden for the same reason it is hidden inside
   [porto_faqs]: an FAQ has no meaningful byline. */
.post-type-archive-faq .wd-post-read-more,
.post-type-archive-faq .wd-post-meta,
.post-type-archive-faq .wd-post-author,
.post-type-archive-faq .wd-post-date {
	display: none;
}

/* The FAQ archive uses Woodmart's masonry blog card, which centres its text.
   That is fine for prose, but the payment-methods answer is a <ul>: centring
   the <li> text leaves the bullet markers stranded at the far left of the card.
   Left-align lists (and give them their indent back) inside FAQ cards only. */
.post-type-archive-faq .wd-post-excerpt ul,
.post-type-archive-faq .wd-post-excerpt ol {
	text-align: start; /* CL032-DEV08.18: was `left`; the Arabic FAQ archive now has RTL content */
	padding-inline-start: 1.25em;
	margin-inline: auto;
	display: table;
}

/* ============================================================================
   Hankerz Index gauges — base geometry, ported from porto_settings['css-code'].
   ----------------------------------------------------------------------------
   135 published products render <section class="hankerz-gauges"> with two
   semicircular dials, "Gaming Performance" and "Work Performance". Porto served
   the geometry from its theme-option CSS blob (porto_settings['css-code'],
   32 KB) via style-internal.php:897; Woodmart has no reader for that option, so
   under Woodmart the section rendered as two orphan labels and nothing else.

   The per-product NEEDLE ANGLE is a separate storage location — postmeta
   'custom_css' — emitted by woodmart-child/functions.php. Neither half works
   without the other: without this file the angles rotate an invisible element,
   and without the postmeta every needle sits at zero.

   HOW THE DIAL WORKS, because it explains --hz-gauge-bg:
     .semi-circle          a red->yellow->green gradient half-disc
     .semi-circle::before  an opaque half-disc that punches out the middle,
                           turning the disc into an arc
     .semi-circle--mask::before
                           a second opaque half-disc, rotated by the per-product
                           angle, that covers the unearned part of the arc
   Both cut-outs work by painting the PAGE BACKGROUND over the gradient, so the
   colour has to match whatever sits behind the gauge or the "cut" shows up as a
   visible crescent.

   Porto hard-coded #f2f2f2 because its product pages were light. Measured on
   Woodmart staging, the element behind the gauge (.wd-page-content) computes to
   rgb(26,26,26) — hence the value below.

   DO NOT replace this with var(--wd-main-bgcolor): that token resolves to #FFF
   on this site, which would paint two white crescents across a dark page.
   If the page background ever changes, this one line is the only edit needed.
   ========================================================================== */
.hankerz-gauges {
	--hz-gauge-bg: #1a1a1a;
	display: flex;
}

.hankerz-gauges .mask {
	position: relative;
	overflow: hidden;
	display: block;
	width: 12.5rem;
	height: 6.25rem;
	margin: auto;
}

.hankerz-gauges .semi-circle {
	position: relative;
	display: block;
	width: 12.5rem;
	height: 6.25rem;
	background: linear-gradient(to right, #c0392b 0%, #f1c40f 50%, #1abc9c 100%);
	border-radius: 50% 50% 50% 50%/100% 100% 0% 0%;
}

.hankerz-gauges .semi-circle::before {
	content: "";
	position: absolute;
	bottom: 0;
	left: 50%;
	z-index: 2;
	display: block;
	width: 8.75rem;
	height: 4.375rem;
	margin-left: -4.375rem;
	background: var(--hz-gauge-bg);
	border-radius: 50% 50% 50% 50%/100% 100% 0% 0%;
}

.hankerz-gauges .semi-circle--mask {
	position: absolute;
	top: 0;
	left: 0;
	width: 12.5rem;
	height: 12.5rem;
	background: transparent;
	transform-origin: center center;
	backface-visibility: hidden;
	transition: all 0.3s ease-in-out;
}

.hankerz-gauges .semi-circle--mask::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0%;
	z-index: 2;
	display: block;
	width: 12.625rem;
	height: 6.375rem;
	margin: -1px 0 0 -1px;
	background: var(--hz-gauge-bg);
	border-radius: 50% 50% 50% 50%/100% 100% 0% 0%;
}

.hankerz-gauges .box {
	width: 50%;
	padding: 10px;
}

@media (max-width: 420px) {
	.hankerz-gauges {
		display: flex;
		flex-wrap: wrap;
	}

	.hankerz-gauges .box {
		width: 100%;
		padding: 10px;
		margin-bottom: 15px;
	}
}

/* The tooltip marker. Porto drew this with content:"\e707" in font-family:"porto";
   that font is NOT loaded under Woodmart, so the original rules would paint a
   missing-glyph box on the 38 products whose label carries a <span>. Substituted
   with a font-independent character, same size and same Hankerz orange. */
.hankerz-gauges .gaming-gauge-tip span,
.hankerz-gauges .work-gauge-tip span {
	padding-left: 5px;
}

.hankerz-gauges .gaming-gauge-tip span::after,
.hankerz-gauges .work-gauge-tip span::after {
	content: "\24D8"; /* circled latin small letter i */
	display: inline-block;
	width: 1em;
	margin-left: 0.1em;
	margin-right: 0.1em;
	text-align: center;
	line-height: 1.2em;
	font-size: 18px;
	font-style: normal;
	font-weight: 400;
	color: #d14609;
	-webkit-font-smoothing: antialiased;
}

/* Hover explanations. These stay a LIGHT chip with dark text on purpose — they
   are self-contained bubbles with an orange border, legible over the dark page,
   and that is how they read on production. Ported verbatim, including Porto's
   own quirk that the work tip uses ::before unconditionally while the gaming tip
   is split ::before below 420px / ::after above it. */
.hankerz-gauges .work-gauge-tip:hover::before {
	content: "Hankerz index that shows how this product perform in workload apps.";
	font-size: 0.8rem;
	font-weight: 600;
	color: black;
	background-color: #f2f2f2;
	border-radius: 5px;
	border: 2px solid #ea4f0b;
	z-index: 1000;
	padding: 10px 10px;
	white-space: pre-wrap;
	position: absolute;
}

@media (max-width: 420px) {
	.hankerz-gauges .gaming-gauge-tip:hover::before {
		content: "Hankerz index that shows how this product perform in gaming.";
		font-size: 0.8rem;
		font-weight: 600;
		color: black;
		background-color: #f2f2f2;
		border-radius: 5px;
		border: 2px solid #ea4f0b;
		z-index: 1000;
		padding: 10px 10px;
		white-space: pre-wrap;
		position: absolute;
	}
}

@media (min-width: 421px) {
	.hankerz-gauges .gaming-gauge-tip:hover::after {
		content: "Hankerz index that shows how this product perform in gaming.";
		font-size: 0.8rem;
		font-weight: 600;
		color: black;
		background-color: #f2f2f2;
		border-radius: 5px;
		border: 2px solid #ea4f0b;
		z-index: 1000;
		padding: 10px 10px;
		white-space: pre-wrap;
		position: absolute;
	}
}

/* ============================================================================
   "Ask an Expert" pre-footer banner.
   ----------------------------------------------------------------------------
   Restores audit item 8. On production this sits in Porto's `footer-top` sidebar
   as widget block-widget-9 -> porto_builder post 20956 ("footer-banner"), which
   Woodmart never reads; the widget was dropped outright by the theme switch (2, 4,
   6 and 7 survived into wp_inactive_widgets — 9 did not).

   Rebuilt as cms_block 46824 in Woodmart's own pre-footer slot
   (prefooter_content_type = html_block), so the client can edit it under
   HTML Blocks rather than it living in a theme-option string.

   Porto used two rows toggled by CSS — .pc-banner hidden below 767px and
   .mobile-banner hidden above 768px — which downloads both images on every
   device. The two assets are art-directed rather than resolution variants
   (1760x632 desktop vs 1760x900 mobile), so this uses a <picture> element at the
   same 767px breakpoint: identical result, one download.
   ========================================================================== */
.hz-ask-expert-banner {
	display: block;
	line-height: 0;
}

.hz-ask-expert-banner img {
	display: block;
	width: 100%;
	height: auto;
}

/* ============================================================================
   PC Builder (WooCommerce Composite Products) — audit item 7.
   ----------------------------------------------------------------------------
   38 published composite products are the store's flagship "build your own PC"
   feature. Porto styled them from porto_settings['css-code']; Woodmart has no
   reader for that option.

   WHAT WAS ACTUALLY MISSING, measured rather than assumed. The audit described
   the UI as rendering with "zero styling"; comparing the same product side by
   side shows that is not the case — Woodmart styles the composite form perfectly
   legibly on its own, and the step layout (including the uneven step heights) is
   IDENTICAL on both environments. The real deltas were typography on the option
   labels, the validation message, and the summary layout on small screens.

   PORTED — these selectors exist in staging's markup and the rules change something:
     .select_label                    was 400/16px, production 700/14px
     .validation_message              needs display:flex + red, or it reads as body copy
     .component_ordering ...          inline-block sort control
     @media (max-width:525px) summary two-up summary tiles on phones
   Thumbnail rules are included as LATENT cover: all 128 components across the 21
   products carrying _bto_data have options_style unset, i.e. dropdown mode, so the
   markup is only a JS template today. The rules cost nothing and are correct if
   any component is ever switched to thumbnail mode.

   DELIBERATELY NOT PORTED, with reasons:
     .component_option_thumbnail_select { background:#000 }  and
     .component_options_inner .thumbnail_buttons button { background:#000 }
        Black buttons on rgb(26,26,26). Production's buttons are ORANGE — that
        colour comes from Porto's own theme stylesheet, not from this rule, so
        replaying the rule would not reproduce production, it would produce
        invisible controls. Woodmart's own button styling is kept instead, and the
        .selected highlight below is ported so the chosen option still stands out.
     .select_label { color:#000000 }
        Same trap. Staging renders the label white on a dark page, which is right;
        production's black is right for ITS light page. Only the weight/size port.
     .component_filter_option a
        0 occurrences in staging's markup (3 on production) — Woodmart renders no
        such filter control. Inert.
     h2.product_title / .product-summary-wrap / the "How to Use PC Builder?" tooltip
        Cannot apply: staging emits <h1 class="product_title"> and has 0
        .product-summary-wrap. That copy is audit item 25 and needs re-authoring as
        real markup — it is a hover-only CSS `content:` string, unreachable on touch
        and to screen readers, so it should not be ported as-is regardless.
        Its icon also depends on font-family:"porto", which Woodmart does not load.
   ========================================================================== */
.product-type-composite .component_section_title .select_label {
	font-size: 14px;
	font-weight: 700;
}

.product-type-composite .validation_message.woocommerce-info {
	display: flex;
	color: red;
}

.product-type-composite .validation_message.woocommerce-info ul {
	padding-left: 1rem;
}

.product-type-composite .component_ordering .component_section_title {
	display: inline-block;
	padding-right: 15px;
}

/* Latent — dropdown mode is in use today, see note above. */
.product-type-composite .component_option_thumbnails ul.component_option_thumbnails_container {
	display: flex;
	flex-wrap: wrap;
}

.product-type-composite .component_option_thumbnails ul.component_option_thumbnails_container h5.thumbnail_title {
	overflow: hidden;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	display: -webkit-box;
	height: 36.66666px;
}

@media screen and (max-width: 525px) {
	.product-type-composite .small_width ul.component_option_thumbnails_container li.component_option_thumbnail_container {
		width: 46%;
		margin-bottom: 1em;
		float: left;
	}

	.product-type-composite .small_width .component_option_thumbnail .image {
		width: 100%;
		margin: 0 auto;
	}

	.woocommerce .product-type-composite ul.component_option_thumbnails_container li.component_option_thumbnail_container .thumbnail_description .price {
		font-size: 1em !important;
	}

	.product-type-composite .thumbnail_buttons .component_option_thumbnail_select {
		padding-right: 20px;
		padding-left: 20px;
		padding-bottom: 6px;
		padding-top: 6px;
	}

	/* The chosen option keeps its brand-orange highlight. Ported without the
	   black base rule above it, so selected reads against Woodmart's default. */
	.product-type-composite .selected .thumbnail_buttons .component_option_thumbnail_select {
		background-color: #ea4f0b;
		border-color: #ea4f0b;
	}

	.product-type-composite .component_option_thumbnail.selected button.component_option_thumbnail_select {
		opacity: 1;
	}

	/* 2026-09-04: the Porto-era rule that hid .composited_product_details_wrapper here
	   (the chosen option's image, price and stock under "Your selection") was removed —
	   the client wants that box on phones exactly as on desktop. */

	.product-type-composite .composite_summary ul.summary_elements li.summary_element {
		width: 46%;
		margin-bottom: 1em;
		float: left;
	}

	.product-type-composite .composite_summary ul.summary_elements li .summary_element_content .content_product_title {
		overflow: hidden;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		display: -webkit-box;
		height: 44px;
	}

	.product-type-composite .small_width .summary_element_image {
		width: 100%;
		margin: 0 auto;
	}

	.product-type-composite .composite_summary ul.summary_elements {
		padding-left: 0rem;
	}

	.product-type-composite .composite_summary ul.summary_elements li h3.title.summary_element_content {
		text-align: center !important;
	}

	.product-type-composite .composite_summary ul.summary_elements li h3.title.summary_element_content .step_index {
		display: none;
	}

	.product-type-composite .composite_summary ul.summary_elements li h3.title.summary_element_content .step_title {
		overflow: hidden;
		-webkit-line-clamp: 1;
		-webkit-box-orient: vertical;
		display: -webkit-box;
	}
}

/* ============================================================================
   Category archives: no page heading, category image in its place.
   ----------------------------------------------------------------------------
   Driven by two native Woodmart mechanisms, not by overriding templates:
     xts-woodmart-options['shop_title'] = 0
        -> template-tags.php:1638 adds .without-title and drops the <h1>.
           shop_categories stays 1 so the band itself still renders (the block is
           gated on `shop_categories || shop_title`, :1619) and keeps carrying the
           category navigation.
     term meta 'title_image' = {id,url}
        -> woodmart_get_category_page_title_image(), :1767. NOTE this is NOT
           WooCommerce's 'thumbnail_id'; it is Woodmart's own key, and it falls
           back to the PARENT category's image when a child has none.

   The scrim below exists because the category nav is white text
   (color-scheme-light) laid directly over a photograph. On artwork with bright
   regions — the GPU fan hub on graphic-cards.png, for instance — the labels
   became unreadable. :has(img) scopes it to bands that actually carry an image,
   so the imageless categories (currently 141 of 146) keep their flat background
   untouched rather than being darkened for no reason.
   ========================================================================== */
.wd-page-title.without-title .wd-page-title-bg:has(img)::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.35));
	pointer-events: none;
}

/* Keep the nav above the scrim. */
.wd-page-title.without-title > .container {
	position: relative;
	z-index: 1;
}

/* ============================================================================
   Category header image (replaces the page title + category-nav band).
   ----------------------------------------------------------------------------
   Constrained to the theme container rather than full-bleed, per the client.
   Rendered by hankerz_category_header_image() in functions.php.

   The fixed aspect ratio is deliberate. The one purpose-built banner in the
   library (laptop-banner-.jpg) is 1760x632 = 2.78:1, so the band is set to that
   ratio and the image is object-fit: cover. A correctly-sized banner therefore
   fills it with no crop at all.

   ARTWORK WARNING: the five images currently assigned are 300x300 WooCommerce
   category THUMBNAILS, not banners — product cut-outs on a light background.
   At container width they upscale about 4x and crop to a narrow strip, so they
   look soft and oddly framed. That is a source-artwork problem, not a layout
   one; replacing them with 1760x632 banners fixes it with no code change.
   ========================================================================== */
.hz-cat-header {
	margin-bottom: 30px;
}

.hz-cat-header .container {
	padding-inline: 0;
}

.hz-cat-header-img {
	display: block;
	width: 100%;
	aspect-ratio: 1760 / 632;
	object-fit: cover;
	object-position: center;
	border-radius: 4px;
}

@media (max-width: 768.98px) {
	.hz-cat-header {
		margin-bottom: 20px;
	}

	.hz-cat-header-img {
		/* taller crop on phones so the subject stays readable */
		aspect-ratio: 16 / 9;
	}
}

/* ============================================================================
   QA01 / M7 — one wishlist control on the product page, not two.
   ----------------------------------------------------------------------------
   YITH renders .yith-wcwl-add-to-wishlist on woocommerce_single_product_summary and Woodmart
   renders its own control in the action row, so "Add to wishlist" appeared twice.

   This is done with CSS on purpose. Removing YITH's markup in PHP (via the yith_wcwl_positions
   filter) was tried first and BROKE the feature: Woodmart's control is not self-contained — it
   proxies the add through YITH's form, so with the form gone the control degraded to a plain
   <a href="/stg/wishlist"> that fired no request at all and stored nothing. The form therefore
   has to stay in the DOM; it just must not be shown twice.

   Scoped to the single-product summary so wishlist controls elsewhere (loop, quick view) are
   untouched.
   ========================================================================== */
.single-product .summary-inner > .yith-wcwl-add-to-wishlist {
	display: none !important;
}

/* ============================================================================
   QA01 M1 — compact main navigation.
   ----------------------------------------------------------------------------
   QA: "reduce font size, padding and item spacing for the main navigation menu so it sits
   compactly near the centre next to the logo".

   The native control is already maxed: the mainmenu header element has items_gap = 's' and
   menu_align = 'center'. Measured before: 7 items, 20px gaps, 13px/700, nav 882px wide.

   Tightened to 14px gaps and 12px type — deliberately modest. Hankerz's labels are much longer
   than the demo's ("CUSTOMER SUPPORT CENTER", "CREATORS PORTAL"), so an aggressive cut would
   hurt legibility rather than look like the reference. Desktop only: below 1024px the menu is
   the burger drawer and these rules must not touch it.
   ========================================================================== */
@media (min-width: 1025px) {
	/* The nav is inline-flex; its spacing is column-gap from .wd-gap-s (20px), NOT li margins.
	   An earlier attempt added margin-inline to the li and made the nav WIDER (20px -> 34px
	   effective, 882 -> 887px, wrapping to a second row). Set the gap itself instead. */
	.whb-general-header .wd-nav-main {
		column-gap: 14px;
	}

	.whb-general-header .wd-nav-main > li > a {
		font-size: 12px;
	}
}

/* ============================================================================
 * QA02 / A1E — footer payment icons, rebuilt as uniform badges.
 *
 * Was: a single 360x32 sprite (uploads/2021/12/payment-logos.png) carrying six
 * DARK pills with white logos. Three problems, all visible in QA's screenshot:
 *   - dark pills on the dark footer read as a low-contrast smudge,
 *   - the six cells are not the same width, so the row looks ragged,
 *   - "Bank Installments" is set as TEXT inside the sprite and is illegible at 32px.
 * Being one flat image, none of it could be fixed with CSS.
 *
 * The file is not even present in staging's uploads — the request 302s across to
 * production's copy — so it would have broken the moment that fallback went away.
 *
 * Now: the individual 50x50 logo badges the store already ships for the checkout
 * gateway icons (hankerz-store-rules/images/, see porto_custom_woocommerce_gateway_icon()),
 * copied into uploads/2026/08/payment/ so the markup does not depend on a plugin that
 * exists on staging only. Emitted from the `copyrights2` theme option.
 *
 * COD and AMAN have no logo asset anywhere in the install, so they stay as text pills
 * styled to match the image badges exactly — nothing invented, nothing dropped from what
 * the footer advertises. Swap them for real artwork when design supplies it.
 * ---------------------------------------------------------------------------- */
.wd-copyrights .hz-payment-methods {
	display: inline-flex;
	flex-wrap: wrap;
	gap: 6px;
	align-items: center;
	justify-content: flex-end;
}

.wd-copyrights .hz-payment-methods .hz-pay {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 44px;
	height: 28px;
	margin: 0;
	padding: 0;
	border-radius: 4px;
	background-color: #fff;
	vertical-align: middle;
}

/* The source PNGs are square badges with their own white ground; contain keeps the
   logo intact inside the wider pill instead of stretching it. */
.wd-copyrights .hz-payment-methods img.hz-pay {
	object-fit: contain;
	/* 4px, not 2px. Every badge except two is a transparent PNG, so the tile's white
	   background shows through and 2px was enough. The Souhoola and Halan files came
	   out of the Porto theme's dark footer and have NO alpha channel — they carry solid
	   purple and black backgrounds — so at 2px they filled their tile edge to edge and
	   read as colour blocks rather than logos. The extra inset gives them a visible
	   white frame so they sit in the row like the rest.

	   Proper transparent versions of those two would be better than this; worth asking
	   the client for them. */
	padding: 4px;
}

.wd-copyrights .hz-payment-methods .hz-pay-text {
	color: #1a1a1a;
	letter-spacing: .02em;
	font-weight: 700;
	font-size: 11px;
	line-height: 1;
	font-family: inherit;
}

@media (max-width: 768.98px) {
	.wd-copyrights .hz-payment-methods {
		justify-content: center;
	}
}

/* ============================================================================
 * QA02 / A1D — top-bar language switcher, matched to the Woodmart hardware demo.
 *
 * The demo's top bar opens with `ENGLISH v | COUNTRY v | FREE SHIPPING ...` —
 * uppercase, 12px, thin vertical rule between entries, no flag.
 *
 * Ours rendered as mixed-case "English" with WPML's en.png flag glued to the left
 * (wd-nav-img) and no separator, because the header builder's `languages` element
 * ships with show_language_flag on and Woodmart's default secondary-nav style
 * (wd-style-default) draws no rule. The flag is now off in whb_header_947287; the
 * rest is here, since the element exposes no style parameter.
 *
 * The rule is drawn on the RIGHT of the switcher (not the left) so it reads as the
 * divider between this element and whatever the top bar puts next to it, exactly as
 * the demo's first divider sits after ENGLISH.
 *
 * :lang-scoped to the switcher's own column so the top bar's other secondary nav —
 * the Contact Us group on the right — keeps Woodmart's own separated style.
 * ---------------------------------------------------------------------------- */
.whb-top-bar .wd-header-secondary-nav .wd-nav-secondary > li > a > .nav-link-text {
	text-transform: uppercase;
	letter-spacing: .02em;
	font-weight: 600;
	font-size: 12px;
}

.whb-top-bar .whb-col-left .wd-header-secondary-nav .wd-nav-secondary > li {
	padding-inline-end: 12px;
	border-inline-end: 1px solid rgba(255, 255, 255, .25);
}

.whb-top-bar .whb-col-left .wd-header-secondary-nav .wd-nav-secondary > li:last-child {
	padding-inline-end: 0;
	border-inline-end: 0;
}

/* Belt and braces: the flag is off in the header options, but WPML re-adds
   wd-nav-img whenever the switcher is rebuilt from its own settings. */
.whb-top-bar .wd-header-secondary-nav .wpml-ls-link .wd-nav-img {
	display: none;
}

/* ============================================================================
 * QA02 / header — top bar brought in line with the Woodmart hardware demo.
 *
 * The demo's .whb-top-bar-inner reads:
 *   left   ENGLISH v | COUNTRY v | FREE SHIPPING FOR ALL ORDERS OF $150
 *   right  f X ig yt | (rule) | (envelope) NEWSLETTER | CONTACT US | FAQS
 *
 * Ours was left: ENGLISH, right: f ig yt + CONTACT US. The COUNTRY switcher is
 * deliberately NOT reproduced — the store prices in EGP only, so a country/currency
 * dropdown would be decoration with nothing behind it.
 *
 * Added in the header options: a Text/HTML element in the left column running
 * [hankerz_free_shipping_notice] (see functions.php — it reads the shipping zone so the
 * strip can never advertise a threshold checkout does not enforce), plus Newsletter and
 * FAQs in menu 106. The rest is presentation and lives here.
 * ---------------------------------------------------------------------------- */

/* The promo strip: same weight and case as the language switcher beside it, with the
   divider drawn on ITS leading edge — the switcher is a single <li>, so the earlier
   nav-item rule (which skips :last-child) can never produce this one. */
.whb-top-bar .hz-topbar-promo {
	padding-inline-start: 12px;
	border-inline-start: 1px solid rgba(255, 255, 255, .25);
	text-transform: uppercase;
	letter-spacing: .02em;
	font-weight: 600;
	font-size: 12px;
	line-height: 1;
}

/* Matching rule between the social block and the Newsletter/Contact/FAQs group. */
.whb-top-bar .whb-col-right .wd-header-secondary-nav {
	padding-inline-start: 12px;
	border-inline-start: 1px solid rgba(255, 255, 255, .25);
}

/* Envelope on the Newsletter item, as an inline SVG rather than a woodmart-font glyph:
   the theme font has no mail codepoint, and matching on the href keeps this working when
   the menu item is recreated with a different ID (staging vs production). */
.whb-top-bar .wd-nav-secondary a[href$="#hz-newsletter-popup"] .nav-link-text::before {
	content: "";
	display: inline-block;
	width: 14px;
	height: 11px;
	margin-inline-end: 6px;
	background-color: currentColor;
	vertical-align: -1px;
	-webkit-mask: var(--hz-mail-icon) no-repeat center / contain;
	mask: var(--hz-mail-icon) no-repeat center / contain;
}

.whb-top-bar .wd-nav-secondary {
	--hz-mail-icon: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 16'%3E%3Cpath d='M2 0h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm8 9.2L18 3.6V2H2v1.6l8 5.6zM2 6v8h16V6l-8 5.6L2 6z'/%3E%3C/svg%3E");
}

/* Newsletter modal — see hankerz_newsletter_popup_markup() in functions.php.
   --wd-popup-width is read by contentPopup.js off the popup node and copied onto the
   magnificPopup wrapper, so it has to be declared here rather than on the wrapper. */
.hz-newsletter-popup {
	--wd-popup-width: 500px;
	padding: 40px 30px;
	max-width: 100%;
	background-color: var(--bgcolor-white);
	text-align: center;
}

.hz-newsletter-popup .hz-newsletter-popup-title {
	margin-bottom: 10px;
	text-transform: uppercase;
	font-size: 20px;
}

.hz-newsletter-popup .hz-newsletter-popup-text {
	margin-bottom: 20px;
	color: var(--color-gray-600);
}

/* The CF7 newsletter form inside the modal — see hankerz_newsletter_form_shortcode().
   CF7 wraps its own <form> around our markup, so the flex row is on .hz-newsletter-form
   inside it rather than on the form element itself. Sized off --wd-form-height so the modal
   keeps its shape if Klaviyo is connected later and its embed takes over. */
.hz-newsletter-popup .hz-newsletter-form {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	justify-content: center;
}

.hz-newsletter-popup .hz-newsletter-form input[type="email"] {
	flex: 1 1 220px;
	height: var(--wd-form-height, 42px);
	padding: 0 15px;
	min-width: 0;
}

.hz-newsletter-popup .hz-newsletter-form input[type="submit"] {
	flex: 0 0 auto;
	height: var(--wd-form-height, 42px);
}

/* CF7 puts validation text and the response banner outside our wrapper. */
.hz-newsletter-popup .wpcf7-not-valid-tip,
.hz-newsletter-popup .wpcf7-response-output {
	margin: 12px 0 0;
	padding: 0;
	border: 0;
	text-align: center;
	font-size: 13px;
}

.hz-newsletter-popup .wpcf7-spinner {
	margin: 0 auto;
}

/* ============================================================================
 * QA03 / 1F — social login buttons: the divider and the demo's two layouts.
 *
 * Everything here is scoped to the FORM, never to a wrapper of ours, because Nextend moves the
 * buttons after render: its embedded-login script does `form.appendChild(container)` on DOM
 * ready, relocating #nsl-custom-login-form-N to the end of the <form>. Any selector rooted in
 * markup we printed around it matches on the server and stops matching in the browser — which
 * is exactly why the first attempt at this looked correct in the HTML and wrong on screen.
 *
 * Specificity is also load-bearing. Nextend prints its CSS inline from wp_head priority 100,
 * this file is printed at priority 8, so Nextend always wins ties. Its rule
 *   div.nsl-container.nsl-container-block .nsl-container-buttons        (0,3,1)
 *     { display: inline-grid; grid-template-columns: minmax(145px, auto); }
 * is what keeps the buttons stacked and narrow, so every rule below is built to outrank it.
 * ---------------------------------------------------------------------------- */

/* The "OR LOGIN WITH" rule. Drawn on the container Nextend itself tags during the move, so the
   label travels with the buttons. Text comes from --hz-login-with (set in functions.php) to
   keep it translatable; the fallback keeps it readable if that ever fails to load. */
.woocommerce-form-login .nsl-container-embedded-login-layout-below {
	margin-top: 20px;
	padding-top: 20px;
	border-top: 1px solid var(--brdcolor-gray-300);
}

.woocommerce-form-login .nsl-container-embedded-login-layout-below::before {
	content: var(--hz-login-with, "Or login with");
	display: block;
	margin-bottom: 15px;
	color: var(--color-gray-500);
	text-align: center;
	text-transform: uppercase;
	letter-spacing: .02em;
	font-weight: 600;
	font-size: 12px;
}

/* (0,3,2) — beats Nextend's (0,3,1) on element count without relying on it keeping
   the .nsl-container-block class name. */
body .woocommerce-form-login div.nsl-container .nsl-container-buttons {
	display: grid;
	gap: 10px;
	width: 100%;
	padding: 0;
}

body .woocommerce-form-login div.nsl-container .nsl-container-buttons > a {
	width: 100%;
	max-width: none;
	margin: 0;
}

/* Side drawer / login popup — one full-width column. (0,4,2) */
body .login-form-side .woocommerce-form-login div.nsl-container .nsl-container-buttons {
	grid-template-columns: 1fr;
}

/* My Account page — two columns, 50% each, as QA asked. (0,5,2) */
body.woocommerce-account .col-login .woocommerce-form-login div.nsl-container .nsl-container-buttons {
	grid-template-columns: 1fr 1fr;
}

@media (max-width: 575px) {
	body.woocommerce-account .col-login .woocommerce-form-login div.nsl-container .nsl-container-buttons {
		grid-template-columns: 1fr;
	}
}

/* ============================================================================
 * QA04 — product grid: uneven card heights, price and category out of line.
 *
 * Hankerz product titles are catalogue-style and carry the full spec, e.g.
 * "HP OmniBook 5 Flip 14-fp0052ne , Core 5-120U (10C) 16GB LPDDR5 5200 ,] 512GB PCIe Gen4
 * Value, Intel Graphics, Sky Blue , Touch/14.0 2K (1920x1200) IPS, KBD ARAB, Win 11, 3 years".
 * At three columns that wraps to eight lines while a neighbour wraps to five, so every element
 * underneath starts at a different height and the row reads as ragged.
 *
 * TWO blocks vary, not one. The obvious fix is to pin the title, but .wd-product-cats wraps too
 * ("Cooling Systems, Water Cooling, Thermalright" is two lines where "Lexar, Ram" is one), so
 * pinning only the title still leaves the prices off by a line. Both are clamped here.
 *
 * Clamping rather than min-height alone: a min-height reserves space for SHORT titles but does
 * nothing to cap long ones, so the tallest card would still set the row height. Clamp plus a
 * matching min-height makes the block exactly N lines in every card, long or short — which is
 * what actually lines the prices up.
 *
 * Scoped to grid cards via :not(.product-list-item) — list view is one product per row, where
 * the full title is wanted and there is no neighbour to align to. Woodmart puts BOTH
 * product-grid-item and product-list-item on list rows, hence the negation rather than a plain
 * .product-grid-item match.
 *
 * Line count is a variable: raise --hz-grid-title-lines to 3 to show more of the title at the
 * cost of a taller row. Clamping is visual only — the full title stays in the DOM for screen
 * readers and for search engines.
 * ---------------------------------------------------------------------------- */
.wd-product.product-grid-item:not(.product-list-item) {
	--hz-grid-title-lines: 2;
	--hz-grid-title-lh: 1.4;
	--hz-grid-cats-lh: 1.4;
}

.wd-product.product-grid-item:not(.product-list-item) .wd-entities-title {
	display: -webkit-box;
	-webkit-line-clamp: var(--hz-grid-title-lines);
	line-clamp: var(--hz-grid-title-lines);
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: var(--hz-grid-title-lh);
	min-height: calc(var(--hz-grid-title-lines) * var(--hz-grid-title-lh) * 1em);
}

.wd-product.product-grid-item:not(.product-list-item) .wd-product-cats {
	display: -webkit-box;
	-webkit-line-clamp: 1;
	line-clamp: 1;
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: var(--hz-grid-cats-lh);
	min-height: calc(var(--hz-grid-cats-lh) * 1em);
}

/* ============================================================================
 * QA06 — shop toolbar: one row, spread across the container instead of two
 * left-packed rows.
 *
 * Woodmart already builds this correctly. .shop-loop-head is a flex row with
 * justify-content:space-between holding two .wd-shop-tools groups:
 *   group 1  breadcrumbs + result count
 *   group 2  sidebar button + "Show: 9/12/18/24" + view switcher + sort dropdown
 * so the intent is group 1 hard left, group 2 hard right.
 *
 * It only collapses because of `flex-wrap: wrap` on .shop-loop-head. On these category pages the
 * left CATEGORIES sidebar takes three columns, and a breadcrumb like
 * "Home / PC Hardware Components / Graphic Cards" plus the whole tool group no longer fits the
 * remaining width — so group 2 wraps onto its own line and, having no width to fill, packs to
 * the left with dead space to its right. That is precisely what QA screenshotted. The Woodmart
 * demo does not hit it because its breadcrumb is "Home / Shop" and its shop page is full width.
 *
 * So the fix is not to rebuild the toolbar — it is to stop it wrapping at desktop widths and let
 * group 2 claim the leftover space:
 *   nowrap            keeps both groups on one line
 *   flex: 1 1 auto    lets group 2 absorb the remaining width
 *   justify-content   pushes its contents (ending with the sort dropdown) to the right edge
 *   min-width: 0      lets the breadcrumb shrink rather than force an overflow
 *
 * Left as wrapping below 1025px on purpose — on a phone these genuinely do need to stack, and
 * Woodmart already hides the sidebar and shrinks the gaps there.
 *
 * `body` prefix for specificity: css/parts/woo-mod-shop-loop-head.css is force-enqueued by the
 * theme and can print after this stylesheet, so a bare .shop-loop-head would tie and lose.
 * ---------------------------------------------------------------------------- */
@media (min-width: 1025px) {
	body .shop-loop-head {
		flex-wrap: nowrap;
	}

	body .shop-loop-head > .wd-shop-tools:first-child {
		flex: 0 1 auto;
		min-width: 0;
	}

	body .shop-loop-head > .wd-shop-tools:last-child {
		flex: 1 1 auto;
		justify-content: flex-end;
	}
}

/* ============================================================================
 * QA07 — Customer Support Center: uneven card heights and misaligned text.
 *
 * Page 22638 (same ID on staging and production, so scoping by it is portable). Four cards, each
 * an Elementor container holding an image widget, a Porto-era [porto_sicon_box] for the title,
 * and a heading widget used as the body copy.
 *
 * The offset starts with the ARTWORK, not the text. The four banners were exported at three
 * different aspect ratios:
 *
 *   ask-expert-900.jpg          1760x900   1.96
 *   b2b-850-600.jpg             1700x1200  1.42
 *   hankerz-maintenance.png     1700x1200  1.42
 *   internship-banner.jpg       1600x1000  1.60
 *
 * At equal column width a 1.96 image renders far shorter than a 1.42 one, so the "Ask Experts"
 * title starts ~45px higher than its neighbours and every block below it inherits the offset.
 * The titles then compound it by wrapping to one or two lines ("Hankerz B2B Consultations").
 *
 * Both are pinned here: one ratio for the images, a fixed two-line box for the titles.
 *
 * 7/5 (1.4) is chosen deliberately over a more conventional 16/9. These banners carry burnt-in
 * text near the TOP ("BUSINESS SOLUTIONS B2B", "ONLINE MAINTENANCE"), and cropping to 16/9 would
 * take ~10% off the top of the two 1.42 images and risk clipping it. 7/5 matches those two
 * exactly — they are not cropped at all — and trims the other two horizontally instead, where
 * their wording is centred and survives.
 *
 * The real fix is re-exporting all four banners at one ratio; this makes the grid uniform
 * without touching the artwork.
 * ---------------------------------------------------------------------------- */
.page-id-22638 .elementor-widget-image img,
.page-id-46930 .elementor-widget-image img {
	width: 100%;
	height: auto;
	aspect-ratio: 7 / 5;
	object-fit: cover;
	object-position: center;
}

/* 2026-09-04 (client: "fix UI of Customer Support Center posts list"): the Porto title shortcode
   is gone — both pages (EN 22638, AR 46930) now use an Elementor heading for the title and, until
   today, ANOTHER heading widget for the body copy, so the description rendered as a 22px semibold
   H3. The four description widgets were converted to text widgets (class hz-csc-desc) and the titles
   carry hz-csc-title, so the rules below key on those classes and not on page ids. */
.hz-csc-title .elementor-heading-title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-size: 20px;
	line-height: 1.3;
	min-height: calc(2 * 1.3em);
	margin: 14px 0 6px;
}

.hz-csc-desc p {
	font-size: 15px;
	line-height: 1.6;
	font-weight: 400;
	color: rgba(255, 255, 255, .78);
	margin: 0;
}

.hz-csc-desc p:last-child {
	margin-bottom: 0;
}

.page-id-22638 .elementor-widget-image a,
.page-id-46930 .elementor-widget-image a {
	display: block;
}

/* ============================================================================
 * QA08 — LIST view: one line of product name, one line of description, then "…".
 *
 * Counterpart to the grid rules above, which deliberately exclude list rows
 * (:not(.product-list-item)). List view gets ONE line each rather than two, per QA: enough to
 * identify the product, with the ellipsis signalling that the rest is on the product page.
 *
 * The description needs flattening before it can be clamped. Hankerz short descriptions are
 * spec LISTS, not prose:
 *
 *   <div class="woocommerce-product-details__short-description">
 *     <ul><li><strong>Processor:</strong> Intel Core Ultra 7 355</li>
 *         <li><strong>Memory:</strong> 16GB LPDDR5X</li> ...
 *
 * -webkit-line-clamp only counts line boxes in ONE inline flow, so against block <li> children
 * it clamps unpredictably. Collapsing the list to inline first gives a single flow that clamps
 * to exactly one line and puts the ellipsis at the end of it.
 *
 * The separator is there because the flattened items would otherwise depend on incidental
 * whitespace in the stored HTML — some products are saved as `</li> <li>` and some as
 * `</li><li>`, and the latter would read "…Integrated GraphicsDisplay: 14…".
 *
 * No PHP fallback for products with an empty short description: 2172 of 2717 published products
 * have one, and for the remaining 545 WooCommerce renders no element at all, so nothing is
 * misaligned — the row simply has no description line. 462 products have neither a short nor a
 * long description, so a post_content fallback would not rescue those anyway; that is a content
 * gap for the catalogue team rather than something CSS can fix.
 * ---------------------------------------------------------------------------- */
.wd-product.product-list-item .wd-entities-title {
	display: -webkit-box;
	-webkit-line-clamp: 1;
	line-clamp: 1;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* Description clamp starts at 769px on purpose. Woodmart hides the short description entirely
   in list view below that (`@media (max-width: 768.98px) { .wd-product.product-list-item
   [class*=short-description] { display: none } }`), and that rule ties with these on specificity
   — so declaring `display` here at all widths would flip the theme's mobile behaviour depending
   on which stylesheet happened to load last. Above the breakpoint there is no conflict. */
@media (min-width: 769px) {
	.wd-product.product-list-item .woocommerce-product-details__short-description {
		display: -webkit-box;
		-webkit-line-clamp: 1;
		line-clamp: 1;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}

	/* Flatten the spec list into one inline run so the clamp has a single flow to measure. */
	.wd-product.product-list-item .woocommerce-product-details__short-description :is( ul, ol, li, p ) {
		display: inline;
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.wd-product.product-list-item .woocommerce-product-details__short-description li + li::before {
		content: " · ";
	}
}

/* List rows: align the image and the text column to the TOP rather than the middle.
   Woodmart centres them — `.wd-product.product-list-item .wd-product-wrapper{flex-direction:row;
   align-items:center}` in css/parts/woo-product-loop-list.css — which floats short rows against
   tall thumbnails and makes the clamped title/description sit at inconsistent heights down the
   page. `body` prefix takes this to (0,3,1) so it outranks the theme's (0,3,0) whichever
   stylesheet loads last. */
body .wd-product.product-list-item .wd-product-wrapper {
	align-items: flex-start;
}

/* ============================================================================
 * PLP list mode — price BELOW the description instead of above it.
 *
 * content-product-list.php prints the price before the excerpt:
 *   title → categories → rating → stock → PRICE → swatches → DESCRIPTION → add to cart
 * and .product-list-content is already `display:flex; flex-direction:column`, so this is a
 * reorder rather than a template override — no copy of the theme template to maintain.
 *
 * Only the price and the add-to-cart button are given an order. Everything else stays at the
 * default 0 and therefore keeps its DOM sequence, so a rating, stock line or swatch row on other
 * product types still lands where the theme put it relative to the title. Ordering the
 * description instead would have pushed those below it too.
 *
 * add-to-cart needs order:2 explicitly — without it the button stays in the default group and
 * the price, at order:1, would jump past it to the very bottom of the row.
 *
 * Scoped to .product-list-item, a class that only exists in list mode, so grid cards keep the
 * theme's price position.
 * ---------------------------------------------------------------------------- */
.wd-product.product-list-item .product-list-content > .price {
	order: 1;
}

.wd-product.product-list-item .product-list-content > .wd-add-btn {
	order: 2;
}

/* ============================================================================
 * PDP — breadcrumb and product title, desktop brought in line with mobile.
 *
 * Hankerz product names are catalogue strings of ~200 characters. Woodmart already accounts for
 * that below 1024px — it hides the product name from the breadcrumb and steps the title down to
 * 20px — but on desktop it prints the whole name twice: once as the last breadcrumb crumb
 * (wrapping the trail to two lines) and again as a 34px H1 that runs to four lines.
 *
 *   .product_title                                34px  /  24px <=1024  /  20px <=768.98
 *   .woocommerce-breadcrumb .wd-last-link ~ span  display:none only <=1024px
 *
 * 1. The crumb rule is lifted out of its media query so it applies at every width, but ONLY on
 *    the product page. It must be scoped: on a category archive the same markup shape means
 *    "wd-last-link ~ span" is the CURRENT CATEGORY —
 *
 *      <a class="wd-last-link">PC Hardware Components</a>
 *      <span class="wd-delimiter">/</span><span class="wd-last">Graphic Cards</span>
 *
 *    so an unscoped rule silently drops "Graphic Cards" from every category breadcrumb. Keyed to
 *    body.single-product, which WooCommerce sets on the product page and nowhere else (verified:
 *    category archives get "archive tax-product_cat" instead). The trail becomes
 *    "Home / Laptops / Business Grade Laptops" on one line, exactly as it already is on mobile.
 *
 * 2. The title is pinned to 20px at ALL widths rather than only on desktop. Overriding desktop
 *    alone would leave the theme's 24px tablet step in place and make tablet render the title
 *    LARGER than desktop; a flat 20px keeps the scale monotonic.
 *
 * 3. The breadcrumb inherits --wd-text-font-size (16px) since the theme sets no size for it,
 *    which is why it reads as heavy as body copy. 13px puts it back in a supporting role.
 * ---------------------------------------------------------------------------- */
body.single-product .woocommerce-breadcrumb .wd-last-link ~ span {
	display: none;
}

body .product_title {
	font-size: 20px;
}

.single-breadcrumbs-wrapper,
.single-breadcrumbs-wrapper :is( a, span ) {
	font-size: 13px;
}

/* ============================================================================
 * Customer Support Center — four cards on one row at desktop.
 *
 * The cards were ALREADY set to a quarter each in Elementor:
 *   row      6350f57  --flex-direction:row; --flex-wrap:wrap
 *   4 cards  3fd7d9c / 1c91bac / 2dab0a4 / 55182aa   --width:25%
 *
 * which is why this looks like it should already work. It cannot: 4 x 25% is exactly 100% of the
 * row, so the moment any column gap is applied the total exceeds the line and flex-wrap drops the
 * fourth card ("Hankerz Internship") onto its own row. A percentage width in a flex row does not
 * subtract the gap.
 *
 * Rather than fight it with calc(25% - gap*3/4) — which silently rebreaks whenever someone edits
 * the gap in Elementor — the inner row becomes a four-column grid. Grid divides the space AFTER
 * removing the gaps, so the columns stay equal whatever gap is set.
 *
 * The children's explicit --width has to be neutralised as well: as grid items, a 25% width would
 * resolve against their own COLUMN rather than the row and shrink each card to a quarter of a
 * quarter. minmax(0, 1fr) rather than 1fr so a long unbroken word cannot force a column wider
 * than its share.
 *
 * Desktop only; below 1025px Elementor's wrap behaviour is left alone so the cards stack as they
 * already do on tablet and phone. Pairs with the QA07 rules above, which pin the image ratio and
 * the title height so the four columns line up once they share a row.
 * ---------------------------------------------------------------------------- */
@media (min-width: 1025px) {
	.page-id-22638 .elementor-element-6350f57 > .e-con-inner {
		display: grid;
		grid-template-columns: repeat(4, minmax(0, 1fr));
		align-items: start;
	}

	.page-id-22638 .elementor-element-6350f57 > .e-con-inner > .e-con {
		--width: 100%;
		width: 100%;
	}
}

/* ============================================================================
 * "LATEST EVENTS" blog cards — uniform image ratio and equal card heights.
 *
 * The 3-column layout was never the problem; the widget already emits
 * --wd-col-lg:3; --wd-col-md:3; --wd-col-sm:1. What breaks the row is the artwork, exactly as on
 * the Customer Support Center page — the posts' featured images are wildly different shapes:
 *
 *   maya-banner.jpg    1920x717   ratio 2.68   (wide banner)
 *   blender-1.jpg      1200x1272  ratio 0.94   (portrait — QA's "stretched" centre card)
 *
 * At a fixed column width a 0.94 image renders nearly three times taller than a 2.68 one, which
 * is what drags the middle card down and leaves the row ragged.
 *
 * 16/9 is the compromise. There is no ratio that leaves both of those uncropped — one is wider
 * than 2:1 and the other is taller than square — so this picks the conventional landscape card
 * shape for event/news listings and lets object-fit crop to it from the centre.
 *
 * Equal heights are then made explicit rather than left to content length: the carousel item
 * becomes a flex box and the card inner fills it, so all three cards reach the bottom of the row
 * even when one post has a longer title or excerpt than its neighbours.
 *
 * Scoped to BOTH blog containers: .wd-blog-element (the Elementor blog widget, used by LATEST
 * EVENTS on the home page) and .wd-blog-holder (the blog archive template behind
 * /resources-center). They are different wrappers around the same card markup, so a rule
 * written for one silently misses the other — which is exactly what happened on the first
 * pass. Nothing else on the site uses those two classes.
 *
 * As on the support centre: re-exporting the featured images at one ratio is the real fix — this
 * makes the grid uniform without touching the media library.
 * ---------------------------------------------------------------------------- */
:is( .wd-blog-element, .wd-blog-holder ) .wd-post-img img {
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	object-position: center;
}

:is( .wd-blog-element, .wd-blog-holder ) .wd-carousel-item {
	display: flex;
}

:is( .wd-blog-element, .wd-blog-holder ) .wd-post-inner {
	display: flex;
	flex-direction: column;
	/* height as well as width: on the home page the card sits in a flex .wd-carousel-item and is
	   stretched for us, but on the /resources-center archive it sits directly in a CSS grid, where
	   the ITEM stretches and the inner would otherwise only be as tall as its content. */
	width: 100%;
	height: 100%;
}

/* Blog cards, second pass: the IMAGES are uniform now, but the text below them still is not.
 *
 *   title    "Maya Recommended Specs" 1 line vs "Horizon Forbidden West Recommended Specs" 2
 *   excerpt  5 lines on Maya and Blender, 7 on Horizon
 *
 * so the meta row, the excerpt and CONTINUE READING each start at a different height and the row
 * reads ragged even though the cards themselves are now the same height.
 *
 * Same treatment as the product grid: clamp BOTH variable blocks to a fixed number of lines with
 * a matching min-height, so every card reserves identical space whether its text is long or
 * short. 5 lines for the excerpt because that is what two of the three already show — only the
 * longest is trimmed.
 *
 * CONTINUE READING is additionally pinned to the bottom with margin-top:auto, which needs
 * .wd-post-content to be a growing flex column (the read-more sits inside it, not inside
 * .wd-post-inner). That is the safety net: if any other row — a wrapped meta line, a second
 * category badge — ever differs between cards, the link still lines up.
 */
:is( .wd-blog-element, .wd-blog-holder ) .wd-post-content {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
}

:is( .wd-blog-element, .wd-blog-holder ) .wd-post-title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: 1.3;
	min-height: calc(2 * 1.3em);
}

:is( .wd-blog-element, .wd-blog-holder ) .wd-post-excerpt {
	display: -webkit-box;
	-webkit-line-clamp: 5;
	line-clamp: 5;
	-webkit-box-orient: vertical;
	overflow: hidden;
	line-height: 1.6;
	min-height: calc(5 * 1.6em);
}

:is( .wd-blog-element, .wd-blog-holder ) .wd-post-read-more {
	margin-top: auto;
}

/* ============================================================================
   QA03 / item 1 — CALL US NOW replaces the free-shipping strip in the top bar
   ----------------------------------------------------------------------------
   Live runs this as a two-line porto_info_box in the MAIN header row (11px label
   over an 18px number). Reproducing that here would roughly double the top bar's
   height, so the shortcode emits one line and this sizes it to the bar's own
   13px rhythm: the label stays at the promo strip's 12px, the number goes one
   step up and heavier so the digits are what the eye lands on.

   .hz-topbar-promo is kept on the element, so the leading divider and the
   uppercase/letter-spacing treatment above still apply and the strip sits
   flush against the language switcher exactly as the shipping text did.

   Below 768px the label is kept at a smaller size (DEV08.04: the client asked for the
   words "Call Us Now" on mobile too); only below 375px is it dropped — a phone number is
   self-explanatory next to a handset icon, and wrapping is what pushes the bar to two
   rows on the narrowest widths.
   ============================================================================ */

.whb-top-bar .hz-topbar-call .hz-call-us {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	color: inherit;
	white-space: nowrap;
}

/* The bar's links are already light-on-dark; only the hover needs stating, and it
   uses the brand colour so it matches the nav hover set in item 8. */
.whb-top-bar .hz-topbar-call .hz-call-us:hover {
	color: var(--wd-primary-color);
}

.whb-top-bar .hz-topbar-call .hz-call-icon {
	flex: 0 0 auto;
	width: 14px;
	height: 14px;
}

.whb-top-bar .hz-topbar-call .hz-call-number {
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .01em;
}

@media (max-width: 767px) {
	.whb-top-bar .hz-topbar-call .hz-call-label {
		font-size: 11px;
		letter-spacing: 0;
	}

	.whb-top-bar .hz-topbar-call .hz-call-number {
		font-size: 12px;
	}
}

@media (max-width: 374px) {
	.whb-top-bar .hz-topbar-call .hz-call-label {
		display: none;
	}
}

/* ============================================================================
   QA03 / item 8 — brand colour, main-nav hover
   ----------------------------------------------------------------------------
   The blue everywhere else was one theme option: primary-color was
   rgb(89,94,224) (the Woodmart hardware demo's purple) and it feeds
   --wd-primary-color, which .price, .wd-tools-count (the Compare/Wishlist/Cart
   badges) and the accented buttons all read. Setting it to live's #d14609
   (porto_settings.skin-color) fixes all of those at once, so none of that is
   restated here.

   The main-nav hover is the one thing the option does NOT reach. Woodmart's base
   rule is already what QA wants —

       .wd-nav.wd-style-default { --nav-color-hover: var(--wd-primary-color) }

   — but header-base.css overrides it for light-on-dark headers:

       .whb-color-light .wd-nav-header.wd-style-default { --nav-color-hover: rgba(255,255,255,.7) }

   ...which is the grey QA flagged.

   Scope: every header nav, not just the main menu — top bar included. The two
   selectors carrying .wd-style-default are there to outrank that (0,3,0) override
   with a (0,3,1) of their own; the bare .wd-nav-header line is the catch-all for
   the top bar's wd-style-separated group, which has no theme override to beat.

   Body links are handled by the theme option instead of here: link-color.hover is
   now #d14609, so Woodmart writes --wd-link-color-hover orange into its own
   generated CSS. Overriding that in this file would lose anyway — the generated
   block is inline in <head> and lands after this stylesheet.

   Dropdown items needed nothing: .wd-sub-menu already resolves
   --sub-menu-color-hover to var(--wd-primary-color), so they turned orange the
   moment the primary colour changed.
   ============================================================================ */

body .whb-color-light .wd-nav-header.wd-style-default,
body .whb-color-dark .wd-nav-header.wd-style-default,
body .whb-header .wd-nav-header {
	--nav-color-hover: var(--wd-primary-color);
}

/* The top bar's Text/HTML element sets its own link colours for the light scheme,
   so the phone line and anything else dropped in there needs the same treatment. */
body .whb-color-light .wd-header-text {
	--wd-link-color-hover: var(--wd-primary-color);
}

/* ============================================================================
   QA03 / item 3 — hero banner
   ----------------------------------------------------------------------------
   The demo's 3-slide "Hardware slider" is replaced by a new slider, "Hankerz Home"
   (Theme Settings → Sliders), carrying the live PC BUILD artwork as its only slide
   for now. It stays a SLIDER rather than becoming a single image widget because
   more banners are coming: adding one is then "duplicate the slide, swap image and
   link" in wp-admin, with no Elementor or code change, and no second edit on the
   Arabic page — both home pages point at the same slider slug.

   Two departures from the demo slider, both to match live:

   1. Not stretched. Live renders this banner inside the content container, with
      whitespace either side, not edge-to-edge.
   2. Height follows the artwork instead of the slider's fixed px height. The demo
      used min-height: 900px with a background-size: cover image, which crops a
      designed banner — and this artwork has its headline baked in, so cropping
      eats the words. aspect-ratio keeps the whole 16:9 frame at every width and
      makes the fixed heights in the slider settings a floor rather than the rule.

   Future banners must be 16:9 (1920×1080 is the source here) or they will letterbox
   against this ratio. That is the one constraint to hand over with the slider.
   ============================================================================ */

.wd-hankerz-hero .wd-slide {
	/* !important is doing real work here, not papering over a guess. Woodmart writes
	   the slider's height as an inline #slider-<term_id> rule, so it carries ID
	   specificity (1,0,1) that no class selector can outrank — and the term ID is
	   environment-specific, so hard-coding #slider-2129 would silently stop matching
	   the day this ships to production. The heights in the slider settings stay set
	   to the 16:9 equivalents, so they remain a sensible fallback if this rule is
	   ever removed. */
	min-height: 0 !important;
	aspect-ratio: 16 / 9;

	/* No max-height. An earlier version capped this at the demo slider's 900px so a
	   very wide monitor would not get a very tall hero — but the slider is full-bleed,
	   so on a wide or zoomed-out viewport the cap made the frame far wider than 16:9
	   and object-fit cropped the artwork to a horizontal slice, cutting the "PC BUILD"
	   headline in half. QA raised exactly that (round 4, item 1).

	   The ratio now governs at every width, which is what "fully responsive" means for
	   a banner whose text is baked into the image: it scales, it never crops. The cost
	   is a tall hero on an ultra-wide monitor, which is the right trade — a banner that
	   is too tall is still readable, a banner with its headline sliced off is not. */
}

/* The slide image is absolutely filled by .wd-slide-bg; keep it covering the frame
   so a slightly-off source still fills rather than leaving bars. With the frame
   already at the source ratio, "cover" crops nothing. */
.wd-hankerz-hero .wd-slide-bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ============================================================================
   QA03 / item 4 — the three promo banners live has
   ----------------------------------------------------------------------------
   Left column: gaming chairs (850x1000). Right column: monitors over laptops
   (1700x980 each). Those ratios are why live's two columns finish level — the
   left image is 0.588 of the row width tall, and the two stacked right images
   come to 0.577 plus the 14px gap. Nothing forces the heights here, they agree
   on their own.

   The one guard is object-fit on the left image: if a future banner ships at a
   different ratio the columns would otherwise end at different heights, and a
   ragged bottom edge is the exact thing QA has been raising all week.
   ============================================================================ */

/* Geometry lifted from live's own settings, not eyeballed: porto_settings has
   grid-gutter-width = 20 and container-width = 1250, and the only bespoke value in
   the whole block is a 14px margin-bottom between the monitors and laptops images.

   Nothing here forces heights. Live doesn't either — its columns finish level purely
   because of the artwork: chairs is 850x1000 (0.85) and monitors/laptops are 1700x980
   (1.735), so in a 615px column the left image is 723.5px and the two stacked right
   images are 708.9 + the 14px gap = 722.9. Live lands within a pixel; at our wider
   1440px container the columns end about 3px apart.

   An earlier version of this stretched the row and cropped the images with object-fit
   to close that 3px. That was solving a problem nobody had at the cost of behaving
   differently from live, which is what was actually asked for. Natural heights it is.

   Grid rather than flex only because 1fr columns subtract the gap instead of adding
   to it, so the row can never overflow. */
/* The grid goes on .e-con-inner, not on the container.

   Elementor renders a BOXED container's children inside a .e-con-inner wrapper; a
   FULL container's children sit directly on it. hzp0001 has to be boxed — it is a
   top-level container, and "full" there means edge-to-edge rather than the content
   width live uses. So the two columns are grandchildren, and putting the grid on
   .hz-promo-banners itself produced a one-cell grid wrapping .e-con-inner while the
   columns inside stayed in Elementor's default flex-direction: column. That is why
   they stacked.

   Plain `display`/`gap` rather than Elementor's --display/--row-gap custom properties
   on purpose: those inherit, and .hz-promo-col below would have picked up the 20px
   column gap in place of live's 14px. Specificity ties Elementor's own
   `.e-con>.e-con-inner{display:var(--display)}` at (0,2,0), and child-style-css is
   enqueued after elementor-frontend-css, so source order settles it. */
.hz-promo-banners > .e-con-inner {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 20px;
}

.hz-promo-banners .hz-promo-col {
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.hz-promo-banners .hz-promo-banner img {
	display: block;
	width: 100%;
	height: auto;
}

/* One per row on phones: at half of a 390px screen the baked-in text in each banner
   is unreadable, and there is no second column left to line up with anyway. */
@media (max-width: 767px) {
	.hz-promo-banners > .e-con-inner {
		grid-template-columns: 1fr;
	}
}

/* ============================================================================
   QA03 / items 5, 6, 7 — category tiles and See All Products
   ----------------------------------------------------------------------------
   This row used to be a wd_product_categories widget. It is now five authored
   tiles, for three reasons that all came out of QA's own requirements:

     * the titles have to read like live's ("Play Station" where the term is
       "Gaming Consoles"), and the widget can only ever print the term name;
     * the artwork has to be these tiles' artwork only — pushing it onto the
       terms as thumbnails would repaint every category archive header too;
     * the widget carried English term IDs, and WPML filters get_terms() by
       language, so on /stg/ar it resolved to nothing and rendered an empty
       band. That was item 6. Authored tiles have no term-ID dependency, so
       Arabic works by construction rather than by translation bookkeeping.

   The supplied artwork is square (1000x1000, and 1254x1254 for the PS5 render),
   so the tiles are uniform without any cropping.
   ============================================================================ */

.hz-cat-row {
	display: grid;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	gap: 20px;
	align-items: flex-start;
}

@media (max-width: 1024px) {
	.hz-cat-row {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.hz-cat-row {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.hz-promo-banners {
		grid-template-columns: 1fr;
	}
}

.hz-cat-tile .hz-cat-image img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1 / 1;
	object-fit: cover;
}

/* Elementor colours .elementor-heading-title, but the anchor it wraps picks up the
   theme's link colour instead, which would leave four orange headings and one blue
   one the moment a title is linked. Inherit puts the widget's own colour back. */
.hz-cat-tile .elementor-heading-title a {
	color: inherit;
}

.hz-cat-tile .elementor-heading-title a:hover {
	opacity: .75;
}

/* CL032-DEV08.17 (2026-09-04): the client wants this button ORANGE "like before" (live's
   Porto home shows it in the brand colour on the dark page). The earlier black-with-hairline
   treatment is gone. body prefix + !important are kept from the previous version: Elementor's
   per-page CSS paints `.elementor-widget-button .elementor-button{background-color:var(--e-global-color-accent)}`
   at the same (0,2,0) and had been winning in practice, so this stays deliberately heavier. */
body .hz-see-all .elementor-button {
	border: 1px solid var(--wd-primary-color);
	border-radius: 5px;
	background-color: var(--wd-primary-color) !important;
	padding: 10px 30px;
	color: #fff;
}

body .hz-see-all .elementor-button:hover {
	border-color: #b53d07;
	background-color: #b53d07 !important;
	color: #fff;
}

/* With a single banner the arrows and dots are chrome with nothing to navigate — live
   has neither. :has() counts the slides rather than hard-coding "hide them", so both
   come back on their own the moment a second slide is added in wp-admin, which is the
   whole point of keeping this a slider. */
.wd-hankerz-hero .wd-slider:not(:has(.wd-carousel-wrap > .wd-slide:nth-child(2))) :is(.wd-slider-arrows, .wd-slider-pagin) {
	display: none;
}

/* ============================================================================
   QA03 / RTL — the phone number must stay LTR
   ----------------------------------------------------------------------------
   "+20 102 986 5787" is left-to-right text sitting inside a right-to-left line.
   Without isolation the bidi algorithm resolves the leading "+" against the
   surrounding paragraph direction and renders it at the wrong end of the number
   — a classic RTL bug that looks like a typo rather than a layout fault.

   isolate rather than embed/override: the number is a self-contained run, so it
   should neither inherit the line's direction nor leak its own into the Arabic
   label beside it. The label is deliberately left alone so it reads RTL.
   ============================================================================ */

.hz-call-us .hz-call-number {
	direction: ltr;
	unicode-bidi: isolate;
}

/* ============================================================================
   Footer link hover — orange
   ----------------------------------------------------------------------------
   Setting link-color.hover in the theme options turned body links orange via
   :root, but the footer has two link types that never read that variable.

   1. The 15 menu links. They live in .wp-block-wd-menu-list.wd-sub-menu inside
      <footer class="... color-scheme-light">, and their hover comes from
      --sub-menu-color-hover, not --wd-link-color-hover. Woodmart's base.css sets
      that variable to var(--wd-primary-color) by default, then overrides it for
      light-on-dark contexts:

          [class*=color-scheme-light] .wd-sub-menu            { --sub-menu-color-hover: #FFF }
          [class*=color-scheme-light] .wd-sub-accented>li>a   { --sub-menu-color-hover: rgba(255,255,255,.6) }

      ...which is the near-white hover QA is seeing. Both selectors are matched
      here with one extra element (body) so this outranks them at (0,2,1) and
      (0,3,2) rather than relying on stylesheet order.

   2. The three social links. Those used to carry an inline
      style="color:rgba(255,255,255,.65);text-decoration:none;margin-right:16px;"
      written into the footer block's HTML, which meant they never changed on hover
      at all — an inline declaration beats every selector, so only !important could
      have touched them. The attribute has now been removed from BOTH footer blocks
      (cms_block 46739 EN and 46972 AR) and all three declarations moved here, so no
      !important is needed and the two states are owned in one place.

      margin-inline-end rather than the original margin-right: the inline version put
      the gap on the wrong side in Arabic, where the row runs right-to-left.
   ============================================================================ */

body .wd-footer .wd-sub-menu,
body .wd-footer .wd-sub-accented > li > a {
	--sub-menu-color-hover: var(--wd-primary-color);
}

.wd-footer .hkz-socials a {
	color: rgba(255, 255, 255, .65);
	text-decoration: none;
	margin-inline-end: 16px;
}

.wd-footer .hkz-socials a:hover {
	color: var(--wd-primary-color);
}

/* ============================================================================
   QA04 / items 2 and 3 — every muted hover goes to the brand orange
   ----------------------------------------------------------------------------
   Setting primary-color and link-color.hover covered plain links, but Woodmart
   routes most interactive elements through their OWN hover variable, and for
   light-on-dark contexts it deliberately mutes each one to a translucent white
   or a grey. Those muted values are what QA is seeing. Each block below names
   the default it replaces so the next person can tell what was deliberate.

   Everything is expressed as a variable override rather than a `color`
   declaration, so Woodmart's own rules keep doing the work — icons, text and
   pseudo-element glyphs all read the same variable and stay in step.
   ============================================================================ */

/* Login / Register, search, compare, wishlist, cart in the header.
   Default: .whb-color-light .wd-tools-element { --wd-header-el-color-hover: rgba(255,255,255,.8) } */
body .whb-color-light .wd-tools-element {
	--wd-header-el-color-hover: var(--wd-primary-color);
}

/* Social icons — the top bar set and the "Share:" row on a product page.
   Default: [class*=color-scheme-light] .wd-social-icons.wd-style-default { --wd-social-color-hover: rgba(255,255,255,.6) } */
body .wd-social-icons.wd-style-default.color-scheme-light,
body [class*="color-scheme-light"] .wd-social-icons.wd-style-default {
	--wd-social-color-hover: var(--wd-primary-color);
}

/* Items inside any header dropdown — this is what turns العربية orange in the
   language switcher, and it covers the main menu's dropdowns at the same time.
   Default: [class*=color-scheme-light] .wd-sub-menu { --sub-menu-color-hover: #FFF } */
body .wd-dropdown-menu .wd-sub-menu,
body .wd-dropdown-menu .wd-sub-accented > li > a {
	--sub-menu-color-hover: var(--wd-primary-color);
}

/* Product-card hover actions (compare / quick view / wishlist) and the same
   controls on a product page. This one is grey in BOTH schemes, not just the
   light one — Woodmart's own default is a mid grey.
   Default: .wd-action-btn { --wd-action-color-hover: var(--color-gray-500) } */
body .wd-action-btn {
	--wd-action-color-hover: var(--wd-primary-color);
}

/* Breadcrumb links on a product page.
   These already resolve to :root's --wd-link-color-hover, which is #d14609, so in
   principle they were orange already — but QA reported them as grey and there is no
   browser on this box to reproduce it with. Stating it explicitly costs one rule and
   removes the doubt; the current-page crumb keeps its muted colour on purpose, since
   it is not a link anywhere to hover to. */
body .wd-breadcrumbs a:not(.wd-last):hover,
body .woocommerce-breadcrumb a:hover {
	color: var(--wd-primary-color);
}

/* ============================================================================
   QA04 / item 6 — live's Online Maintenance Center and portal blocks
   ----------------------------------------------------------------------------
   These replace the demo "POWER AND BEAUTY" testimonial. Both containers are
   top-level and therefore BOXED (live keeps this content at container width),
   so — as with the promo banners — the grid has to go on .e-con-inner rather
   than on the container itself, or the columns stay in Elementor's default
   flex-column and stack. That mistake has cost a round already.
   ============================================================================ */

.hz-maintenance > .e-con-inner {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 40px;
	align-items: center;
}

.hz-maintenance .hz-maint-image img {
	display: block;
	width: 100%;
	height: auto;
}

.hz-maintenance .hz-maint-btns {
	display: flex;
	flex-direction: row;
	gap: 15px;
	margin-top: 24px;
}

/* Live pairs a black button with an orange one. The hairline is here for the same
   reason as the See All Products button: this page is near-black, so a black fill
   with no edge disappears into it. */
body .hz-maintenance .hz-btn-dark .elementor-button {
	border: 1px solid rgba(255, 255, 255, .25);
	background-color: #000;
	color: #fff;
}

body .hz-maintenance .hz-btn-accent .elementor-button {
	background-color: var(--wd-primary-color);
	color: #fff;
}

.hz-maintenance :is(.hz-btn-dark, .hz-btn-accent) .elementor-button:hover {
	background-color: var(--wd-primary-color);
	border-color: var(--wd-primary-color);
	color: #fff;
}

.hz-portals > .e-con-inner {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 20px;
}

.hz-portals .hz-portal-image img {
	display: block;
	width: 100%;
	height: auto;
}

@media (max-width: 767px) {
	.hz-maintenance > .e-con-inner,
	.hz-portals > .e-con-inner {
		grid-template-columns: 1fr;
	}
}

/* B2B reuses the maintenance block's two-column layout, mirrored: live puts the copy
   on the left and the artwork on the right, the opposite way round to the maintenance
   block above it. The shared .hz-maintenance class carries the grid; only the internship
   banner needs anything of its own. */
.hz-internship .hz-portal-image img {
	display: block;
	width: 100%;
	height: auto;
}

/* ----------------------------------------------------------------------------
   QA04 / item 1 follow-up — the hero must clear the overlay header on small screens
   ----------------------------------------------------------------------------
   The home page uses the OVERLAP header, which floats over the first section. That
   is fine on desktop, where the 16:9 hero is 800px+ tall and the header covers a
   thin strip of sky. On a phone the same ratio makes the hero only ~220px tall, so
   the header covers most of it and the logo lands directly on top of the "PC BUILD"
   headline — caught on a 390px capture, not visible at desktop widths.

   Pushing the slider down by the header's own height keeps the whole 16:9 frame
   visible below the header instead of cropping the artwork to buy space. The strip
   left behind the header is the page background, which is already black here.

   --wd-header-sm-h is Woodmart's own mobile header height variable, so this follows
   the header if its height is ever changed in the builder.
   ---------------------------------------------------------------------------- */

@media (max-width: 1024px) {
	.wd-hankerz-hero {
		margin-top: var(--wd-header-sm-h, 60px);
	}
}

/* ----------------------------------------------------------------------------
   Porto -> WoodMart migration (CL032-DEV11, 2026-09-03): counter number order

   The About page counters were [porto_stat_counter] shortcodes. Porto's template
   (shortcodes/templates/porto_stat_counter.php) emits stats-desc (prefix, number,
   suffix) FIRST and the stats-text title BELOW it. Elementor's own Counter widget
   emits .elementor-counter-title first and .elementor-counter-number-wrapper
   second - the reverse - and it has no order control to change that.

   Rather than accept a flipped layout, the migrated widgets carry the
   hkz-counter-number-first class (set via Elementor's _css_classes, which is the
   widget-level key; containers use css_classes instead) and this rule puts the
   number back on top.

   Applies to: About Hankerz 848 (EN) / 46951 (AR), and any counter migrated the
   same way later. Safe to keep even if a counter is rebuilt in the UI - it only
   matches elements that opt in via the class.
   ---------------------------------------------------------------------------- */

.hkz-counter-number-first .elementor-counter {
	display: flex;
	flex-direction: column-reverse;
}

/* ============================================================================
   QA04 / item 4 — FEATURED PRODUCTS: static tiles REVERTED (CL032-DEV08.13 / .14, 2026-09-04)
   ----------------------------------------------------------------------------
   On 2026-09-03 this section was rebuilt as 8 hard-coded image/heading tiles so it
   would not depend on product images that only exist on live. The client then
   reported the consequences as bugs: no Compare / Wishlist / Quick view / Add to
   cart on hover (DEV08.13), no 2-line ellipsis and no category line (DEV08.14).
   Both home pages (EN 46697, AR 46831) are back on the dynamic wd_products widget
   (8 products by ID), so the loop card, its hover actions and the QA04 grid clamp
   above apply again. The .hz-feat-* rules that styled the tiles were removed with
   them. The QA-supplied renders were kept: each product stores one as
   `_hankerz_home_image_id` and functions.php swaps it in ONLY while this widget
   renders (see "CL032-DEV08.13" there) — PDP, grids and quick view keep the real photo.
   ============================================================================ */

/* ============================================================================
   CL032-DEV08 — WoodMart mobile-view polish (client screenshots, 2026-09-03)
   ============================================================================ */

/* DEV08.01 — mini-cart & cart page: product name single line + ellipsis.
   Title attribute (hover = full name) added via hankerz_cart_item_name_tooltip()
   in functions.php; this is just the truncation. .cart-info needs min-width:0
   because it's a flex item (flex:1 1 auto, no fixed width) — ellipsis can't
   engage on a flex child without it. */
.widget_shopping_cart .cart-info,
.site-header-cart .cart-info {
	min-width: 0;
}

.hkz-cart-item-name {
	display: block;
	max-width: 100%;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

/* WoodMart makes the cart-page link an inline-block (td.product-name a). An
   inline-block is one atomic box to text-overflow, so the ellipsis would hide
   the whole name instead of trimming it — the link has to be plain inline. */
.hkz-cart-item-name a,
.shop_table td.product-name .hkz-cart-item-name a {
	display: inline;
}

/* Cart page above WoodMart's 768.98px breakpoint is a real <table>
   (woo-mod-shop-table.css only stacks the cells below it). A nowrap block
   makes the cell's minimum width the full title, so one long name pushed
   price / quantity / subtotal off-screen. width:0 takes the title out of the
   column's intrinsic width, the percentage keeps the column from collapsing
   (auto layout gives a 0-content column no share of the spare width), and
   min-width:100% stretches the block back to the cell so the ellipsis has a
   box. 65% matches the column's natural share with ordinary names; it yields
   to the other columns' minimum widths on narrower desktops. */
@media (min-width: 769px) {
	.woocommerce-cart-form .shop_table td.product-name {
		width: 65%;
	}

	.woocommerce-cart-form .shop_table td.product-name .hkz-cart-item-name {
		width: 0;
		min-width: 100%;
	}
}

/* DEV08.02 — search results: product name single line + ellipsis.
   Both result layouts are flex: the full-screen search lays tiles out as
   `flex: 0 1 200px` columns (header-el-search-fullscreen-1.css) and the
   dropdown/mobile-menu results are thumb + content rows. Flex items default to
   min-width:auto, i.e. never narrower than their min-content width — so a
   nowrap title alone made every tile as wide as its full product name (one
   grew to 1820px and pushed the rest of the row off-screen). min-width:0 on
   the item and its content box lets them shrink back to the layout's width,
   which is what gives the ellipsis a box to clip against. */
.wd-suggestion,
.wd-suggestion .wd-suggestion-content {
	min-width: 0;
}

.wd-dropdown-results .wd-suggestion-content {
	flex: 1 1 auto;
}

.wd-suggestion .wd-suggestion-content .wd-entities-title {
	display: block;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

/* DEV08.03 — mobile side menu: RTL arrow direction + remove arrow/row divider.
   WoodMart's modular CSS loader never registers an RTL variant for the
   nav-opener part (inc/configs/css-files.php has no 'rtl' => true for it, and
   no mod-nav-opener-rtl.css exists on disk), so the arrow glyph never mirrors
   for Arabic even though the RTL bundle (style-rtl.css) has the correct glyph
   defined - it's just never loaded. Hardcoding the mirrored glyph here doesn't
   depend on that loader. border-inline-start is the vertical line between the
   arrow button and the row label; border-bottom (row-to-row separator) is left
   alone since only the arrow/row divider was reported.
   WoodMart draws that divider in header-el-mobile-nav.css as
   `.mobile-nav .wd-nav-opener` (0-2-0), a deferred part printed AFTER this
   stylesheet, so an equal-specificity override here lost on source order and
   the line stayed. `.wd-side-hidden` is always on the off-canvas nav, so
   adding it makes this 0-3-0 without !important. */
html[dir="rtl"] .wd-nav-opener::after {
	content: "\f114";
}
.mobile-nav.wd-side-hidden .wd-nav-opener {
	border-inline-start: none;
}

/* DEV08.06 — My Account dashboard: 2 icons per row on mobile (was 1).
   Matches .wd-builder-off .wd-nav-my-acc's specificity via a real ancestor
   (WC core's own .woocommerce-MyAccount-content wrapper) rather than depending
   on whether .wd-builder-off is present. */
.woocommerce-MyAccount-content .wd-nav-my-acc {
	--wd-col-sm: 2;
}

/* DEV08.10 — checkout: payment gateway icons on the same line as their label.
   The icons come from hankerz-store-rules (porto_custom_woocommerce_gateway_icon
   replaces every gateway's own icon, paymob's #paymob-logo included) wrapped in
   span.wc_payment_method_icon, and that plugin's inline CSS turns the span into
   a block-level flex box at ≤499px (a Porto-era rule: display:flex; width:50%;
   justify-content:flex-end) — that is what pushes the icons onto their own line
   on phones. Desktop is unaffected: the span stays inline there. Overridden here
   rather than in the plugin because the plugin is shared with live/Porto, where
   that rule still matches its checkout layout. 0-3-2 beats the plugin's
   span.wc_payment_method_icon (0-1-1) at every width, no !important needed.
   Icons drop to 28px on phones so "Bank Installments" (4 logos) still fits
   beside its label on a 390px screen. */
.woocommerce-checkout .payment_methods li > label .wc_payment_method_icon {
	display: inline-flex;
	align-items: center;
	justify-content: flex-start;
	flex-wrap: wrap;
	vertical-align: middle;
	width: auto;
	margin-inline-start: 4px;
}

@media only screen and (max-width: 499px) {
	.woocommerce-checkout .payment_methods li img {
		max-height: 28px;
		margin-inline: 3px;
	}
}

/* DEV08.11 — REVERTED 2026-09-04 (QA cycle 1, 86d487rd3, Amira: "revert everything and make
   it like before, with Wishlist icon and add to cart icon only"). The phone card is WoodMart's
   default again: wishlist heart in the pill, the 40px Add-to-cart icon, no Compare / Quick view,
   the sort control is the theme's ⇅ icon and the per-page / columns switches stay hidden below
   1024px (hankerz_dev0811_mobile_columns() is unhooked in functions.php). Only item 3b below is
   kept — it fixes a genuine rendering bug (the first three list-view images were smaller), not
   part of the desktop-on-mobile design. Pre-revert file: backups/*pre-TR01-grid-revert-*. */

/* 3b. "First product image is smaller" (list view on phones). Not the photo:
      WordPress leaves the first three loop images eager with the fixed default
      sizes="(max-width:300px) 100vw, 300px", so their intrinsic width is 300px;
      every later image is lazy and gets WP 6.7's sizes="auto, …", which resolves
      to the full tile. WoodMart's list layout only fixes the image column on
      desktop (.wd-product-thumb{flex:0 0 300px} above 769px); below that the
      column shrink-wraps the image, so tiles 1-3 render 300px wide and tiles 4+
      360px. Make the stacked list thumb fill the tile for every product. */
@media (max-width: 768.98px) {
	.wd-product.product-list-item .wd-product-thumb,
	.wd-product.product-list-item .product-element-top {
		width: 100%;
	}

	.wd-product.product-list-item .product-element-top img {
		width: 100%;
	}
}

/* ===== QA05 — wide desktops: Elementor stretch sections must break out of the boxed page wrapper.
   The theme's Elementor stretch stylesheet (parts/int-elem-base.css) is not enqueued on this page; only the
   WPBakery one is, and Elementor's `max-width:min(100%,var(--width))` then caps the section at the 1410px
   `main.container`. Same formula WoodMart uses; --wd-scroll-w is .001px where 100vw already excludes the scrollbar.
   Logical inset: in RTL the over-wide block already sits right-aligned, so a physical `left` would double-shift. */
.wd-content-layout.container .e-con[class*="wd-section-stretch"] {
  max-width: none;
  min-width: 0;
  width: calc(100vw - var(--wd-scroll-w));
  inset-inline-start: calc(50% - 50vw + var(--wd-scroll-w) / 2);
  inset-inline-end: auto;
}

/* QA05 — Arabic keeps live's physical column order. A grid in an RTL document auto-places the
   first child on the right, which flips these two-column blocks; live's Arabic home does not
   flip them (Maintenance: image left / copy right, B2B: copy left / image right, portals:
   Gamer's left / Creator's right). Placement is LTR, the content inside stays RTL. */
html[dir="rtl"] :is(.hz-maintenance, .hz-portals) > .e-con-inner {
  direction: ltr;
}
html[dir="rtl"] :is(.hz-maintenance, .hz-portals) > .e-con-inner > .e-con {
  direction: rtl;
}

/* ===== DEV08.04 — mobile: Categories, Featured Products, Ready PC Builds and Custom Desktops
   become horizontal swipe carousels (native overflow scroll + scroll-snap, no JS; tablet and
   desktop grids unchanged). Custom Desktops: the two demo row containers are dissolved with
   display:contents so the four builds share one scroller. Ids are identical on 46697/46831.
   2026-09-04 (DEV08.13/.14): Featured Products is the wd_products widget 51a5705 again, so its
   scroller is the widget's .wd-products grid (the .hz-feat-row tiles no longer exist). */
@media (max-width: 767px) {
	.hz-cat-row,
	.elementor-element-51a5705 .wd-products,
	.elementor-element-7c1bd4c .pricing-tables,
	.elementor-element-fbad311 > .e-con-inner {
		display: grid;
		grid-template-columns: none;
		grid-auto-flow: column;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		-webkit-overflow-scrolling: touch;
		overscroll-behavior-x: contain;
		scrollbar-width: none;
		padding-bottom: 6px;
	}

	.hz-cat-row::-webkit-scrollbar,
	.elementor-element-51a5705 .wd-products::-webkit-scrollbar,
	.elementor-element-7c1bd4c .pricing-tables::-webkit-scrollbar,
	.elementor-element-fbad311 > .e-con-inner::-webkit-scrollbar {
		display: none;
	}

	.hz-cat-row { grid-auto-columns: 42%; gap: 14px; }
	.elementor-element-51a5705 .wd-products { grid-auto-columns: 68%; gap: 16px; }
	.elementor-element-7c1bd4c .pricing-tables { grid-auto-columns: 80%; gap: 16px; }
	/* Custom Desktops: one build per screen. QA cycle 1 (86d486tbn, item 3): "when we do a
	   horizontal scroll and stop at a certain item, nothing from the item behind it shows" —
	   the 84% column left a 16% sliver of the next build visible. 100% + mandatory snap
	   means a snapped build fills the scroller edge to edge; the gap only shows mid-swipe. */
	.elementor-element-fbad311 > .e-con-inner { grid-auto-columns: 100%; gap: 20px; }

	.hz-cat-row > .hz-cat-tile,
	.elementor-element-51a5705 .wd-products > .wd-product,
	.elementor-element-7c1bd4c .wd-price-table,
	.elementor-element-fbad311 > .e-con-inner > .e-con > .e-con {
		scroll-snap-align: start;
		min-width: 0;
		width: auto;
	}

	.elementor-element-8360312,
	.elementor-element-98ce8cc {
		display: contents;
	}
}

/* DEV08.04 — mobile top bar: keep Call Us beside the language switcher (same side, switcher
   first). WoodMart gives its nav element flex:1 1 auto; on the single mobile column that has
   spare width, so the switcher grew and pushed Call Us to the opposite edge. */
@media (max-width: 1024px) {
	.whb-top-bar .whb-column_mobile1 > .wd-header-nav,
	.whb-top-bar .whb-hidden-lg > .wd-header-nav {
		flex: 0 0 auto;
	}

	/* The mobile column centres its content by default; the pair should hug the start
	   edge like the desktop left column does (left in LTR, right in RTL). */
	.whb-top-bar .whb-column_mobile1 {
		justify-content: flex-start;
	}
}

/* CL032-DEV08.09 — Brands page (18233 / AR 46963).
   THE PAGE: one Elementor html widget holding the # A–Z list, then a boxed section per letter
   with a [porto_animation]<h3>X</h3> heading and a row of 33.33% columns of image widgets.
   Measured with chrome-headless-shell (scratchpad/browser/measure.py) at 1920 / 1440 / 390.

   FILTER: horizontal on live only through the page's Porto-era `custom_css` postmeta, which
   Woodmart never reads (pages are deliberately excluded in hankerz_emit_product_custom_css()),
   so on staging the <ul> rendered as a bulleted column and — the Elementor conversion having
   dropped WPBakery's el_id — all 27 links were dead. The letter sections now carry an id
   (0-9, A–Z) + `hz-brand-letter` in the Elementor data. The bar is a grid with FIXED column
   counts (27 / 14 / 9 per row): with repeat(auto-fit, minmax(36px,1fr)) Chromium sized the
   widget — a flex item in Elementor's column container — as if the grid had ONE column, so at
   ≤1023px the bar was 155px tall but its widget 1006px (27 rows) and ~850px of blank followed
   it; a fixed track count removes the width dependency (measured with measure.py: 390/700 bad,
   1024 fine). Letters whose section has no logos are dimmed by a footer script in functions.php.

   WIDTH ("not full container"): Elementor boxed containers cap .e-con-inner at the kit's
   container width — unset here, so the 1140px default — while the page sits in Woodmart's
   1440 container: content started 135px inside the container on each side. Lifted for these
   two pages only; changing the kit would resize every Elementor page.

   ROWS: 3 × 33.33% flex columns + Elementor's 20px gap never fit, so desktop showed two
   ~460px logos per row. The rows (`hz-brand-row`) are CSS grid instead — 6 / 4 / 3 / 2 per row by
   breakpoint (fixed counts, same Chromium reason as the bar) — with the column widths neutralised, because a grid cannot share a row with
   children that still carry Elementor widths (see hankerz-elementor-json-surgery). Logos sit
   centred in equal cells with a common max-height so ARCTIC's 80px square and ASUS's 411px
   wordmark read as one wall. Sections with no logos yet are hidden with :has(); browsers
   without it simply keep showing the empty heading. */
.elementor-18233 .e-con,
.elementor-46963 .e-con {
	--content-width: 100%;
}

ul.brands-letter-list {
	display: grid;
	grid-template-columns: repeat(27, 1fr);
	gap: .35em .25em;
	list-style: none;
	margin: .5em 0 1.5em;
	padding: 0 0 1.1em;
	border-bottom: 1px solid rgba(255, 255, 255, .12);
}

ul.brands-letter-list > li {
	margin: 0;
	padding: 0;
	text-align: center;
}

ul.brands-letter-list > li::before {
	content: none;
}

ul.brands-letter-list a {
	display: block;
	padding: .5em .2em;
	font-size: 14px;
	font-weight: 600;
	line-height: 1;
	color: var(--wd-title-color, #fff);
	border: 1px solid transparent;
	border-radius: 4px;
	transition: color .2s ease, border-color .2s ease;
}

ul.brands-letter-list a:hover,
ul.brands-letter-list a:focus-visible {
	color: var(--wd-primary-color);
	border-color: currentColor;
}

ul.brands-letter-list li.is-empty a {
	opacity: .3;
	pointer-events: none;
}

/* Latin alphabet index: keep # → Z left-to-right on the Arabic page too. */
.rtl ul.brands-letter-list {
	direction: ltr;
}

.hz-brand-letter {
	scroll-margin-top: 120px;
}

.hz-brand-letter:not(:has(img)) {
	display: none;
}

/* The 33.33% design left empty placeholder columns in most rows; as grid cells they would
   reserve a whole blank row of 110px cells under the logos. */
.hz-brand-row > .e-con-inner > .e-con:not(:has(img)) {
	display: none;
}

.hz-brand-row > .e-con-inner {
	display: grid;
	grid-template-columns: repeat(6, 1fr);
	gap: 24px;
	max-width: none;
}

.hz-brand-row > .e-con-inner > .e-con {
	width: 100%;
	min-height: 110px;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.hz-brand-row .elementor-widget-image {
	width: 100%;
	margin: 0;
	text-align: center;
}

.hz-brand-row .elementor-widget-image img {
	width: auto;
	height: auto;
	max-width: min(100%, 180px);
	max-height: 72px;
	object-fit: contain;
}

@media (max-width: 1279px) {
	.hz-brand-row > .e-con-inner {
		grid-template-columns: repeat(4, 1fr);
	}
}

@media (max-width: 1023px) {
	ul.brands-letter-list {
		grid-template-columns: repeat(14, 1fr);
	}
}

@media (max-width: 991px) {
	.hz-brand-row > .e-con-inner {
		grid-template-columns: repeat(3, 1fr);
	}
}

@media (max-width: 575px) {
	ul.brands-letter-list {
		grid-template-columns: repeat(9, 1fr);
	}

	.hz-brand-row > .e-con-inner {
		grid-template-columns: repeat(2, 1fr);
		gap: 16px;
	}

	.hz-brand-row > .e-con-inner > .e-con {
		min-height: 90px;
	}

	.hz-brand-row .elementor-widget-image img {
		max-height: 56px;
	}
}

/* ============================================================================
   CL032-QA04 retest / item 5 — "Build of the Month": product name on ONE line
   ----------------------------------------------------------------------------
   The wd_title 9032c14 ("Valkyrie – Gaming Build") is set to 60px in a 50% column of
   the 1440 container, so from ~1300px down it wraps to "Valkyrie – Gaming / Build" —
   the client asked for the full name on a single line. A fixed smaller size would
   either still wrap on the QA laptop (~1100px viewport, ~500px column) or look tiny on
   a 1920 screen, so the size follows the viewport and is capped where the boxed column
   stops growing: clamp(28px, 3.1vw, 48px) keeps 23 characters inside the column at
   every desktop width. Below 768px the two columns stack and wrapping is allowed again.
   Same element id on EN 46697 and AR 46831, so one rule covers both.
   CL032-DEV13 (2026-09-04) took the font-size over: the clamp() is gone and the size now
   comes from the 30/26/18 heading scale at the end of this file (26px desktop / 22px below
   1025px). Both are under the clamp's old 28px floor, so the one-line requirement this block
   exists for still holds; only `white-space: nowrap` is owned here now.
   ============================================================================ */
body .elementor-element-9032c14 .title {
	white-space: nowrap;
}

@media (max-width: 767.98px) {
	body .elementor-element-9032c14 .title {
		white-space: normal;
	}
}

/* ============================================================================
   CL032-DEV08.18 — Arabic Contact Us page (46947)
   ----------------------------------------------------------------------------
   The form is a separate Arabic CF7 form whose locale is `ar`, so CF7 itself emits
   dir="rtl" on the wrapper and the labels start from the right (the client's
   arrows). These two rules only cover what the markup cannot: the info boxes'
   phone number / e-mail are Latin runs inside an RTL paragraph, and the leading
   "+" was landing at the wrong end (rendered "201029865787+").
   ============================================================================ */
html[dir="rtl"] .custom-info-1 :is(.porto-sicon-description, .porto-sicon-header-text, .porto-sicon-subtitle, .porto-sicon-header p, .porto-sicon-header a) {
	/* plaintext keeps "+20…" and the e-mail reading left-to-right, but it also makes those
	   paragraphs resolve as LTR, and their `text-align: start` then meant LEFT — the client saw
	   the phone and e-mail values drift away from their right-aligned titles (2026-09-04).
	   A physical `right` keeps every value on the title's edge whatever its direction. */
	unicode-bidi: plaintext;
	text-align: right;
}

html[dir="rtl"] .wpcf7 form label {
	display: block;
	text-align: right;
}

/* ============================================================================
   Resources Center articles on Arabic pages — alignment follows the text (2026-09-04)
   ----------------------------------------------------------------------------
   Pairs with hankerz_rtl_autodir_markup() in functions.php, which puts dir="auto" on every
   text block of a single post on RTL requests. `start` then resolves per block: an English
   paragraph/list is LTR → left edge, bullets on the left; an Arabic one is RTL → right edge.
   Beats WoodMart's `text-left` / `text-right` wrapper classes on the text widget because the
   rule sits on the block itself, one level deeper. Excerpts on the blog cards get the same
   behaviour through unicode-bidi: plaintext (they carry no lists, so no markup is needed).
   ============================================================================ */
/* Scope widened 2026-09-04 (QA05 item 10): also the English-content pages on /ar/ (Gamers /
   Creators Portal, Customer Support Center and its sub-pages) — see hankerz_rtl_autodir_applies(). */
html[dir="rtl"] main [dir="auto"] {
	text-align: start;
}

html[dir="rtl"] main :is(ul, ol)[dir="auto"] {
	padding-inline-start: 1.5em;
	padding-inline-end: 0;
}

html[dir="rtl"] .wd-post-excerpt p,
html[dir="rtl"] .wd-post-excerpt {
	unicode-bidi: plaintext;
	text-align: start;
}

/* The excerpt itself is wrapped in <div dir="auto" class="hz-excerpt-auto"> on RTL listings
   (functions.php), so the box has a real direction: English → ltr/left, Arabic → rtl/right. */
html[dir="rtl"] .wd-post-excerpt .hz-excerpt-auto {
	text-align: start;
}

/* ============================================================================
   My Account — no navigation sidebar on PHONES (client, 2026-09-04)
   ----------------------------------------------------------------------------
   WoodMart renders the WooCommerce account navigation (Dashboard, Orders, Addresses,
   Account details, Wishlist, Log out…) as a 3/12 grid column (.wd-my-account-sidebar)
   beside a 9/12 content column on every /my-account/* endpoint, in both languages.
   Below 769px the grid stacks and that list sits ABOVE the content, pushing orders,
   addresses and the account form a full screen down. The client wants it gone on
   phones only (first ask was "all pages", then narrowed to mobile view): desktop and
   tablet keep the column. The dashboard's icon tiles (DEV08.06) still carry the same
   links on phones. WoodMart sets the column spans as INLINE custom properties
   (style="--wd-col-lg:9…"), hence !important on the overrides. The Wishlist page
   (/wishlist, body class woocommerce-wishlist — a page, not an account endpoint) uses
   the same account layout and is covered too.
   ============================================================================ */
@media (max-width: 768.98px) {
	.woocommerce-account .wd-my-account-sidebar,
	.woocommerce-wishlist .wd-my-account-sidebar {
		display: none !important;
	}

	.woocommerce-account .woocommerce-MyAccount-content.wd-grid-col,
	.woocommerce-wishlist .woocommerce-MyAccount-content.wd-grid-col {
		--wd-col-sm: 12 !important;
		width: 100%;
		max-width: 100%;
	}
}

/* ============================================================================
   CL032-DEV13 (2026-09-04) — main heading scale: 30 / 26 / 18
   ----------------------------------------------------------------------------
   The client asked for the main headings to come down site-wide; the assignee
   confirmed the scale on 86d48m1ju: Main title 30px, Sub title 26px, sub sub
   title 18px. Scope agreed as page titles + section titles ONLY — product card
   titles, footer/sidebar widget titles, the PDP title and the category tiles
   (hzc0012..hzc0052) are deliberately left alone.

   SPECIFICITY IS THE WHOLE GAME HERE — the first attempt at this block failed
   silently because it was one class short. The numbers, measured in-browser:

     theme      .wd-page-title  /  .title-size-default                  (0,1,0)
     theme      .wd-fontsize-xxxl                                       (0,1,0)
     Elementor  .elementor-46697 .elementor-element.elementor-element-X
                .title                                                  (0,4,0)

   Note the DOUBLE class on the Elementor widget wrapper —
   `.elementor-element.elementor-element-X` — it is easy to miss when reading
   the generated CSS and it is what makes Elementor's rules (0,4,0) rather than
   (0,3,0). Anything targeting an Elementor-rendered heading therefore needs
   four classes plus an element to win. Source order cannot rescue a tie either:
   child-style is enqueued at wp_enqueue_scripts 10010 (functions.php:28) but
   WoodMart's parts loader runs at 10100
   (inc/modules/parts-css-files/class-parts-css-files.php:88), so the theme CSS
   lands AFTER this file. Everything below out-specifies its target rather than
   reaching for !important, so the sizes stay overridable by a later, more
   specific rule.

   NOTHING MAY GROW. WoodMart already collapses xl/xxl/xxxl to 22px below
   1025px (css/parts/helpers-wpb-elem.css) and `l` is 22px at every width, so
   the non-Elementor rules are desktop-only and skip `l` entirely — applying
   26/30px below 1025px, or to `l` anywhere, would have made headings BIGGER.
   Inside Elementor the per-breakpoint values are the large ones (80/60/40 and
   60/40/30), so there both breakpoints are pinned.

   `xl` is already 26px and is intentionally untouched. Element ids are
   identical on EN 46697 and AR 46831 (verified), so one rule covers both store
   views; no RTL variant is needed because css/parts/page-title.css has none.
   ============================================================================ */

/* --- Main title — the page title band, every page ------------------------- */
/* Was 44 / 68 / 78px at >=1025px for title-size-small|default|large, 36px      */
/* below. Keyed on .wd-page-title itself, not .title-size-*, so bands that ship */
/* an empty title-size- class (the blog/FAQ band) are covered too.              */
body .wd-page-title {
	--wd-title-font-s: 24px;
}

@media (min-width: 1025px) {
	body .wd-page-title {
		--wd-title-font-s: 30px;
	}
}

/* --- Section titles rendered OUTSIDE Elementor ---------------------------- */
/* Beats the theme's (0,1,0) at (0,3,1). Only xxxl (46px) and xxl (36px) sit    */
/* above the target; `l` is already 22px, so it is left alone here.             */
@media (min-width: 1025px) {
	body .woodmart-title-container.title.wd-fontsize-xxxl,
	body .woodmart-title-container.title.wd-fontsize-xxl {
		font-size: 30px;
	}
}

/* --- Section titles rendered INSIDE Elementor ----------------------------- */
/* (0,4,1) to clear Elementor's (0,4,0). `.elementor-element` is the ancestor   */
/* widget wrapper, which is what supplies the fourth class.                     */
@media (min-width: 1025px) {
	body .elementor-element .woodmart-title-container.title.wd-fontsize-xxxl,
	body .elementor-element .woodmart-title-container.title.wd-fontsize-xxl {
		font-size: 30px;
	}

	body .elementor-element .woodmart-title-container.title.wd-fontsize-l {
		font-size: 26px;
	}
}

/* Below 1025px Elementor still prints the hero's 60/40px and the sections'     */
/* 26/22px, which would otherwise sit ABOVE the new desktop sizes and invert    */
/* the ladder. 22px is WoodMart's own sub-1025px step for this scale.           */
@media (max-width: 1024px) {
	body .elementor-element .woodmart-title-container.title.wd-fontsize-xxxl,
	body .elementor-element .woodmart-title-container.title.wd-fontsize-xxl,
	body .elementor-element .woodmart-title-container.title.wd-fontsize-l {
		font-size: 22px;
	}
}

/* --- Two Elementor heading widgets used as section titles ----------------- */
/* hzm0006 "Online Maintenance Center" and hzb0004 "Hankerz B2B", both 34px.    */
/* Their <=767px value is already 20px, so no max-width rule is needed.         */
@media (min-width: 1025px) {
	body .elementor-element.elementor-element-hzm0006.elementor-widget-heading .elementor-heading-title,
	body .elementor-element.elementor-element-hzb0004.elementor-widget-heading .elementor-heading-title {
		font-size: 26px;
	}
}

/* --- sub sub title — the eyebrow line above each section title ------------- */
/* Elementor prints 26 / 22 / 18px; the theme default is only 12px, so this is  */
/* scoped to wd_title widgets rather than to .title-subtitle globally, which    */
/* would ENLARGE any un-overridden subtitle elsewhere. .title-subtitle is a     */
/* SIBLING of .woodmart-title-container inside .title-wrapper, not a child.     */
body .elementor-element.elementor-widget-wd_title .title-wrapper .title-subtitle {
	font-size: 18px;
}

@media (max-width: 1024px) {
	body .elementor-element.elementor-widget-wd_title .title-wrapper .title-subtitle {
		font-size: 16px;
	}
}

/* --- sub sub title — eyebrows built as their OWN wd_title widget ------------ */
/* Two blocks put the eyebrow in a separate widget instead of the subtitle      */
/* field: 1f5654c "Gear Up" (above THROW DOWN) and 676a525 "Build of the Month" */
/* (above Valkyrie – Gaming Build). Both carried the xxxl size, so the generic  */
/* rule above made them 30px MAIN titles; the client flagged Gear Up ("missing */
/* sub sub title font size", 2026-09-04). Same 18 / 16 as .title-subtitle.     */
/* (0,5,1) — one class over the xxxl rule so it wins at every width.           */
/* 676a525 was dropped from this rule by CL032-DEV21 (2026-09-21): it is no longer */
/* an eyebrow. See the DEV21 block at the end of this file.                        */
body .elementor-element.elementor-element-1f5654c.elementor-widget-wd_title .woodmart-title-container.title {
	font-size: 18px;
}

@media (max-width: 1024px) {
	body .elementor-element.elementor-element-1f5654c.elementor-widget-wd_title .woodmart-title-container.title {
		font-size: 16px;
	}
}

/* ============================================================================
   CL032-DEV08.30 — product data row under the product title
   ----------------------------------------------------------------------------
   Printed by hankerz_product_data_row() (functions.php) at summary priority 6, i.e.
   directly under the H1. Brand logo + name (linked to the brand category),
   Availability, SKU. The theme's own stock line under the price and the SKU in
   the meta block are hidden so nothing is shown twice; categories in the meta
   block stay.
   ============================================================================ */
.hz-product-data {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 22px;
	margin: -6px 0 14px;
	font-size: 13px;
	line-height: 1.4;
}

.hz-product-data .hz-pd {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	position: relative;
}

.hz-product-data .hz-pd + .hz-pd::before {
	content: "";
	position: absolute;
	inset-inline-start: -11px;
	top: 50%;
	height: 14px;
	width: 1px;
	background: var(--brdcolor-gray-300, rgba(255, 255, 255, .2));
	transform: translateY(-50%);
}

.hz-product-data .hz-pd-label {
	color: var(--color-gray-500, rgba(255, 255, 255, .6));
}

.hz-product-data .hz-pd-value {
	font-weight: 600;
	color: inherit;
}

.hz-product-data .hz-pd-brand a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: inherit;
}

.hz-product-data .hz-pd-brand a:hover .hz-pd-value {
	color: var(--wd-primary-color);
}

.hz-product-data .hz-pd-logo {
	height: 22px;
	width: auto;
	max-width: 90px;
	object-fit: contain;
}

.hz-product-data .hz-pd-stock.is-instock .hz-pd-value {
	color: #3fbf6f;
}

.hz-product-data .hz-pd-stock.is-outofstock .hz-pd-value {
	color: #e8543c;
}

/* Duplicates of what the row already says. */
.single-product .summary-inner > p.stock,
.single-product .summary-inner .product_meta .sku_wrapper {
	display: none;
}

/* ============================================================================
   Footer (client, 2026-09-04): logo 150px wide, section titles 15px — every width
   ----------------------------------------------------------------------------
   The footer is a WoodMart HTML block (one per language). The logo is the image block
   `wp-image-2937` inside a.wd-block-image-link (rendered 220px wide before), the four
   column titles are h5.wp-block-wd-title (17.6px before). First asked for desktop,
   then "apply same to mobile", so no media query.
   ============================================================================ */
.footer-container a.wd-block-image-link > img,
.footer-container .wd-block-image img.wp-image-2937 {
	width: 150px;
	max-width: 150px;
	height: auto;
}

.footer-container h5.wp-block-wd-title.title,
.footer-container .wp-block-wd-title.title {
	font-size: 15px;
}

/* ============================================================================
   Arabic "Sold out" badge (2026-09-04): whole words only
   ----------------------------------------------------------------------------
   WoodMart's round product label breaks inside words to squeeze "SOLD OUT" into
   its fixed circle; Arabic must never break mid-word ("غير متو / فر"). On RTL the
   circle keeps its size as a minimum, grows to the longest word and wraps only
   between words.
   ============================================================================ */
html[dir="rtl"] .wd-product-label.out-of-stock,
html[dir="rtl"] .product-labels .out-of-stock,
html[dir="rtl"] .wd-product-label .out-of-stock {
	word-break: normal;
	overflow-wrap: normal;
	hyphens: none;
	width: auto;
	min-width: 55px;
	padding-inline: 8px;
}

/* ============================================================================
   CL032-DEV08.21 — landing-page banners (shop, portals, support, resources, brands)
   ----------------------------------------------------------------------------
   Printed by hankerz_page_banner_id()/the woodmart_after_header hook in functions.php
   in the category-banner band. Unlike the category banner these keep their own
   ratio (the artwork is 16:9 / 2.4:1 with the page name baked in), so no crop.
   ============================================================================ */
.hz-page-banner .hz-page-banner-img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 4px;
}

/* ============================================================================
   CL032 — Home hero slider full-bleed up to 1920 (2026-09-05)
   ----------------------------------------------------------------------------
   With the site container at 1920 the client wants the hero to touch both screen
   edges on every screen up to full HD. The hero is the first top-level Elementor
   container (3c542c8, same id on EN 46697 and AR 46831), boxed and sitting inside
   main.container's 15px gutters, so it stopped 15px short of each edge. Here it
   grows by the two gutters and pulls itself back over them; above 1920 the main
   container stops growing, so the hero is capped at 1920 and centred like the
   rest of the page. The slider itself keeps stretch_slider=off (QA04 item 1), the
   1920x920 slide art is shown 1:1 on a full-HD screen. Symmetric logical margins
   so RTL needs no mirror rule. */
.e-con.elementor-element-3c542c8 {
	width: calc(100% + 2 * var(--hz-container-pad, 15px));
	max-width: none;
	margin-inline: calc(-1 * var(--hz-container-pad, 15px));
}

.e-con.elementor-element-3c542c8 > .e-con-inner {
	max-width: none;
	padding-inline: 0;
}

/* ============================================================================
   CL032 — Header rows follow the 1920 container (2026-09-05)
   ----------------------------------------------------------------------------
   The header rows are set to "full width" in the header builder; WoodMart then sizes
   their inner .container to clamp(container, 95%, 100%). Up to 1920 that is 100% and
   the logo, top bar and icons already sit on the page's 15px content edge. Wider than
   ~2020px the 95% wins and the header spreads beyond the 1920 content box (at 2560:
   logo at 79px, content at 328px). Cap the header content to the site container so
   both edges stay aligned on every screen; the row backgrounds remain full width.
   Also covers the sticky clone. Remove this block to restore the 95% behaviour. */
.whb-full-width .whb-row > .container,
.whb-full-width + .whb-clone .whb-row > .container {
	width: 100%;
	max-width: var(--wd-container-w);
}

/* ============================================================================
   CL032 — Portal article cards aligned (2026-09-05)
   ----------------------------------------------------------------------------
   Creators Portal row e604a2e and Gamers Portal row 69a98a0 (same ids on the Arabic
   twins 46929 / 46928): three cards, each wd_title > image > wd_text_block > wd_button,
   laid out as three independent flex columns. A title that wraps to two lines pushed
   its image, text and button down (Creators at 1920: image tops 139 vs 103, buttons at
   660 / 623 / 598), and text length did the same to the buttons. The row is now a
   3-column grid and each card a subgrid spanning the four widget rows, so every row is
   as tall as its tallest cell: images start on one line and buttons end on one line
   whatever the title or text length, at any width. Elementor's 20px gap is kept.
   Below 768px the cards stack one per row; Elementor had been squeezing two 153px cards
   side by side on a 390px phone. Browsers without subgrid still get equal-height cards. */
.e-con:is(.elementor-element-e604a2e, .elementor-element-69a98a0) > .e-con-inner {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	grid-template-rows: repeat(4, auto);
}

.e-con:is(.elementor-element-e604a2e, .elementor-element-69a98a0) > .e-con-inner > .e-con {
	display: grid;
	grid-template-rows: subgrid;
	grid-row: span 4;
	width: auto;
	max-width: none;
	min-width: 0;
}

@media (max-width: 767.98px) {
	.e-con:is(.elementor-element-e604a2e, .elementor-element-69a98a0) > .e-con-inner {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
	}

	.e-con:is(.elementor-element-e604a2e, .elementor-element-69a98a0) > .e-con-inner > .e-con {
		display: flex;
		flex-direction: column;
		grid-row: auto;
	}
}

/* ============================================================================
   CL032 — Container gutter 25px on desktop (2026-09-05)
   ----------------------------------------------------------------------------
   Client: "container padding-inline = 25px, but not for mobile view, only for
   desktop views & big media". WoodMart hard-codes 15px on .container/.container-fluid
   and repeats the 30px total in three places: the stretched-section content cap, the
   footer block row cap and the negative-gap inner padding of stretched sections. All of
   them now read one variable, 15px by default and 25px from WoodMart's desktop
   breakpoint (1025px) up, so header rows, page body, banners' wrapper and footer keep
   sharing one edge. The hero full-bleed rule above reads the same variable. The
   Elementor kit width was set to 1870 (1920 - 2 x 25) at the same time. */
:root {
	--hz-container-pad: 15px;
}

@media (min-width: 1025px) {
	:root {
		--hz-container-pad: 25px;
	}

	.container,
	.container-fluid {
		padding-inline: var(--hz-container-pad);
	}

		/* one class more than the theme's selectors: its deferred part stylesheets load after this file */
	.e-con.e-con-boxed.wd-section-stretch {
		--container-max-width: calc(var(--wd-container-w) - 2 * var(--hz-container-pad));
	}

	.elementor .elementor-section.wd-section-stretch > .elementor-container {
		max-width: calc(var(--wd-container-w) - 2 * var(--hz-container-pad) + var(--wd-el-column-gap, 0.0001px));
	}

	.e-con[class*="wd-section-stretch"].wd-negative-gap,
	.elementor-section[class*="wd-section-stretch"].wd-negative-gap {
		--padding-left: var(--hz-container-pad);
		--padding-right: var(--hz-container-pad);
	}

	.website-wrapper .wp-block-wd-row {
		max-width: calc(var(--wd-container-w) - 2 * var(--hz-container-pad));
	}
}

/* ============================================================================
   CL032-DEV08.01 follow-up (2026-09-05) — mini cart hover + composite option lines
   ----------------------------------------------------------------------------
   Client: "in the web mini cart, hovering a product does not show the full name;
   composite product options show the full option text instead of one line, web and
   mobile". Three causes:
   1. WoodMart lays a full-size "Show" link (a.cart-item-link.wd-fill, z-index 1) over
      every mini-cart item, so the pointer never reaches the name span and its title
      tooltip can never fire. The item itself IS hovered (the link is its child), so
      the name expands on li:hover instead — instant, and it works in the header
      dropdown cart as well as the side cart.
   2. Composite Products prints its component choices as item meta (ul.variation > li,
      label + value with a <p> inside), which nothing truncated: 2–6 lines each. Label
      and value now share one flex line and the value is ellipsised; full text on hover.
   3. On the cart page each component is its own row whose name is <dl><dt>RAM:</dt>
      <dd><p>…</p></dd></dl> — blocks, so the label sat on one line and the value on the
      next, and on the stacked phone cart the nowrap value (a flex child with
      min-width:auto) ran 743px wide and off-screen. dt/dd/p become inline so the
      single-line rule applies to the whole "RAM: Lexar…" text, and the phone cell gets
      min-width:0 so the ellipsis has a box. */
.woocommerce-mini-cart-item ul.variation > li {
	display: flex;
	align-items: baseline;
	gap: 4px;
	min-width: 0;
}

.woocommerce-mini-cart-item ul.variation .item-variation-name {
	flex: 0 0 auto;
}

.woocommerce-mini-cart-item ul.variation .item-variation-value {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.woocommerce-mini-cart-item ul.variation .item-variation-value p {
	display: inline;
	margin: 0;
}

.woocommerce-mini-cart-item:hover .hkz-cart-item-name,
.woocommerce-mini-cart-item:hover ul.variation .item-variation-value {
	white-space: normal;
}

/* Cart page: Composite component rows read "RAM: Lexar THOR…" on one line. */
.shop_table td.product-name .hkz-cart-item-name dl.component,
.shop_table td.product-name .hkz-cart-item-name dl.component dt,
.shop_table td.product-name .hkz-cart-item-name dl.component dd,
.shop_table td.product-name .hkz-cart-item-name dl.component dd p {
	display: inline;
	float: none;
	margin: 0;
	padding: 0;
}

.woocommerce-cart-form .cart_item:hover .hkz-cart-item-name {
	white-space: normal;
}

@media (max-width: 768.98px) {
	.woocommerce-cart-form .shop_table td.product-name {
		min-width: 0;
	}

	/* Composite Products wraps component names in .component-name, which is then the
	   flex child of the cell; both it and the bare span need the same treatment. */
	.woocommerce-cart-form .shop_table td.product-name > .component-name,
	.woocommerce-cart-form .shop_table td.product-name > .hkz-cart-item-name {
		flex: 1 1 auto;
		width: 100%;
		min-width: 0;
	}
}

/* ============================================================================
   CL032-QA02 (86d498bup, 2026-09-05) — DEV08.11 items 2 and 4 restored on phones
   ----------------------------------------------------------------------------
   QA cycle 1 asked for "revert everything" on DEV08.11 and all four items were taken
   out; cycle 2 says the sort options (item 2) and the view-mode / products-per-page
   controls (item 4) must stay, in both language views. Only the icon block (item 1)
   stays reverted. Blocks below are the original DEV08.11 rules 3, 3a and 4; the
   columns switch is mirrored to the phone grid again by hankerz_dev0811_mobile_columns()
   in functions.php. */
/* Sort by: below 768.98px WoodMart renders the ordering <select> as a 30px icon with
   transparent text; the <option>s inherit it, so in Chrome's device-emulation popup only
   the highlighted row is readable, which reads as "the other sort options are missing"
   (all of them are in the DOM). Give the options their own colours. */
@media (max-width: 768.98px) {
	.wd-shop-tools .woocommerce-ordering.wd-ordering-mb-icon select option {
		color: #333;
		background-color: #fff;
	}
}

/* Sort by on phones shows the chosen option: restore the desktop underline select
   (same font, colour and chevron) instead of the 30px icon, so "Sort by latest" is
   visible and the list matches the web version label for label. */
@media (max-width: 768.98px) {
	.wd-shop-tools .woocommerce-ordering.wd-ordering-mb-icon {
		display: inline-flex;
		width: auto;
		height: auto;
	}

	.wd-shop-tools .woocommerce-ordering.wd-ordering-mb-icon select {
		position: static;
		width: auto;
		height: auto;
		padding-block: 5px;
		padding-inline: 2px 20px;
		border: 0;
		border-bottom: var(--wd-form-brd-width, 1px) solid var(--wd-form-brd-color);
		border-radius: 0;
		background-color: transparent;
		background-image: var(--wd-form-chevron);
		background-repeat: no-repeat;
		background-position: right 0 top 50%;
		background-size: auto 18px;
		color: var(--color-gray-900) !important;
		font-weight: 600;
		font-size: 14px;
		line-height: 1.2;
	}

	html[dir="rtl"] .wd-shop-tools .woocommerce-ordering.wd-ordering-mb-icon select {
		background-position: left 0 top 50%;
	}

	.wd-shop-tools .woocommerce-ordering.wd-ordering-mb-icon::after {
		display: none;
	}
}

/* Products per page + view mode: woo-shop-predefined.css hides both below 1024px.
   .wd-shop-tools is flex-wrap, so on phones they wrap onto their own row. */
@media (max-width: 1024px) {
	.shop-loop-head .wd-shop-tools .wd-products-per-page,
	.shop-loop-head .wd-shop-tools .wd-products-shop-view {
		display: inline-flex;
	}
}

/* QA02 follow-up (2026-09-05): on phones the view-mode switch offers list / 2 / 3 only;
   the 4-columns icon is hidden below 768.98px (four 79px cards are not usable on a phone).
   Tablets keep all four. */
@media (max-width: 768.98px) {
	.wd-products-shop-view .shop-view.per-row-4 {
		display: none;
	}
}

/* ============================================================================
   CL032-DEV08.23 (86d49acqx, 2026-09-05) — phone grid toolbar rearranged
   ----------------------------------------------------------------------------
   Client, phones only, shop and category pages, both languages:
   1. drop "Showing 1–9 of 279 results" and put the 9 / 12 / 18 / 24 selector there;
   2. drop "Show sidebar" (filters open from the sticky bottom toolbar) and put the
      view-mode icons there.
   Target: row 1 = breadcrumb | per page, row 2 = view mode | sort.
   The head is two fixed .wd-shop-tools rows in archive-product.php and the per-page
   control sits in the second one, so on phones the rows' boxes are dissolved
   (display:contents) and the head becomes a 2-column grid whose items are ordered
   breadcrumb, per page, view mode, sort. The first row's divider (padding + 1px
   border, previously on the row wrapper) is re-created on its two items; column-gap
   is 0 so the line is continuous, and the per-page item carries the gap as padding.
   Tablets (≥769px) are untouched. */
@media (max-width: 768.98px) {
	.shop-loop-head {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: center;
		column-gap: 0;
		row-gap: 15px;
	}

	.shop-loop-head > .wd-shop-tools {
		display: contents;
	}

	/* the theme's deferred part CSS sets these at 0-2-0 and loads after this file */
	.wd-content-layout .shop-loop-head .wd-shop-tools .woocommerce-result-count,
	.wd-content-layout .shop-loop-head .wd-shop-tools .wd-show-sidebar-btn {
		display: none;
	}

	/* explicit cells (row / column), so nothing depends on source order */
	.shop-loop-head .wd-breadcrumbs {
		grid-area: 1 / 1;
	}

	.shop-loop-head .wd-products-per-page {
		grid-area: 1 / 2;
		justify-self: end;
		padding-inline-start: 10px;
	}

	.shop-loop-head .wd-products-shop-view {
		grid-area: 2 / 1;
	}

	.shop-loop-head .woocommerce-ordering.wd-ordering-mb-icon {
		grid-area: 2 / 2;
		justify-self: end;
	}

	/* row-1 divider: one line across both cells, drawn on the head itself so it does
	   not depend on the items' widths */
	.shop-loop-head .wd-breadcrumbs,
	.shop-loop-head .wd-products-per-page {
		align-self: stretch;
		align-items: center;
		padding-bottom: 15px;
	}

	.shop-loop-head::before {
		content: "";
		grid-area: 1 / 1 / 2 / 3;
		align-self: end;
		height: 0;
		border-bottom: 1px solid rgba(255, 255, 255, 0.15);
		pointer-events: none;
	}
}

/* ============================================================================
   CL032-DEV21 — "Build Your / NEW PC": the WoodMart demo's display treatment
   ----------------------------------------------------------------------------
   The ticket asks this section to match the original WoodMart theme design. The
   reference is the Hardware demo, whose own copy for this block is literally
   "Build Your" / "NEW PC":
       https://woodmart.xtemos.com/demo-hardware/?opt=hardware
   Computed there: 80px/100 weight/90px line-height, then 60px/600/70px. Both
   Elementor widgets already carry 80px and 60px, so this only has to win the
   cascade back.

   Why they were losing it, and why this is not a regression of earlier work:
     - DEV13's 30/26/18 heading scale flattens every wd_title on the site, and
     - DEV08 (2026-09-04) additionally pinned 676a525 to 18px because back then it
       was the small eyebrow "Build of the Month" above "Valkyrie – Gaming Build",
       and the client had flagged it as too large.
   DEV21 replaced that copy with a two-line display headline, so the eyebrow
   treatment no longer applies to 676a525. Its entry in that rule was removed
   above; 1f5654c ("GEAR UP") is still a genuine eyebrow and keeps 18/16px.

   This section is a hero block, deliberately outside the 30/26/18 scale — hence
   the two ids rather than anything generic. (0,5,1) clears both the scale's
   (0,4,1) and the eyebrow rule's (0,5,1) by also coming later in the file.
   Same ids on EN 46697 and AR 46831, so one rule covers both languages.
   The breakpoint values are the ones already set on the widgets in Elementor.
   ============================================================================ */
body .elementor-element.elementor-element-676a525.elementor-widget-wd_title .woodmart-title-container.title {
	font-size: 80px;
	font-weight: 100;
	line-height: 1.125;
}

body .elementor-element.elementor-element-9032c14.elementor-widget-wd_title .woodmart-title-container.title {
	font-size: 60px;
	font-weight: 600;
	line-height: 1.17;
}

@media (max-width: 1024px) {
	body .elementor-element.elementor-element-676a525.elementor-widget-wd_title .woodmart-title-container.title {
		font-size: 60px;
	}

	body .elementor-element.elementor-element-9032c14.elementor-widget-wd_title .woodmart-title-container.title {
		font-size: 40px;
	}
}

@media (max-width: 767.98px) {
	body .elementor-element.elementor-element-676a525.elementor-widget-wd_title .woodmart-title-container.title {
		font-size: 40px;
	}

	body .elementor-element.elementor-element-9032c14.elementor-widget-wd_title .woodmart-title-container.title {
		font-size: 30px;
	}
}

/* ============================================================================
   CL032-DEV16 — Logitech brand page: text scale
   ----------------------------------------------------------------------------
   The page was rebuilt in Elementor for the new theme and every text role came
   out as a plain <h3>, which WoodMart's base.css sizes at 22px. Page title,
   intro paragraph, section headings, tile labels, eyebrows, block titles and
   block body were therefore all the same size, and the client flagged the intro
   paragraph as "very big".

   The twelve Elementor heading widgets now carry their own sizes, set on the
   widgets so each page owns them. The three blocks below cannot: they are raw
   markup inside [porto_ultimate_content_box], where every line is an <h3>:
       h3:nth-of-type(1)  the eyebrow      ("Raise Your Voice")
       h3:nth-of-type(2)  the block title  ("STREAM NOW")
       h3:nth-of-type(3)  the body copy
   Sizes are the live Porto page's, measured 2026-09-21: 11.2 / 25.2 / 15.4px at
   weights 400 / 700 / 400. Colours are not copied - live is a light theme and
   this one is dark - so body and eyebrow use the muted white already used for
   secondary text elsewhere on the site.

   Deliberately NOT scoped to element ids: this markup comes from a shortcode, so
   there are no per-line ids to target, and the structural selector covers EN 18292
   and AR 46964 alike. (For the record, those two pages DO share most widget ids -
   54 of 61; only the seven category tiles rebuilt per page differ.)
   ============================================================================ */
.porto-ultimate-content-box h3:nth-of-type(1) {
	font-size: 12px;
	font-weight: 400;
	line-height: 1.6;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: #FFFFFF99;
	margin-bottom: 4px;
}

.porto-ultimate-content-box h3:nth-of-type(2) {
	font-size: 25px;
	font-weight: 700;
	line-height: 1.2;
	margin-bottom: 18px;
}

.porto-ultimate-content-box h3:nth-of-type(3) {
	font-size: 15px;
	font-weight: 400;
	line-height: 1.7;
	color: #FFFFFFB3;
	margin-top: 18px;
}

@media (max-width: 1024px) {
	.porto-ultimate-content-box h3:nth-of-type(2) {
		font-size: 22px;
	}
}

@media (max-width: 767.98px) {
	.porto-ultimate-content-box h3:nth-of-type(2) {
		font-size: 20px;
	}

	.porto-ultimate-content-box h3:nth-of-type(3) {
		font-size: 14px;
	}
}

/* ============================================================================
   CL032-DEV16 — Arabic Logitech page (46964): keep Latin headings on the RTL edge
   ----------------------------------------------------------------------------
   WPML puts dir="auto" on every heading of an RTL page, so each one takes its
   direction from its first strong character. Once the page copy was translated
   that resolves RTL everywhere except the brand name "Logitech", which is Latin
   and therefore renders LTR — left-aligned, alone, on an otherwise right-aligned
   page. That mismatch is what the client reported as "RTL have ltr content".

   Elementor's own align control is no use here: it writes `text-align: start`,
   and `start` on a dir=auto element that resolved LTR is the LEFT edge, i.e.
   exactly the thing being fixed. An explicit `right` is needed.

   Aligning the BOX, not the text run: dir="auto" still orders the characters
   inside, so "Logitech" and any future Latin term keep correct LTR ordering and
   simply sit at the page's start edge. Scoped to .elementor-46964 so the English
   page (18292), which shares these widget ids, is untouched.
   ============================================================================ */
.rtl .elementor-46964 .elementor-widget-heading .elementor-heading-title {
	text-align: right;
}

/* ============================================================================
   CL032-SUP02 (2026-10-26): narrower "All Products" category dropdown.

   The item was WoodMart's `full-width` design, so the panel spanned the whole
   viewport (1920px on wide screens) with the columns bunched at the left, and
   at ~1200px Gaming Consoles wrapped onto a second row. Both language twins
   (EN 2895, AR 46936) now use the `sized` design (menu item meta), and this
   block shrinks the panel to its content: each column is as wide as its
   longest link instead of the uniform 180px basis set above, so the panel is
   ~1000px (headings wrap at 170px, columns shrink rather than wrap) and sits under the menu (WoodMart's menuOffsets JS keeps it inside
   the viewport). IDs give this rule a specificity the (0,6,0) basis rule and
   the deferred theme parts can't beat. Mobile menus ignore the design.
   ============================================================================ */
.whb-header .wd-nav-main > li:is(#menu-item-2895, #menu-item-46936) > .wd-dropdown-menu.wd-design-sized {
	--wd-dropdown-width: max-content;
	--wd-dropdown-padding: 30px 35px;
	max-width: calc(100vw - 30px);
}
.whb-header .wd-nav-main > li:is(#menu-item-2895, #menu-item-46936) > .wd-dropdown-menu.wd-design-sized > .container > .wd-sub-menu.wd-grid-f-inline {
	--wd-f-basis: auto;
	column-gap: 30px;
	flex-wrap: nowrap;
}
.whb-header .wd-nav-main > li:is(#menu-item-2895, #menu-item-46936) > .wd-dropdown-menu.wd-design-sized > .container > .wd-sub-menu.wd-grid-f-inline > .wd-col {
	flex: 0 1 auto;
	max-width: 170px;
}
