/*
 Theme Name:   Printerland v2.1
 Theme URI:    https://printerland.md
 Description:  Printerland storefront v2.1 — cartridge finder homepage, category-standard design (navy + terracotta). Astra child; successor of Printerland Astra Child.
 Author:       Printerland
 Template:     astra
 Version:      2.1.0
 Text Domain:  printerland-astra-child
*/

:root {
	/* Inter (Google-hosted, see inc/typography.php for the enqueue —
	   matches the original printerlandmd2 Next.js site's font, chosen over
	   the earlier self-hosted Montserrat swap per explicit request). */
	--pl-font: 'Inter', sans-serif;
	/* Slate-navy palette (2026-08 redesign, impeccable skill pass) — prior
	   iterations only ever adjusted LIGHTNESS of a plain royal-blue hue
	   (~205°) and papered the banner gradient with a white radial "sheen",
	   which reads patchy/washed rather than designed (mixing white into a
	   saturated hue desaturates/muddies it). This pass shifts hue toward a
	   muted slate-indigo (~210°, lower chroma) — ref: Wise/Revolut navy-on-
	   white restraint — and replaces the sheen with a real 3-stop
	   same-family gradient (ink -> navy -> mid), no white mixed in. */
	--pl-ink: #12283d;    /* gradient dark stop */
	--pl-navy: #23496b;   /* primary — headings/buttons/topbar/text, ~8:1 both directions on white */
	--pl-navy-rgb: 35, 73, 107;
	--pl-navy-mid: #3d6a91;   /* gradient midpoint */
	--pl-navy-light: #7ba3c4; /* gradient light stop — a real light BLUE, not white */
	--pl-mist: #eaf2f8;       /* light panel tint — icon circles, hover fills */
	/* Deepened slightly to hold its own against the richer navy (was
	   #d56c4d, tuned against the lighter/brighter navy of the prior pass). */
	--pl-accent: #c85a3c;
	--pl-accent-hover: #ad4a2f;
	/* Small navy/accent buttons, badges, and pills were flat solid fills
	   with no depth, disconnected from the gradient bands. Consistency
	   pass (2026-08): every clickable/badge navy or accent surface gets a
	   matching 2-stop gradient + a tinted shadow (not generic black —
	   navy-tinted, so it reads as the brand's own shadow, not a default). */
	--pl-accent-gradient: linear-gradient(135deg, var(--pl-accent) 0%, var(--pl-accent-hover) 100%);
	--pl-shadow-chip: 0 3px 10px rgba(var(--pl-navy-rgb), 0.28);
	--pl-radius-card: 26px;
	--pl-radius-sm: 8px; /* replaces the ad-hoc 0.5rem/8px/0.75rem/0.85rem scattered across small chips/rows */
	--pl-gray-600: #6b7280; /* muted text — replaces #888/#666/#556/#667/#555 */
	--pl-gray-100: #f5f7fa; /* light surface — replaces #fafbfc/#f0f0f0/#eef0f3/#eee */
	/* Deepened per feedback — the original was too subtle to read as a
	   clear card edge on a white page (white card + white page + a barely-
	   there shadow). Same token everywhere, so this ripples sitewide. */
	--pl-shadow-card: 0 6px 16px -2px rgb(0 0 0 / 0.12), 0 2px 6px -2px rgb(0 0 0 / 0.08);
	--pl-shadow-card-lg: 0 4px 24px 0 rgb(0 0 0 / 0.12);
	/* Homepage section rhythm — was a flat 1.5rem margin-top AND
	   margin-bottom on every section, which (adjacent-sibling margin
	   collapsing) only ever produced a 1.5rem/24px gap regardless of
	   section weight, tight enough that the navy .ph-deal-bleed band read as
	   colliding with the section above it. -gap is the default vertical
	   rhythm between in-flow homepage sections; -gap-lg is used around
	   full-bleed colored band sections, which need more visual air than a
	   plain white-on-white section boundary. */
	--pl-section-gap: 2.5rem;
	--pl-section-gap-lg: 4rem;
	/* Subtle premium gradient variants of the two dominant surface colors —
	   applied to large banners/cards (deal band, footer, mega-menu panel,
	   product cards) in place of a flat fill, not to buttons, badges, form
	   inputs, or product-image wells (those stay flat so photos/text read
	   cleanly). Shallow angle and close stops keep it a subtle sheen, not a
	   loud effect. */
	/* Small flat elements (mega-menu toggle, maps CTA) — 2-stop, same family. */
	--pl-navy-gradient: linear-gradient(135deg, var(--pl-navy) 0%, var(--pl-navy-mid) 100%);
	/* Large full-bleed banners (deal strip, newsletter, footer, sale promo
	   card, mobile nav drawer) — real 3-stop same-family gradient (ink ->
	   navy -> mid), replacing the old white-radial "sheen" hack. No white
	   mixed in, so it reads as one designed gradient instead of a patched-
	   on highlight; var name kept as -sheen so call sites didn't need
	   touching. */
	--pl-navy-sheen: linear-gradient(150deg, var(--pl-ink) 0%, var(--pl-navy) 55%, var(--pl-navy-mid) 100%);
	--pl-white-gradient: linear-gradient(135deg, #ffffff 0%, var(--pl-gray-100) 100%);
	/* For gray PANEL backgrounds (not cards) — --pl-white-gradient starts at
	   pure white, which would fade to near-invisible at one corner of a
	   panel meant to contrast against the white page itself. Two close gray
	   tones instead, so contrast against white tiles stays consistent
	   everywhere in the panel while still reading as a soft sheen rather
	   than one flat fill. */
	--pl-gray-gradient: linear-gradient(135deg, var(--pl-gray-100) 0%, #eef1f6 100%);
}

/* Site-wide form-field styling (2026-08) — every text-like input, select,
   and textarea gets the same rounded, minimal treatment as the rest of the
   site (--pl-radius-card is already 26px and already used for buttons/
   cards, this just extends it to inputs). !important needed for the same
   reason .ph-search-input already documents above (Astra's own
   input[type] default styling wins over a plain class/element selector on
   specificity) — generalized here instead of fixing one field at a time.
   Covers WooCommerce Blocks checkout, contact form, newsletter, search,
   and My Account login/register/lost-password, plus the buy-now modal. */
input[type="text"],
input[type="tel"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="number"],
select,
textarea {
	border-radius: var(--pl-radius-card) !important;
	font-family: var(--pl-font) !important;
	border: 1px solid rgba(var(--pl-navy-rgb), 0.15) !important;
	padding: 0.75rem 1.25rem !important;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input[type="text"]:focus,
input[type="tel"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="search"]:focus,
input[type="number"]:focus,
select:focus,
textarea:focus {
	outline: none;
	border-color: rgba(var(--pl-navy-rgb), 0.4) !important;
	box-shadow: 0 0 0 3px rgba(var(--pl-navy-rgb), 0.1);
}
textarea {
	border-radius: var(--pl-radius-sm) !important; /* a 26px radius on a multi-line box reads oddly on its top corners; the smaller token still matches the rounded language */
}
/* Compact toolbar selects (shop-page sort/orderby dropdown, .woocommerce-ordering
   select) — same "26px looks disproportionate on a small control" issue as
   textarea above, worse here since the full padding also widened it against
   the "Showing X of Y results" text it sits next to. Smaller radius + tighter
   padding keeps it visually paired with that text instead of ballooning. */
.woocommerce-ordering select,
select.orderby {
	border-radius: var(--pl-radius-sm) !important;
	padding: 0.5rem 0.9rem !important;
}

/* WooCommerce Blocks checkout fields (.wc-block-components-text-input) use a
   floating-label layout — the label is absolutely positioned INSIDE the
   input wrapper and animates to a "floated" position on focus/fill, with
   that animation's VERTICAL math calibrated to WC Blocks' own fixed 50px
   height and 16px top/bottom padding (packages-style.css). The generic
   padding override above collided with that fixed box model — confirmed
   live: it changed the input's actual height, so the floating label
   overlapped/misaligned with the typed text instead of floating cleanly
   above it, reading as "broken"/transparent-looking. Restoring the exact
   height/vertical-padding here, scoped to just this component, keeps that
   animation intact.
   HORIZONTAL padding is a separate story: WC's own 12px left inset (and the
   label's own `left: 10px`, right below) was tuned for their native 4px
   corner radius — nearly square, so 10-12px clears it fine. This site's
   26px radius curves inward much further at the top-left corner, so with
   WC's original inset the label/text sat tucked under/against the curve
   instead of clearing it — confirmed live via screenshot, reads as cramped/
   misaligned "from the top". Widening the horizontal inset (not the
   vertical, which would re-break the float animation) to actually clear a
   26px curve fixes it without touching the height math. */
.wc-block-components-text-input input[type="text"],
.wc-block-components-text-input input[type="email"],
.wc-block-components-text-input input[type="tel"],
.wc-block-components-text-input input[type="number"],
.wc-block-components-text-input input[type="password"] {
	padding: 16px 22px !important;
	height: 50px !important;
	border-radius: var(--pl-radius-card) !important;
	border-color: rgba(var(--pl-navy-rgb), 0.2) !important;
}
.wc-block-components-text-input input[type="text"]:focus,
.wc-block-components-text-input input[type="email"]:focus,
.wc-block-components-text-input input[type="tel"]:focus,
.wc-block-components-text-input input[type="number"]:focus,
.wc-block-components-text-input input[type="password"]:focus {
	border-color: rgba(var(--pl-navy-rgb), 0.5) !important;
}
/* Label's own absolute `left` — independent of the input's own padding
   above, has to be widened to match or the label still sits under the
   curve even though the typed text (governed by input padding) now clears
   it. */
.wc-block-components-text-input label {
	left: 20px !important;
}
/* Same corner-clearance fix for the country/state <select> combobox — a
   separate WC Blocks component (.wc-blocks-components-select, not
   .wc-block-components-text-input) with its own independently-positioned
   label, same "left:10px tuned for a ~4px radius" issue.
   This label ALSO doesn't animate the way text-input labels do — it's a
   permanently-small 13px label fixed at top:6px, by design, since a
   <select> always shows a value and never has a true "empty" state to
   animate from. That's fine on its own, but the select's own value text is
   vertically CENTERED in the box by the browser, which — combined with
   this theme's min-height:48px bump (assets/cart-checkout.css, predates
   today's session) — puts the centered value right where the label sits,
   overlapping it. Confirmed live via screenshot: "Republica Moldova" sat
   directly under/overlapping "Țară/regiune" instead of below it with a
   gap. Asymmetric padding pushes the value down to actually clear the
   label, same fix shape as the text-input corner clearance above but for
   a different underlying cause (vertical centering, not corner curvature). */
.wc-blocks-components-select__label {
	left: 20px !important;
}
select.wc-blocks-components-select__select {
	/* assets/cart-checkout.css sets this to --pl-radius-sm (8px) via the
	   SAME bare-class selector, also !important — equal specificity, so it
	   was winning purely on source order (confirmed live via matched-rules
	   inspection). The extra "select" element qualifier here settles that
	   permanently instead of relying on enqueue order between two files.
	   Reasonable on its own, but inconsistent with every text input on this
	   same form now using the full 26px card radius (reported live: "not
	   all input fields is 26px"). Matching it here for a consistent rounded
	   look across the whole form; the taller height below still does its
	   job independent of radius. */
	border-radius: var(--pl-radius-card) !important;
	/* WC's own default height (50px) isn't tall enough to fit both the label
	   and a full un-clipped line of value text once padding-top is increased
	   to clear the label — confirmed live: "Republica Moldova" was clipped
	   at the bottom before this taller height was added. */
	height: 62px !important;
	padding-top: 28px !important;
	padding-bottom: 8px !important;
}

/* Quantity stepper on the classic PDP form (input.qty, ~58px wide) — Astra
   relies on the browser's native up/down number-spinner arrows (no custom
   +/- buttons in the markup, before assets/quantity-stepper.js added real
   ones below). The generic 1.25rem horizontal padding above left too
   little room inside that narrow a box for Chrome to draw the spinner at
   all — confirmed live via getComputedStyle (padding ate nearly two-thirds
   of the input's total width) — so the stepper silently vanished instead
   of just looking different.

   .wc-block-components-quantity-selector__input is the SEPARATE cart-page
   quantity input (WC Blocks, real +/- buttons already built in) — only
   45px wide, even narrower. Same generic padding left just ~5px of usable
   width there, and confirmed live it was worse than "looks cramped": the
   digit didn't fit at all, Chrome rendered "…" instead of "2" — a real
   content-loss bug, not cosmetic. Same fix, same reason, different
   selector. */
.quantity input[type="number"],
input.qty,
input[type="number"].wc-block-components-quantity-selector__input {
	padding: 0.5rem 0.6rem !important;
	text-align: center;
}

/* Real +/- buttons around the PDP quantity input (assets/quantity-stepper.js,
   inc/quantity-stepper.php) — this input relied entirely on the browser's
   native number-spinner before, which doesn't render on mobile at all. */
.ph-qty-stepper {
	display: flex;
	align-items: stretch;
	width: auto;
	/* Matches the "Adaugă în coș" button beside it (.printerland-buybox
	   .single_add_to_cart_button, shop.css) — confirmed live via
	   getComputedStyle the two were off by ~3px (42px vs 44.8px), and the
	   qty input inside this stepper was itself 2px shorter than its own
	   +/- buttons (40px vs 42px) — neither height was ever set explicitly
	   before, each piece just fell out of its own padding/line-height by
	   coincidence. Fixing the height here and forcing every child to 100%
	   makes the whole row (stepper + button) align on one baseline.
	   44.8px matches the button at mobile widths; Astra's own responsive
	   button padding renders it 2.4px taller from 768px up (confirmed live,
	   not something this theme's CSS controls) — the media query below
	   matches that, same 768px breakpoint already used elsewhere in this
	   file for the desktop/mobile split. */
	height: 44.8px;
}
@media (min-width: 768px) {
	.ph-qty-stepper { height: 47.2px; }
}
.ph-qty-stepper input.qty {
	width: 3rem;
	height: 100%;
	box-sizing: border-box;
	flex: none;
	padding: 0.5rem 0.25rem !important;
	border-radius: 0 !important;
	border-left: none !important;
	border-right: none !important;
}
.ph-qty-btn {
	width: 2.5rem;
	height: 100%;
	box-sizing: border-box;
	border: 1px solid rgba(var(--pl-navy-rgb), 0.15);
	background: var(--pl-gray-100);
	color: var(--pl-navy);
	font-size: 1.1rem;
	line-height: 1;
	cursor: pointer;
}
.ph-qty-btn-minus {
	border-radius: var(--pl-radius-card) 0 0 var(--pl-radius-card);
}
.ph-qty-btn-plus {
	border-radius: 0 var(--pl-radius-card) var(--pl-radius-card) 0;
}
.ph-qty-btn:hover { background: var(--pl-mist); }

/* No focus-visible styling existed anywhere on the site before this — every
   link/button fell back to the browser's raw default focus ring, which in
   Chrome/Safari renders as a thin dotted/dashed outline that lingers after
   a click until focus moves elsewhere ("a broken line stays behind" — the
   dotted default, not a real bug in any one component). Kept (not
   removed — that breaks keyboard-nav accessibility), just replaced with a
   deliberate, on-brand navy ring matching the input-focus treatment already
   used elsewhere (cart-checkout.css), applied once globally instead of
   leaving every interactive element to the browser's own default. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible {
	outline: 2px solid var(--pl-navy);
	outline-offset: 2px;
}

/* !important — Astra's own typography system (Customizer-driven) sets
   font-family directly on body AND separately on headings (its own
   heading-font Customizer setting, not inherited from body) — confirmed
   live, h1-h3 still computed to Geist after the body rule alone. Same
   override class fought repeatedly elsewhere in this file (search input,
   hero dots, etc. — see docs/memory/conventions.md). Headings need their
   own explicit rule, not just body. */
body,
h1, h2, h3, h4, h5, h6 {
	font-family: var(--pl-font) !important;
}

/* Primary CTAs — pill shape, brand accent color, matching the live site's
   rounded-full convention across cart/checkout/PDP. */
.woocommerce a.button.alt,
.woocommerce button.button.alt,
.woocommerce #respond input#submit.alt,
.astra-cart-drawer-checkout,
a.wp-block-button__link {
	background-color: var(--pl-accent) !important;
	border-color: var(--pl-accent) !important;
	border-radius: 9999px !important;
	font-weight: 600;
}
.woocommerce a.button.alt:hover,
.woocommerce button.button.alt:hover,
.woocommerce #respond input#submit.alt:hover {
	background-color: var(--pl-accent-hover) !important;
	border-color: var(--pl-accent-hover) !important;
}

/* Secondary buttons — navy, still pill-shaped. */
.woocommerce a.button:not(.alt),
.woocommerce button.button:not(.alt) {
	border-radius: 9999px !important;
	border-color: var(--pl-navy);
	color: var(--pl-navy);
}

/* Header chrome — mini-cart dropdown (Astra's built-in cart widget). */
.ast-site-header-cart .widget_shopping_cart,
.astra-cart-drawer {
	border-radius: var(--pl-radius-card) !important;
	box-shadow: var(--pl-shadow-card-lg) !important;
	border: none !important;
}
.widget_shopping_cart .quantity {
	color: var(--pl-navy);
}

/* Header chrome — mobile off-canvas menu (Astra's built-in mobile menu). */
.ast-mobile-popup-drawer,
.ast-flyout-svg-container {
	box-shadow: var(--pl-shadow-card-lg) !important;
}
.ast-mobile-popup-drawer .main-header-bar-navigation a {
	color: var(--pl-navy);
}

/* Sitewide H1 (category archive title, PDP title, page title) — bumped to
   700 weight with tight negative tracking for more visual presence/"solid"
   feel with the Montserrat swap; size (32px, Astra's own default) already
   reasonable, left alone. */
h1 {
	font-weight: 700;
	letter-spacing: -0.02em;
}

/* Static content pages — headings + content-block cards inherit the same
   token pass rather than per-page overrides. */
.ast-single-post .entry-content h1,
.page .entry-content h1,
.page .entry-content h2 {
	color: var(--pl-navy);
}
.page .entry-content .wp-block-group,
.page .entry-content .wp-block-columns > .wp-block-column {
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card);
	padding: 1.5rem;
}

/* Hero carousel (see inc/hero-carousel.php shortcode + assets/hero-carousel.js).
   Superseded the earlier static block-pattern hero (functions.php still
   registers printerland_register_hero_pattern for the block inserter, but
   the homepage uses the [printerland_hero] shortcode instead now). */
.printerland-hero-wrap {
	max-width: 1280px;
	margin: 0.5rem auto;
	padding: 0 1rem;
}
.printerland-hero-carousel {
	position: relative;
	aspect-ratio: 4 / 3;
	background: var(--pl-gray-100);
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card-lg);
	overflow: hidden;
}
@media (min-width: 640px) {
	.printerland-hero-carousel { aspect-ratio: 21 / 9; }
}

/* Hero row: carousel (~70%) + 2 product side-cards (~30%), matching
   printerra.md's layout (inc/homepage-sections.php printerland_hero_row_shortcode).
   The carousel markup/JS inside .ph-herorow-main is untouched — only nested
   sizing changes here. */
.ph-herorow {
	max-width: 1280px;
	/* Small top gap (right below the header), full section-gap below — see
	   --pl-section-gap comment in :root. */
	margin: 0.5rem auto var(--pl-section-gap);
	padding: 0 1rem;
	display: grid;
	grid-template-columns: 1fr;
	gap: 1rem;
}
/* .printerland-hero-wrap carries its own max-width/margin/padding for
   contexts where it's used standalone — nested inside .ph-herorow (which
   already provides that same outer spacing), it was double-applying that
   padding at every width below 1024px, visibly shrinking the carousel on
   mobile/tablet. Unconditional, not just at the desktop breakpoint. */
.ph-herorow .printerland-hero-wrap { max-width: none; margin: 0; padding: 0; }
@media (min-width: 1024px) {
	.ph-herorow { grid-template-columns: minmax(0, 7fr) minmax(0, 3fr); }
	.ph-herorow .printerland-hero-carousel { aspect-ratio: 16 / 7; }
}
.ph-herorow-side {
	display: grid;
	grid-template-rows: 1fr 1fr;
	gap: 1rem;
}
.ph-sidecard {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 0.3rem;
	background: var(--pl-white-gradient);
	box-shadow: var(--pl-shadow-card);
	border-radius: var(--pl-radius-card);
	padding: 1rem 6.5rem 1rem 1rem;
	min-height: 110px;
	text-decoration: none;
	overflow: hidden;
}
.ph-sidecard:hover { box-shadow: var(--pl-shadow-card-lg); }
.ph-sidecard-badge {
	align-self: flex-start;
	background: var(--pl-accent-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	padding: 0.15rem 0.5rem;
	border-radius: 9999px;
}
.ph-sidecard-name {
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--pl-navy);
	line-height: 1.3;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.ph-sidecard-prices { font-size: 0.9rem; font-weight: 800; color: var(--pl-navy); }
.ph-sidecard-prices del { color: var(--pl-gray-600); font-weight: 400; font-size: 0.85em; margin-right: 0.3em; }
.ph-sidecard-prices ins { text-decoration: none; }
.ph-sidecard-link { font-size: 0.78rem; color: var(--pl-accent); font-weight: 600; }
.ph-sidecard-img {
	position: absolute;
	right: 0.75rem;
	top: 50%;
	transform: translateY(-50%);
	width: 5.5rem;
	height: 5.5rem;
	display: flex;
	align-items: center;
	justify-content: center;
	/* White, not gray — product/category images already have their own
	   white background baked in on this catalog, so a gray container
	   showed as a visible mismatched box around every photo. Same fix
	   already applied to the main shop grid (assets/shop.css). */
	background: #fff;
	border-radius: calc(var(--pl-radius-card) - 8px);
}
.ph-sidecard-img img { max-width: 80%; max-height: 80%; object-fit: contain; }
.ph-slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 0.7s ease-in-out;
	pointer-events: none;
}
.ph-slide.is-active {
	opacity: 1;
	pointer-events: auto;
	z-index: 1;
}
.ph-slide-img, .ph-slide-link {
	display: block;
	width: 100%;
	height: 100%;
}
.ph-slide-img {
	object-fit: cover;
}
.ph-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
	/* !important — same Astra global <button> padding override fought on
	   .ph-dot below; happened to render close to the intended size here by
	   coincidence of box-sizing, but the padding was still leaking through. */
	width: 2.25rem !important;
	height: 2.25rem !important;
	padding: 0 !important;
	min-width: 0 !important;
	min-height: 0 !important;
	border: none;
	border-radius: 9999px;
	background: rgba(0, 0, 0, 0.25);
	backdrop-filter: blur(4px);
	color: #fff;
	cursor: pointer;
	display: none;
	align-items: center;
	justify-content: center;
}
@media (min-width: 640px) {
	.ph-arrow { display: flex; }
}
.ph-arrow-prev { left: 0.75rem; }
.ph-arrow-next { right: 0.75rem; }
.ph-dots {
	position: absolute;
	bottom: 0.75rem;
	left: 50%;
	transform: translateX(-50%);
	z-index: 2;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	background: rgba(0, 0, 0, 0.25);
	backdrop-filter: blur(4px);
	border-radius: 9999px;
	padding: 0.375rem 0.75rem;
}
/* !important — Astra's global <button> reset (padding, min sizing) was
   winning over this plain class selector, rendering each dot as a 36×24px
   button with 12px/18px padding instead of a 6px circle (confirmed live
   via computed style) — same class of override already fought elsewhere
   in this file (.ph-mega-menu-back). */
/* The visible dot stays a tiny 6px circle (design intent), but the
   button's own box (what Lighthouse's "target-size" audit actually
   measures — a decorative ::before overlay isn't counted) is grown to
   WCAG's 24x24 CSS px floor via padding; the dot itself is drawn as a
   centered ::after so its visual size is unaffected. */
.ph-dot {
	position: relative;
	width: 24px !important;
	height: 24px !important;
	padding: 0 !important;
	min-width: 0 !important;
	min-height: 0 !important;
	border-radius: 9999px !important;
	border: none !important;
	background: transparent !important;
	cursor: pointer;
}
.ph-dot::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 0.375rem;
	height: 0.375rem;
	border-radius: 9999px;
	background: rgba(255, 255, 255, 0.5);
	transform: translate(-50%, -50%);
	transition: width 0.3s ease;
}
.ph-dot.is-active::after {
	width: 1.25rem;
	background: #fff;
}
.ph-progress-track {
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
	z-index: 2;
	height: 3px;
	background: rgba(0, 0, 0, 0.1);
}
.ph-progress-fill {
	height: 100%;
	width: 0;
	background: rgba(255, 255, 255, 0.6);
}
@keyframes printerlandHeroProgress {
	from { width: 0%; }
	to { width: 100%; }
}

/* Homepage sections (see inc/homepage-sections.php) — category icon strip
   and Reduceri/Rate promo banners, modeled on printerland.md's real
   homepage structure but in this theme's own navy/coral visual language. */
.ph-catstrip-wrap {
	position: relative;
	max-width: 1280px;
	/* Larger gap below — the next section (.ph-deal-bleed) is a full-bleed
	   navy band, which needs more separation than a plain section boundary
	   to avoid reading as colliding with the strip above it. */
	margin: 0 auto var(--pl-section-gap-lg);
	/* Gray panel backdrop — every white tile inside sat directly on the
	   page's own white background with nothing behind it, so contrast
	   depended entirely on each tile's own (necessarily subtle) shadow/
	   border — reported repeatedly as low-contrast/hard to see. Same fix
	   already proven on the v2 homepage's category grid (.phv2-catgrid-wrap):
	   a light gray backdrop so white tiles read as cards sitting ON a
	   surface, not floating on the bare page. Applies to both this
	   curated-8 homepage strip and .ph-catstrip-wrap-archive (every
	   category page) for one consistent treatment everywhere this
	   component appears. Gradient, not a flat fill, for a softer/more
	   premium sheen — matches the gradient treatment already used on other
	   surfaces this session. */
	background: var(--pl-gray-gradient);
	border-radius: var(--pl-radius-card);
	padding: 1.25rem;
	display: flex;
	align-items: center;
	gap: 0.5rem;
}
.ph-catstrip {
	flex: 1;
	min-width: 0;
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 140px;
	gap: 0.75rem;
	overflow-x: auto;
	scroll-snap-type: x proximity;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
}
.ph-catstrip::-webkit-scrollbar { display: none; }
/* .ph-catstrip-wrap-archive (category archive pages,
   printerland_category_children_strip()) reuses this same component for
   the CURRENT category's real subcategory count — unlike the curated
   homepage strip below (always exactly 8, fine as a horizontal-scroll
   strip even on mobile), that can be anywhere from 1 to 20+ (e.g.
   "Accesorii și piese de schimb" has 21). Wraps onto rows with a denser
   tile at EVERY width, not just desktop — scrolling sideways through 21
   items on mobile was worse than wrapping+collapsing there too, and this
   keeps the pattern consistent at every viewport instead of switching
   behavior at 1024px. The show-more/less toggle (assets/homepage.js)
   collapses it to 2 rows at any width when there's a 3rd to hide. */
.ph-catstrip-wrap-archive .ph-catstrip {
	display: grid;
	grid-auto-flow: row;
	grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
	/* Wider than the base 0.5rem — at 0.5rem, the shadows of adjacent
	   compact tiles visually merged into what read as a flat gray fill
	   rather than individual card shadows (reported/confirmed live:
	   "shadows very near and look gray"). */
	gap: 0.65rem;
	overflow-x: visible;
}
.ph-catstrip-wrap-archive .ph-catstrip-arrow { display: none; }
.ph-catstrip-wrap-archive .ph-catstrip-item {
	gap: 0.35rem;
	padding: 0.65rem 0.4rem;
	/* Lighter than the base --pl-shadow-card, which is tuned for larger,
	   more spaced-out cards — too heavy at this tile size even with the
	   wider gap above. A crisp border reads at a glance even before the
	   (now subtle) shadow does, per feedback on this specific tile size. */
	border: 1px solid rgba(var(--pl-navy-rgb), 0.1);
	box-shadow: 0 2px 6px -2px rgb(0 0 0 / 0.08);
}
.ph-catstrip-wrap-archive .ph-catstrip-item:hover {
	border-color: rgba(var(--pl-navy-rgb), 0.2);
	box-shadow: 0 4px 10px -2px rgb(0 0 0 / 0.12);
}
.ph-catstrip-wrap-archive .ph-catstrip-name { font-size: 0.75rem; }
.ph-catstrip-wrap-archive .ph-catstrip-count { font-size: 0.66rem; }
@media (min-width: 1024px) {
	/* Enough room for all 8 tiles — fill the container edge-to-edge instead
	   of leaving trailing whitespace after a fixed 96px tile width. */
	.ph-catstrip { grid-auto-columns: minmax(0, 1fr); overflow-x: visible; }
	.ph-catstrip-wrap-archive .ph-catstrip { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
}
.ph-catstrip-item {
	scroll-snap-align: start;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	padding: 1rem 0.5rem;
	background: #fff;
	box-shadow: var(--pl-shadow-card);
	border-radius: var(--pl-radius-card);
	text-decoration: none;
	text-align: center;
	transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.ph-catstrip-item:hover {
	box-shadow: var(--pl-shadow-card-lg);
	transform: translateY(-2px);
}
.ph-catstrip-photo {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	aspect-ratio: 1;
	border-radius: calc(var(--pl-radius-card) - 8px);
	background: #fff;
	color: var(--pl-navy);
	overflow: hidden;
}
.ph-catstrip-photo img {
	max-width: 80%;
	max-height: 80%;
	object-fit: contain;
}
.ph-catstrip-name {
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--pl-navy);
	line-height: 1.25;
	/* Single-word category names ("Multifuncționale") have no space to wrap
	   at, so they rendered on one line wider than the ~78px card and bled
	   into the next card (confirmed live via getBoundingClientRect: name
	   width 108px inside a 78px card). width:100% + break-word forces a
	   mid-word wrap instead, same as the multi-word names already do. */
	width: 100%;
	overflow-wrap: break-word;
	word-break: break-word;
	hyphens: auto;
}
.ph-catstrip-count {
	font-size: 0.7rem;
	color: var(--pl-gray-600);
}
.ph-catstrip-arrow {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 9999px;
	border: none;
	background: #fff;
	color: var(--pl-navy);
	box-shadow: var(--pl-shadow-card);
	cursor: pointer;
}
.ph-catstrip-arrow:hover { box-shadow: var(--pl-shadow-card-lg); }
.ph-catstrip-arrow[hidden] { display: none; }
/* Show more/less toggle for .ph-catstrip-wrap-archive when a category has
   enough subcategories to overflow the collapsed row count
   (assets/homepage.js printerlandInitCatstripCollapse()) — only inserted
   into the DOM when actually needed, so this never shows for a category
   with few subcategories. */
/* Compact centered pill, not a full-width bar — at 100% width with only a
   faint 15%-opacity border and no fill, this read as a flat gray box
   rather than a button (confirmed live/reported). A visible tinted fill
   plus content-width sizing reads as an actual control. */
.ph-catstrip-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	width: auto;
	margin: 0.75rem auto 0;
	padding: 0.5rem 1.1rem;
	/* Stronger than the original 6%-opacity fill (same low-contrast-on-
	   white-page issue as the tiles above) — a visible border plus a
	   slightly bolder tint reads clearly as a real button. */
	background: rgba(var(--pl-navy-rgb), 0.08);
	border: 1px solid rgba(var(--pl-navy-rgb), 0.18);
	border-radius: 9999px;
	color: var(--pl-navy);
	font-weight: 600;
	font-size: 0.82rem;
	cursor: pointer;
}
.ph-catstrip-toggle:hover,
.ph-catstrip-toggle:focus {
	background: rgba(var(--pl-navy-rgb), 0.16);
	border-color: rgba(var(--pl-navy-rgb), 0.3);
	color: var(--pl-navy);
}
.ph-catstrip-toggle .ph-cat-chevron { transition: transform 0.2s ease; }
.ph-catstrip-toggle.is-open .ph-cat-chevron { transform: rotate(180deg); }
@media (min-width: 1024px) {
	/* All 8 tiles fit without scrolling at this width — arrows would be
	   decorative, so hide them; homepage.js also hides them dynamically
	   whenever content doesn't overflow. */
	.ph-catstrip-arrow { display: none; }
}

.ph-promo-banners {
	max-width: 1280px;
	margin: 0 auto var(--pl-section-gap);
	padding: 0 1rem;
	display: grid;
	grid-template-columns: 1fr;
	gap: 1rem;
}
@media (min-width: 640px) {
	.ph-promo-banners { grid-template-columns: 1fr 1fr; }
	/* Credit installments banner removed along with the Credit page — a
	   single remaining banner shouldn't half-fill the two-column grid it
	   used to share. */
	.ph-promo-banners-single { grid-template-columns: 1fr; }
}
.ph-promo-banner {
	display: block;
	min-height: 140px;
	padding: 1.5rem;
	border-radius: var(--pl-radius-card);
	text-decoration: none;
	background: var(--pl-navy-sheen);
	box-shadow: var(--pl-shadow-card-lg);
	transition: transform 0.2s ease;
}
.ph-promo-banner:hover { transform: translateY(-2px); }
.ph-promo-banner-text {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	max-width: 70%;
}
.ph-promo-banner-title {
	font-size: 1.5rem;
	font-weight: 800;
	color: #fff;
}
.ph-promo-banner-sub {
	font-size: 0.85rem;
	color: rgba(255, 255, 255, 0.75);
}
.ph-promo-banner-cta {
	margin-top: 0.5rem;
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	font-weight: 700;
	font-size: 0.85rem;
	color: var(--pl-accent);
}

.ph-brandstrip {
	max-width: 1280px;
	margin: 0 auto var(--pl-section-gap);
	padding: 0 1rem;
}
.ph-brandstrip-title {
	font-size: 1.1rem;
	font-weight: 700;
	color: var(--pl-navy);
	margin-bottom: 0.75rem;
}
.ph-brandstrip-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}
.ph-brandstrip-item {
	padding: 0.5rem 1.1rem;
	border-radius: 9999px;
	border: 1px solid rgb(0 0 0 / 0.08);
	color: var(--pl-navy);
	font-weight: 700;
	font-size: 0.9rem;
	text-decoration: none;
	transition: border-color 0.2s ease, color 0.2s ease;
}
.ph-brandstrip-item:hover {
	border-color: var(--pl-accent);
	color: var(--pl-accent);
}

/* Footer trust strip (inc/footer-extras.php) — shipping/returns/warranty/
   installments row below the footer. Payment methods are styled text
   chips, not brand logos — real Visa/Mastercard SVGs are trademarked
   assets not in this repo and won't be fabricated (matches the existing
   PDP .printerland-payment-chips pattern). */
.ph-footer-trust-bleed {
	background: #10233a;
}
.ph-footer-trust-bleed .ph-bleed-inner {
	padding: 1.5rem 1rem;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}
.ph-footer-trust {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
}
.ph-footer-trust-item {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	color: rgba(255, 255, 255, 0.85);
	font-size: 0.82rem;
}
.ph-footer-pay {
	display: flex;
	gap: 0.5rem;
}
.ph-footer-pay-chip {
	border: 1px solid rgba(255, 255, 255, 0.2);
	border-radius: var(--pl-radius-sm);
	padding: 0.3rem 0.65rem;
	font-size: 0.75rem;
	color: rgba(255, 255, 255, 0.7);
}

/* Footer column link lists (Magazin/Suport/Legal/Contact widgets) rendered
   at ~15px line-height with no padding — under WCAG's 24px touch-target
   minimum on mobile (Lighthouse a11y: "target-size"). */
footer .wp-block-list a {
	display: inline-block;
	padding: 0.375rem 0;
	min-height: 24px;
	line-height: 1.2;
}

.ph-footer-credit {
	text-align: center;
	padding: 0.85rem 1rem;
	background: var(--pl-navy, #0a1f44);
	font-size: 0.75rem;
}
.ph-footer-credit a {
	/* 0.55 measured at 4.07:1 against the navy bg — under WCAG's 4.5:1
	   floor. 0.72 clears it with margin (~4.8:1). */
	color: rgba(255, 255, 255, 0.72);
	text-decoration: none;
}
.ph-footer-credit a:hover {
	color: rgba(255, 255, 255, 0.85);
}

/* Reference homepage has no visible page title — "Acasă"/"Главная"/"Home"
   was rendering above the category strip on every language homepage. */
.home .entry-title { display: none; }

/* calc(-50vw + 50%) full-bleed sections below introduce a few px of
   horizontal scroll on some viewports (confirmed: 20px overflow on a
   390px mobile viewport, whole page shifted left) — 100vw's relationship
   to the actual rendered width isn't perfectly exact everywhere. Hiding
   overflow-x is the correct fix here, not widening the container (that
   would just move the mismatch instead of removing it). */
html, body { overflow-x: hidden !important; max-width: 100%; }

/* WooCommerce's price del/ins markup carries a .screen-reader-text span
   ("Original price was: X. Current price is: Y.") meant to be visually
   invisible — clipped, not display:none, so screen readers still get it.
   Astra/WP core only define the legacy `clip: rect(...)` half of this
   technique; some browsers' copy/text-extraction (and apparently some
   render paths) don't fully treat clip-rect alone as excluded. Adding the
   modern clip-path pairing WP core itself now ships is the actual fix —
   redeclared here with !important since this must always win regardless
   of where it's nested (deal boxes, side-cards, price displays). */
.screen-reader-text {
	border: 0 !important;
	clip: rect(1px, 1px, 1px, 1px) !important;
	clip-path: inset(50%) !important;
	height: 1px !important;
	width: 1px !important;
	overflow: hidden !important;
	position: absolute !important;
	word-wrap: normal !important;
	margin: -1px !important;
	padding: 0 !important;
}
/* Belt-and-braces: even if reader-only text somehow renders in some
   environment, these price containers can never visually exceed their box. */
.ph-deal-box-price,
.ph-deal-box-alt-price,
.ph-sidecard-prices {
	overflow: hidden;
}

/* Full-bleed band utility — breaks a section out of the .ast-container
   (which caps content at 1320px) to span the full viewport width, while
   keeping its content aligned to the same 1320px column other sections
   use. Copies Astra's own known-good idiom for this container (its
   .ast-article-image-container--full uses the same calc()). */
.ph-bleed {
	/* calc(-50vw + 50%) only cancels out correctly when the element's own
	   containing block equals the full viewport width — it doesn't here,
	   Astra's .ast-container/.entry-content carries its own horizontal
	   padding, so "50%" and "50vw" weren't actually equal-and-opposite.
	   Confirmed live: elements using this sat at x:20-410 on a 390px
	   viewport instead of 0-390 — visually clipped on the right by
	   overflow-x:hidden, not caught by any page-level scroll check.
	   position:relative + left:50% + translateX(-50%) is the version that
	   correctly handles a padded, centered parent: left:50% shifts from
	   the element's static (already-padded) position by half the
	   container's width, and the transform pulls back by half the
	   element's own (100vw) width — net result lands on the true
	   viewport edges regardless of the parent's padding. */
	position: relative;
	left: 50%;
	transform: translateX(-50%);
	width: 100vw;
	max-width: 100vw;
}
.ph-bleed-inner {
	max-width: 1320px;
	margin: 0 auto;
	padding: 2.5rem 1rem;
}

/* Deal strip — two boxes ("Oferta săptămânii" + "Produse populare"), each a
   main pick plus up to 3 alternates, on a full-bleed navy band. Mirrors
   printerra.md's homepage layout (inc/homepage-sections.php). */
/* Top margin left at 0 — .ph-catstrip-wrap above already carries the
   section-gap-lg needed here via its own margin-bottom. */
.ph-deal-bleed { background: var(--pl-navy-sheen); margin: 0 0 var(--pl-section-gap-lg); }
.ph-deal-bleed .ph-bleed-inner { padding: 2.5rem 1rem; }
.ph-deal-section {
	display: grid;
	/* minmax(0, 1fr), not plain 1fr — a bare 1fr grid track still respects
	   its content's min-content width by default. Real bug found live: the
	   right box (.ph-deal-box-info's own min-width:180px, below, plus the
	   fixed-width image/gaps/padding around it) added up to ~340-390px of
	   unshrinkable content, wider than a 390px mobile viewport, so the box
	   rendered cut off past the right edge instead of wrapping/shrinking. */
	grid-template-columns: minmax(0, 1fr);
	gap: 1.5rem;
}
@media (min-width: 900px) {
	.ph-deal-section { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.ph-deal-box {
	min-width: 0;
	background: var(--pl-white-gradient);
	border-radius: var(--pl-radius-card);
	padding: 1.5rem;
	box-shadow: var(--pl-shadow-card-lg);
}
.ph-deal-box-eyebrow {
	display: block;
	color: var(--pl-accent);
	font-weight: 700;
	font-size: 0.8rem;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	margin-bottom: 1rem;
}
.ph-deal-box-main {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
	align-items: center;
	padding-bottom: 1.25rem;
	border-bottom: 1px solid var(--pl-gray-100);
	margin-bottom: 1.25rem;
}
.ph-deal-box-image {
	position: relative;
	background: #fff;
	border-radius: calc(var(--pl-radius-card) - 8px);
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 140px;
	height: 140px;
}
.ph-deal-box-image img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	padding: 0.75rem;
}
.ph-deal-box-badge {
	position: absolute;
	top: 0.5rem;
	left: 0.5rem;
	background: var(--pl-accent-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	font-weight: 800;
	font-size: 0.85rem;
	padding: 0.25rem 0.6rem;
	border-radius: 9999px;
}
.ph-deal-box-info {
	flex: 1 1 180px;
	/* Was min-width:180px — the actual overflow driver on narrow viewports
	   (see .ph-deal-section comment above). 0 lets it shrink and wrap the
	   product name instead of forcing the row past the container edge. */
	min-width: 0;
}
.ph-deal-box-info h3 {
	margin: 0 0 0.5rem;
	font-size: 1.1rem;
}
.ph-deal-box-info h3 a {
	color: var(--pl-navy);
	text-decoration: none;
}
.ph-deal-box-price {
	color: var(--pl-navy);
	font-weight: 800;
	font-size: 1.25rem;
	margin-bottom: 0.85rem;
}
.ph-deal-box-cta {
	display: inline-flex;
	background: var(--pl-accent-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	font-weight: 700;
	padding: 0.6rem 1.4rem;
	border-radius: 9999px;
	text-decoration: none;
	font-size: 0.9rem;
}
.ph-deal-box-alts {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.75rem;
}
.ph-deal-box-alts li a {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	text-decoration: none;
	color: inherit;
	min-width: 0;
}
.ph-deal-box-alts img {
	width: 44px;
	height: 44px;
	object-fit: contain;
	background: #fff;
	border-radius: var(--pl-radius-sm);
	flex-shrink: 0;
}
.ph-deal-box-alt-name {
	flex: 1;
	min-width: 0;
	font-size: 0.85rem;
	color: var(--pl-navy);
	line-height: 1.3;
}
.ph-deal-box-alt-price {
	font-size: 0.85rem;
	font-weight: 700;
	color: var(--pl-navy);
	white-space: nowrap;
}

/* Product grid rows (inc/homepage-sections.php printerland_product_rows())
   — alternating full-bleed backgrounds, replacing the flat h2+[products]
   siblings that used to live in the homepage post_content (couldn't be
   banded there). Grid/card styling for ul.products itself comes from
   assets/shop.css, already enqueued on the front page. */
.ph-prow { background: #fff; }
.ph-prow-alt { background: var(--pl-gray-100); }
/* These 4 rows (Recomandate/Imprimante/Cartușe/Populare) stack with zero
   margin between them, distinguished only by an alternating background —
   2rem padding gave a 64px combined gap, which read as cramped next to a
   dense 4-column product grid (measured live, not guessed: last product
   card and the next section's heading sat closer than the breathing room
   used elsewhere on the page). Bumped to 3rem for real separation. */
.ph-prow .ph-bleed-inner { padding: 3rem 1rem; }
.entry-content h2.ph-prow-title {
	/* Astra's .entry-content h2 default (36px) otherwise wins over a bare
	   .ph-prow-title class on specificity — this runs inside .entry-content
	   since it's prepended via the_content. Bumped size/weight and tightened
	   tracking with the Montserrat swap — more presence for section titles,
	   tight negative tracking is the standard "premium" heading treatment. */
	text-align: left;
	color: var(--pl-navy);
	font-size: 1.6rem;
	font-weight: 700;
	letter-spacing: -0.01em;
	margin: 0 0 1.25rem;
}

/* SEO/about text block (inc/homepage-sections.php) — full-bleed light band.
   Collapsed <details>: fully indexed by crawlers, one-line toggle for visitors. */
.ph-seo-bleed { background: var(--pl-gray-100); margin: var(--pl-section-gap-lg) 0 0; }
.ph-seo-text {
	color: var(--pl-gray-600);
	font-size: 0.9rem;
	line-height: 1.7;
	padding: 1.25rem 0;
}
.ph-seo-text summary {
	cursor: pointer;
	font-weight: 600;
	color: var(--pl-navy);
	list-style: revert;
}
.ph-seo-text p { margin: 1rem 0 0; }

/* Category/subcategory/brand archive term-description (inc/archive-
   description-collapse.php) — same collapsed-<details> treatment as
   .ph-seo-text above, scoped to the shop-loop intro instead of the homepage. */
.printerland-archive-copy {
	margin: 0 0 1.5rem;
	color: var(--pl-gray-600);
	font-size: 0.9rem;
	line-height: 1.7;
}
.printerland-archive-copy summary {
	cursor: pointer;
	font-weight: 600;
	color: var(--pl-navy);
	list-style: revert;
}
.printerland-archive-copy p { margin: 1rem 0 0; }

/* Newsletter signup (inc/homepage-sections.php + assets/newsletter.js).
   No top margin — sits directly against .ph-seo-bleed above; both are
   full-bleed colored bands, so a gap here would show a strip of plain page
   background wedged between two bands rather than reading as intentional
   spacing. */
.ph-newsletter-bleed {
	background: var(--pl-navy-sheen);
	margin: 0;
}
.ph-newsletter-bleed .ph-bleed-inner { padding: 2.5rem 1.5rem; }
.ph-newsletter {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	max-width: 1280px;
	margin: 0 auto;
}
.ph-newsletter-text h3 { color: #fff; margin: 0 0 0.35rem; font-size: 1.25rem; }
.ph-newsletter-text p { color: rgba(255,255,255,0.75); margin: 0; font-size: 0.9rem; }
.ph-newsletter-form {
	display: flex;
	gap: 0.5rem;
	flex: 1;
	max-width: 26rem;
}
.ph-newsletter-form input {
	flex: 1;
	padding: 0.75rem 1.1rem;
	border-radius: 9999px;
	border: none;
	font-size: 0.9rem;
}
.ph-newsletter-form button {
	background: var(--pl-accent-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	border: none;
	font-weight: 700;
	padding: 0.75rem 1.5rem;
	border-radius: 9999px;
	cursor: pointer;
	white-space: nowrap;
}
.ph-newsletter-message {
	width: 100%;
	text-align: center;
	font-size: 0.85rem;
	margin-top: 1rem;
	color: #fff;
}
.ph-newsletter-message.is-error { color: var(--pl-accent); }

/* Header (see inc/header.php + assets/header.js) — replaces Astra's default header. */
.ph-topbar {
	background: var(--pl-navy-gradient);
	color: #fff;
	font-size: 0.8rem;
}
.ph-topbar-inner {
	max-width: 1280px;
	margin: 0 auto;
	padding: 0.4rem 1rem;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
}
.ph-topbar-contact {
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
	/* flex-shrink:0 (was min-width:0, letting this shrink) — the phone
	   number is white-space:nowrap unbreakable text, so shrinking the
	   CONTAINER below the text's natural width didn't wrap or truncate it,
	   it just overflowed straight out of this box into the nav row next to
	   it — confirmed live on mobile, "022-802-022" visibly overlapping
	   "Acasă". The nav row already handles overflow properly (internal
	   horizontal scroll), so it should be the one giving up space, not the
	   phone number. */
	flex-shrink: 0;
}
.ph-topbar-contact a {
	color: #fff;
	text-decoration: none;
	white-space: nowrap;
}
.ph-topbar-phone {
	font-size: 1.05rem;
	font-weight: 700;
}
.ph-topbar-hours {
	color: rgba(255, 255, 255, 0.75);
	white-space: nowrap;
	font-size: 0.75rem;
}
@media (max-width: 767px) {
	.ph-topbar-hours { display: none; }
}
/* Utility links (Credit/Showroom/Promoții/Livrare/Contact) used to be
   display:none below 768px — only the phone number showed, which read as
   "language switching doesn't reach these" since their translated labels
   were simply never rendered on mobile at all. Compact horizontal scroll
   instead of hiding outright. */
.ph-topbar-nav {
	display: flex;
	gap: 1rem;
	overflow-x: auto;
	scrollbar-width: none;
	min-width: 0;
	position: relative;
}
.ph-topbar-nav::-webkit-scrollbar { display: none; }
@media (max-width: 767px) {
	/* Hidden scrollbar gives no hint there's more to the right (Promoții,
	   Contact) — a fade at the edge is the standard affordance for a
	   horizontally-scrollable row like this. */
	.ph-topbar-inner { position: relative; }
	.ph-topbar-inner::after {
		content: "";
		position: absolute;
		top: 0;
		right: 0;
		bottom: 0;
		width: 1.5rem;
		background: linear-gradient(to right, transparent, var(--pl-navy) 85%);
		pointer-events: none;
	}
}
@media (min-width: 768px) {
	.ph-topbar-nav { gap: 1.5rem; overflow-x: visible; }
}
.ph-topbar-nav a {
	color: rgba(255, 255, 255, 0.85);
	text-decoration: none;
	white-space: nowrap;
}
.ph-topbar-nav a:hover { color: #fff; }

/* Astra's own below-header nav row (Astra core rendering the 'primary' menu
   location — this theme has no wp_nav_menu() call of its own). Its 5 links
   are now merged into the topbar above (inc/header.php) — same links,
   fewer rows — so this whole row is redundant. */
.ast-primary-header-bar {
	display: none !important;
}

.ph-header {
	background: #fff;
	border-bottom: 1px solid var(--pl-gray-100);
	position: sticky;
	top: 0;
	z-index: 999;
}
.ph-header-inner {
	max-width: 1280px;
	margin: 0 auto;
	padding: 0.75rem 1rem;
	display: flex;
	align-items: center;
	gap: 1rem;
	flex-wrap: wrap;
	/* Anchor for .ph-search-wrap's true absolute centering on desktop —
	   see that rule for why plain auto-margin centering wasn't "correct". */
	position: relative;
}
.ph-logo {
	font-weight: 900;
	font-size: 1.7rem;
	color: var(--pl-navy);
	text-decoration: none;
	white-space: nowrap;
}
.ph-logo-accent { color: var(--pl-accent); }

/* Catalog menu is reachable at every breakpoint now — it used to be
   display:none below 768px, meaning there was no way to browse categories
   on mobile except Astra's generic hamburger drawer, which doesn't know
   about product categories at all. */
.ph-mega-menu-wrap { position: relative; }
/* Hides the header Catalog button ONLY on the v2 homepage's desktop
   layout, where its own persistent sidebar (.phv2-sidebar,
   assets/home-v2.css) does the same job — matches that sidebar's exact
   breakpoint (display:none below this) so mobile visitors on v2 always
   have one category-nav entry point, never zero. inc/header.php only
   adds this class on is_front_page() + v2, so it never applies anywhere
   else (v1 homepage, category/product/cart/search pages keep this
   button unconditionally at every width). */
@media (min-width: 1024px) {
	.ph-mega-menu-wrap-v2-home { display: none; }
}
.ph-mega-menu-toggle {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.65rem 1.25rem;
	background: var(--pl-navy-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	border: none;
	border-radius: var(--pl-radius-card);
	font-weight: 600;
	cursor: pointer;
	transition: background 0.15s ease;
}
.ph-mega-menu-toggle:hover,
.ph-mega-menu-toggle[aria-expanded="true"] {
	background: var(--pl-accent);
}
/* Dropdown affordance — nothing on the button previously signaled it opens
   a menu rather than navigating away. */
.ph-mega-menu-toggle .ph-svg-icon {
	width: 16px;
	height: 16px;
	transition: transform 0.15s ease;
}
.ph-mega-menu-toggle[aria-expanded="true"] .ph-svg-icon {
	transform: rotate(180deg);
}
.ph-mega-menu {
	position: absolute;
	top: 100%;
	left: 0;
	margin-top: 0.5rem;
	background: var(--pl-white-gradient);
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card-lg);
	/* Left padding tightened — was the same 1.5rem as every other side,
	   reading as more empty space before the category list than needed.
	   Top/right/bottom stay 1.5rem — .ph-mega-menu-right's negative margin
	   bleed trick (below) is keyed to those three, not this one. */
	padding: 1.5rem 1.5rem 1.5rem 1.15rem;
	display: flex;
	gap: 1.5rem;
	/* `width: max-content` computed preferred size from content (including
	   long unwrapped product names) and only clamped AFTER that — in
	   practice still overflowed the viewport. An explicit width, capped by
	   max-width, is predictable regardless of content length. */
	width: 920px;
	max-width: calc(100vw - 2rem);
	/* Each pane scrolls independently (see .ph-mega-menu-categories /
	   .ph-mega-menu-right below) — this used to be overflow-y:auto here,
	   which scrolled BOTH columns as one unit: opening a category with many
	   subcategories (e.g. "Accesorii și piese de schimb", 21 items) scrolled
	   the left category list out of view along with the right-hand list. */
	align-items: stretch;
	overflow: hidden;
	z-index: 1000;
}
/* The `hidden` attribute (assets/header.js toggles it on open/close) has the
   same 0,1,0 specificity as the class rule above, and author styles always
   win ties over the UA stylesheet's default `[hidden]{display:none}` — so
   without this, the dropdown rendered open on every page load, for every
   visitor, until first click. */
.ph-mega-menu[hidden] { display: none; }
.ph-mega-menu-categories {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 220px;
	flex-shrink: 0;
	padding-right: 1rem;
	/* Darkened from 0.06 — at that opacity the pane split was barely
	   perceptible next to the .ph-mega-menu-right background change. */
	border-right: 1px solid rgb(0 0 0 / 0.1);
	/* Scrolls independently from .ph-mega-menu-right — see note on
	   .ph-mega-menu above. Caps to the panel's own max-height (70vh) minus
	   its vertical padding (1.5rem top + bottom). */
	max-height: calc(70vh - 3rem);
	overflow-y: auto;
}
.ph-mega-menu-category-item {
	padding: 0.5rem 0.5rem;
	border-radius: var(--pl-radius-sm);
}
.ph-mega-menu-category-item.is-active,
.ph-mega-menu-category-item:hover {
	background: rgba(var(--pl-navy-rgb), 0.06);
}
.ph-mega-menu-category {
	font-weight: 700;
	color: var(--pl-navy);
	text-decoration: none;
	display: flex;
	align-items: center;
	gap: 0.6rem;
}
.ph-mega-menu-category-icon {
	width: 28px;
	height: 28px;
	object-fit: contain;
	flex-shrink: 0;
}
/* Right-hand pane — all of the active category's subcategories as a plain
   list (was a wrapping grid of bordered pill tiles — changed per request
   to a simple list, same row style as the left-hand category list, not
   card-shaped tiles). Two columns on wide screens once there are enough
   items to make one long column awkward. */
.ph-mega-menu-right {
	flex: 1;
	display: flex;
	flex-direction: column;
	min-width: 0;
	/* Slightly darker than the left category list (plain white) — a flat
	   two-pane panel with no background difference read as one
	   undifferentiated block; this gives the primary/secondary nav split
	   real visual separation, common practice in mega-menus. */
	background: var(--pl-gray-100);
	border-radius: 0 var(--pl-radius-card) var(--pl-radius-card) 0;
	margin: -1.5rem -1.5rem -1.5rem 0;
	padding: 1.5rem;
	/* Inset shadow along the shared edge, on top of the border-right on
	   .ph-mega-menu-categories — one flat border alone read as too subtle a
	   split between the two panes. */
	box-shadow: inset 6px 0 10px -10px rgb(0 0 0 / 0.15);
	/* Scrolls independently from .ph-mega-menu-categories — see note on
	   .ph-mega-menu above. */
	max-height: calc(70vh - 3rem);
	overflow-y: auto;
}
/* Thin, visibly-scrollable scrollbar on both panes — native default
   scrollbars are easy to miss at this panel size, which is part of why the
   old single-scroll layout read as "broken" rather than "has more below". */
.ph-mega-menu-categories,
.ph-mega-menu-right {
	scrollbar-width: thin;
	scrollbar-color: rgba(var(--pl-navy-rgb), 0.25) transparent;
}
.ph-mega-menu-categories::-webkit-scrollbar,
.ph-mega-menu-right::-webkit-scrollbar {
	width: 6px;
}
.ph-mega-menu-categories::-webkit-scrollbar-thumb,
.ph-mega-menu-right::-webkit-scrollbar-thumb {
	background: rgba(var(--pl-navy-rgb), 0.25);
	border-radius: 9999px;
}
.ph-mega-menu-subcats {
	display: grid;
	/* Narrowed from 220px — the right pane is ~600px wide, so 220px only
	   ever fit 2 columns. At 190px a category with many subcategories (e.g.
	   "Accesorii și piese de schimb", 21 items) flows into 3 columns instead
	   of one long scrolling ribbon. */
	grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
	gap: 0.15rem 1rem;
	align-content: start;
}
.ph-mega-menu-subcats[hidden] { display: none; }
.ph-mega-menu-subcat-pill {
	display: flex;
	align-items: flex-start;
	gap: 0.85rem;
	padding: 0.6rem 0.75rem;
	border-radius: var(--pl-radius-sm);
	font-size: 0.92rem;
	font-weight: 500;
	color: var(--pl-navy);
	text-decoration: none;
}
.ph-mega-menu-subcat-pill:hover {
	background: #fff;
	color: var(--pl-accent);
	box-shadow: var(--pl-shadow-card);
}
.ph-mega-menu-subcat-pill span {
	/* Was nowrap + ellipsis — long labels ("Imprimante cu jet de
	   cerneală") got silently cut off, losing information a visitor can't
	   recover without clicking through. Wrapping to 2 lines instead never
	   hides text; line-clamp caps runaway wrapping. */
	line-height: 1.3;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	padding-top: 0.15rem;
}

/* Thumbnail per subcategory row — real category photo
   (printerland_category_image_url(), same source the homepage strip and
   shop-page subcategory grid already use). Bumped up from 22px (near-
   illegible at that size) to a size that actually reads as a photo. */
.ph-mega-menu-subcat-img {
	width: 40px;
	height: 40px;
	object-fit: contain;
	flex-shrink: 0;
}

/* Mobile drilldown chrome — hidden on desktop, where the "back" step and
   category-name header don't apply (both panes sit side by side there). */
.ph-mega-menu-back,
.ph-mega-menu-subcats-head {
	display: none;
}
/* Fullscreen-only close button (mobile) — desktop's dropdown closes via
   outside-click, same as it always has, no dedicated button needed there. */
.ph-mega-menu-close {
	display: none;
}

@media (max-width: 767px) {
	/* Fullscreen takeover instead of a positioned popover (2026-08 refactor)
	   — the previous version anchored `top` from a JS-measured header
	   height and capped height with a `bottom` inset, which worked but
	   still followed the header's position. `inset: 0` removes that
	   dependency entirely: no offset to compute, no constant to drift
	   stale, matches the site's other mobile fullscreen drawer
	   (assets/shop.css .ph-filter-toggle / #secondary), same z-index tier. */
	.ph-mega-menu {
		position: fixed;
		inset: 0;
		/* Desktop's base rule sets margin-top:0.5rem (dropdown-under-button
		   spacing) — fixed-position elements still respect margin even with
		   inset:0, so without this override the panel rendered a few px
		   short of the true viewport top. */
		margin: 0;
		z-index: 1200;
		width: auto;
		max-width: none;
		max-height: none;
		border-radius: 0;
		box-shadow: none;
		flex-direction: column;
		gap: 0;
		/* Top padding clears the fixed .ph-mega-menu-close button (2.75rem
		   tall + its own 1rem inset) so the category list doesn't render
		   underneath it — same amount .ph-filter-close's host (#secondary,
		   assets/shop.css) reserves for the equivalent close button there. */
		padding: calc(5.5rem + env(safe-area-inset-top)) 1rem calc(1rem + env(safe-area-inset-bottom));
		overflow-y: auto;
		-webkit-overflow-scrolling: touch;
	}
	body.ph-catalog-open {
		overflow: hidden;
	}
	.ph-mega-menu-close {
		display: flex;
		align-items: center;
		justify-content: center;
		position: fixed;
		top: calc(1rem + env(safe-area-inset-top));
		right: 1rem;
		z-index: 1201;
		width: 3.5rem;
		height: 3.5rem;
		border: 2px solid rgb(255 255 255 / 0.35);
		border-radius: 9999px;
		background: var(--pl-navy-gradient);
		box-shadow: var(--pl-shadow-chip);
		color: #fff;
		cursor: pointer;
	}
	/* Only one pane is visible at a time here (drilldown) — unlike desktop
	   (both panes visible side-by-side, genuinely needing independent
	   scroll), nesting a second scroll container inside the outer one here
	   just gave two max-height calcs that drift out of sync (confirmed
	   live: the last subcategory sometimes uncrollable-to, clipped between
	   the inner pane's own boundary and the outer one's). The outer
	   `.ph-mega-menu` is the only scroll container on mobile now; panes
	   size to their natural content height instead. */
	.ph-mega-menu-categories,
	.ph-mega-menu-right {
		max-height: none;
		overflow-y: visible;
	}
	.ph-mega-menu-categories {
		min-width: 0;
		border-right: none;
		padding-right: 0;
	}
	.ph-mega-menu-right { display: none; }
	.ph-mega-menu.is-drilldown .ph-mega-menu-categories { display: none; }
	.ph-mega-menu.is-drilldown .ph-mega-menu-right { display: flex; }
	/* Subcategory pills stack full-width on mobile — easier to tap than a
	   wrapped grid. */
	.ph-mega-menu-subcats { grid-template-columns: 1fr; }
	/* Fullscreen has the room a 220px popover column never did — bigger
	   rows, bigger photos, easier to tap/scan than the compact desktop size. */
	.ph-mega-menu-category-item { padding: 0.85rem 0.75rem; }
	.ph-mega-menu-category { gap: 1rem; font-size: 1.05rem; }
	.ph-mega-menu-category-icon { width: 48px; height: 48px; }
	.ph-mega-menu-subcat-pill { padding: 0.9rem 0.75rem; gap: 1rem; font-size: 1rem; }
	.ph-mega-menu-subcat-img { width: 56px; height: 56px; }
	.ph-mega-menu-back,
	.ph-mega-menu-subcats-head {
		display: block;
		text-decoration: none;
	}
	.ph-mega-menu-back {
		/* !important — Astra's parent-theme global button style (customizer
		   color, pill shape) otherwise wins on this bare <button> element.
		   Bigger/clearer per feedback — was a small plain-text link (0.85rem,
		   no background), easy to miss above the subcategory list; now a
		   proper tappable pill matching the rest of the fullscreen catalog's
		   sizing. */
		display: inline-flex !important;
		align-items: center;
		gap: 0.35rem;
		background: var(--pl-mist) !important;
		border: none !important;
		border-radius: 9999px !important;
		color: var(--pl-navy) !important;
		font-weight: 700;
		font-size: 1rem;
		padding: 0.65rem 1.1rem !important;
		margin-bottom: 0.5rem;
		width: auto !important;
		cursor: pointer;
		text-align: left;
	}
	.ph-mega-menu-subcats-head {
		color: var(--pl-navy);
		font-weight: 700;
		font-size: 1rem;
		padding: 0.3rem 0 0.75rem;
	}
}

.ph-search-wrap {
	position: relative;
	/* flex:0 1 (not flex:1/grow) so it stops force-filling the row — a
	   growing item ignores auto side-margins, which is what centering here
	   needs. Was left-hugging right after the Catalog button; now sits
	   centered in the row's remaining space, shifted right of center of the
	   whole header (logo eats the left side). */
	flex: 0 1 32rem;
	max-width: 32rem;
	margin-left: auto;
	margin-right: auto;
	/* Was display:none below 768px with no mobile alternative at all —
	   search was completely absent on phones. Now shown as its own full-
	   width row directly under the logo row (order:1, below logo+catalog
	   toggle which stay at the default order:0) instead of squeezing into
	   the same row (no space for a real input there next to logo+3 icons+
	   hamburger on a narrow screen) — and instead of sorting last, below
	   the icons/hamburger row, which read as "not near the top". */
	display: block;
	order: 1;
	flex-basis: 100%;
	max-width: 100%;
	margin-top: 0.6rem;
}
@media (max-width: 767px) {
	.ph-header-icons {
		order: 2;
		/* Logo+Catalog row and the icon row both left-align by default
		   (flex-wrap's per-line justify-content default), leaving a dead
		   gap on the right on narrow screens — the search row already
		   spans full width so this only affects those two rows.
		   margin-left:auto (desktop's push-to-the-right-of-the-search-bar
		   trick) has to go too, or centering only shifts the icon cluster
		   within whatever leftover space auto-margin already claimed. */
		flex-basis: 100%;
		margin-left: 0;
		justify-content: center;
	}
	.ph-header-inner { justify-content: center; }
}
@media (min-width: 768px) {
	.ph-search-wrap {
		/* In-flow flex sizing (not absolute) — reserves its own space in the
		   row, so it can never overlap the logo/Catalog button or the icon
		   cluster regardless of viewport width. A prior attempt used
		   position:absolute for "true" centering against the whole header
		   row, but that doesn't reserve space at all — confirmed live at
		   1280px it rendered directly on top of the Catalog button, hiding
		   it completely.
		   flex-grow:0 is the important part here — flex:1 (grow) made the
		   bar's actual width depend on how much space its siblings left
		   over, which differs per page (the Catalog button is hidden on the
		   v2 homepage only, freeing ~150px there) — confirmed live: same
		   viewport width, visibly narrower search bar on /shop/ than on
		   the homepage. A fixed clamp()'d width instead of max-width makes
		   it the same size everywhere regardless of what else is in the
		   row; flex-shrink:1 is the only give, for genuinely tight widths. */
		order: 0;
		flex: 0 1 auto;
		flex-basis: auto;
		/* Pulled narrower again — reported still overflowing live past the
		   Catalog button despite passing every viewport this session could
		   test (900/1024/1150/1280px, clean every time); rather than keep
		   chasing an unreproduced width, dropping to a smaller, safer size
		   outright. 24vw stays well clear of the Catalog button even with
		   headroom this session's measurements didn't account for. */
		width: clamp(16rem, 24vw, 28rem);
		margin: 0 auto;
	}
}
@media (min-width: 1200px) {
	.ph-search-wrap {
		/* True whole-row centering (not just centered in the leftover flex
		   space between the Catalog button and the icon cluster, which
		   reads as "off-center" since those two groups aren't the same
		   width) — safe at this width with the smaller 28rem cap above,
		   confirmed clear of both neighbors. */
		position: absolute;
		left: 50%;
		transform: translateX(-50%);
		width: 28rem;
		max-width: 28rem;
		margin: 0;
	}
}
/* !important on radius — Astra's own input[type] default styling was
   winning over this class selector (computed to 4px live), same override
   class documented in docs/memory/conventions.md. Border color also had
   the OLD navy hardcoded as a literal rgb triple — same stale-tint bug as
   the 4 hover tints fixed earlier, fixed here too via --pl-navy-rgb. */
.ph-search-input {
	width: 100%;
	height: 3rem;
	padding: 0 3.25rem 0 1.25rem;
	border-radius: var(--pl-radius-card) !important;
	border: 1px solid rgba(var(--pl-navy-rgb), 0.12);
	background: var(--pl-gray-100);
	transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.ph-search-input:focus {
	outline: none;
	background: #fff;
	border-color: rgba(var(--pl-navy-rgb), 0.25);
	box-shadow: 0 0 0 3px rgba(var(--pl-navy-rgb), 0.12);
}
.ph-search-form { position: relative; display: flex; }
.ph-search-submit {
	position: absolute;
	right: 0.4rem;
	top: 50%;
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 9999px;
	border: none;
	cursor: pointer;
	background: var(--pl-navy-gradient);
	color: #fff;
	transition: transform 0.15s ease;
}
.ph-search-submit:active { transform: translateY(-50%) scale(0.94); }
.ph-search-submit:hover {
	/* Now a filled navy circle (was a bare icon needing this override to
	   stay visible against Astra's global accent-fill button:hover rule) —
	   kept the !important since that global rule still applies, just kept
	   the same navy-gradient fill instead of stripping it to transparent. */
	background: var(--pl-navy-gradient) !important;
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
}
.ph-search-results {
	position: absolute;
	left: 0;
	right: 0;
	margin-top: 0.5rem;
	background: #fff;
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card-lg);
	overflow: hidden;
	z-index: 60;
}
.ph-search-result {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.75rem 1rem;
	text-decoration: none;
	color: inherit;
	border-bottom: 1px solid var(--pl-gray-100);
}
.ph-search-result img { width: 40px; height: 40px; object-fit: cover; border-radius: var(--pl-radius-sm); }
.ph-search-result strong { margin-left: auto; color: var(--pl-navy); }
.ph-search-empty { padding: 1rem; color: var(--pl-gray-600); font-size: 0.9rem; }
.ph-search-view-all {
	display: block;
	text-align: center;
	padding: 0.75rem 1rem;
	color: var(--pl-accent);
	font-weight: 600;
	font-size: 0.9rem;
	text-decoration: none;
}
.ph-search-view-all:hover { background: var(--pl-gray-100); }

.ph-lang-switcher { position: relative; }
.ph-lang-current {
	background: none;
	border: 1px solid rgb(0 0 0 / 0.1);
	border-radius: var(--pl-radius-card);
	color: var(--pl-navy);
	font-weight: 600;
	font-size: 0.8rem;
	padding: 0.4rem 0.75rem;
	cursor: pointer;
}
/* Astra's global button:hover fills a solid accent background — clashes with
   the subtle navy-tint hover language used by every other header control
   (.ph-icon, .ph-lang-option, .ph-mobile-menu-toggle). Override explicitly. */
.ph-lang-current:hover {
	background: rgba(var(--pl-navy-rgb), 0.06) !important;
	color: var(--pl-navy) !important;
	border-color: rgba(var(--pl-navy-rgb), 0.1);
}
.ph-lang-options {
	position: absolute;
	top: 100%;
	right: 0;
	margin-top: 0.4rem;
	background: #fff;
	/* Floating panel, same family as .ph-search-results/.ph-mega-menu —
	   card radius, not the small 8px used for tight inline chips. */
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card-lg);
	padding: 0.4rem;
	display: flex;
	flex-direction: column;
	min-width: 8rem;
	z-index: 1000;
}
.ph-lang-options[hidden] { display: none; }
.ph-lang-option {
	color: var(--pl-navy);
	text-decoration: none;
	padding: 0.4rem 0.6rem;
	border-radius: var(--pl-radius-sm);
	font-size: 0.85rem;
}
.ph-lang-option:hover { background: rgba(var(--pl-navy-rgb), 0.06); }
.ph-lang-option.is-active { color: var(--pl-accent); font-weight: 700; }

.ph-header-icons {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin-left: auto;
}
/* Bare icon, no hit-target boundary or hover feedback — every other header
   control (lang switcher, mega-menu toggle) is a pill with a visible hover
   state, so these read as dead/unclickable next to them. Give wishlist/
   compare/cart the same circular pill treatment, sized to a comfortable
   44px tap target. */
.ph-icon {
	position: relative;
	background: none;
	border: none;
	font-size: 1.25rem;
	cursor: pointer;
	color: var(--pl-navy);
	text-decoration: none;
	width: 2.75rem;
	height: 2.75rem;
	/* Card radius (26px), not a full circle — matches the Catalog button,
	   search bar and every other primary header control. */
	border-radius: var(--pl-radius-card);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.15s ease, color 0.15s ease;
}
.ph-icon:hover {
	background: rgba(var(--pl-navy-rgb), 0.06);
	color: var(--pl-accent);
}
.ph-svg-icon { display: block; flex-shrink: 0; }
.ph-loop-action, .ph-pdp-action, .ph-mobile-menu-toggle { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; }
.ph-icon-badge {
	position: absolute;
	top: -0.25rem;
	right: -0.25rem;
	background: var(--pl-accent-gradient);
	box-shadow: var(--pl-shadow-chip);
	color: #fff;
	font-size: 0.65rem;
	min-width: 1.1rem;
	height: 1.1rem;
	border-radius: 9999px;
	display: flex;
	align-items: center;
	justify-content: center;
}
.ph-icon-badge[hidden] { display: none; }
.ph-mobile-menu-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: var(--pl-radius-card);
	background: none;
	border: none;
	font-size: 1.5rem;
	cursor: pointer;
	color: var(--pl-navy);
	transition: background-color 0.15s ease;
}
.ph-mobile-menu-toggle:hover,
.ph-mobile-menu-toggle:focus {
	/* Astra's global `button:focus, button:hover { color: ... }` rule beats
	   this class on specificity (a pseudo-class counts same as a class,
	   button:focus = 0,1,1 vs .ph-mobile-menu-toggle = 0,1,0) and was
	   turning the icon white — invisible against this button's own
	   transparent/light background once tapped (confirmed live, icon
	   vanished after opening the mobile menu). */
	background: rgba(var(--pl-navy-rgb), 0.06);
	color: var(--pl-navy) !important;
}
@media (min-width: 922px) {
	/* Matches the breakpoint the rest of the header (search row, icon
	   cluster) reflows at. */
	.ph-mobile-menu-toggle { display: none; }
}

.ph-mobile-nav-drawer {
	position: absolute;
	top: 100%;
	left: 1rem;
	right: 1rem;
	margin-top: 0.5rem;
	background: var(--pl-navy-sheen);
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card-lg);
	padding: 0.5rem;
	display: flex;
	flex-direction: column;
	z-index: 1000;
}
.ph-mobile-nav-drawer[hidden] { display: none; }
.ph-mobile-nav-drawer a {
	color: rgba(255, 255, 255, 0.85);
	text-decoration: none;
	font-weight: 600;
	padding: 0.75rem 1rem;
	border-radius: var(--pl-radius-sm);
}
.ph-mobile-nav-drawer a:hover { background: rgb(255 255 255 / 0.1); color: #fff; }
@media (min-width: 922px) {
	.ph-mobile-nav-drawer { display: none; }
}

/* WooCommerce archive pages (shop/category) get Astra's default
   "separate containers" top spacing (.content-area.primary margin-top,
   ~58px on mobile) — makes sense as breathing room under a plain theme
   header, but this theme's own header already ends with clean white
   space before the breadcrumb, so it read as a large dead gap before
   anything started. Homepage/static pages don't use this wrapper (0px
   there already) — scoped to WooCommerce archives only. */
@media (max-width: 767px) {
	body.woocommerce .content-area.primary,
	body.woocommerce-page .content-area.primary {
		margin-top: 1rem !important;
	}
}

/* Wishlist / compare virtual pages (see inc/wishlist-compare.php). */
.ph-page-shell { max-width: 1200px; margin: 0 auto; padding: 2rem 1.5rem 4rem; }
.ph-empty-state { color: var(--pl-gray-600); padding: 2rem 0; }

/* Static content pages (Despre/Livrare/Credit/etc. — see
   inc/static-page-icons.php). */
.ph-page-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	margin-bottom: 1rem;
	border-radius: 9999px;
	background: color-mix(in srgb, var(--pl-navy) 8%, transparent);
	color: var(--pl-navy);
}
.ph-page-icon svg { width: 22px; height: 22px; }
.ph-wishlist-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
	gap: 1.25rem;
}
.ph-wishlist-card {
	background: var(--pl-white-gradient);
	box-shadow: var(--pl-shadow-card);
	border-radius: var(--pl-radius-card);
	padding: 1rem;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
.ph-wishlist-card img { width: 100%; aspect-ratio: 1; object-fit: contain; background: #fff; border-radius: var(--pl-radius-sm); }
.ph-wishlist-card-name { color: var(--pl-navy); font-weight: 600; text-decoration: none; font-size: 0.95rem; }
.ph-wishlist-card-price { color: var(--pl-accent); font-weight: 700; }
.ph-wishlist-remove {
	border: 1px solid rgb(0 0 0 / 0.1);
	border-radius: 9999px;
	background: none;
	padding: 0.4rem 0.9rem;
	font-size: 0.8rem;
	cursor: pointer;
	color: var(--pl-gray-600);
}
.ph-wishlist-remove:hover {
	background: rgba(var(--pl-navy-rgb), 0.06) !important;
	color: var(--pl-navy) !important;
}
.ph-compare-table { width: 100%; border-collapse: collapse; }
.ph-compare-table th, .ph-compare-table td {
	padding: 0.85rem 1rem;
	border-bottom: 1px solid var(--pl-gray-100);
	text-align: left;
	vertical-align: middle;
}
.ph-compare-table th { color: var(--pl-gray-600); font-weight: 600; font-size: 0.85rem; white-space: nowrap; }
.ph-compare-table img { width: 80px; height: 80px; object-fit: contain; background: #fff; border-radius: var(--pl-radius-sm); }
.ph-compare-remove {
	border: 1px solid rgb(0 0 0 / 0.1);
	border-radius: 9999px;
	background: none;
	padding: 0.35rem 0.85rem;
	font-size: 0.8rem;
	cursor: pointer;
	color: var(--pl-gray-600);
}
.ph-compare-remove:hover {
	background: rgba(var(--pl-navy-rgb), 0.06) !important;
	color: var(--pl-navy) !important;
}

/* [product_categories] grid — used on the homepage, loaded here (not
   shop.css) since is_shop()/is_product_category() etc. don't cover the
   front page. Source product images vary wildly in native size, so
   without a forced aspect-ratio the tiles rendered at wildly inconsistent
   visual sizes (a small connector part next to a full product box shot). */
/* Matches li.product's card treatment (assets/shop.css) instead of
   rendering flat/borderless — when a category archive shows subcategory
   tiles mixed into the same grid as real products (WooCommerce's "show
   subcategories" / "show both" display setting), the two card types used
   to look like they belonged to different sites. Also resets the
   width/margin/float WooCommerce core sets on li.product-category by
   default — li.product already cancels these (assets/shop.css) but
   nothing previously did for li.product-category, leaving it to a
   percentage float width inside this theme's display:grid parent. */
.woocommerce ul.products li.product-category {
	text-align: center;
	border: none !important;
	border-radius: var(--pl-radius-card);
	box-shadow: var(--pl-shadow-card);
	padding: 1rem;
	transition: box-shadow 0.2s ease;
	width: auto !important;
	margin: 0 !important;
	float: none !important;
}
.woocommerce ul.products li.product-category:hover {
	box-shadow: var(--pl-shadow-card-lg);
}
.woocommerce ul.products li.product-category img {
	width: 100% !important;
	height: auto !important;
	aspect-ratio: 1 !important;
	object-fit: contain !important;
	border-radius: var(--pl-radius-sm);
	background: #fff;
}
.woocommerce ul.products li.product-category .woocommerce-loop-category__title {
	color: var(--pl-navy);
	font-weight: 600;
}

/* Astra's native mobile header row (id="ast-mobile-header") — its logo is
   gone now (see functions.php custom_logo removal) but the trigger button
   inside it is still needed in the DOM: header.js's hamburger delegates a
   click to it. Left visible it was just a redundant lone hamburger row
   under our own custom header — hide it, keep it clickable via JS. */
@media (max-width: 921px) {
	#ast-mobile-header {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip: rect(0, 0, 0, 0);
	}
}

/* PDP description tab (inc/pdp-description-format.php) — the formatter's
   own output classes (.ph-spec-grid, .ph-compat-chips, etc.) had never
   been styled at all, so even a paragraph it successfully classified
   still rendered as a bare unstyled <dl>/<ul>. */
.ph-spec-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	border: 1px solid var(--pl-gray-100);
	border-radius: var(--pl-radius-card);
	overflow: hidden;
	margin: 0 0 1.5rem;
}
/* Adjacent grids get fused into one continuous <dl> by the PHP formatter
   (inc/pdp-description-format.php) whenever nothing but whitespace sits
   between them, so a long spec dump renders as one compact table instead
   of dozens of separately-bordered boxes — this just tightens row height
   inside that table now that it's genuinely long. */
.ph-spec-row dt,
.ph-spec-row dd {
	padding-top: 0.55rem;
	padding-bottom: 0.55rem;
}
/* display:contents — the wrapping row div isn't itself a grid item, its
   dt/dd children are, so they land in the 2-column grid directly. Doesn't
   affect :nth-child matching, which still walks the DOM regardless of box
   generation. */
/* !important — Astra applies its own display:flex to dl > div children on
   mobile (confirmed live: computed style showed display:flex overriding
   this at 390px, laying dt/dd side by side instead of stacking with the
   single-column grid below), the same class of override already fought
   elsewhere in this file (.ph-mega-menu-back). */
.ph-spec-row { display: contents !important; }
.ph-spec-row dt,
.ph-spec-row dd {
	margin: 0;
	padding: 0.75rem 1rem;
	font-size: 0.9rem;
	border-bottom: 1px solid var(--pl-gray-100);
}
.ph-spec-row dt { font-weight: 600; color: var(--pl-navy); background: var(--pl-gray-100); }
/* Astra's own WooCommerce styles right-align <dd> by default — fine
   stacked in a 2-column grid, wrong once stacked to 1 column on mobile. */
.ph-spec-row dd { color: var(--pl-gray-600); text-align: right !important; }
.ph-spec-row:last-child dt,
.ph-spec-row:last-child dd { border-bottom: none; }
@media (max-width: 480px) {
	/* Long labels next to long values get cramped in two narrow columns
	   on a phone — stack label above value instead. */
	.ph-spec-grid { grid-template-columns: 1fr; }
	.ph-spec-row dt { border-bottom: none; padding-bottom: 0.25rem; }
	.ph-spec-row dd { padding-top: 0; text-align: left !important; }
}

.ph-desc-bullets {
	margin: 0 0 1.5rem;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
.ph-desc-bullets li {
	position: relative;
	padding-left: 1.25rem;
	color: var(--pl-gray-600);
	line-height: 1.6;
}
.ph-desc-bullets li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.6em;
	width: 6px;
	height: 6px;
	border-radius: 9999px;
	background: var(--pl-accent);
}

.ph-desc-heading,
.ph-compat-heading {
	font-size: 1.05rem;
	font-weight: 700;
	color: var(--pl-navy);
	margin: 1.5rem 0 0.75rem;
}
.ph-compat-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0 0 1.5rem;
}
.ph-compat-chip {
	border: 1px solid rgb(0 0 0 / 0.1);
	border-radius: 9999px;
	padding: 0.35rem 0.9rem;
	font-size: 0.82rem;
	color: var(--pl-navy);
}

.ph-desc-text {
	color: var(--pl-gray-600);
	line-height: 1.7;
	max-width: 68ch;
	margin: 0 0 1rem;
}

/* Astra's native scroll-to-top button — set via the Customizer as a plain
   near-square (2px radius) with the OLD navy hardcoded as a literal color,
   not this stylesheet's --pl-navy token, so it silently went stale/
   mismatched the moment the palette was refreshed. Pull it onto the same
   token and shape system as everything else. */
#ast-scroll-top {
	border-radius: var(--pl-radius-card) !important;
	background-color: var(--pl-navy) !important;
}
#ast-scroll-top:hover {
	background-color: var(--pl-accent) !important;
}
/* Astra places this at the same bottom-right corner (bottom:30/right:30)
   as the tawk.to chat launcher (bottom:70/right:15, ~64px tall) —
   confirmed live: the two overlapped/touched once the chat window was
   open. Stacked above the launcher's top edge on mobile, where both
   widgets actually compete for the same corner. */
@media (max-width: 480px) {
	#ast-scroll-top {
		bottom: 145px !important;
	}
}

/* Astra "Above Header" builder row (Customizer-configured plain text,
   "Livrare gratuită pentru comenzi peste 300 lei") — redundant with the
   same message already in the topbar/footer trust strip in this theme's
   own header. Hiding just the inner text element left its OUTER wrapper
   (.ast-above-header-bar) still rendering as an empty 32px light-gray
   bar — confirmed live, that wrapper has its own background/min-height
   independent of its (now empty) content. Hide the whole row. */
.ast-above-header-bar { display: none !important; }

/* Contact page form (inc/contact-form.php). */
.ph-contact-form-wrap {
	max-width: 40rem;
	margin: 2rem 0;
	background: #fff;
	box-shadow: var(--pl-shadow-card);
	border-radius: var(--pl-radius-card);
	padding: 1.75rem;
}
.ph-contact-form-row {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin-bottom: 1.1rem;
}
.ph-contact-form-row label {
	font-weight: 600;
	color: var(--pl-navy);
	font-size: 0.9rem;
}
.ph-contact-form-row input,
.ph-contact-form-row textarea {
	border: 1px solid rgba(0, 0, 0, 0.12);
	border-radius: var(--pl-radius-sm);
	padding: 0.65rem 0.9rem;
	font: inherit;
	color: var(--pl-navy);
	resize: vertical;
}
.ph-contact-form-row input:focus,
.ph-contact-form-row textarea:focus {
	outline: none;
	border-color: var(--pl-navy);
	box-shadow: 0 0 0 2px rgba(var(--pl-navy-rgb), 0.15);
}
.ph-contact-form-submit {
	background: var(--pl-accent-gradient) !important;
	box-shadow: var(--pl-shadow-chip);
	color: #fff !important;
	border: none !important;
	border-radius: 9999px !important;
	padding: 0.85rem 2rem !important;
	font-weight: 700 !important;
	cursor: pointer;
}
.ph-contact-form-submit:hover { background: var(--pl-accent-hover) !important; }
/* Honeypot — visually hidden but still present/focusable in the DOM (real
   `display:none`/`hidden` fields are the first thing spam bots skip when
   deciding which fields to fill; off-screen positioning is harder to
   detect programmatically). */
.ph-contact-form-honeypot {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}
.ph-contact-form-notice {
	border-radius: var(--pl-radius-sm);
	padding: 0.85rem 1.1rem;
	margin-bottom: 1.25rem;
	font-weight: 600;
}
/* Semantic status colors, not the brand accent — coral already means
   "sale/CTA" elsewhere on the site; reusing it for an error state would
   read as a promo, not a problem. */
.ph-contact-form-notice-success { background: rgb(22 131 62 / 0.1); color: #16833e; }
.ph-contact-form-notice-error { background: rgb(200 40 40 / 0.1); color: #c82828; }

/* Footer — was a real accessibility bug, not just unbranded: the widget
   column headings were pure white and links a pale gray (#e5e7eb),
   clearly designed for a dark background that was never actually applied
   — confirmed live, footer background computed transparent (inheriting
   the white page), giving link text a 1.24:1 contrast ratio against
   white (near-invisible). Giving the footer the brand navy fixes both the
   accessibility failure and the "looks unbranded/disconnected" complaint
   in one move — the existing white/light-gray text scheme becomes exactly
   what it was clearly meant to be. */
.site-footer {
	background: var(--pl-navy-sheen);
	/* .ph-newsletter-bleed sits directly above this and is the same navy —
	   with no seam between them they read as one uninterrupted band rather
	   than two distinct sections, confirmed live (the "Subscribe" band and
	   the footer visually fused into a single oversized block). A thin
	   light seam is enough to separate them without reintroducing a plain
	   page-background gap between two same-color bands. */
	border-top: 1px solid rgb(255 255 255 / 0.12);
}
/* Astra's own "content top/bottom spacing" Customizer setting adds 60px
   margin-top AND margin-bottom on #primary — invisible on normal pages
   (white content on white page background), but on the homepage: the
   bottom one sits BELOW the full-bleed .ph-bleed sections (those only
   escape horizontally, this margin is untouched) and reintroduced a large
   plain-white gap between the navy newsletter band and the footer even
   after the border-top seam fix above; the top one stacked with
   .phv2-herorow's own intentional 0.5rem top margin, measured live as an
   84px gap below the header instead of the ~8px the hero row's own CSS
   comment says it should be. Scoped to the front page only via
   WordPress's own `.home` body class (added whenever is_front_page() is
   true) — every other page keeps Astra's normal top/bottom spacing.
   !important — Astra's own rule for this has higher specificity/its own
   !important (same recurring Astra-override gotcha as elsewhere in this
   file); a plain override was confirmed live to not win. */
.home #primary { margin-top: 0 !important; margin-bottom: 0 !important; }
.footer-widget-area a {
	color: rgb(255 255 255 / 0.75);
	text-decoration: none;
	transition: color 0.15s ease;
}
.footer-widget-area a:hover {
	color: #fff;
}
.footer-widget-area h6,
.footer-widget-area .wp-block-spectra-content {
	color: #fff;
	font-weight: 700;
	letter-spacing: 0.04em;
}
.site-below-footer-wrap {
	border-top: 1px solid rgb(255 255 255 / 0.12);
}
.site-below-footer-wrap,
.site-below-footer-wrap * {
	color: rgb(255 255 255 / 0.6);
}

/* PDP: gallery card vs buybox card height mismatch — WooCommerce's default
   float-based layout (Astra) sizes .images purely by its own content, so a
   single-image product (no thumbnail strip under it) leaves a visibly
   shorter card next to the taller .summary buybox card beside it, bottom
   edges misaligned. Confirmed live: 396px vs 610px on a single-image
   product. Flex + stretch lets the shorter card grow to match its sibling,
   with the image centered in the extra space instead of pinned to the top.
   768px matches the breakpoint WooCommerce/Astra already switches these
   two columns to a stacked single-column layout at (assets/shop.css uses
   the same 767/768 split for the mobile buy bar) — below it they're full
   width anyway, nothing to equalize. */
@media (min-width: 768px) {
	.single-product div.product {
		display: flex;
		flex-wrap: wrap;
		align-items: stretch;
		/* WooCommerce/Astra's own float layout left only ~12px between the
		   two cards (their own small right/left margins) — cramped for two
		   large shadowed cards sitting side by side, confirmed live. */
		gap: 2rem;
	}
	.single-product div.product > .woocommerce-product-gallery,
	.single-product div.product > .summary {
		float: none;
		margin-right: 0;
		margin-left: 0;
	}
	.single-product div.product > .woocommerce-product-gallery {
		display: flex;
		flex-direction: column;
		justify-content: center;
	}
}

/* PDP stock badge + "Comandă acum" button — both unstyled before this
   (bare <p> and Astra's generic button defaults), confirmed live: the
   button sat directly under the stock text with no gap, and a stray
   margin-left:auto-ish 12px (a leftover from once sitting inline next to
   another element) nudged it slightly off the badge's left edge instead
   of lining up under it. */
.ph-stock-badge {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin: 1rem 0 0.65rem;
	color: #1a7f37;
	font-weight: 600;
	font-size: 0.92rem;
}
.printerland-pdp-buy-now {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	margin: 0 0 1rem;
	min-width: 12rem;
	height: 47.2px; /* matches .single_add_to_cart_button, same reasoning as .ph-qty-stepper above */
	border-radius: 9999px;
	background: var(--pl-navy);
	color: #fff;
	border: none;
	font-weight: 700;
	cursor: pointer;
	box-shadow: var(--pl-shadow-chip);
}
.printerland-pdp-buy-now:hover {
	background: var(--pl-navy-mid);
}
