/**
 * Boutique + WooCommerce category archives — 0.2.0-dev.14.
 *
 * Enqueued only on is_shop() / is_product_category() / is_product_tag()
 * (see inc/shop.php), after assets/css/woocommerce.css — this file only
 * adds what that one doesn't already cover: the intro/hub area, sub-
 * category cards, the filter sidebar/drawer, product badges/brand, and
 * the empty state. The header/mega-menus/footer/mobile bar this page
 * shares with the rest of the site are untouched by this file.
 */

/* =========================================================
   Page header — breadcrumb (Storefront's own, real) + title (WooCommerce's
   own woocommerce_products_header()) restyled to match the homepage's own
   typographic language, never rebuilt.
   ========================================================= */
.woocommerce-breadcrumb {
	color: var(--color-neutral);
	font-family: var(--font-nav);
	font-size: .82rem;
	margin: var(--space-6) 0 var(--space-2);
	padding: 0 max(var(--space-6), calc((100% - var(--container-max)) / 2));
}

.woocommerce-breadcrumb a {
	color: var(--color-neutral);
}

@media (hover: hover) and (pointer: fine) {
	.woocommerce-breadcrumb a:hover {
		color: var(--color-gold-hover);
	}
}

/* 0.2.0-dev.20: back to the theme's own standard container gutter (the
   same formula .woocommerce-breadcrumb/.cristaline-shop-layout already
   use) instead of a bespoke 1000px cap — 0.2.0-dev.19's narrower column
   was reported as making the cards below feel cramped/too small. Title,
   description and the subcategory-card grid below all live inside this
   SAME real <header> (confirmed 0.2.0-dev.15: woocommerce_archive_description
   fires from loop/header.php, inside <header class="woocommerce-products-
   header">, unconditionally, right after the real <h1>) — the title stays
   text-align:center and the card row below centers itself independently
   (flexbox, see .cristaline-shop-subcats) within this same wide box, so
   both share the same visual center without needing the box itself to be
   narrow. */
.woocommerce-products-header {
	padding: 0 max(var(--space-6), calc((100% - var(--container-max)) / 2));
}

.woocommerce-products-header__title.page-title {
	color: var(--color-ink);
	font-family: var(--font-heading);
	font-size: clamp(1.75rem, 1.4rem + 1.5vw, 2.5rem);
	font-weight: 500;
	margin: 0 0 var(--space-4);
	text-align: center;
}

.term-description {
	/* No horizontal padding here: 0.2.0-dev.15 confirmed this always renders
	   inside WooCommerce's own <header class="woocommerce-products-header">
	   above, which already supplies the container gutter — an own copy here
	   would double it, same reasoning as .cristaline-shop-intro/-hub/-subcats
	   below. margin-inline:auto centers the block itself within that column
	   (its own max-width:60ch is usually narrower than the column). */
	color: var(--color-neutral);
	font-family: var(--font-body);
	margin: 0 auto var(--space-6);
	max-width: 60ch;
	text-align: center;
}

/* =========================================================
   Boutique root — kicker + short intro, above the Femme/Homme/Enfants
   hub cards. Same shared kicker class the homepage already uses
   (.cristaline-section__kicker, assets/css/homepage.css) — not
   redeclared here, this file just supplies the layout around it.
   ========================================================= */
.cristaline-shop-intro {
	/* Horizontal gutter intentionally omitted — see .term-description above,
	   same reasoning: always nested inside .woocommerce-products-header. */
	padding-top: var(--space-6);
	text-align: center;
}

.cristaline-shop-intro .cristaline-section__kicker {
	text-align: center;
}

.cristaline-shop-intro__text {
	color: var(--color-neutral);
	font-family: var(--font-body);
	margin: 0 auto;
	max-width: 60ch;
}

/* =========================================================
   Hub cards (Boutique root: Femme / Homme / Enfants) — same visual
   language as the homepage's "Nos univers" cards (client's own explicit
   ask), reusing the same 3 bundled photos.
   ========================================================= */
.cristaline-shop-hub {
	/* Horizontal gutter intentionally omitted — see .term-description above. */
	display: grid;
	gap: var(--space-6);
	grid-template-columns: 1fr;
	padding: var(--space-8) 0;
}

@media (min-width: 768px) {
	.cristaline-shop-hub {
		grid-template-columns: repeat(3, 1fr);
	}
}

.cristaline-shop-hub__card,
.cristaline-shop-hub__card:visited,
.cristaline-shop-hub__card:hover,
.cristaline-shop-hub__card:focus-visible {
	color: var(--color-ink);
	display: block;
	transition: transform 180ms ease;
}

.cristaline-shop-hub__card:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 4px;
}

.cristaline-shop-hub__card:active {
	transform: scale(.985);
}

.cristaline-shop-hub__media {
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-card);
	display: block;
	margin-bottom: var(--space-3);
	overflow: hidden;
}

.cristaline-shop-hub__media img {
	aspect-ratio: 4 / 3.4;
	display: block;
	height: auto;
	object-fit: cover;
	width: 100%;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-shop-hub__media img {
		transition: transform 500ms ease;
	}

	.cristaline-shop-hub__card:hover .cristaline-shop-hub__media img {
		transform: scale(1.015);
	}
}

.cristaline-shop-hub__label {
	display: block;
	font-family: var(--font-heading);
	font-size: 1.25rem;
	font-weight: 600;
	text-align: center;
}

/* =========================================================
   Sub-category cards — every level that shows a card grid (Femme/Homme's
   own Vêtements/Chaussures/Accessoires, Fille/Garçon/Bébé/Bébé fille/Bébé
   garçon and their own children, Enfants' own 4 profiles, and any deeper
   branch, e.g. Bébé fille > Vêtements' own 6 detailed categories).
   Deliberately typographic (no photo) — no dedicated photography exists
   for these levels.

   0.2.0-dev.20: rebuilt on flexbox instead of the doubled-fine-track CSS
   Grid technique from 0.2.0-dev.19 — that system was correct on paper (hand-
   verified against every example the client gave) but produced smaller,
   near-square cards in real rendering, and 4 rounds running the local
   browser tool has been unable to confirm why. Rather than keep debugging
   a technique this project can't currently verify live, this is a simpler,
   long-established, harder-to-get-subtly-wrong approach: a fixed card
   width (never based on its own text, never stretched to fill a row) plus
   `flex-wrap` + `justify-content: center`, which is a NATIVE browser
   behaviour that centers ANY incomplete last row — full or partial, any
   real count — with zero custom CSS logic and no :nth-child() arithmetic
   to get wrong. Card width (260px) is deliberately wider/more "confortable"
   than 0.2.0-dev.19's computed ~220px, matching the client's own "revenir
   à des cartes plus proches du rendu précédent" ask. */
.cristaline-shop-subcats {
	/* Horizontal gutter intentionally omitted — see .term-description above. */
	display: flex;
	flex-wrap: wrap;
	gap: 24px;
	justify-content: center;
	padding-bottom: 0;
	padding-top: var(--space-8); /* ~48px below the title together with its own margin-bottom (16px). */
}

.cristaline-shop-subcats__card,
.cristaline-shop-subcats__card:visited,
.cristaline-shop-subcats__card:hover,
.cristaline-shop-subcats__card:focus-visible {
	align-items: center;
	background-color: var(--color-bg-alt);
	border: 1px solid var(--color-accent-soft);
	border-radius: var(--radius-md);
	color: var(--color-ink);
	display: flex;
	flex: 0 0 260px; /* fixed width — never grows to fill a partial row, never shrinks for its own text. */
	justify-content: center;
	max-width: 100%; /* safety net: never wider than its own viewport on an extreme-narrow screen. */
	min-height: 96px;
	padding: var(--space-4);
	text-align: center;
	transition: border-color 180ms ease, box-shadow 180ms ease;
}

.cristaline-shop-subcats__card:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-shop-subcats__card:hover {
		border-color: var(--color-gold);
		box-shadow: var(--shadow-card);
	}
}

.cristaline-shop-subcats__card:active {
	transform: scale(.985);
}

.cristaline-shop-subcats__label {
	font-family: var(--font-nav);
	font-size: .95rem;
	font-weight: 600;
	letter-spacing: .02em;
	text-transform: uppercase;
}

/* =========================================================
   2-column layout — filter sidebar + main column. Sidebar is a real,
   always-visible column from 1024px up; below that it collapses into
   an off-canvas drawer (assets/js/shop-filters.js drives the open/close,
   this file only draws the two states).
   ========================================================= */
.cristaline-shop-layout {
	/* 0.2.0-dev.21: padding-top added — on a leaf category (straight to
	   filters/products, no subcategory cards above), the only spacing
	   between the title and the result-count/ordering row was the title's
	   own 16px margin-bottom, noticeably tighter than the ~48px rhythm used
	   everywhere else on this page (e.g. title → subcategory cards). Matches
	   that same var(--space-8) rhythm instead of leaving it as a one-off. */
	display: block;
	padding: var(--space-8) max(var(--space-6), calc((100% - var(--container-max)) / 2)) var(--space-16);
}

/* 0.2.0-dev.29 — Femme/Homme/Enfants only (body.cristaline-shop-genre-root,
   set by inc/shop.php scoped to exactly those 3 real genre root archives):
   the gap between the Vêtements/Chaussures/Accessoires cards row above and
   this layout's own filters/catalogue start, trimmed from var(--space-8)
   (32px) to var(--space-6) (24px) — a 25% reduction, inside the client's
   own requested 20-30% range — reusing an existing token rather than a new
   arbitrary value. Leaf categories (no cards above, a different visual
   rhythm entirely — see the 0.2.0-dev.21 comment above) keep the full
   var(--space-8), untouched. Only padding-top changes here — card size,
   width, alignment, the title, the product grid and every product's own
   internal spacing are all unaffected (defined elsewhere, none of these
   selectors touch them). */
body.cristaline-shop-genre-root .cristaline-shop-layout {
	padding-top: var(--space-6);
}

@media (min-width: 1024px) {
	.cristaline-shop-layout {
		display: grid;
		gap: var(--space-8);
		grid-template-columns: 280px 1fr;
		align-items: start;
	}
}

.cristaline-shop-main {
	min-width: 0; /* real grid-blowout guard — a long product name/price must never force this column wider than its own track. */
}

/* 0.2.0-dev.24: the filter sidebar and the main column are already the same
   grid row (align-items:start on .cristaline-shop-layout), so their own
   BOXES already start level — but the sidebar panel's own padding
   (var(--space-6), 24px, all sides) pushes its first visible line down
   further than the sort bar's tiny native Storefront padding (`.327em`,
   ~5px) does for the main column, leaving a ~19px visual mismatch at the
   top even though the boxes themselves are aligned. Matches the panel's
   own inset instead of shrinking the panel's padding (a deliberate,
   card-like breathing room this round doesn't ask to change). */
@media (min-width: 1024px) {
	.cristaline-shop-main {
		padding-top: calc(var(--space-6) - .327em);
	}
}

/* Result count + sort — WooCommerce's own real markup
   (.woocommerce-result-count / .woocommerce-ordering), just laid out as
   one row and the native <select> restyled to match the theme instead of
   the browser's own default control. */
/* 0.2.0-dev.23: Storefront's own real assets/css/woocommerce/woocommerce.css
   ships `.woocommerce-result-count{float:left;...}` AND
   `.woocommerce-ordering{float:left;margin-right:1em;...}` — genuinely the
   correct starting point for this round's own "tri et nombre de résultats
   alignés à gauche" ask (two floats, same direction, naturally sit side by
   side on one row). A PREVIOUS, incomplete attempt here reset only
   `.woocommerce-result-count`'s float to `none` at 600px+ (turning it into
   a full-width block, on its own line, below the still-floated ordering
   dropdown) while leaving a `::before` clearfix that doesn't actually clear
   anything (a real clearfix needs `::after`, and floats don't visually
   detach from following elements via `::before` in the first place) — the
   two elements ended up looking unrelated instead of forming one toolbar
   row. Removed that incomplete pair; kept Storefront's own working default
   for desktop, added a genuine, explicit mobile stack below. */
.woocommerce-result-count {
	margin: 0;
}

.woocommerce ul.products {
	margin-top: var(--space-6);
}

/* 0.2.0-dev.24: shop/category archives keep the filter sidebar visible from
   1024px up (.cristaline-shop-layout above), so the sitewide 4-column grid
   (assets/css/woocommerce.css — shared with contexts that have NO sidebar,
   like the homepage's Nouveautés section and single-product related-products
   rows) leaves noticeably less room per card here than on those other
   pages. This round's own explicit spec: 3 columns on large screens when
   the sidebar is visible (not 4), 2 on tablet/mobile. `.cristaline-shop-main`
   only exists on real shop-context pages (inc/shop.php), so this scoped
   override never reaches the homepage or single-product grids. */
@media (min-width: 900px) and (max-width: 1279px) {
	.cristaline-shop-main ul.products {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1280px) {
	.cristaline-shop-main ul.products {
		grid-template-columns: repeat(3, 1fr);
	}
}

@media (max-width: 599px) {
	.woocommerce-ordering,
	.woocommerce-result-count {
		float: none;
		width: 100%;
	}

	.woocommerce-ordering {
		margin: var(--space-3) 0 0;
	}
}

.woocommerce-ordering select.orderby {
	appearance: none;
	background-color: var(--color-bg);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23171717' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-position: right var(--space-3) center;
	background-repeat: no-repeat;
	border: 1px solid var(--color-neutral);
	border-radius: var(--radius-sm);
	color: var(--color-ink);
	font-family: var(--font-nav);
	font-size: .85rem;
	padding: var(--space-2) var(--space-8) var(--space-2) var(--space-3);
}

.woocommerce-ordering select.orderby:focus-visible {
	border-color: var(--color-gold);
	box-shadow: 0 0 0 2px rgba(197, 173, 138, .22);
	outline: none;
}

/* 0.2.0-dev.24: found a SECOND copy of the exact same broken pattern the
   0.2.0-dev.23 comment above already describes and fixed once — this one
   had survived untouched in a different part of the file (the
   `min-width:600px` block re-broke `.woocommerce-result-count`'s float back
   to `none` on desktop, and the `::before` clearfix next to it never
   cleared anything). Removed for the same reason as dev.23's own fix:
   Storefront's native `float:left` on both `.woocommerce-ordering` and
   `.woocommerce-result-count` already puts them on one left-aligned row,
   unaided. Lesson for next time: when "fixing" a pattern that repeats,
   grep the WHOLE file for every instance before considering it done. */

/* =========================================================
   Filter sidebar / drawer.
   ========================================================= */
/* 0.2.0-dev.38 — shorter (40px, was 44px + the global ink-fill button's
   own 12px/24px padding it was silently inheriting, see components.css's
   own docblock for the real cause), sentence-case (never full caps —
   client's own explicit "éviter le texte entièrement en majuscules"),
   full content width, centred. */
.cristaline-shop-filters__toggle {
	align-items: center;
	background-color: var(--color-bg);
	border: 1px solid rgba(23, 23, 23, .18);
	border-radius: var(--radius-sm);
	color: var(--color-ink);
	display: flex;
	font-family: var(--font-nav);
	font-size: .92rem;
	font-weight: 600;
	gap: var(--space-2);
	justify-content: center;
	min-height: 40px;
	padding: var(--space-2) var(--space-4);
	width: 100%;
}

.cristaline-shop-filters__toggle-icon {
	color: var(--color-ink);
	flex-shrink: 0;
}

.cristaline-shop-filters__toggle:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-shop-filters__count {
	align-items: center;
	background-color: color-mix(in srgb, var(--color-gold) 55%, var(--color-bg) 45%);
	border-radius: var(--radius-pill);
	color: var(--color-ink);
	display: inline-flex;
	font-size: .72rem;
	font-weight: 700;
	height: 18px;
	justify-content: center;
	min-width: 18px;
	padding: 0 var(--space-1);
}

.cristaline-shop-filters__close {
	background: none;
	border: none;
	color: var(--color-ink);
	cursor: pointer;
	font-size: 1.5rem;
	line-height: 1;
	padding: var(--space-2);
}

.cristaline-shop-filters__header,
.cristaline-shop-filters__backdrop {
	display: none;
}

/* 0.2.0-dev.36 — each section is a real, accessible disclosure: a genuine
   <button aria-expanded> (see inc/shop.php) controlling a sibling
   `.__section-body`, with a chevron that rotates via CSS from the button's
   own `aria-expanded` attribute — no `[open]`/`<details>` state to key off
   any more. Collapsing itself (hiding `.__section-body` when
   aria-expanded="false") is done by assets/js/shop-filters.js adding
   `.is-collapsed` to the section — with JS disabled the button has no
   click handler at all, so every section simply stays open and fully
   usable (same guarantee the previous <details> version already gave). */
.cristaline-shop-filters__section {
	border-bottom: 1px solid var(--color-accent-soft);
	padding: var(--space-4) 0;
}

.cristaline-shop-filters__section:first-child {
	padding-top: 0;
}

.cristaline-shop-filters__section-title {
	align-items: center;
	background: none;
	border: none;
	color: var(--color-ink);
	cursor: pointer;
	display: flex;
	font-family: var(--font-nav);
	font-size: .82rem;
	font-weight: 700;
	justify-content: space-between;
	letter-spacing: .04em;
	margin: 0 0 var(--space-3);
	padding: 0;
	text-transform: uppercase;
	width: 100%;
}

.cristaline-shop-filters__chevron {
	color: var(--color-ink);
	flex-shrink: 0;
	margin-left: var(--space-2);
	transform: rotate(180deg);
	transition: transform 180ms ease;
}

.cristaline-shop-filters__section-title[aria-expanded="false"] .cristaline-shop-filters__chevron {
	transform: rotate(0deg);
}

.cristaline-shop-filters__section.is-collapsed .cristaline-shop-filters__section-body {
	display: none;
}

.cristaline-shop-filters__section-title:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-shop-filters__options {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.cristaline-shop-filters__options label {
	align-items: center;
	color: var(--color-ink);
	display: flex;
	font-family: var(--font-body);
	font-size: .9rem;
	gap: var(--space-2);
}

.cristaline-shop-filters__options input[type="checkbox"] {
	accent-color: var(--color-gold);
	height: 18px;
	margin: 0;
	width: 18px;
}

/* "Marque" — search input + "Voir plus/Voir moins" overflow toggle
   (0.2.0-dev.36, client's own explicit ask for a compact list with 20+
   real brands). `.__option--extra` items are hidden ONLY once JS adds
   `.is-capped` to the options list — with JS disabled the full brand list
   (every real option, never just 8) stays visible, same progressive-
   enhancement guarantee as the accordion itself. */
.cristaline-shop-filters__brand-search {
	display: block;
	margin-bottom: var(--space-3);
}

.cristaline-shop-filters__brand-search-input {
	background-color: var(--color-bg);
	border: 1px solid #D8D9D7;
	border-radius: 4px;
	color: var(--color-ink);
	font-family: var(--font-body);
	font-size: .85rem;
	padding: var(--space-2) var(--space-3);
	width: 100%;
}

.cristaline-shop-filters__brand-search-input:focus-visible {
	border-color: var(--color-gold);
	outline: 2px solid var(--color-gold);
	outline-offset: 1px;
}

.cristaline-shop-filters__options--brand.is-capped .cristaline-shop-filters__option--extra {
	display: none;
}

.cristaline-shop-filters__options--brand li[hidden] {
	display: none;
}

.cristaline-shop-filters__brand-toggle {
	background: none;
	border: none;
	color: var(--color-ink);
	cursor: pointer;
	font-family: var(--font-nav);
	font-size: .82rem;
	font-weight: 600;
	margin-top: var(--space-3);
	padding: 0;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: .2em;
}

.cristaline-shop-filters__brand-toggle:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-shop-filters__price {
	align-items: center;
	display: flex;
	gap: var(--space-2);
}

/*
 * 0.2.0-dev.49 — real fix for a confirmed-live bug: 0.2.0-dev.48's own
 * "[ Prix min.  CHF ]" in-field currency suffix left too little real width
 * for the placeholder text at the sidebar's actual column width, so it
 * visibly truncated ("Prix min." reading as "Prix r"). The currency moved
 * OUT of the fields entirely (now in the section's own title, "Prix
 * (CHF)" — inc/shop.php) — `.cristaline-shop-filters__price-currency` is
 * removed (no longer used anywhere). Height set explicitly to 46px
 * (client's own requested 44-48px range) rather than derived from
 * padding + line-height, so it holds regardless of font-metric rounding
 * at any width — border/background/radius still live on the LABEL (the
 * whole field reads as one bordered box), the input itself stays
 * transparent/borderless inside it. `flex: 1 1 0` on both fields keeps
 * them evenly split at any sidebar/drawer width, desktop through mobile.
 */
.cristaline-shop-filters__price-field {
	align-items: center;
	background-color: var(--color-bg-alt);
	border: 1px solid var(--color-neutral);
	border-radius: var(--radius-sm);
	display: flex;
	flex: 1 1 0;
	min-width: 0;
}

.cristaline-shop-filters__price-field:focus-within {
	border-color: var(--color-gold);
	outline: 2px solid var(--color-gold);
	outline-offset: 1px;
}

.cristaline-shop-filters__price-field input[type="number"] {
	background: transparent;
	border: none;
	flex: 1 1 auto;
	height: 46px;
	min-width: 0;
	padding: 0 var(--space-3);
	width: auto;
}

.cristaline-shop-filters__price-field input[type="number"]:focus-visible {
	outline: none;
}

.cristaline-shop-filters__price-sep {
	color: var(--color-neutral);
	flex: 0 0 auto;
}

/* 0.2.0-dev.25: accessible price-range validation message (assets/js/
   shop-filters.js toggles the `hidden` attribute and fills the text; this
   rule only styles it once visible — [hidden] already handles display:none
   natively, no extra selector needed for the hidden state). */
.cristaline-shop-filters__price-error {
	color: var(--color-sale);
	font-size: .82rem;
	margin: var(--space-2) 0 0;
}

.cristaline-shop-filters__actions {
	display: flex;
	gap: var(--space-3);
	margin-top: var(--space-4);
}

.cristaline-shop-filters__actions .button {
	flex: 1;
	font-size: .82rem;
	justify-content: center;
	text-align: center;
}

/* =========================================================
   Active-filter pills bar (0.2.0-dev.32) — above the product grid,
   rendered inside .cristaline-shop-main (see the woocommerce_before_shop_loop
   hook, inc/shop.php), one removable pill per active filter option plus a
   "Tout réinitialiser" link. Empty (not rendered at all) when no filter is
   active — never an empty bar reserving space.
   ========================================================= */
.cristaline-shop-active-filters {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-4);
	margin-bottom: var(--space-6);
}

.cristaline-shop-active-filters__list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	list-style: none;
	margin: 0;
	padding: 0;
}

.cristaline-shop-active-filters__pill {
	align-items: center;
	background-color: var(--color-bg-alt);
	border: 1px solid var(--color-neutral);
	border-radius: var(--radius-pill);
	color: var(--color-ink);
	display: inline-flex;
	font-family: var(--font-nav);
	font-size: .82rem;
	gap: var(--space-2);
	padding: var(--space-1) var(--space-3);
	transition: background-color 150ms ease, border-color 150ms ease;
}

.cristaline-shop-active-filters__pill span[aria-hidden] {
	font-size: 1.1em;
	line-height: 1;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-shop-active-filters__pill:hover {
		background-color: var(--color-gold);
		border-color: var(--color-gold);
	}
}

.cristaline-shop-active-filters__pill:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-shop-active-filters__reset {
	color: var(--color-ink);
	font-family: var(--font-nav);
	font-size: .82rem;
	font-weight: 600;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: .2em;
	white-space: nowrap;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-shop-active-filters__reset:hover {
		color: var(--color-gold-hover);
	}
}

.cristaline-shop-active-filters__reset:focus-visible {
	color: var(--color-gold-hover);
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

/* --- Desktop (>=1024px): always-visible sidebar column, no drawer. --- */
@media (min-width: 1024px) {
	.cristaline-shop-filters__toggle {
		display: none;
	}

	.cristaline-shop-filters__panel {
		background-color: var(--color-bg-alt);
		border-radius: var(--radius-md);
		padding: var(--space-6);
		position: sticky;
		top: calc(89px + var(--space-6)); /* clears the sticky header (89px, desktop tier, see layout.css). */
	}
}

/* --- Below 1024px: off-canvas drawer, closed by default. --- */
@media (max-width: 1023px) {
	.cristaline-shop-filters__panel {
		background-color: var(--color-bg);
		bottom: 0;
		box-shadow: -4px 0 24px rgba(23, 23, 23, .18);
		display: flex;
		flex-direction: column;
		max-width: 92vw;
		outline: none;
		overflow-y: auto;
		padding: var(--space-6);
		position: fixed;
		right: 0;
		top: 0;
		transform: translateX(100%);
		transition: transform 220ms ease;
		width: 360px;
		z-index: 1000;
	}

	.cristaline-shop-filters.is-open .cristaline-shop-filters__panel {
		transform: translateX(0);
	}

	.cristaline-shop-filters__header {
		align-items: center;
		border-bottom: 1px solid var(--color-accent-soft);
		display: flex;
		justify-content: space-between;
		margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) var(--space-4);
		padding: var(--space-4) var(--space-6);
	}

	.cristaline-shop-filters__title {
		font-family: var(--font-heading);
		font-size: 1.1rem;
		font-weight: 600;
	}

	.cristaline-shop-filters__backdrop {
		background-color: rgba(23, 23, 23, .4);
		bottom: 0;
		display: block;
		left: 0;
		opacity: 0;
		pointer-events: none;
		position: fixed;
		right: 0;
		top: 0;
		transition: opacity 220ms ease;
		z-index: 999;
	}

	.cristaline-shop-filters.is-open .cristaline-shop-filters__backdrop {
		opacity: 1;
		pointer-events: auto;
	}

	.cristaline-shop-filters__actions {
		margin-top: auto;
		padding-top: var(--space-4);
	}
}

/* Scroll lock while the filter drawer is open — same mechanism as the
   main mobile nav drawer (navigation.css's own .cristaline-menu-open),
   deliberately a separate class so the two can never be confused, and the
   bottom bar hides the same way so nothing fixed stacks behind the
   drawer's own backdrop. */
@media (max-width: 1023px) {
	body.cristaline-filters-open {
		left: 0;
		overflow: hidden;
		position: fixed;
		right: 0;
		width: 100%;
	}

	body.cristaline-filters-open .storefront-handheld-footer-bar {
		display: none;
	}
}

/* =========================================================
   Product cards.
   ========================================================= */
.woocommerce ul.products li.product {
	/* 0.2.0-dev.22 first fixed this against Storefront's MAIN compiled
	   style.css (`ul.products li.product{width:45.45%;float:left;margin-
	   right:9.09%}`, 0,0,2). 0.2.0-dev.23 found and fixed a SECOND, higher-
	   specificity Storefront rule family the dev.22 fix never beat — see
	   the real fix (`!important` width/float/margin/clear/max-width reset)
	   in assets/css/woocommerce.css, which now also covers single-product
	   related/upsell grids that never enqueue this file at all.
	   `display:flex; flex-direction:column` (also 0.2.0-dev.23) turns each
	   card into its own vertical stack, so the add-to-cart button below can
	   use `margin-top:auto` to sit flush at the card's bottom edge
	   regardless of how many lines the title/brand above it take — without
	   this, two cards in the same grid row with a 1-line vs 2-line title
	   left their buttons at two different heights.
	   0.2.0-dev.26: `min-width: 0` added — a `1fr` grid track never shrinks
	   below its item's own CONTENT min-width by default (grid items get an
	   implicit `min-width: auto`, matching content's min-content size);
	   with a long nowrap price string (an on-sale product's old+new amount
	   together) this silently forced that ONE card's column wider than its
	   siblings. `min-width: 0` is the standard, well-established fix — the
	   grid's own equal 1fr distribution wins regardless of content width. */
	display: flex;
	flex-direction: column;
	min-width: 0;
	position: relative;
}

.woocommerce ul.products li.product a.woocommerce-LoopProduct-link {
	display: block;
	position: relative;
}

/* 0.2.0-dev.23: unified to ONE rule for every card image — real photo or
   WooCommerce's own placeholder fallback alike (both carry .wp-post-image;
   the theme previously had a second, competing rule further down scoped to
   that exact class, `object-fit:contain` + padding, which is what a real
   product photo must NEVER get: this round's brief explicitly asks for the
   SAME 4:5/cover treatment on every card, no placeholder-only exception).
   4:5 (not the previous 3:4) matches this round's own explicit ratio ask. */
.woocommerce ul.products li.product img {
	aspect-ratio: 4 / 5;
	background-color: var(--color-bg-alt);
	border-radius: var(--radius-md);
	display: block;
	height: auto;
	object-fit: cover;
	object-position: center;
	width: 100%;
}

@media (hover: hover) and (pointer: fine) {
	.woocommerce ul.products li.product img {
		transition: transform 400ms ease, box-shadow 220ms ease;
	}

	.woocommerce ul.products li.product a.woocommerce-LoopProduct-link:hover img {
		box-shadow: var(--shadow-card);
		transform: scale(1.02);
	}
}

/* 0.2.0-dev.24 tried to make WooCommerce's own placeholder icon (a small
   camera/mountain graphic centered inside a much larger pale square canvas
   — confirmed by downloading and viewing the real file) look bigger with
   `transform:scale(1.5)` + `clip-path:inset(0 round …)`, reasoning the
   clip-path would clip the scaled render back to the image's own box.
   0.2.0-dev.26 found this was a real, confirmed regression: measured live
   via getBoundingClientRect() on the actual site, the image PAINTED at
   386×483px against a 258×322px card column — `clip-path`'s reference box
   is resolved AFTER the transform is applied, so `inset(0)` on an
   already-scaled element just clips to its OWN already-enlarged box, doing
   nothing useful. The oversized image visually bled into the badge area
   above it and the brand/title/price text below it in the same card —
   confirmed as the real cause of this round's own "images excessivement
   agrandies" / "grands espaces verticaux" reports. Reverted to the
   simplest, safest treatment per this round's own explicit instruction:
   `object-fit:contain` for the placeholder ONLY (scoped to WooCommerce's
   own `.woocommerce-placeholder` class, never a real product photo, which
   keeps `cover` from the general rule above) — the placeholder icon reads
   small again, but it can now NEVER exceed its own 4:5 box under any
   circumstance, which this round's brief explicitly prioritises over a
   bigger-looking icon. */
.woocommerce ul.products li.product img.woocommerce-placeholder {
	object-fit: contain;
}

.woocommerce ul.products li.product a.woocommerce-LoopProduct-link:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

/* 0.2.0-dev.39 — added an explicit min-height (2 real lines at this exact
   font-size/line-height, not an approximation) so every card reserves the
   SAME vertical space here regardless of whether the real title happens to
   be 1 or 2 lines long. Without this, a short title left less space above
   the price than a long one in the very same row — this, combined with
   the brand-span fix below, is the real cause of the client's "le prix ne
   tombe pas au même niveau" report; -webkit-line-clamp alone only ever
   caps the MAXIMUM height, it never reserves a minimum. */
.woocommerce ul.products li.product .woocommerce-loop-product__title {
	font-weight: 500;
	hyphens: none;
	line-height: 1.35;
	margin: var(--space-3) 0 var(--space-1);
	min-height: calc(1rem * 1.35 * 2);
	overflow-wrap: normal;
	word-break: normal;
	/* stable card height regardless of a 1- vs 2-line product name. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* 0.2.0-dev.39 — single-line + ellipsis (was a 2-line clamp): a brand name
   is always short in this real catalogue, and a single fixed-height line is
   simpler to reserve consistently than a clamp that can still range from 0
   to 2 lines tall. min-height reserves this line's height even when the
   span is empty (inc/shop.php's cristaline_shop_render_product_brand() now
   always prints the span, aria-hidden when there's no real brand) — this is
   the other half of the same fix: previously the span was entirely ABSENT
   from the DOM for a no-brand product, so that card's title/price started
   visibly higher than a same-row card that DOES show a brand line. */
.cristaline-product-brand {
	/* 0.2.0-dev.23: #A8B0B3 (--color-neutral) on this card's #F8F7F4
	   background measures ~2.05:1 — well under WCAG AA's 4.5:1 for real
	   text (as opposed to e.g. a border or a strikethrough price, where
	   --color-neutral is still fine). color-mix() darkens it without
	   introducing a new hardcoded hex or touching the shared token itself
	   (used in many non-text contexts elsewhere this round must not touch,
	   per the brief's own "ne modifie pas le header/footer/accueil" scope). */
	color: color-mix(in srgb, var(--color-neutral) 40%, var(--color-ink) 60%);
	display: block;
	font-family: var(--font-nav);
	font-size: .72rem;
	letter-spacing: .04em;
	line-height: 1.4;
	min-height: calc(.72rem * 1.4);
	overflow: hidden;
	text-overflow: ellipsis;
	text-transform: uppercase;
	white-space: nowrap;
}

/* min-height reserves up to 2 real lines (an on-sale price can show its
   old+new amounts on 2 separate lines, see the del/ins nowrap comment
   below) so the button's own margin-top:auto gap above it stays visually
   consistent whether a card is on sale or not. */
.woocommerce ul.products li.product .price {
	display: block;
	font-size: .95rem;
	line-height: 1.3;
	min-height: calc(.95rem * 1.3 * 2);
}

/* 0.2.0-dev.26: `white-space:nowrap` directly on `.price` (0.2.0-dev.23)
   was too broad — for an on-sale product, `.price` contains BOTH the old
   (`del`) and new (`ins`) amounts as one nowrap run, e.g. "CHF 169.00 CHF
   139.00". Since this theme's product grid uses `grid-template-columns:
   repeat(N, 1fr)` (a `1fr` track never shrinks below its own content's
   min-content width by default), that single long nowrap string forced
   ITS OWN column wider than its siblings the moment it didn't fit —
   confirmed live via the Browser tool at 390px: two cards in the same row
   measured 172px and 109px instead of two equal ~140px columns, exactly
   matching this round's own "carte isolée avec une largeur différente"
   report. Fixed by keeping `nowrap` on EACH price fragment individually
   (a single amount like "CHF 139.00" still never breaks mid-number, this
   round's own original ask) while letting the two fragments wrap onto
   separate lines from EACH OTHER if a column is ever too narrow for both —
   combined with `li.product`'s own `min-width:0` below, the grid's equal
   columns now win instead of being forced wider by one card's price. */
.woocommerce ul.products li.product .price del,
.woocommerce ul.products li.product .price ins {
	white-space: nowrap;
}

.woocommerce ul.products li.product .price del {
	color: var(--color-neutral);
	opacity: 1;
}

.woocommerce ul.products li.product .price ins {
	color: var(--color-sale);
	font-weight: 600;
	text-decoration: none;
}

/* 0.2.0-dev.23: WooCommerce's OWN default sale ribbon
   (`woocommerce_show_product_loop_sale_flash`, a real `<span class="onsale">
   Promo !</span>` — styled, never hidden, by components.css's own
   `.cristaline-badge--sale, .onsale` rule) was rendering on every on-sale
   card ALONGSIDE this theme's own `.cristaline-product-badge--sale`
   "Promotion" badge — confirmed live, a genuine "Promotion status shown
   twice" case, exactly what this round's brief flags. Hidden here, scoped
   to the shop-grid card only — the single-product page's own `.onsale`
   ribbon (components.css) is the sole sale indicator there and stays. */
.woocommerce ul.products li.product .onsale {
	display: none;
}

.cristaline-product-badges {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	left: var(--space-3);
	position: absolute;
	top: var(--space-3);
	z-index: 1;
}

.cristaline-product-badge {
	border-radius: var(--radius-sm);
	font-family: var(--font-nav);
	font-size: .68rem;
	font-weight: 700;
	letter-spacing: .04em;
	padding: var(--space-1) var(--space-2);
	text-transform: uppercase;
}

.cristaline-product-badge--new {
	background-color: var(--color-bg);
	color: var(--color-ink);
}

.cristaline-product-badge--sale {
	background-color: var(--color-sale);
	color: var(--color-bg);
}

.cristaline-product-badge--outofstock {
	background-color: var(--color-neutral);
	color: var(--color-bg);
}

/* 0.2.0-dev.21: WooCommerce's own real "outofstock" class (post_class(),
   confirmed live on the real <li>) had no visual treatment at all beyond
   the text badge above — dim the photo too, a common, honest e-commerce
   convention (never hides the product, just signals it's unavailable). */
.woocommerce ul.products li.product.outofstock img {
	opacity: .55;
}

/* 0.2.0-dev.23: the add-to-cart/"read more" link WooCommerce renders in
   every card (`.button`, styled sitewide by components.css) had no
   card-specific width or position rule at all — its rendered width came
   purely from its own text length ("Ajouter au panier" vs "Choisir une
   option" vs the now-corrected "Rupture de stock", see inc/shop.php's new
   woocommerce_product_add_to_cart_text filter), so two cards in the same
   row could show visibly different button widths, and — combined with the
   real card-width bug fixed above — a long label had no room and wrapped
   near-vertically. `width:100%` makes every button match its own card's
   width (therefore consistent across a row); `margin-top:auto` (the card
   is now `display:flex;flex-direction:column`, see li.product above) pins
   it to the bottom of the card regardless of title/brand/price height. */
.woocommerce ul.products li.product .button {
	/* `.button` (components.css) never sets its own `display` — a real <a>
	   defaults to `inline`, which silently ignores `width` altogether.
	   Caught before shipping by checking Storefront's real style.css for a
	   competing display rule (none exists) rather than assuming width:100%
	   alone would take effect. */
	display: block;
	margin-top: auto;
	text-align: center;
	width: 100%;
}

/* 0.2.0-dev.40 — real, confirmed cause of "les boutons ne tombent pas sur
   la même ligne" on mobile: at 2 columns (this grid's own default below
   1024px) and a narrow phone width, a card column is only ~150-165px
   wide; `.button`'s SITEWIDE padding (components.css, var(--space-3)
   var(--space-6) = 12px/24px) leaves under ~115px for the label itself —
   too narrow to fit "Ajouter au panier"/"Choisir une option" (both ~18-19
   characters) on one line at the button's normal font-size. When ONE
   card's button wraps to 2 lines and its row sibling's stays 1 line,
   `margin-top:auto` still pins BOTH buttons' BOTTOM edge to the same row
   height (grid's own row-stretch), but their TOP edges — and therefore
   their visible text — no longer line up, which is exactly what reads as
   "buttons not on the same line". Fixed by tightening padding and
   font-size specifically at this narrow tier (never touching the sitewide
   `.button` default used elsewhere on the site) so all 3 real label
   lengths in this catalogue (Ajouter au panier / Choisir une option /
   Rupture de stock) reliably fit on one line again. */
@media (max-width: 480px) {
	.woocommerce ul.products li.product .button {
		font-size: .82rem;
		padding: var(--space-3) var(--space-2);
	}
}

/* Out-of-stock: reads as an unavailable STATE, not an "add" action — never
   hidden or unlinked (this round's brief explicitly keeps WooCommerce's own
   button logic/links untouched), only restyled to the theme's existing
   muted "secondary" treatment instead of the solid ink fill. */
.woocommerce ul.products li.product.outofstock .button {
	background-color: transparent;
	border-color: var(--color-neutral);
	color: var(--color-neutral);
}

@media (hover: hover) and (pointer: fine) {
	.woocommerce ul.products li.product.outofstock .button:hover {
		background-color: transparent;
		border-color: var(--color-neutral);
		color: var(--color-neutral);
	}
}

/* =========================================================
   Pagination — WooCommerce's own real markup, restyled.
   ========================================================= */
/* 0.2.0-dev.23: Storefront's own real assets/css/woocommerce/woocommerce.css
   ships `.woocommerce-pagination{float:right;...}` (specificity 0,1,0) —
   with nothing here ever resetting `float`, pagination genuinely escaped
   normal document flow and floated to the far right of `.cristaline-shop-
   main`, detached from the grid above it — confirmed live, exactly this
   round's own "pagination flotte loin à droite" complaint. `float:none`
   puts it back in normal flow directly below the grid; the real alignment
   (right-aligned, same max-width as the product zone since it's still
   inside `.cristaline-shop-main`) now comes from flexbox on its own list,
   not a float. */
.woocommerce-pagination {
	float: none;
	margin-top: var(--space-8);
}

.woocommerce-pagination ul.page-numbers {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	justify-content: flex-end;
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (max-width: 599px) {
	.woocommerce-pagination ul.page-numbers {
		justify-content: center;
	}
}

.woocommerce-pagination .page-numbers li .page-numbers {
	align-items: center;
	border: 1px solid var(--color-accent-soft);
	display: flex;
	font-family: var(--font-nav);
	font-size: .9rem;
	justify-content: center;
	min-height: 40px;
	min-width: 40px;
	padding: 0 var(--space-2);
}

.woocommerce-pagination .page-numbers li .page-numbers.current {
	border-color: var(--color-gold);
}

@media (hover: hover) and (pointer: fine) {
	.woocommerce-pagination .page-numbers li a.page-numbers:hover {
		border-color: var(--color-gold);
	}
}

.woocommerce-pagination .page-numbers li a.page-numbers:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

/* =========================================================
   Empty states.
   ========================================================= */
.woocommerce-no-products-found,
.cristaline-shop-empty {
	/* 0.2.0-dev.20: margin-inline uses the SAME gutter formula as
	   .woocommerce-products-header above (not a bespoke width:min(...)
	   calc tied to a 1000px cap that no longer exists) — a normal block box
	   with width:auto (the default) already fills 100% of the space left
	   after these margins, so its content edges land exactly where the
	   header's own padding-inset content starts/ends, at any viewport. */
	background-color: var(--color-bg-alt);
	border-radius: var(--radius-md);
	margin-inline: max(var(--space-6), calc((100% - var(--container-max)) / 2));
	margin-top: var(--space-16); /* ~64px below the cards. */
	padding: var(--space-12) var(--space-6);
	text-align: center;
}

.cristaline-shop-empty__title {
	color: var(--color-ink);
	font-family: var(--font-heading);
	font-size: 1.4rem;
	font-weight: 500;
	margin: 0 0 var(--space-2);
}

.cristaline-shop-empty__text {
	color: var(--color-neutral);
	margin: 0 auto var(--space-6);
	max-width: 48ch;
}

.cristaline-shop-empty__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	justify-content: center;
}

@media (prefers-reduced-motion: reduce) {
	.cristaline-shop-hub__card,
	.cristaline-shop-hub__media img,
	.cristaline-shop-subcats__card,
	.woocommerce ul.products li.product img,
	.cristaline-shop-filters__panel,
	.cristaline-shop-filters__backdrop {
		transition: none;
	}
}

/* =========================================================
   0.2.0-dev.28 — Marques page: genre filter row + brand card grid.
   Deliberately a FIXED column-count grid (1/2/3, per this round's own
   explicit spec), unlike .cristaline-shop-subcats above (a flex-wrap row
   chosen specifically because THAT component's real item count varies
   2-4 and centers any incomplete row natively) — the brand grid's own
   requirement is a strict, predictable column count, not auto-centering
   of a partial last row.
   ========================================================= */
.cristaline-brands-index {
	padding: var(--space-8) max(var(--space-6), calc((100% - var(--container-max)) / 2)) var(--space-16);
}

.cristaline-brands-index__filters {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	justify-content: center;
	margin: 0 0 var(--space-8);
}

.cristaline-brands-index__filter,
.cristaline-brands-index__filter:visited {
	border: 1px solid var(--color-accent-soft);
	border-radius: var(--radius-sm);
	color: var(--color-ink);
	font-family: var(--font-nav);
	font-size: .9rem;
	font-weight: 600;
	padding: var(--space-2) var(--space-4);
	text-decoration: none;
	transition: background-color 180ms ease, border-color 180ms ease, color 180ms ease;
}

.cristaline-brands-index__filter.is-active {
	background-color: var(--color-ink);
	border-color: var(--color-ink);
	color: var(--color-bg);
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-brands-index__filter:not(.is-active):hover {
		border-color: var(--color-gold);
	}
}

.cristaline-brands-index__filter:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-brands-index__grid {
	display: grid;
	gap: var(--space-6);
	grid-template-columns: repeat(1, 1fr);
}

@media (min-width: 600px) {
	.cristaline-brands-index__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1024px) {
	.cristaline-brands-index__grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* 0.2.0-dev.32 — restructured to top-align (logo/name/count) with the CTA
   pinned to the bottom via margin-top:auto (was justify-content:center,
   vertically centering everything — the client's own new "aligner les
   boutons en bas des cartes" spec needs a real anchor point, not a
   centered block). CSS Grid's own default align-items:stretch already
   makes every card in a row match the tallest one, so this — combined
   with the fixed-height logo zone below — is what keeps "toutes les
   cartes gardent la même hauteur" true regardless of name length. */
.cristaline-brands-index__card {
	align-items: center;
	background-color: var(--color-bg-alt);
	border: 1px solid var(--color-accent-soft);
	border-radius: var(--radius-md);
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	min-height: 236px;
	padding: var(--space-6);
	text-align: center;
	transition: border-color 180ms ease, box-shadow 180ms ease;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-brands-index__card:hover {
		border-color: var(--color-gold);
		box-shadow: var(--shadow-card);
	}
}

/* Fixed-height logo zone — identical box for every card regardless of the
   real logo's own natural dimensions; object-fit:contain never stretches
   or crops it. Renders nothing (this whole element is omitted server-side,
   see cristaline_marques_get_logo_url()) if a brand genuinely has no logo
   file yet, rather than showing an empty/broken box. */
.cristaline-brands-index__logo {
	align-items: center;
	display: flex;
	height: 64px;
	justify-content: center;
	width: 100%;
}

.cristaline-brands-index__logo img {
	height: 100%;
	max-width: 100%;
	object-fit: contain;
	width: auto;
}

.cristaline-brands-index__name {
	color: var(--color-ink);
	font-family: var(--font-heading);
	font-size: 1.15rem;
	font-weight: 500;
}

.cristaline-brands-index__count {
	/* Same color-mix() contrast fix already established for
	   .cristaline-product-brand above (0.2.0-dev.23) — --color-neutral
	   alone measures well under WCAG AA on this light a background. */
	color: color-mix(in srgb, var(--color-neutral) 40%, var(--color-ink) 60%);
	font-family: var(--font-body);
	font-size: .875rem;
}

.cristaline-brands-index__cta {
	margin-top: auto;
}

@media (prefers-reduced-motion: reduce) {
	.cristaline-brands-index__filter,
	.cristaline-brands-index__card {
		transition: none;
	}
}

/* =========================================================
   Marques page — 0.2.0-dev.40: mobile tier rebuilt as a REAL CSS Grid
   (was flex-basis:calc(50%) — arithmetically equivalent), but the
   client's own repeated, explicit "IMPORTANT: une VRAIE grille mobile en
   2 colonnes" wording (twice now, across 0.2.0-dev.39 and this round)
   called for the more literal, structurally unambiguous tool: a 2-track
   `display:grid` can never wrap to 1 column or drift, by construction —
   there is no calculation to get subtly wrong. 600px and up switch to
   flex-wrap + justify-content:center (0.2.0-dev.20's established
   technique for centring any incomplete last row natively — CSS Grid has
   no native per-line stretch/centre for a partial last row, which is why
   the WIDER tiers, where an incomplete row is a real possibility, keep
   flex). At exactly 2 columns with this catalogue's real 22 brands
   (11 full rows, no remainder), Grid has no incomplete-row case to
   mishandle on mobile either way.

   0.2.0-dev.39/40 — the card itself is no longer a visible box at all by
   default: no background, no border (both fully transparent), no
   border-radius — per the client's own explicit "supprimer l'effet gros
   carré encadré... aucune grosse bordure visible". 0.2.0-dev.40 also
   removes the article count entirely (client's own explicit "je ne veux
   plus le nombre d'articles affiché") — every card is now just the logo,
   then the brand name centred directly below it. A very subtle background
   tint + a barely-visible border only appear on desktop hover (never on
   mobile/touch, this project's own standing "no stuck hover state after a
   tap" rule), as a discreet affordance rather than a permanent frame.
   ========================================================= */
/* 0.2.0-dev.41 — row/column gaps tuned to the client's own explicit ranges:
   mobile 24-32px rows (was already 28px, kept) / a tighter 16px columns
   (was 20px — client's own "réduire légèrement l'espace horizontal entre
   les 2 colonnes" ask); tablet 28-36px rows (was 40px, now 32px); desktop
   36-48px rows (was also 40px — now split into its own >=1024px tier at
   44px, since the previous single >=600px rule gave tablet and desktop
   the exact same row gap, never matching both of the client's two
   different requested ranges at once). */
.cristaline-brands-gallery__grid {
	display: grid;
	gap: 28px 16px;
	grid-template-columns: repeat(2, 1fr);
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (min-width: 600px) {
	.cristaline-brands-gallery__grid {
		display: flex;
		flex-wrap: wrap;
		gap: 32px 24px;
		justify-content: center;
	}
}

@media (min-width: 1024px) {
	.cristaline-brands-gallery__grid {
		gap: 44px 24px;
	}
}

.cristaline-brands-gallery__cell {
	max-width: 320px;
}

@media (min-width: 600px) {
	.cristaline-brands-gallery__cell {
		flex: 0 1 100%;
		flex-basis: calc(33.333% - (var(--space-6) * 2 / 3));
	}
}

@media (min-width: 1024px) {
	.cristaline-brands-gallery__cell {
		flex-basis: calc(25% - (var(--space-6) * 3 / 4));
	}
}

@media (min-width: 1440px) {
	.cristaline-brands-gallery__cell {
		flex-basis: calc(20% - (var(--space-6) * 4 / 5));
	}
}

/* 0.2.0-dev.41 — real, confirmed cause of "trop d'espace entre le logo et
   le nom": the logo zone was `flex: 1 1 auto` inside this flex-column card
   — meaning it GREW to absorb 100% of whatever extra height the row's
   own tallest sibling created (CSS Grid/flex's own default
   align-items:stretch), and the logo image was centred WITHIN that tall,
   variable box. The name below it was never actually far from the LOGO
   ZONE's own edge — it was far from the IMAGE itself, because the zone
   around the image had grown far taller than the image needed. Fixed by
   giving the card `justify-content: flex-start` (content hugs the top,
   never stretches to fill the row) and the logo zone a genuinely FIXED
   `height` (not `flex:1`, not a `min-height` that still lets it grow) —
   see .cristaline-brands-gallery__logo below. The `gap` here is the ONLY
   source of space between the logo zone and the name (the footer element
   itself carries no padding of its own, so nothing can silently add to it
   a second time). 0.2.0-dev.43: tightened again to 6px (was 8px since
   0.2.0-dev.42, 12px before that), the tight end of the client's own
   6-10px range. Real logo files checked pixel-by-pixel this round
   (System.Drawing, sampled every 2px) — every one is already tightly
   cropped (0-2% internal transparent padding), so the file assets
   themselves were never the cause; the remaining visual gap came from the
   logo ZONE's own fixed height (below) being taller than most real logos
   need, not from this `gap` value. */
.cristaline-brands-gallery__card,
.cristaline-brands-gallery__card:visited {
	align-items: center;
	background-color: transparent;
	border: 1px solid transparent;
	border-radius: var(--radius-md);
	color: var(--color-ink);
	display: flex;
	flex-direction: column;
	gap: 6px;
	height: 100%;
	justify-content: flex-start;
	padding: var(--space-2) var(--space-2) var(--space-3);
	transition: border-color 200ms ease, background-color 200ms ease, transform 200ms ease;
}

.cristaline-brands-gallery__card:not(.cristaline-brands-gallery__card--static) {
	cursor: pointer;
}

/* Subtle, desktop-only affordance: a barely-visible tint + border appear
   from fully transparent, plus a slight lift — never a heavy shadow, never
   on touch (gated to hover:hover, this project's own standing rule against
   a hover state sticking after a mobile tap). */
@media (hover: hover) and (pointer: fine) {
	.cristaline-brands-gallery__card:not(.cristaline-brands-gallery__card--static):hover {
		background-color: var(--color-bg-alt);
		border-color: rgba(23, 23, 23, .07);
		transform: translateY(-2px);
	}
}

.cristaline-brands-gallery__card:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.cristaline-brands-gallery__card {
		transition: none;
	}
}

/* Logo zone — 0.2.0-dev.41: a genuinely FIXED height (never `flex:1`, never
   just a `min-height` that still lets the box grow) so every card reserves
   the identical zone regardless of the row's own tallest sibling — this is
   what keeps every brand's name aligned at the same distance from the top
   even when logo files have very different real proportions (a wide logo
   like Gant vs a tall/square one), the client's own explicit "uniformiser
   la zone... même lorsque les logos ont des proportions différentes" ask.
   No background of its own (transparent, matching the card). `flex-shrink:
   0` protects the fixed height from ever being compressed by the column's
   own layout. Never stretched (object-fit:contain on the img).
   0.2.0-dev.43: height trimmed (72→60px mobile, 96→80px desktop) — most
   real logos in this catalogue are wide/short (e.g. Gant's own file is
   ~6:1), so `object-fit:contain` renders them well under the zone's own
   max-height, leaving real empty space ABOVE and BELOW the logo inside
   this box, on top of the `gap` below it. Still comfortably taller than
   the logo `img`'s own max-height (56/68px below) at every breakpoint —
   no logo is clipped, the image itself is completely untouched. */
.cristaline-brands-gallery__logo {
	align-items: center;
	display: flex;
	flex-shrink: 0;
	height: 60px;
	justify-content: center;
	width: 100%;
}

@media (min-width: 600px) {
	.cristaline-brands-gallery__logo {
		height: 80px;
	}
}

.cristaline-brands-gallery__logo img {
	max-height: 56px;
	max-width: 100%;
	object-fit: contain;
	object-position: center;
	width: auto;
}

@media (min-width: 600px) {
	.cristaline-brands-gallery__logo img {
		max-height: 68px;
	}
}

/* Footer — 0.2.0-dev.40: the article count is gone entirely (client's own
   explicit "je ne veux plus le nombre d'articles affiché"), so this is now
   just the brand name, centred under the logo — no more left/right flex
   row, no .cristaline-brands-gallery__count rule (removed, was dead the
   moment inc/brands.php stopped printing that span). 0.2.0-dev.41: no
   padding of its own any more — the card's own `gap` (12px) is now the
   SINGLE source of the logo-to-name spacing, so nothing can silently add
   to it a second time. */
.cristaline-brands-gallery__footer {
	display: flex;
	justify-content: center;
	text-align: center;
	width: 100%;
}

.cristaline-brands-gallery__name {
	color: var(--color-ink);
	font-family: var(--font-body);
	font-size: .8125rem;
	font-weight: 500;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
