/* ============================================================================
   BENIS SHOES — PAGE LAYER
   ----------------------------------------------------------------------------
   Styles that belong to a specific page rather than to a shared component.
   Anything here that starts being used by a second page moves down into
   04-components.css instead of being copied.
   ========================================================================== */

/* ============================================================================
   HERO — LANDSCAPE BANNER SLIDER
   ----------------------------------------------------------------------------
   One landscape frame per slide, cross-faded. Photography is media; the
   headline, sub-copy, CTA and controls are all real HTML laid over it.

   The frame is inset and softly rounded rather than full-bleed — the rounded
   campaign card is Benis, and a banner running to the viewport edge reads as
   any fashion site's opening spread.

   CROP: a landscape frame cannot hide the baked interface on the current
   slide-1 asset the way the old portrait panel did, so each slide widens its
   own image box via --hero-zoom and pins it to the frame's left edge. Clean
   artwork sets zoom to 1 and the whole composition is shown.
   ========================================================================== */

/* No bottom margin. The section that follows carries its own block padding, and
   the two were stacking into 80px of empty canvas between the banner and the
   service strip — the first thing a desktop visitor saw after the banner was a
   gap the height of the strip itself. */
.hero-section {
	position: relative;
	padding-inline: var(--gutter);

	/* A hairline of air under the header on desktop. The banner is a framed
	   card, and running its rounded top edge flush into the header bar made the
	   two read as one welded block. On a phone the viewport is too scarce to
	   spend on it, so this starts at 1024. */
	padding-block-start: 0;
	background:
		radial-gradient(120% 90% at 85% 0%, var(--blue-50) 0%, transparent 60%),
		/* Resolves INTO the page canvas, not into pure white, so the hero's
		   ground and the document's ground are the same colour where they meet. */
		linear-gradient(180deg, var(--neutral-25) 0%, var(--surface-page) 100%);
}

@media (min-width: 1024px) {
	.hero-section { padding-block-start: var(--space-4); }
}

/* Width is capped so the RATIO never has to bend.
   ----------------------------------------------------------------------------
   Height on a wide screen is controlled by capping the frame's width, not by
   changing its shape: width = height x ratio, so capping width at (Nvh x ratio)
   caps the banner at N% of the viewport height at any size, while the crop stays
   identical to the phone's.

   N is 80, and it used to be 72. At 72 on a 1440x900 laptop the cap resolved to
   1152px — inside a 1280px content container, so the banner sat visibly
   NARROWER than the product rows beneath it, with a 64px step in at each edge.
   A hero that is smaller than the content it introduces reads as an
   afterthought. At 80 the cap resolves to 1280 on that same screen, which is
   exactly the container, so the banner and everything below it share one edge.

   The width it aligns to is the container's CONTENT box — the container minus
   its two gutters — not the container's own box. That is where the service
   strip's card, the section headings and the product cards all begin. Matching
   the container box instead left the banner 32px proud on each side: two
   stacked rounded cards of almost-but-not-quite the same width, which reads as
   a mistake rather than as hierarchy.

   The cap still does its real job on a short screen: at 800px tall the frame
   comes down to 1138px and the fold is not swallowed. */
.hero {
	position: relative;
	/* Vertical panning stays with the browser; horizontal is ours.
	   Without this the browser claims the horizontal gesture too and fires
	   `pointercancel` partway through, so a swipe on a phone never reached
	   pointerup and the banner simply would not move. */
	touch-action: pan-y;
	max-inline-size: min(
		calc(var(--container) - var(--gutter) * 2),
		var(--hero-maxw, 100%)
	);
	margin-inline: auto;
	border-radius: var(--radius-2xl);
	overflow: hidden;
	background-color: var(--neutral-900);
	box-shadow: var(--shadow-md);
}

/* ── Track and slides ────────────────────────────────────────────────────── */

/* ONE ratio, every screen.
   ----------------------------------------------------------------------------
   Set inline from the customizer (سفارشی‌سازی → بنر اصلی), never overridden per
   breakpoint. There were three different ratios here — 4/5, 16/10 and a fixed
   height band — which framed the same artwork three different ways and made the
   banner impossible to design for. The shop owner picks one ratio to match the
   files they produce, and that is what everyone sees.

   Height on a wide screen is controlled by capping the frame's WIDTH (see
   .hero below), not by overriding the ratio. */
.hero__track {
	position: relative;
	/* 16:9 is the fallback because it is the shape of the banner files
	   themselves (1536×864). A frame that matches the artwork needs no
	   letterboxing to show all of it. */
	aspect-ratio: var(--hero-ratio, 16 / 9);
}

/* The phone overlay rules are NOT here. They live directly after the
   .hero__content block further down, because they target the same single-class
   selectors it does and the cascade breaks ties by order — placed up here they
   were being overridden by the very rules they exist to replace. */

.hero__slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	visibility: hidden;
	/* A touch of scale on the outgoing/incoming frame — the difference between
	   a cross-fade and a cheap dissolve. */
	scale: 1.03;
	transition:
		opacity 700ms var(--ease),
		scale 900ms var(--ease-out),
		visibility 0s linear 700ms;
}

.hero__slide.is-active {
	opacity: 1;
	visibility: visible;
	scale: 1;
	transition:
		opacity 700ms var(--ease),
		scale 900ms var(--ease-out),
		visibility 0s;
}

/* ── Media ───────────────────────────────────────────────────────────────── */

.hero__media {
	position: absolute;
	inset: 0;
}

/* A DETERMINISTIC crop.
   ----------------------------------------------------------------------------
   The image box is made --hero-zoom times the frame's width and pinned to the
   frame's physical left edge, so exactly 1/zoom of the source's width is in
   shot — 1.8 shows the leftmost 55%, whatever aspect ratio the frame happens to
   be at that breakpoint.

   `scale` + `object-position` was tried first and is not predictable: the two
   compound, and the result drifts with the frame ratio, so the flattened
   banner's baked headline and button crept back into frame at some widths.

   `left`, not `inset-inline-start`: the shoe sits on the image's physical left
   side, which does not move when the document direction is RTL. */
.hero__media img {
	position: absolute;
	top: 0;
	left: 0;
	block-size: 100%;
	inline-size: calc(100% * var(--hero-zoom, 1));
	max-inline-size: none;
	object-fit: cover;
	object-position: left center;
}

/* `cover` is a crop by definition — it scales the file until it fills both axes
   and discards the overflow — which is exactly right HERE and only here: the
   frame is 16:9 and the Customizer refuses to save a banner that is not, so at
   zoom 1 there is nothing for it to discard. A `contain` fallback lived here
   briefly, to rescue mismatched files with bars down the sides; the mismatch is
   now rejected at the door instead, which is a better place to solve it. */

/* A scrim, and ONLY when there is type to protect.
   ----------------------------------------------------------------------------
   This is a dark veil across the artwork — 90% opaque along the bottom edge on
   a phone, 82% down the inline-start edge on a desktop. That is the correct
   price to pay for legible white copy over arbitrary photography, and a pure
   waste on a banner that carries no copy at all: the shop uploads a finished
   piece of artwork, picks «بدون متن و دکمه», and the theme dims it anyway for
   text that is not there.

   It is keyed on a class the template adds only when the slide actually renders
   a kicker, a headline or a sub-paragraph. A slide carrying just a button does
   not get one either — the glass CTA supplies its own contrast. */
.hero__slide--scrim::after {
	content: "";
	position: absolute;
	inset: 0;
	/* Reaches high enough to cover the whole copy block, not just its last line.
	   The shallower version put the kicker and the top of the headline over the
	   pale upper of a white shoe, where white type is barely legible — the scrim
	   has to guarantee contrast for arbitrary photography, not for one image. */
	background: linear-gradient(
		to top,
		rgb(8 20 32 / 0.9) 0%,
		rgb(8 20 32 / 0.74) 38%,
		rgb(8 20 32 / 0.34) 62%,
		rgb(8 20 32 / 0) 86%
	);
}

@media (min-width: 900px) {
	.hero__slide--scrim::after {
		background: linear-gradient(
			to left,
			rgb(8 20 32 / 0.82) 0%,
			rgb(8 20 32 / 0.5) 42%,
			rgb(8 20 32 / 0) 72%
		);
	}

	html[dir="ltr"] .hero__slide--scrim::after {
		background: linear-gradient(
			to right,
			rgb(8 20 32 / 0.82) 0%,
			rgb(8 20 32 / 0.5) 42%,
			rgb(8 20 32 / 0) 72%
		);
	}
}

/* ── Content ─────────────────────────────────────────────────────────────── */

.hero__content {
	position: absolute;
	inset-block-end: 0;
	inset-inline: 0;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	padding: var(--space-5) var(--space-5) var(--space-10);
	color: var(--text-inverse);
}

@media (min-width: 900px) {
	.hero__content {
		inset-block: 0;
		inset-inline-end: auto;
		justify-content: center;
		inline-size: min(34rem, 52%);
		padding: var(--space-12);
	}
}

.hero__kicker {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	font-size: var(--text-caption);
	font-weight: var(--weight-semibold);
	color: var(--blue-300);
	margin-block-end: var(--space-3);
}

.hero__kicker::after {
	content: "";
	inline-size: 2.5rem;
	block-size: 2px;
	border-radius: var(--radius-pill);
	background-color: var(--brand);
}

.hero__title {
	font-size: clamp(1.75rem, 1.1rem + 3.2vw, 3.5rem);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-heading);
	line-height: 1.24;
	color: var(--text-inverse);
	margin-block-end: var(--space-3);
	max-inline-size: 16ch;
}

/* The second clause in brand blue — a signature Benis device, and real text
   rather than pixels baked into a JPEG. */
.hero__title em {
	font-style: normal;
	display: block;
	color: var(--blue-300);
}

.hero__text {
	font-size: var(--text-label);
	line-height: var(--leading-normal);
	color: rgb(255 255 255 / 0.84);
	max-inline-size: 38ch;
	margin-block-end: var(--space-5);
}

@media (min-width: 900px) {
	.hero__text { font-size: var(--text-body-lg); }
}

/* The CTA's pixel nudge, from سفارشی‌سازی → بنر اصلی.
   ----------------------------------------------------------------------------
   `translate` rather than margin or inset, so moving the button to line it up
   with a gap in the artwork cannot reflow the headline sitting above it.

   The X axis is FLIPPED under RTL. The Customizer calls the control «مثبت = به
   سمت مرکز صفحه», and on a right-aligned Persian overlay "toward the centre"
   means leftward — the opposite of what a raw positive translate does. Handling
   it here rather than negating the number in PHP keeps the stored value meaning
   the same thing in either direction, so a shop that switches locale does not
   find every banner button mirrored. */
.hero__actions {
	--hero-cta-dir: 1;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	translate: calc(var(--hero-cta-x, 0px) * var(--hero-cta-dir)) var(--hero-cta-y, 0px);
}

html[dir="rtl"] .hero__actions { --hero-cta-dir: -1; }

/* ── The whole banner as a link ──────────────────────────────────────────────
   «بدون متن و دکمه»: no overlay is drawn and the frame itself is the control.
   An absolutely positioned anchor over the artwork rather than a wrapper around
   it, because wrapping the slide would put the slider's own arrows and dots
   inside the link.

   It keeps a visible focus ring: this is the only interactive thing on the
   slide in this mode, and a keyboard user has to be able to see where they are.
   The ring is inset so it is not clipped by the frame's rounded corners. */
.hero__cover {
	position: absolute;
	inset: 0;
	z-index: 1;
	display: block;
}

.hero__cover:focus-visible {
	outline: 3px solid var(--border-focus);
	outline-offset: -5px;
	border-radius: inherit;
}

/* ── Phone overlay ───────────────────────────────────────────────────────────
   On a phone the copy sheds everything but the headline and the button.

   THE ARITHMETIC IS THE WHOLE ARGUMENT. One 16:9 frame at every width means a
   390px phone gets a banner 200px tall. The full overlay — eyebrow, two-line
   headline, sub-paragraph, button — measured 299px. That is not "cramped", it
   physically does not fit: it was spilling a hundred pixels out of the bottom
   of the banner.

   These rules used to hang off a `.hero--wide` class that PHP added only when
   the chosen ratio was 1.9 or wider. That threshold was set when the frame was
   2:1. At 16:9 — 1.78 — the class stopped being added and the full overlay came
   back onto a frame that had got SHORTER, which is the worst of both. The gate
   is gone: a landscape banner on a phone is short at every ratio this theme
   allows, so the compact overlay is simply what a phone gets.

   POSITION MATTERS. Dropping the `.hero--wide` prefix also dropped a level of
   specificity, so this block has to sit AFTER .hero__content, .hero__kicker,
   .hero__title, .hero__text and .hero__actions rather than before them. Left up
   near .hero__track where it used to be, every declaration here lost the tie to
   the base rule it was meant to override, and the eyebrow stayed on screen.

   A container query was the obvious tool and did not work: `container-type:
   size` on an element whose height comes from `aspect-ratio` is a cyclic
   dependency, and the query never matched. */
@media (max-width: 767px) {
	.hero__kicker,
	.hero__text { display: none; }

	.hero__title {
		font-size: clamp(1.0625rem, 0.85rem + 1.6vw, 1.375rem);
		margin-block-end: var(--space-2);
		max-inline-size: 22ch;
	}

	/* Inline, so a two-clause headline stays on one or two short lines instead
	   of forcing a third. */
	.hero__title em { display: inline; }

	.hero__content { padding: var(--space-3) var(--space-4) var(--space-5); }

	.hero__actions .btn {
		--btn-height: 2.5rem;
		--btn-padding: var(--space-4);
		font-size: var(--text-small);
	}
}

/* ── Controls ────────────────────────────────────────────────────────────── */

.hero__controls {
	position: absolute;
	z-index: 2;
	inset-block-end: var(--space-4);
	inset-inline: var(--space-4);
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-3);
}

@media (min-width: 900px) {
	.hero__controls {
		inset-inline-start: auto;
		inset-inline-end: var(--space-8);
		inset-block-end: var(--space-8);
		justify-content: flex-end;
	}
}

.hero__arrow {
	display: none;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	place-items: center;
	border-radius: 50%;
	background-color: rgb(255 255 255 / 0.16);
	backdrop-filter: blur(8px);
	border: 1px solid rgb(255 255 255 / 0.28);
	color: var(--neutral-0);
	transition: background-color var(--duration-fast) var(--ease);
}

/* Arrows are a pointer affordance. Touch swipes, and two extra 44px targets on
   a phone would crowd the CTA sitting just above them. */
@media (hover: hover) and (pointer: fine) {
	.hero__arrow { display: grid; }
	.hero__arrow:hover { background-color: rgb(255 255 255 / 0.3); }
}

.hero__arrow svg { inline-size: 1.125rem; block-size: 1.125rem; }

.hero__dots {
	display: flex;
	align-items: center;
	/* The dots carry their own hit padding now, so the visual gap comes from
	   that rather than from a gap between 4px bars. */
	gap: 0;
	/* Cancel the padding on the outer edges so the row still lines up with
	   whatever sits beside it. */
	margin-inline: calc(-1 * var(--space-2));
}

/* No pagination on desktop.
   ----------------------------------------------------------------------------
   The banner advances on its own timer and can be dragged or stepped with the
   arrows, so a row of dots was a third control for something already handled
   twice — and on a wide banner it read as leftover UI in the corner.

   It stays on touch, where there are no arrows and the dots are the only thing
   telling the visitor there is more than one banner at all. */
@media (min-width: 900px) {
	.hero__dots { display: none; }
}

/* Bars, not dots — they read as progress through a set rather than as
   decoration, and they give the active state somewhere to grow into. */
/* Bars, not dots — they read as progress through a set rather than as
   decoration, and they give the active state somewhere to grow into.

   The BAR is 4px; the BUTTON is 44px tall. The padding is transparent and
   `background-clip: content-box` keeps the fill off it, so the control is a
   proper touch target while still looking like a hairline. These are the
   mobile-only control — there are no arrows at this width — so a 4px hit area
   meant the one affordance saying "there are more banners" was essentially
   unhittable. */
.hero__dot {
	inline-size: 1.5rem;
	block-size: 4px;
	box-sizing: content-box;
	padding-block: 20px;
	padding-inline: var(--space-1);
	border: none;
	border-radius: var(--radius-pill);
	background-color: rgb(255 255 255 / 0.4);
	background-clip: content-box;
	cursor: pointer;
	transition: inline-size var(--duration-base) var(--ease),
	            background-color var(--duration-base) var(--ease);
}

.hero__dot:hover { background-color: rgb(255 255 255 / 0.7); background-clip: content-box; }

.hero__dot.is-active {
	inline-size: 2.75rem;
	background-color: var(--brand);
	background-clip: content-box;
}

/* ── Motion off ──────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.hero__slide,
	.hero__dot,
	.hero__arrow {
		transition: none;
	}

	.hero__slide { scale: 1; }
}
/* ============================================================================
   EDITORIAL BREAK
   ----------------------------------------------------------------------------
   An asymmetric campaign split that interrupts the run of product sections.
   The copy sits in a soft tinted panel that overlaps the photograph on desktop,
   which is what stops it reading as "image on one side, text on the other" —
   the overlap is the composition.
   ========================================================================== */

.story {
	position: relative;
	display: grid;
	gap: var(--space-5);
}

@media (min-width: 900px) {
	.story {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		align-items: center;
	}
}

.story__media {
	overflow: hidden;
	border-radius: var(--radius-2xl);
	background: linear-gradient(168deg, var(--blue-50) 0%, var(--neutral-50) 70%);
	aspect-ratio: 4 / 3;
}

@media (min-width: 900px) {
	.story__media {
		grid-column: 1 / span 8;
		/* Explicit row REQUIRED. The copy panel below is placed explicitly into
		   row 1, which makes auto-placement skip past it and drop this image
		   into row 2 — the overlap silently became a stack. */
		grid-row: 1;
		aspect-ratio: 16 / 10;
	}
}

.story__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	transition: transform 900ms var(--ease-out);
}

@media (hover: hover) {
	.story:hover .story__media img { transform: scale(1.03); }
}

.story__copy {
	background-color: var(--surface);
	border-radius: var(--radius-xl);
	padding: var(--space-6);
}

@media (min-width: 900px) {
	.story__copy {
		/* Overlaps the photograph by two columns. */
		grid-column: 7 / span 6;
		grid-row: 1;
		z-index: 1;
		padding: var(--space-10);
		box-shadow: var(--shadow-lg);
	}
}

.story__kicker {
	font-size: var(--text-caption);
	font-weight: var(--weight-semibold);
	color: var(--text-link);
	margin-block-end: var(--space-3);
}

.story__title {
	font-size: var(--text-h1);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-heading);
	line-height: 1.3;
	margin-block-end: var(--space-4);
}

.story__text {
	color: var(--text-muted);
	line-height: var(--leading-normal);
	margin-block-end: var(--space-6);
	max-inline-size: 42ch;
}

/* ============================================================================
   CATEGORY MOSAIC
   ----------------------------------------------------------------------------
   Asymmetric by design. The brief for this page was explicitly "do not build
   eight identical heading → four cards sections", and category browse is the
   right place to break the grid: it is the first thing a visitor does, and a
   feature tile gives that moment a focal point.

   On phones it degrades to the same swipeable rail the product sections use —
   a mosaic at 390px is just six small squares, which is worse than a rail.
   ========================================================================== */

.cat-mosaic {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 68%;
	gap: var(--space-3);
	/* Rail behaviour on small screens. */
	overflow-x: auto;
	/* Proximity for the same reason as .rail — mandatory snapping on a mosaic
	   that also scrolls the page vertically past it fights the gesture. */
	scroll-snap-type: x proximity;
	scrollbar-width: none;
	margin-inline: calc(var(--gutter) * -1);
	padding-inline: var(--gutter);
	padding-block-end: var(--space-2);
}

.cat-mosaic::-webkit-scrollbar { display: none; }

.cat-mosaic > * { scroll-snap-align: start; }

@media (min-width: 768px) {
	.cat-mosaic {
		grid-auto-flow: row;
		grid-template-columns: repeat(4, minmax(0, 1fr));
		grid-auto-rows: 1fr;
		gap: var(--space-4);
		overflow: visible;
		margin-inline: 0;
		padding-inline: 0;
	}

	/* The feature tile: two columns wide and two rows tall, so it is the
	   obvious entry point without needing a label to say so. */
	.cat-mosaic > :first-child {
		grid-column: span 2;
		grid-row: span 2;
	}

	/* Tiles fill their grid cell rather than carrying their own aspect ratio —
	   that is what lets the feature tile be genuinely taller than the rest.
	   The row height is set by the card, so it stays correct whether the tile
	   holds a photograph or the branded placeholder. */
	.cat-mosaic .cat-card { min-block-size: 13rem; }
	.cat-mosaic .cat-card__media {
		aspect-ratio: auto;
		block-size: 100%;
		min-block-size: inherit;
	}
	.cat-mosaic > :first-child { min-block-size: 27rem; }
}

/* ============================================================================
   CATEGORY CARD
   ========================================================================== */

/* The label sits ON the image under a bottom scrim, with a circular arrow
   button in the opposite corner. This is the Benis category tile and it is
   doing real work: the scrim gives the name guaranteed contrast over any
   photograph, and the arrow makes the tile read as something you enter rather
   than a caption you read. Labels set underneath were tried and left the grid
   looking like an unstyled archive listing.

   The scrim is what makes arbitrary photography safe here — it does not
   require the source images to be dark at the bottom, it makes them dark. */
.cat-card {
	display: block;
	position: relative;
	overflow: hidden;
	border-radius: var(--radius-media);
	background: linear-gradient(168deg, var(--blue-50) 0%, var(--neutral-50) 64%);
}

.cat-card__media {
	aspect-ratio: var(--ratio-product);
	overflow: hidden;
}

.cat-card__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	transition: transform 600ms var(--ease-out);
}

/* The branded placeholder is a fixed-size illustration, not photography.
   Letting it fill the feature tile scaled one shoe to 500px tall and made the
   mosaic look broken; it is contained and capped instead, so an unphotographed
   category still reads as a tidy branded tile at any cell size. */
/* Same reasoning as the product card's placeholder: the asset is a finished
   tile with its own ground, so it covers the cell rather than being inset
   inside it and drawing a panel within a panel. */
.cat-card__img--placeholder {
	object-fit: cover;
}

@media (hover: hover) {
	.cat-card:hover .cat-card__media img { transform: scale(1.04); }
}

/* Scrim + label, anchored to the bottom of the plate. */
.cat-card__label {
	position: absolute;
	inset-block-end: 0;
	inset-inline: 0;
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--space-2);
	padding: var(--space-5) var(--space-4) var(--space-4);
	background: linear-gradient(
		to top,
		rgb(15 27 42 / 0.88) 0%,
		rgb(15 27 42 / 0.45) 55%,
		transparent 100%
	);
	font-size: var(--text-label);
	font-weight: var(--weight-bold);
	line-height: var(--leading-tight);
	color: var(--text-inverse);
}

.cat-card__count {
	display: block;
	font-size: var(--text-caption);
	font-weight: var(--weight-regular);
	color: rgb(255 255 255 / 0.75);
	margin-block-start: var(--space-1);
}

/* The circular arrow — white puck by default, filling with the brand blue on
   engagement so the colour appears as a reward for interaction. */
.cat-card__go {
	flex: 0 0 auto;
	inline-size: 2.25rem;
	block-size: 2.25rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background-color: var(--neutral-0);
	color: var(--neutral-900);
	transition: background-color var(--duration-base) var(--ease),
	            transform var(--duration-base) var(--ease);
}

.cat-card__go svg { inline-size: 1rem; block-size: 1rem; }

.cat-card:hover .cat-card__go,
.cat-card:focus-visible .cat-card__go {
	background-color: var(--brand);
	color: var(--text-on-brand);
	transform: translateX(-0.125rem);
}

html[dir="ltr"] .cat-card:hover .cat-card__go { transform: translateX(0.125rem); }

/* ============================================================================
   SERVICE / TRUST STRIP
   ----------------------------------------------------------------------------
   Four soft cards with brand-blue icons, sitting directly under the hero. This
   is a Benis fixture, not decoration: sizing, exchange and authenticity are the
   objections that stop an Iranian shoe purchase online, and answering them
   above the first product is the point. Stripping it to bare rules and grey
   icons made it read as a footnote, which is the one thing it must not be.
   ========================================================================== */

.trust-strip {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-3);
}

@media (min-width: 768px) {
	.trust-strip { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Each promise is its own soft card with a brand-tinted icon plate and a
   gradient wash bleeding from the reading edge. The flat grey boxes read as
   placeholders; the wash and the ring give them enough presence to be believed,
   which is the entire job of a trust strip.

   The number is a quiet ordinal in the far corner — it makes four separate
   statements read as one considered set rather than four repeated boxes. */
.trust-strip__item {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--space-3);
	padding: var(--space-4);
	border-radius: var(--radius-lg);
	background:
		linear-gradient(135deg, var(--blue-50) 0%, var(--surface-soft) 58%);
	border: 1px solid var(--neutral-100);
	transition: transform var(--duration-base) var(--ease),
	            box-shadow var(--duration-base) var(--ease),
	            border-color var(--duration-base) var(--ease);
}

@media (hover: hover) {
	.trust-strip__item:hover {
		transform: translateY(-3px);
		border-color: var(--blue-200);
		box-shadow: 0 10px 24px rgb(1 125 178 / 0.12);
	}
}

@media (prefers-reduced-motion: reduce) {
	.trust-strip__item { transition: none; }
	.trust-strip__item:hover { transform: none; }
}

/* The icon sits on a white plate with a soft brand ring, so it reads as a
   pressed seal rather than a bare glyph on a tint. */
.trust-strip__item svg {
	inline-size: 1.25rem;
	block-size: 1.25rem;
	color: var(--brand-active);
	flex-shrink: 0;
	box-sizing: content-box;
	padding: var(--space-3);
	background-color: var(--surface);
	border-radius: var(--radius-md);
	box-shadow: 0 0 0 1px var(--blue-100), 0 2px 6px rgb(1 125 178 / 0.1);
}

@media (min-width: 768px) {
	.trust-strip__item {
		flex-direction: row;
		align-items: center;
	}
}

.trust-strip__item strong {
	display: block;
	font-weight: var(--weight-semibold);
	color: var(--text);
}

.trust-strip__item span { color: var(--text-muted); }

/* ── Phones: ONE panel, four quadrants ───────────────────────────────────────
   The desktop treatment is four stacked cards, each with a 44px icon plate over
   its own title and description. Reflowed onto a 390px screen that came to
   ~350px of viewport — a third of the phone spent on four sentences the shopper
   has not asked about yet, with the first product pushed entirely below the
   fold.

   Four floating boxes is also the wrong gesture at this size: it is the same
   promise repeated four times, competing with the campaign banner directly
   above it. So on mobile the four cards become one quiet panel divided into
   quadrants by hairlines, and each promise becomes a single compact row —
   icon chip beside the text, not stacked over it.

   ~350px → ~124px, with nothing removed: both lines of every promise survive,
   because "ارسال رایگان" without "خرید بالای ۲ میلیون" is a claim missing its
   condition. Desktop is untouched. */
@media (max-width: 767px) {
	.trust-strip {
		gap: 0;
		background-color: var(--surface);
		border: 1px solid var(--neutral-100);
		border-radius: var(--radius-lg);
		overflow: hidden;
		box-shadow: var(--shadow-xs);
	}

	.trust-strip__item {
		flex-direction: row;
		align-items: center;
		gap: var(--space-3);
		padding: var(--space-3);
		background: none;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		transform: none;
		/* The quadrant rules. `inline-start` is the shared edge for the second
		   item of each row in BOTH directions — in RTL that is its right side,
		   in LTR its left — so the grid divides correctly without a dir hack.
		   The odd children are always the outer column and drop theirs. */
		border-inline-start: 1px solid var(--neutral-100);
		border-block-start: 1px solid var(--neutral-100);
	}

	.trust-strip__item:nth-child(odd)      { border-inline-start: 0; }
	.trust-strip__item:nth-child(-n + 2)   { border-block-start: 0; }

	/* Tinted chip rather than a white plate — the panel it now sits on is
	   already white, so a white plate would have nothing to lift off. */
	.trust-strip__item svg {
		inline-size: 1rem;
		block-size: 1rem;
		padding: var(--space-2);
		background-color: var(--surface-brand);
		border-radius: var(--radius-sm);
		box-shadow: none;
	}

	.trust-strip__item > div { min-inline-size: 0; }

	.trust-strip__item strong {
		font-size: var(--text-small);
		line-height: var(--leading-tight);
	}

	.trust-strip__item span {
		display: block;
		font-size: var(--text-caption);
		line-height: var(--leading-snug);
	}
}

/* ============================================================================
   RAIL CONTROLS
   ========================================================================== */

.rail-nav { display: none; }

/* Arrow controls are a pointer affordance; touch users swipe, and the peeking
   next card already signals that the rail scrolls. */
@media (hover: hover) and (pointer: fine) {
	.rail-nav {
		display: flex;
		gap: var(--space-2);
	}
}

/* ============================================================================
   CONTENT PAGES — about, contact, FAQ, generic page, blog post
   ========================================================================== */

/* .page-head lives in 04-components.css and is not restated here. This file
   used to carry a second copy — same padding, same title size, and a --space-2
   sub margin that quietly overrode the component's --space-3. Two definitions
   of one component in two files is how the padding above every content page
   ends up being edited in the wrong one. */

.entry-content {
	max-inline-size: var(--container-text);
	line-height: var(--leading-normal);
}

.entry-content > * + * { margin-block-start: var(--space-4); }

.entry-content :is(h2, h3) {
	margin-block-start: var(--space-8);
	margin-block-end: var(--space-3);
}

.entry-content img { border-radius: var(--radius-md); }

/* ============================================================================
   404
   ========================================================================== */

.error-404 {
	text-align: center;
	padding-block: var(--space-20);
	max-inline-size: 32rem;
	margin-inline: auto;
}

.error-404__code {
	font-size: clamp(3rem, 2rem + 5vw, 5rem);
	font-weight: var(--weight-bold);
	line-height: 1;
	color: var(--blue-200);
}

.error-404__title {
	font-size: var(--text-h2);
	margin-block: var(--space-4) var(--space-2);
}

.error-404__text { color: var(--text-muted); margin-block-end: var(--space-6); }

/* ============================================================================
   ABOUT
   ----------------------------------------------------------------------------
   Editorial, but still Benis: framed media with an expressive radius rather
   than full-bleed photography, soft rounded panels, cyan as the accent. The
   brief was never "make it look like a fashion magazine" — it is the same
   storefront, writing about itself.
   ========================================================================== */

.about-hero {
	display: grid;
	gap: var(--space-8);
	align-items: center;
}

@media (min-width: 900px) {
	.about-hero {
		grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
		gap: var(--space-16);
	}
}

.about-hero__title {
	font-size: var(--text-display);
	line-height: var(--leading-tight);
	letter-spacing: var(--tracking-heading);
}

.about-hero__lead {
	margin-block-start: var(--space-5);
	font-size: var(--text-body-lg);
	line-height: var(--leading-normal);
	color: var(--text-muted);
	max-inline-size: 44ch;
}

.about-hero__cta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-block-start: var(--space-8);
}

/* radius-2xl, the most expressive step on the scale — the same one the campaign
   hero uses. This is the other place on the site where a single image carries
   the brand. */
.about-hero__media {
	border-radius: var(--radius-2xl);
	overflow: hidden;
	background-color: var(--surface-brand);
	aspect-ratio: 4 / 5;
}

.about-hero__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/* ── Pillars ─────────────────────────────────────────────────────────────── */

.about-pillars {
	display: grid;
	gap: var(--space-4);
}

@media (min-width: 768px) {
	.about-pillars { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.about-pillar {
	position: relative;
	padding: var(--space-6);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	background-color: var(--surface);
	overflow: hidden;
}

/* A quiet ordinal in the far corner. It makes three separate cards read as one
   numbered set without adding a heading to each. */
.about-pillar__num {
	position: absolute;
	inset-block-start: var(--space-4);
	inset-inline-end: var(--space-5);
	font-size: var(--text-h1);
	font-weight: var(--weight-bold);
	line-height: 1;
	color: var(--neutral-100);
}

.about-pillar__icon {
	display: grid;
	place-items: center;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	border-radius: var(--radius-md);
	background-color: var(--surface-brand);
	color: var(--blue-700);
	margin-block-end: var(--space-4);
}

.about-pillar__icon svg { inline-size: 1.25rem; block-size: 1.25rem; }

.about-pillar__title {
	font-size: var(--text-h3);
	margin-block-end: var(--space-2);
}

.about-pillar__text {
	color: var(--text-muted);
	line-height: var(--leading-normal);
	font-size: var(--text-label);
}

/* ── Numbers ─────────────────────────────────────────────────────────────── */

/* A CARD, not a bare band.
   The numbers used to sit on a `.section--soft` background, and that band went
   away when the canvas turned warm and the inverted white band was retired — so
   the statistics were left as loose type floating between two carded sections,
   with nothing holding them together. They carry their own surface now, which
   is also what the pillars and the steps above them do. */
.about-stats {
	display: grid;
	gap: var(--space-6);
	grid-template-columns: repeat(2, minmax(0, 1fr));
	text-align: center;
	padding: var(--space-8) var(--space-6);
	border-radius: var(--radius-xl);
	background-color: var(--surface);
	border: 1px solid var(--border);
}

@media (min-width: 768px) {
	.about-stats { grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); }
}

/* Reversed in source order — <dd> before <dt> — so the number is announced with
   its label rather than before it, and so the visual hierarchy (big number,
   small caption) needs no reordering in CSS. */
.about-stats__num {
	font-size: var(--text-display);
	font-weight: var(--weight-bold);
	line-height: 1;
	color: var(--blue-700);
	font-variant-numeric: proportional-nums;
}

.about-stats__label {
	margin-block-start: var(--space-2);
	font-size: var(--text-label);
	color: var(--text-muted);
}

/* ── Story ───────────────────────────────────────────────────────────────── */

.about-story {
	position: relative;
	max-inline-size: var(--container-text);
	margin-inline: auto;
	text-align: center;
}

/* The wordmark's initial, set very large and very pale behind the heading. It
   is decoration that belongs to this brand specifically, which is the only
   kind this page should carry. */
.about-story__mark {
	display: block;
	font-size: clamp(5rem, 3rem + 10vw, 9rem);
	font-weight: var(--weight-bold);
	line-height: 0.8;
	color: var(--blue-50);
	margin-block-end: calc(-1 * var(--space-6));
	user-select: none;
}

.about-story__title {
	font-size: var(--text-h1);
	letter-spacing: var(--tracking-heading);
	margin-block-end: var(--space-5);
}

.about-story__p {
	color: var(--text-muted);
	line-height: var(--leading-loose);
	text-align: start;
}

.about-story__p + .about-story__p { margin-block-start: var(--space-4); }

/* ── Process steps ───────────────────────────────────────────────────────── */

.about-steps {
	display: grid;
	gap: var(--space-4);
}

@media (min-width: 640px) {
	.about-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
	.about-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.about-step {
	padding: var(--space-5);
	border-radius: var(--radius-lg);
	background-color: var(--surface-page);
}

.about-step__num {
	display: block;
	font-size: var(--text-small);
	font-weight: var(--weight-bold);
	color: var(--brand);
	font-variant-numeric: proportional-nums;
}

.about-step__icon {
	display: block;
	color: var(--blue-700);
	margin-block: var(--space-3) var(--space-3);
}

.about-step__icon svg { inline-size: 1.5rem; block-size: 1.5rem; }

.about-step__title {
	font-size: var(--text-body);
	font-weight: var(--weight-semibold);
	margin-block-end: var(--space-2);
}

.about-step__text {
	font-size: var(--text-small);
	color: var(--text-muted);
	line-height: var(--leading-normal);
}

/* ── Trust seals ─────────────────────────────────────────────────────────── */

.about-seals {
	display: grid;
	gap: var(--space-6);
	align-items: center;
	padding: var(--space-8);
	border-radius: var(--radius-xl);
	background-color: var(--surface-soft);
}

@media (min-width: 900px) {
	.about-seals { grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-10); }
}

.about-seals__title { font-size: var(--text-h2); margin-block-end: var(--space-3); }

.about-seals__text {
	color: var(--text-muted);
	line-height: var(--leading-normal);
	max-inline-size: 52ch;
}

/* Three equal slots, so the row keeps its shape whether the shop has one
   licence or three — a single plate floating alone beside a paragraph looks
   like something failed to load. */
.about-seals__marks {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
	gap: var(--space-4);
	align-items: stretch;
}

@media (min-width: 900px) {
	.about-seals__marks { grid-template-columns: repeat(3, minmax(7.5rem, 8.5rem)); }
}

/* The seal HTML comes from the certifying body and cannot be restyled, so the
   plate around it is what does the design work. */
.about-seals__mark {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	padding: var(--space-4);
	border-radius: var(--radius-md);
	background-color: var(--surface);
	text-align: center;
	min-block-size: 8rem;
}

.about-seals__mark img { max-inline-size: 5.5rem; block-size: auto; }

.about-seals__mark span {
	font-size: var(--text-caption);
	color: var(--text-muted);
	line-height: var(--leading-snug);
}

/* ── Administrator-only empty slot ───────────────────────────────────────────
   Dashed, unfilled and visibly not a badge, because it is scaffolding: it shows
   the shop owner that the slot exists and what belongs in it. A shopper never
   sees this — see $benis_show_seal_slots in the template. */
.about-seals__mark--empty {
	background-color: transparent;
	border: 1px dashed var(--border-strong);
	color: var(--text-muted);
}

.about-seals__slot {
	display: grid;
	place-items: center;
	inline-size: 2rem;
	block-size: 2rem;
	border-radius: 50%;
	background-color: var(--surface-soft);
	color: var(--icon-muted);
	font-size: var(--text-body-lg);
	line-height: 1;
}

.about-seals__hint {
	font-size: var(--text-caption);
	color: var(--icon-muted);
	direction: ltr;
}

.about-seals__admin {
	margin-block-start: var(--space-4);
	padding: var(--space-3) var(--space-4);
	border-radius: var(--radius-md);
	background-color: var(--surface-soft);
	border: 1px dashed var(--border-strong);
	font-size: var(--text-small);
	color: var(--text-muted);
	line-height: var(--leading-normal);
}

.about-seals__admin a { color: var(--text-link); text-decoration: underline; }

/* ── Closing CTA ─────────────────────────────────────────────────────────── */

.about-cta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-6);
	padding: var(--space-8);
	border-radius: var(--radius-xl);
	background-color: var(--surface-brand);
}

.about-cta__title {
	font-size: var(--text-h2);
	letter-spacing: var(--tracking-heading);
	color: var(--blue-900);
}

.about-cta__sub {
	margin-block-start: var(--space-2);
	color: var(--neutral-700);
}

/* ============================================================================
   CONTACT
   ----------------------------------------------------------------------------
   No form. The page's whole job is to get someone talking to a human as fast
   as possible, so the phone panel is the loudest thing on it and the messaging
   apps sit right under it. Everything else is supporting detail.
   ========================================================================== */

.contact-grid {
	display: grid;
	gap: var(--space-6);
	align-items: start;
}

@media (min-width: 900px) {
	.contact-grid { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
}

/* ── The call panel ──────────────────────────────────────────────────────────
   The only surface on the page carrying the brand fill, because it is the only
   one that gets an answer in seconds. Dark ink on cyan — the pairing the
   primary CTA uses — so it reads as the page's action, not as a decorative
   band. */
.call-panel {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--space-4);
	padding: var(--space-8);
	border-radius: var(--radius-2xl);
	background-color: var(--brand);
	color: var(--text-on-brand);
}

.call-panel__label {
	font-size: var(--text-label);
	font-weight: var(--weight-medium);
	opacity: 0.8;
}

/* The number IS the content, so it is set at display size and is itself the
   link — on a phone, tapping the number people are already reading is the
   gesture they reach for before they find a button. */
.call-panel__number {
	font-size: clamp(1.75rem, 1.2rem + 2.6vw, 2.75rem);
	font-weight: var(--weight-bold);
	line-height: 1;
	letter-spacing: var(--tracking-heading);
	color: inherit;
	font-variant-numeric: proportional-nums;
}

.call-panel__number:hover { text-decoration: underline; text-underline-offset: 0.15em; }

.call-panel__hours {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-size: var(--text-small);
	opacity: 0.85;
}

.call-panel__hours svg { inline-size: 1rem; block-size: 1rem; }

/* ── Open / closed badge ─────────────────────────────────────────────────────
   A live status, driven by the shop's own support hours against the site
   clock — so it cannot claim someone is answering at 3am.

   The base rules live here rather than beside the modifier by accident: when
   the contact page was rewritten, this block was dropped and only the
   `--onbrand` modifier survived. The badge kept its white plate and lost
   everything else — the dot is a <span>, which is `display: inline` by
   default, and inline boxes ignore width and height, so it collapsed to
   nothing. It looked "fine" because the modifier still painted the pill. */
.open-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding-inline: var(--space-3);
	padding-block: var(--space-1);
	border-radius: var(--radius-pill);
	background-color: var(--success-surface);
	color: var(--green-700);
	font-size: var(--text-small);
	font-weight: var(--weight-medium);
	margin-block-end: var(--space-4);
}

.open-badge__dot {
	inline-size: 0.5rem;
	block-size: 0.5rem;
	border-radius: 50%;
	background-color: currentColor;
	flex-shrink: 0;
}

/* The pulse runs only while someone is genuinely there. A dot that keeps
   breathing after hours is the same lie as a static green one. */
@media (prefers-reduced-motion: no-preference) {
	.open-badge:not(.is-closed) .open-badge__dot {
		animation: benis-pulse 2s var(--ease) infinite;
	}
}

@keyframes benis-pulse {
	0%, 100% { opacity: 1; transform: scale(1); }
	50%      { opacity: 0.45; transform: scale(0.75); }
}

.open-badge.is-closed {
	background-color: var(--surface-sunken);
	color: var(--text-muted);
}

/* On the brand fill the neutral badge surfaces would disappear, so it switches
   to a translucent white plate that works over cyan in both states. */
.open-badge--onbrand {
	background-color: rgb(255 255 255 / 0.9);
	color: var(--green-700);
	margin-block-end: 0;
}

.open-badge--onbrand.is-closed {
	background-color: rgb(255 255 255 / 0.75);
	color: var(--neutral-700);
}

/* ── Messaging channels ──────────────────────────────────────────────────── */

.contact-channels__title {
	font-size: var(--text-h3);
	margin-block-end: var(--space-4);
}

.contact-channels__grid {
	display: grid;
	gap: var(--space-3);
}

@media (min-width: 560px) {
	.contact-channels__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.channel-card {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-4);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	background-color: var(--surface);
	transition: border-color var(--duration-fast) var(--ease),
	            box-shadow var(--duration-fast) var(--ease);
}

.channel-card:hover {
	border-color: var(--brand);
	box-shadow: var(--shadow-sm);
}

/* Each app keeps its own colour on the icon plate. These are the one place in
   the theme where a foreign brand colour is correct: a green WhatsApp tile is
   recognised before the label is read, and neutralising them to house cyan
   would make four identical tiles the eye has to parse word by word. */
.channel-card__icon {
	display: grid;
	place-items: center;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	border-radius: var(--radius-md);
	flex-shrink: 0;
	color: var(--neutral-0);
}

.channel-card__icon svg { inline-size: 1.375rem; block-size: 1.375rem; }

.channel-card__icon--whatsapp  { background-color: #25D366; }
.channel-card__icon--telegram  { background-color: #229ED9; }
.channel-card__icon--instagram { background: linear-gradient(135deg, #F58529, #DD2A7B 55%, #8134AF); }
.channel-card__icon--bale      { background-color: #1F8A4C; }

.channel-card__body { flex: 1 1 auto; min-inline-size: 0; }

.channel-card__body strong {
	display: block;
	font-size: var(--text-label);
	font-weight: var(--weight-semibold);
}

.channel-card__body span {
	display: block;
	font-size: var(--text-small);
	color: var(--text-muted);
	margin-block-start: 0.125rem;
}

.channel-card__go {
	inline-size: 1rem;
	block-size: 1rem;
	color: var(--icon-muted);
	flex-shrink: 0;
	transition: transform var(--duration-fast) var(--ease);
}

.channel-card:hover .channel-card__go { transform: translateX(-3px); }

/* ── Facts row ───────────────────────────────────────────────────────────── */

.contact-facts-row {
	display: grid;
	gap: var(--space-5);
	padding: var(--space-6);
	border-radius: var(--radius-lg);
	background-color: var(--surface);
	border: 1px solid var(--border);
}

@media (min-width: 768px) {
	.contact-facts-row { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-6); }
}

.contact-fact {
	display: flex;
	align-items: flex-start;
	gap: var(--space-3);
	font-size: var(--text-small);
	color: var(--text-muted);
	line-height: var(--leading-normal);
}

.contact-fact svg {
	inline-size: 1.125rem;
	block-size: 1.125rem;
	color: var(--brand);
	flex-shrink: 0;
	margin-block-start: 0.125rem;
}

.contact-fact strong {
	display: block;
	color: var(--text);
	font-weight: var(--weight-semibold);
	margin-block-end: 0.125rem;
}

/* ── FAQ band ────────────────────────────────────────────────────────────── */

.contact-faq-band {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-6);
	padding: var(--space-8);
	border-radius: var(--radius-xl);
	background-color: var(--surface-brand);
}

.contact-faq-band__title {
	font-size: var(--text-h2);
	letter-spacing: var(--tracking-heading);
	color: var(--blue-900);
}

.contact-faq-band__sub {
	margin-block-start: var(--space-2);
	color: var(--neutral-700);
	max-inline-size: 48ch;
}

/* ============================================================================
   FAQ
   ========================================================================== */

.faq {
	display: grid;
	gap: var(--space-10);
	max-inline-size: 52rem;
	margin-inline: auto;
}

.faq__group-title {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	font-size: var(--text-h3);
	margin-block-end: var(--space-4);
}

.faq__group-title svg {
	inline-size: 1.25rem;
	block-size: 1.25rem;
	color: var(--brand);
}

/* The accordion's own trigger typography is set for a control; inside an <h3>
   here it should still read as a question, so the heading resets its own
   default margins and weight rather than the trigger fighting them. */
.faq .accordion h3 { font-size: inherit; font-weight: inherit; margin: 0; }

.faq__footer {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-5);
	max-inline-size: 52rem;
	margin-inline: auto;
	margin-block-start: var(--space-10);
	padding: var(--space-8);
	border-radius: var(--radius-xl);
	background-color: var(--surface-soft);
}

.faq__footer-title { font-size: var(--text-h3); }

.faq__footer-sub {
	margin-block-start: var(--space-2);
	color: var(--text-muted);
	font-size: var(--text-label);
}

/* The search field on the 404 — the most useful control on a dead end, since
   someone who mistyped a URL usually still knows what they wanted. */
.error-404__search {
	display: flex;
	gap: var(--space-2);
	margin-block: var(--space-6);
	text-align: start;
}

.error-404__search .input { flex: 1 1 auto; min-inline-size: 0; }
.error-404__search .btn { flex-shrink: 0; }

/* The code is set behind the heading rather than above it, so the page reads
   as a sentence with a watermark and not as an error dump. */
.error-404__code {
	margin-block-end: calc(-1 * var(--space-6));
	user-select: none;
}

/* ============================================================================
   MAGAZINE — post card, lead article, grid
   ----------------------------------------------------------------------------
   One card, used by the archive, search results and any related rail. An
   article that looks different in two places reads as two different things.
   ========================================================================== */

.post-grid {
	display: grid;
	gap: var(--space-6);
	grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}

.post-card {
	display: flex;
	flex-direction: column;
	background-color: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	overflow: hidden;
	transition: border-color var(--duration-fast) var(--ease),
	            box-shadow var(--duration-fast) var(--ease);
}

.post-card:hover {
	border-color: var(--border-strong);
	box-shadow: var(--shadow-sm);
}

/* 3:2, not the product card's 3:4. An article's image is a landscape
   photograph or a graphic; forcing it into the portrait plate the catalogue
   uses crops the subject out of most of them. */
.post-card__media {
	display: block;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	background-color: var(--surface-soft);
}

.post-card__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	transition: transform var(--duration-slow) var(--ease-out);
}

@media (hover: hover) {
	.post-card:hover .post-card__media img { transform: scale(1.04); }
}

.post-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	padding: var(--space-5);
	flex: 1 1 auto;
}

.post-card__cat {
	font-size: var(--text-caption);
	font-weight: var(--weight-semibold);
	color: var(--blue-800);
}

.post-card__title {
	font-size: var(--text-body-lg);
	line-height: var(--leading-tight);
}

.post-card__title a:hover { color: var(--text-link); }

.post-card__excerpt {
	font-size: var(--text-small);
	color: var(--text-muted);
	line-height: var(--leading-normal);
	flex: 1 1 auto;
}

.post-card__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	font-size: var(--text-caption);
	color: var(--text-muted);
	margin-block-start: var(--space-1);
}

/* ── Lead article ────────────────────────────────────────────────────────── */

.post-lead {
	display: grid;
	gap: var(--space-6);
	margin-block-end: var(--space-10);
	align-items: center;
}

@media (min-width: 900px) {
	.post-lead {
		grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
		gap: var(--space-10);
	}
}

.post-lead__media {
	display: block;
	aspect-ratio: 3 / 2;
	border-radius: var(--radius-xl);
	overflow: hidden;
	background-color: var(--surface-soft);
}

.post-lead__media img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.post-lead__body { display: flex; flex-direction: column; gap: var(--space-3); align-items: flex-start; }

.post-lead__title {
	font-size: var(--text-h1);
	line-height: var(--leading-tight);
	letter-spacing: var(--tracking-heading);
}

.post-lead__title a:hover { color: var(--text-link); }

.post-lead__excerpt {
	color: var(--text-muted);
	line-height: var(--leading-normal);
}
