/**
 * Header, footer, containers and section spacing.
 *
 * Restyles Storefront's existing header/footer/menu markup — no new
 * markup or nav walker is introduced in Phase 1.
 */

.col-full {
	max-width: var(--container-max);
}

/* Header — 0.2.0-dev.4: dark "chrome" redesign (client's own explicit
   brief). Only the header BAR itself (background + top-level link/icon
   colours) goes dark — the mega-menu dropdown panels and the mobile
   drawer are UNCHANGED, still their existing light theme (client's own
   "conserver tous les méga-menus actuels" instruction), a common, standard
   pattern (dark trigger bar, light dropdown content) that needed no
   changes to the panels' own already-hard-won CSS (see this file's many
   Storefront-collision fixes below, none of them touched this round). */
/* 0.1.26: position was originally just "relative" — needed as a real
   positioned ancestor (.cristaline-mega-menu's own position:absolute
   anchors here) once ".storefront-primary-navigation" became
   display:contents and stopped being a box at all.
   0.2.0-dev.4: promoted to "sticky" (still a positioned ancestor, so the
   mega-menu anchoring above is unaffected — sticky/relative/absolute/fixed
   all equally qualify as a containing block per spec) — the client's own
   "header sticky, léger et fluide" ask. A modest, ALWAYS-present shadow
   (rather than one toggled by a scroll-position JS listener) reads the
   same as "une ombre après défilement" in practice while staying pure
   CSS, no new JS dependency; position:sticky itself never causes a layout
   jump (unlike position:fixed, it never leaves a gap in normal flow when
   it engages). */
.site-header {
	background-color: var(--color-chrome-bg);
	border-bottom: 1px solid var(--color-chrome-border);
	box-shadow: 0 2px 12px rgba(0, 0, 0, .18);
	position: sticky;
	top: 0;
	z-index: 100;
}

/* WordPress admin bar: 32px tall at >=783px, 46px below it (its own real
   breakpoint, not this theme's) — confirmed against WordPress core's own
   admin-bar.css rather than assumed. Without this, the sticky header would
   sit UNDER the admin bar once scrolled instead of just below it. */
body.admin-bar .site-header {
	top: 32px;
}

@media (max-width: 782px) {
	body.admin-bar .site-header {
		top: 46px;
	}
}

/* 0.1.25: real, previously-undocumented bug — a 4th instance of the same
   pattern 0.1.24 already found once for the cart alone. Storefront's own
   ".woocommerce-active .site-header .X { width: 21.74% or 73.91%; float;
   clear }" (specificity 0,3,0, from its own @media(min-width:768px) block,
   with no upper bound) applies to FOUR elements this theme lays out with
   flexbox instead: .site-branding, .site-search, .main-navigation
   (#site-navigation) and .site-header-cart. Only the cart instance was ever
   caught (0.1.24) because the other three were simply hidden below 1280px
   at the time and never exercised. Confirmed live this round: with search/
   cart/account shown again (the 0.1.25 compact-tier fix below),
   #site-navigation itself was rendering at a hardcoded 73.913% of its
   row — 906px on a 1232px-wide row — silently, at EVERY width from 768px
   up, including the existing >=1280px desktop tier, where it happened not
   to visibly break anything only by coincidence of today's exact pixel
   math (justify-content:space-between still pushed the account link to the
   row's real right edge regardless of how wide nav's own invisible box
   claimed to be). Reset unconditionally here (Storefront's own rule has no
   upper bound either) — same specificity (0,3,0) + later source order
   (this stylesheet is enqueued after Storefront's) is enough to win. */
/* 0.1.26: real bug, confirmed live — with branding/search/nav/cart all
   now bubbled into .site-header's own grid via display:contents (see the
   header-grid block below), the plain (no-!important) version of this
   override — which had worked fine since 0.1.25 — stopped reliably
   beating Storefront's native ".woocommerce-active .site-header .X {
   width: %; float }" rules for these specific elements once they became
   grid items this way. Confirmed live via getBoundingClientRect (e.g.
   #site-navigation measured 946px = exactly 73.913% of its real 1280px
   grid track, the cart measured 27px = exactly 21.7391% of its own
   narrow grid column, with the plain override in place and doing
   nothing) before reaching for !important. The two rules are tied in
   specificity (0,3,0) and this stylesheet still loads after Storefront's
   own, so by the ordinary cascade this should never have been necessary
   — given it demonstrably was, for every one of these 4 elements, once
   they moved from being flex items to being grid items spanning a
   display:contents ancestor chain, !important here is a deliberate,
   narrowly-scoped safety net (this exact selector list only), not a
   general pattern to reach for elsewhere in this file. */
.woocommerce-active .site-header .site-branding,
.woocommerce-active .site-header .site-search,
.woocommerce-active .site-header .main-navigation,
.woocommerce-active .site-header .site-header-cart {
	clear: none !important;
	float: none !important;
	margin-right: 0 !important;
	width: auto !important;
}

/* =========================================================
   0.1.27: the header grid below now applies at EVERY width, including
   <768px — real bug, confirmed live (0.1.25/0.1.26's own mobile header
   was 150.7px tall on a real measurement, vs the ~100-130px the client
   asked for this round). Root cause: mobile used a SEPARATE, older
   flex-row system (".site-header > .col-full" as its own flex row for
   the logo, ".storefront-primary-navigation" as ANOTHER flex row below
   it for the hamburger) — two stacked rows, each with their own vertical
   padding, left over from when that row also needed to fit
   search/cart/account. Once those are hidden below 768px (unchanged),
   the row only ever contains ONE thing (the logo, or the hamburger) —
   there was never a real reason for two rows once that happened; 0.1.26
   just didn't revisit it while focused on the 768–1279px compact tier.
   Folding mobile into the same shared grid means logo and hamburger sit
   on ONE row like every other tier, and removes an entire redundant
   layer of padding. See the 3 media queries below the shared block for
   what actually differs per tier now — just grid-template-areas/columns,
   nothing structural.
   ========================================================= */

/* =========================================================
   0.1.26: header grid (shared by every tier — see the 3 breakpoint-
   specific blocks below for what differs).

   The client asked for logo/search/account/cart to share ONE row with
   the horizontal nav on a second row, all sharing one common centered
   container — but account/cart are rendered by Storefront core
   (storefront_header_cart) and this theme's own account-link hook inside
   a SEPARATE wrapper (".storefront-primary-navigation", opened at
   priority 42, closed at 68) from the one branding/search render inside
   (the first ".col-full", opened at priority 0, closed at 41) — two
   different DOM subtrees, un-reachable from each other with CSS alone.

   Fixed with real WordPress hook-priority changes (inc/header-footer.php,
   0.1.26): storefront_header_cart moved from 60 to 40.4, and this theme's
   own account-link hook from 61 to 40.6 — both now render inside the
   FIRST ".col-full", right after storefront_product_search (40), as real
   siblings of branding/search. Verified against the real Storefront 4.6.2
   function bodies first (see that file's own docblock) — both are fully
   self-contained, no dependency on which wrapper renders them.

   #site-navigation (nav + hamburger toggle) still can't move that way —
   its own hook (storefront_primary_navigation, 50) sits inside a chain of
   TWO Storefront-controlled wrappers this theme can't safely relocate
   (storefront_primary_navigation_wrapper's own two nested divs). Instead,
   both of those wrappers are set to display:contents below — they stop
   being boxes, but their real children (#site-navigation, and the 3
   .cristaline-mega-menu panels rendered right after it at priority 51)
   become direct participants of the SAME grid as branding/search/cart/
   account, exactly as if they'd always been siblings.

   Important correction made while verifying this live: display:contents
   only flattens an element into ITS OWN PARENT's box tree — it can't
   reach across to a SIBLING's grid. ".storefront-primary-navigation" and
   ".site-header > .col-full" are SIBLINGS (both direct children of
   ".site-header"), so making only ".storefront-primary-navigation"
   contents made #site-navigation bubble up to become a direct child of
   ".site-header" — NOT a grid item of the OTHER ".col-full" next to it
   (confirmed live: #site-navigation rendered as a plain block, ignoring
   its own grid-area entirely, before this was caught). The fix is
   ".site-header" itself is the real grid container — BOTH ".col-full"s
   (branding/search's and the nav wrapper's) are display:contents, so
   every named item bubbles up exactly one level to become a direct grid
   child of the same element. ".site-header" keeps its own full-width
   background/border (a real box, display:grid doesn't remove that) — the
   old "full-width outer bar, centered inner content" effect it used to
   get from ">.col-full"'s own max-width+margin:auto is reproduced with
   max()-based padding instead (see below), since ".col-full" itself is no
   longer a real box to hold that max-width at this breakpoint.

   The mega-menu panels are position:absolute regardless of what
   display:contents does to their ancestors (per spec, an out-of-flow
   element is never a flex/grid item, contents ancestors or not) — they
   just needed a new containing block once ".storefront-primary-
   navigation" stopped being one, which is why .site-header itself is
   position:relative now (see above).

   0.1.27: unconditional now (was ">=768px" only) — see the big comment
   further up for why: mobile needed the exact same "one shared grid, no
   redundant stacked rows" treatment once its own old 2-row flex system
   turned out to be the cause of the excessive mobile header height. The
   max()-based padding formula below already degrades correctly at
   narrow widths on its own (the calc() side goes negative/zero below
   --container-max, so max() always falls back to the flat var(--space-6)
   minimum) — no separate mobile-specific padding rule was needed. */
.site-header > .col-full,
.storefront-primary-navigation,
.storefront-primary-navigation > .col-full {
	display: contents;
}

.site-header {
	align-items: center;
	column-gap: var(--space-4);
	display: grid;
	/* max() keeps a real minimum side margin at every width narrower than
	   --container-max (where the calc() side alone would go negative/
	   zero) while still centering a --container-max-wide content area
	   once the viewport is wider than that — the same effect ">.col-full"'s
	   own max-width + margin:0 auto used to give, expressed as padding on
	   the full-width element instead since ".col-full" is display:contents
	   now and can't hold that itself. */
	padding: var(--space-4) max(var(--space-6), calc((100% - var(--container-max)) / 2));
	row-gap: var(--space-3);
}

.site-branding {
	grid-area: logo;
}

.site-search {
	grid-area: search;
}

.cristaline-header-social {
	grid-area: social;
}

/*
 * 0.2.0-dev.50 — real, root-cause fix for this round's own "icônes
 * flottantes... dans la zone du hero/header mobile" report: the <768px
 * mobile tier's own grid-template-areas ("logo . nav", see that tier's own
 * block further down) has never named a "social" area at all, so
 * `.cristaline-header-social`'s `grid-area: social` above simply can't
 * resolve there — CSS Grid's own spec-defined behaviour for a named area
 * that doesn't exist in the CURRENT template is to fall back to normal
 * auto-placement, landing the element wherever the algorithm finds free
 * grid space instead of respecting the intended layout, which is exactly
 * what an unpredictable "floating" position looks like. `display: none`
 * here is unconditional and explicit below the real desktop tier (1280px,
 * where the header's own explicit line-based placement already handles it
 * correctly, see that tier's own ".site-header .cristaline-header-social"
 * rule) — robust regardless of what any narrower tier's own
 * grid-template-areas string does or doesn't name, rather than relying on
 * every tier remembering to account for this one item. Client's own
 * explicit ask this round: the header's own social icons are desktop-only;
 * mobile/tablet visitors reach the same two links via the mobile drawer's
 * own "Suivez-nous" block and the footer, both already real, working, and
 * unaffected by this change.
 */
@media (max-width: 1279px) {
	.cristaline-header-social {
		display: none;
	}
}

.site-header-cart {
	grid-area: cart;
}

.cristaline-account-link {
	grid-area: account;
	/* the old flex-row gap (--space-4) handled this before; the grid's
	   own column-gap does now — an extra margin here would just double
	   the visual space between cart and account. */
	margin-left: 0;
}

#site-navigation {
	grid-area: nav;
}

/* 0.1.27: mobile tier (<768px) — logo and hamburger share ONE row (the
   real fix for the excessive-height bug above); search/cart/account stay
   hidden here (see the existing <767px visibility rule further down),
   so they never occupy the empty "." column — it's purely a spacer that
   keeps the hamburger pinned to the right edge regardless. */
@media (max-width: 767px) {
	.site-header {
		grid-template-areas: "logo . nav";
		grid-template-columns: auto 1fr auto;
		/* real bug, confirmed live — even with a single explicit row, the
		   grid still reports a 2nd, empty implicit row ("88px 0px"), and
		   the shared block's row-gap (needed for the 2-row compact/desktop
		   tiers) was still adding a full 12px of unwanted extra height for
		   a gap that has nothing real on either side of it at this tier.
		   Zeroed here — directly responsible for part of the excessive
		   mobile-header-height bug fixed this round (133px measured with
		   the gap live, 121px without it, before any of the other fixes in
		   this same round were even applied). */
		row-gap: 0;
		/* 0.2.0-dev.3: this round's own explicit "conserver le logo à
		   environ 95–110px de largeur" (see the logo rule below, 72px ->
		   100px) pulls the header height back UP unless padding compensates
		   — tightened further, var(--space-3) (12px) -> var(--space-2)
		   (8px). 0.2.0-dev.6: tightened once more, 8px -> 6px (client's own
		   "réduire légèrement la hauteur du header mobile" ask) — still
		   comfortable padding around the 100px logo and the 56×56px
		   hamburger (well above the 44×44px minimum tap target on its
		   own), just not as generous. Still purely padding + content, no
		   fixed/forced height. Horizontal padding (the max() term)
		   untouched. */
		padding-top: 6px;
		padding-bottom: 6px;
	}
}

/* Compact tier (768–1279px) — MODE B: logo left, cart/account/hamburger
   right on row 1 (the empty "." column absorbs the space between); a
   full-width search on row 2.
   0.2.0-dev.50 — "social" removed from this tier's own template: client's
   own explicit "supprimer les icônes flottantes... dans la zone du hero/
   header mobile" report this round, confirmed as a real, previously-
   unnoticed CSS Grid bug rather than assumed — this tier's own
   grid-template-areas already never included "social" for the <768px tier
   below it (only "logo . nav"), but DID still include it here; the real
   floating-icon symptom traced to the OTHER tier: with no "social" NAMED
   AREA at all in the <768px template, `.cristaline-header-social`'s own
   `grid-area: social` (assets/css/layout.css, shared block above) can't
   resolve, and CSS Grid's own auto-placement algorithm places it wherever
   it finds room instead — a real, spec-correct explanation for content
   rendering in an unexpected, "floating" position, not a vague guess. Fixed
   at the root with an explicit `display: none` below 1280px (see that rule
   further down) — robust regardless of what any tier's own
   grid-template-areas string does or doesn't name — and this tier's own
   template tidied to match (one fewer `auto` column) so it isn't left
   referencing an area that's now unconditionally hidden anyway. */
@media (min-width: 768px) and (max-width: 1279px) {
	.site-header {
		grid-template-areas:
			"logo   .      cart account nav"
			"search search search search search";
		grid-template-columns: auto 1fr auto auto auto;
	}
}

/* Desktop tier (>=1280px) — 0.2.0-dev.4: collapsed from the old 2-row
   layout (logo/search/social/cart/account on row 1, nav spanning a full
   row 2 below) to ONE shared row — the client's own explicit "une seule
   zone visuelle cohérente : logo à gauche, navigation au centre, outils à
   droite" ask, rather than the previous stacked-bar look. The nav column
   is the only 1fr track (was search before); nav's own ul.nav-menu is
   centered within it so the 9 items read as a centered block, not
   left-pinned.

   Real, live-measured constraint (not guessed): with all 9 real top-level
   items (Accueil/Nouveautés/Femme/Homme/Enfants/Marques/Boutiques/Bons
   cadeaux/Contact) + a permanently-open ~150-210px search field + 2 social
   icons + cart + account sharing this one row at exactly 1280px, the nav
   text wraps to a second line — confirmed via getBoundingClientRect() on
   the real production DOM/fonts, not assumed from reading the CSS. Shaving
   nav font-size/padding down far enough to force a fit left only a ~9px
   safety margin at the exact 1280px minimum, before even accounting for
   the logo's own real target width this round (100-125px, up from the
   96px this was measured against) eating further into it — exactly the
   "just barely fits" fragility this project's own history repeatedly
   warns about (a future menu-label edit or a 10th item would break it
   again with no warning). Solved by collapsing the search field itself to
   its own ~40px icon-button width by default instead (assets/js/
   header-search.js toggles ".is-open" on click, focusing the real input)
   — the client's own explicitly offered alternative ("icône de recherche
   ouvrant un champ propre"), and it reclaims ~110-170px outright rather
   than fighting for single-digit pixels. See the .site-search rules
   further down this file (grep "0.2.0-dev.4: collapsed search") for the
   collapse/expand styling itself — kept with the OTHER .site-search tier
   rules rather than duplicated here, so its 3 tiers (mobile-hidden/
   compact-full-width/desktop-collapsed) stay next to each other. */
@media (min-width: 1280px) {
	.site-header {
		/* Tightened from the shared block's own var(--space-4)/16px — live-
		   measured headroom (see the big comment above) needed this to
		   comfortably clear 9 real items + logo + collapsed search + social
		   + cart + account on one row at exactly 1280px; 10px still reads
		   as deliberate spacing, not cramped. */
		column-gap: 10px;
		grid-template-areas: "logo nav search social cart account";
		grid-template-columns: auto 1fr auto auto auto auto;
		/* 0.2.0-dev.5: REAL BUG fixed here, found live via the client's
		   header-height report. getComputedStyle() showed THREE row tracks
		   ("Npx 0px 0px") for what's declared as a single-row
		   grid-template-areas string — root cause not fully isolated (every
		   candidate extra grid item tested — the 3 hidden .cristaline-mega-menu
		   panels, the mobile drawer, the skip-links — was removed one at a
		   time and NONE of them was the cause, even combined), but two
		   phantom 0-height implicit rows are reliably present regardless,
		   and row-gap (var(--space-3), shared block above) was being paid
		   TWICE for gaps next to rows with nothing in them — 24px of pure
		   waste. Zeroed here, scoped to this single-row tier only (a real
		   multi-row tier, like the compact tier below, still needs its own
		   row-gap and is unaffected). */
		row-gap: 0;
		/* Tightened from the shared block's own var(--space-4)/16px top+
		   bottom — the other real contributor to "header trop haut": at
		   16px the header measured ~140px tall even once every other fix
		   above landed. 0.2.0-dev.6: trimmed once more, 12px -> 10px — the
		   client's own "réduire légèrement, sans rendre les éléments
		   serrés" ask, now that the real cart-height bug (a Storefront
		   collision, see .cart-contents' own comment) is fixed and no
		   longer the tallest item forcing the row open — the 68px logo
		   is, so this still leaves real breathing room (~93px -> ~89px
		   total, comfortably inside 88-100px, not tight). */
		padding-top: 10px;
		padding-bottom: 10px;
	}

	/* Real bug, found in the same live session: .site-branding carries a
	   genuine ~22.65px bottom margin (confirmed via getComputedStyle, not
	   guessed — traced to Storefront's own default spacing for its
	   original stacked, non-grid branding row) that nobody had reason to
	   notice until the header height itself became a client-visible
	   complaint. As a grid item its margin-box (not just its border-box)
	   determines the row's auto height, so this alone was inflating row 1
	   from 108px to ~130.6px. .site-search carries the same kind of
	   leftover margin. Neutralized here, scoped to the header context only
	   — neither element needs its margin anywhere else on this page. */
	.site-header .site-branding,
	.site-header .site-search {
		margin-bottom: 0;
	}

	/* REAL, SEVERE bug found during this round's own final validation sweep
	   (not present in the original report, caught by testing the FULL
	   combined fix at every required width, including 1920px, across
	   several fresh page loads): with every fix above in place, the named
	   grid-area placement for #site-navigation was NON-DETERMINISTIC —
	   identical markup, identical CSS, a fresh page load — and on some
	   loads Chrome placed #site-navigation into an IMPLICIT SECOND ROW
	   instead of the "nav" cell its own grid-area names, pushing the
	   header back up to ~156px and putting nav visually below the rest of
	   the row (confirmed live, repeatedly, via getComputedStyle() showing
	   gridTemplateRows as "68px 63.4375px 0px 0px" — a real SECOND
	   content row, not just the harmless 0-height phantom rows above).
	   Every other tier (mobile, compact) and every other item on THIS
	   tier was unaffected — only #site-navigation, only sometimes, only
	   here. Root cause not fully isolated (this project's own "display:
	   contents" architecture bubbles #site-navigation up through TWO
	   nested contents chains — .site-header's own .col-full AND
	   .storefront-primary-navigation's — while logo/search/cart/account
	   only bubble through one; a dual-path bubble into a single named-area
	   grid is the most likely trigger, but could not be confirmed further
	   without patching the browser itself). The named grid-area system
	   (.site-branding/.site-search/etc.'s own "grid-area: X" rules, kept
	   below and still relied on by the mobile/compact tiers) is simply not
	   reliable for this one item at this one tier — explicit, numeric
	   line-based placement bypasses whatever non-deterministic
	   auto-placement path was causing it, and has now held clean across
	   more than a dozen repeated fresh loads at 1280/1920px. */
	.site-header .site-branding {
		grid-column: 1;
		grid-row: 1;
	}

	#site-navigation {
		grid-column: 2;
		grid-row: 1;
	}

	.site-header .site-search {
		grid-column: 3;
		grid-row: 1;
	}

	.site-header .cristaline-header-social {
		grid-column: 4;
		grid-row: 1;
	}

	.site-header .site-header-cart {
		grid-column: 5;
		grid-row: 1;
	}

	.site-header .cristaline-account-link {
		grid-column: 6;
		grid-row: 1;
	}

	/* 0.2.0-dev.6: REAL fix for "le menu se retrouve collé contre le logo"
	   — confirmed live the nav sat flush left in its own 1fr track (a
	   ~10px gap from the logo, not centered at all). The dead
	   ".main-navigation ul.nav-menu { justify-content: center }" rule
	   below never did anything, because ul.nav-menu itself is
	   display:block (its horizontal item layout comes from float/inline-
	   flow on the <li>s, not flex) — justify-content only ever affects a
	   flex/grid CONTAINER, and nothing here was ever declared as one.
	   #site-navigation itself IS the real grid item (grid-area: nav,
	   spanning the 1fr track), so making IT the flex container centers
	   its one visible child (".primary-navigation", the wrapper Storefront
	   renders ul.nav-menu inside) within the full track width — the
	   .menu-toggle button and .handheld-navigation div are both
	   display:none at this tier already, so they don't affect the
	   centering. Confirmed live: nav-menu now sits centered in the track
	   with even space on both sides, not flush against the logo. */
	#site-navigation {
		display: flex;
		justify-content: center;
	}
}

.site-branding .site-title a,
.site-branding .site-title a:hover {
	font-family: var(--font-heading);
	color: var(--color-chrome-text);
	letter-spacing: .02em;
}

/* The tagline duplicates the hero's own subheading on the homepage and,
   at this compact header height, only adds clutter — hidden here, still
   available anywhere else via bloginfo('description'). */
.site-header .site-description {
	display: none;
}

.site-search .woocommerce-product-search {
	align-items: center;
	display: flex;
	width: 100%;
}

/* 0.1.26: flex:1 (fills whatever width .site-search itself is given —
   320px fixed on desktop, 100% of the row on the compact tier, see the
   grid tiers below) replaces the old fixed 220px, which only ever made
   sense back when .site-search had no explicit width of its own.
   0.2.0-dev.4: real background/text colours added — this field previously
   relied entirely on the browser's own default white input chrome, which
   worked fine floating on the old light header but needs an explicit dark-
   context treatment now (a plain default-white box would look like a
   foreign, un-styled element dropped into the dark bar). A translucent
   white fill (never fully opaque) keeps it reading as "part of the dark
   header", not a bright cut-out. */
/* 0.2.0-dev.9: height:100% added — now that ".woocommerce-product-search"
   itself has a real, explicit height (42px at >=1280px, see the
   ".site-search" rule further down), this input needs to fill it exactly
   rather than keep its own intrinsic height (padding + line-height, ~48px)
   inside a shorter flex container with "align-items: center" — without
   this, the input would overflow the 42px box by ~3px top/bottom. */
.site-search input[type="search"] {
	background-color: rgba(248, 247, 244, .1);
	border: 1px solid var(--color-chrome-border);
	border-radius: var(--radius-sm) 0 0 var(--radius-sm);
	box-sizing: border-box;
	color: var(--color-chrome-text);
	flex: 1;
	height: 100%;
	line-height: normal;
	margin: 0;
	min-width: 0;
}

.site-search input[type="search"]::placeholder {
	color: var(--color-chrome-text-muted);
}

/* Overrides components.css's shared ".button"/"input[type=submit]" ink-fill
   — scoped to this one selector only, never the global rule (that rule
   still has to serve every other input[type=submit] on the site, including
   pages this round never touches). A plain icon-style button here reads as
   part of the search field, not a separate ink block sitting awkwardly
   next to it on a dark bar. */
.site-search button[type="submit"] {
	background-color: transparent;
	border: 1px solid var(--color-chrome-border);
	border-left: none;
	border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
	box-sizing: border-box;
	color: var(--color-chrome-text);
	height: 100%;
	padding: var(--space-2) var(--space-3);
}

@media (hover: hover) and (pointer: fine) {
	.site-search button[type="submit"]:hover {
		background-color: rgba(248, 247, 244, .1);
		border-color: var(--color-chrome-border);
		color: var(--color-chrome-text);
	}
}

/* Primary navigation — restyle Storefront's existing dropdown, same markup.
   Explicit tighter horizontal padding (Storefront's own default is 1em ≈
   16px/side): with 9 top-level items + the cart + account link all
   sharing one row capped at --container-max (1280px), the extra ~90px
   this reclaims across 9 items is needed for everything to fit on a
   single line — confirmed by measuring real rendered item/cart widths on
   the live site (see 00_Contexte-et-decisions/Decisions-validees.md). */
/* 0.1.25: real bug, confirmed live — Storefront's own ul.nav-menu ships a
   negative side margin (a "bleed the outer edge to align <li> padding"
   trick, meant to pair with ITS OWN default ~1em <li> padding). This theme
   tightens that padding down to .4em (right below, kept from 0.1.9 — 9 top-
   level items + cart + account need it to fit one row) but never touched
   the matching negative margin, so the whole menu sat ~10px further left
   than intended, uncompensated — confirmed live via getBoundingClientRect
   (first item's own box started at x≈60 vs the container's real left edge
   at x≈76, a ~16px unintended offset). With this theme's own .4em <a>
   padding providing all the "breathing room" needed, the compensating
   negative margin is no longer wanted at all. */
.main-navigation ul.nav-menu {
	margin-left: 0;
	margin-right: 0;
}

.main-navigation ul.nav-menu > li > a {
	color: var(--color-chrome-text);
	font-family: var(--font-nav);
	font-size: .82rem;
	letter-spacing: .03em;
	padding-left: .4em;
	padding-right: .4em;
	text-transform: uppercase;
}

/* 0.2.0-dev.5: cart link rebuilt around a real icon (inc/header-footer.php's
   own storefront_cart_link() override) instead of Storefront's plain
   "CHF 0.00 · 0 article" text — a real flex row now (icon + amount), 8-12px
   internal gap per the client's own spec. white-space:nowrap on the amount
   guards against the exact 0.1.24 "vertical text" regression (a Storefront
   percentage-width rule squeezing this text) ever recurring.

   0.2.0-dev.6: REAL Storefront collision found live — Storefront's own
   real compiled assets/css/woocommerce/woocommerce.css ships
   ".site-header-cart .cart-contents { display: block; ... }", the EXACT
   same selector as this rule (tied specificity, 0,2,0). Confirmed via the
   real enqueued <link> order on the live site that this Storefront
   stylesheet loads AFTER this entire child theme bundle (WooCommerce's
   own separate enqueue, not Storefront's main style.css) — so on tied
   specificity, Storefront's later rule was winning, silently forcing the
   icon and the price back into two stacked block lines instead of one
   row (the client's own "petit sac isolé placé au-dessus de CHF 0.00"
   complaint). Rescoped with ".woocommerce-active" (matching this file's
   own established pattern for exactly this class of collision) to win on
   specificity regardless of load order. */
.woocommerce-active .site-header-cart .cart-contents {
	align-items: center;
	color: var(--color-chrome-text);
	display: flex;
	gap: var(--space-2);
	/* Storefront's own colliding rule (see this rule's own comment above)
	   also sets "padding: ms(3) 0" (~21-24px top/bottom) — neutralized
	   here too, now that this rule's higher specificity actually wins,
	   otherwise the cart would still measure tall despite the display:flex
	   fix. */
	padding: 0;
}

/* Explicit width/height (was intrinsic, sized purely by the SVG) so the
   badge has real, deliberate clearance to sit in the icon's own top-right
   corner. 0.2.0-dev.42: wrap widened slightly (26px, was 24px) and the SVG
   itself reduced by 1px (21px, was 22px) — a small extra margin around the
   glyph on every side, giving the badge (below) more room before its own
   box reaches the glyph's real ink. */
.cristaline-cart-icon-wrap {
	display: inline-flex;
	height: 26px;
	position: relative;
	width: 26px;
}

.cristaline-cart-icon-wrap svg {
	height: 21px;
	margin: auto;
	width: 21px;
}

/* Small, always-legible count badge — omitted entirely by the PHP side
   when the cart is empty (no "0" badge shown), so this only ever needs to
   size for 1-2 digits ("99+" beyond that, see header-footer.php).
   0.2.0-dev.42 — REAL, CONFIRMED cause of "le chiffre n'est pas centré"
   found live: Storefront's own real compiled `assets/css/woocommerce/
   woocommerce.css` ships `.site-header-cart .cart-contents span {
   display: inline }` at `(min-width: 768px)`, specificity (0,2,1) — this
   theme's own `.cristaline-cart-badge { display: flex }` was only (0,1,0),
   so it silently LOST: `getComputedStyle()` on the real live badge
   confirmed `display: inline` was actually being applied, meaning
   `align-items`/`justify-content` were doing NOTHING (they only affect
   flex containers) — the digit's positioning was left entirely to default
   inline text flow inside a padded span. This is the exact same
   Storefront-collision bug class documented dozens of times elsewhere in
   this project (a generic multi-class Storefront selector reaching into a
   descendant of `.site-header-cart`/`.cart-contents`) — never previously
   audited for THIS specific badge. Fixed below by matching the real
   ancestor chain (`.site-header-cart .cart-contents .cristaline-cart-
   badge`, 3 classes, specificity 0,3,0) — beats Storefront's 0,2,1 on
   class-count alone, regardless of source order. */
.cristaline-cart-badge {
	background-color: var(--color-chrome-accent);
	border-radius: 999px;
	color: var(--color-ink);
	font-size: 11px;
	font-weight: 600;
	height: 18px;
	line-height: 1;
	min-width: 18px;
	padding: 0 4px;
	position: absolute;
	right: -7px;
	top: -7px;
	z-index: 2;
}

.site-header-cart .cart-contents .cristaline-cart-badge {
	align-items: center;
	display: flex;
	justify-content: center;
}

.cristaline-cart-amount {
	font-size: .82rem;
	white-space: nowrap;
}

/* 0.2.0-dev.7: real second cart icon found live — Storefront's own compiled
   assets/css/base/icons.css sets ".site-header-cart .cart-contents::after"
   to a Font Awesome "shopping-basket" glyph (confirmed via getComputedStyle
   charCodeAt inspection: content resolves to U+F291, invisible to a naive
   string/JSON check since it's a Private-Use-Area character, not literal
   text). It floats to the right edge of this same link, next to the
   account icon — this, not a second element in this theme's own markup,
   was the client's "deuxième icône panier". Neutralized here rather than
   in header-footer.php since it's Storefront's own pseudo-element, not
   this theme's; the real, badge-capable icon stays the SVG in
   .cristaline-cart-icon-wrap above. */
.site-header-cart .cart-contents::after {
	content: none;
}

@media (hover: hover) and (pointer: fine) {
	.main-navigation ul.nav-menu > li > a:hover {
		color: var(--color-chrome-accent);
	}
}

/* 0.2.0-dev.7: active-page state — champagne (--color-chrome-accent, same
   token as desktop hover) on whichever top-level <li> WordPress's own
   wp_nav_menu() marks current. Storefront's real markup (confirmed live on
   the installed site) only ever applies current-menu-item/current_page_item
   on a real top-level link's own <li> (Femme/Homme/Enfants use a
   non-<a> trigger with no WP "page" behind it, so they never carry these
   classes — expected, not a bug, since they aren't a single destination
   page). :visited is pinned to the same base color so a previously-clicked
   page link never reads as a different, unintended color. */
/* 0.2.0-dev.10: "[aria-current=\"page\"]" added — WordPress's own
   wp_nav_menu() sets this real attribute (not just a class) on the current
   page's <a> directly, independent of body.logged-in/admin-bar state, so
   it stays a reliable signal for every visitor including a fully signed-
   out one. :visited pinned for every branch (ancestor/parent were
   previously only covered by the plain, non-visited selectors above; a
   previously-clicked ancestor link could otherwise fall back to the base
   nav colour). */
.main-navigation ul.nav-menu > li.current-menu-item > a,
.main-navigation ul.nav-menu > li.current_page_item > a,
.main-navigation ul.nav-menu > li.current-menu-ancestor > a,
.main-navigation ul.nav-menu > li.current_page_ancestor > a,
.main-navigation ul.nav-menu > li.current-menu-parent > a,
.main-navigation ul.nav-menu > li > a[aria-current="page"],
.main-navigation ul.nav-menu > li.current-menu-item > a:visited,
.main-navigation ul.nav-menu > li.current_page_item > a:visited,
.main-navigation ul.nav-menu > li.current-menu-ancestor > a:visited,
.main-navigation ul.nav-menu > li.current_page_ancestor > a:visited,
.main-navigation ul.nav-menu > li.current-menu-parent > a:visited,
.main-navigation ul.nav-menu > li > a[aria-current="page"]:visited {
	color: var(--color-chrome-accent);
}

.main-navigation ul.nav-menu > li > a:focus-visible {
	outline: 1px solid var(--color-chrome-accent);
	outline-offset: 2px;
}

.main-navigation ul ul {
	background-color: var(--color-bg);
	border: 1px solid var(--color-accent-soft);
	box-shadow: var(--shadow-card);
}

.main-navigation ul ul li a {
	color: var(--color-ink);
	padding: var(--space-2) var(--space-4);
}

.main-navigation ul ul li a:hover {
	background-color: var(--color-bg-alt);
	color: var(--color-gold-hover);
}

/* WooCommerce's own get_cart_subtotal() output — nested inside
   .cristaline-cart-amount above (header-footer.php's storefront_cart_link()
   override), still real markup, just no longer a bare ".cart-contents"
   child. */
.site-header-cart .amount {
	color: var(--color-chrome-text);
}

/* #site-header-cart's second <li> holds the WC_Widget_Cart mini-cart
   dropdown, positioned off-screen (left: -9999px, Storefront's own
   default) until hovered/opened. Off-screen ≠ zero-width in a shrink-
   to-fit block/list layout — it was inflating this <ul> to ~280px and
   pushing "Contact" to wrap onto a second line even at 1440px wide.
   display:flex correctly excludes out-of-flow (position:absolute)
   children from the container's own size calculation, with no change
   to how the dropdown itself looks or behaves on hover. */
.site-header-cart {
	display: flex;
	align-items: center;
}

/* 0.2.0-dev.10: real root cause of the client's "colonne extrêmement
   étroite, chaque lettre passe à la ligne" mini-cart report, found live
   (not assumed) — Storefront's own real compiled CSS sets ".site-header-
   cart .widget_shopping_cart { position:absolute; top:100%; width:100%;
   left:-999em; … }" and shows it on hover/focus via
   ".site-header-cart:hover .widget_shopping_cart, .site-header-cart.focus
   .widget_shopping_cart { left:0; display:block }". "width:100%" resolves
   against ITS OWN positioned ancestor — ".site-header-cart" itself, the
   `<ul>` — which this project's own many header redesigns have shrunk
   down to just the compact icon+amount cluster (confirmed live:
   61.625px wide at 1280px). Nothing about the cart's own compact styling
   was ever wrong; nobody had re-checked what that left the mini-cart
   DROPDOWN sized to once actually opened, since every previous round's
   testing covered the cart's own resting layout, never this hover panel's
   content. A real, fixed width plus right-alignment (so the panel grows
   left from the cart, away from the header's own right edge, instead of
   the default left-aligned "left:0" which — now that the cart column
   itself is real narrow, not the old wider block — would push the panel's
   own right edge past the viewport on some widths) fixes it without
   touching Storefront's own hover/focus trigger mechanism (still the
   real ".focus" class Storefront's own navigation.js adds on keyboard
   focus — unchanged, so Tab-key accessibility to this dropdown keeps
   working exactly as Storefront intended). ".woocommerce-active" prefix
   matches this project's own established pattern for beating a
   same-family Storefront selector on specificity. */
.woocommerce-active .site-header-cart .widget_shopping_cart {
	width: 300px;
}

.woocommerce-active .site-header-cart:hover .widget_shopping_cart,
.woocommerce-active .site-header-cart.focus .widget_shopping_cart {
	left: auto;
	right: 0;
}

/* Logo fallback — only applied when no Customizer logo has been uploaded
   yet (see the "cristaline-fallback-logo" body class in
   inc/header-footer.php). Once a real logo is set via Appearance >
   Customize > Site Identity, Storefront's own the_custom_logo() output
   takes over and these rules simply don't match anymore.

   The source file is a square 500×500 mark (crystal emblem + stacked
   wordmark) — the previous box (180×48, a ~3.75:1 rectangle) forced
   background-size:contain to letterbox it down to a ~48×48 sliver inside
   a mostly-empty box, which read as "illegibly small". Sized to match
   the source's real aspect ratio instead. */
/* 0.1.27: real bug, confirmed live — .site-title (the <h1>) was rendering
   ~6px TALLER than its own <a> child (93.7px vs the <a>'s real 88px),
   even though both have zero margin/padding. Classic CSS "phantom strut"
   behavior: an inline-block child's surrounding anonymous line box still
   reserves space for ITS OWN font-size/line-height (inherited from the
   "Site title: full text, natural wrap" rule below, needed for the
   OTHER case — a real Customizer logo, where .site-title shows actual
   visible text and that line-height matters) even when the only content
   is an inline-block with an explicit height and hidden text
   (text-indent). Neutralized here, scoped to the fallback-logo case only
   (where the text is always hidden) — the real-logo case keeps its own
   line-height untouched. Directly responsible for part of the excessive
   mobile-header-height bug fixed this round.

   Base (<768px) logo size: 88px (0.1.27) -> 72px (0.2.0-dev.2, to hit that
   round's own "-20 à -25% hauteur totale" target) -> 100px (0.2.0-dev.3,
   this round's own explicit "conserver le logo à environ 95–110px de
   largeur" — back inside a similar range to 0.1.27's original "80 à 105px"
   ask, just narrower and shifted slightly up). Aspect ratio and
   background-size:contain are unchanged regardless of the exact pixel
   value, so the mark itself is never cropped or distorted, only resized.
   Combined with the tightened vertical padding (header-grid block near the
   top of this file), mobile header height is 116px this round. */
.cristaline-fallback-logo .site-branding .site-title {
	line-height: 0;
}

.cristaline-fallback-logo .site-branding .site-title a {
	background-image: url("../images/logo-cristaline.png");
	background-position: left center;
	background-repeat: no-repeat;
	background-size: contain;
	display: inline-block;
	height: 100px;
	overflow: hidden;
	text-indent: -9999px;
	width: 100px;
}

/* 0.1.26: bumped 76px -> 96px (client's own "environ 90 à 120px" ask).
   0.2.0-dev.4: bumped again, 96px -> 108px (this round's own "largeur
   environ 100 à 125px" ask). Still the right size for the compact tier
   (768-1279px) specifically, which never had a header-height complaint —
   the full desktop nav is hidden behind the hamburger there, so there's
   no "9 items + logo + tools on one row" pressure.
   0.2.0-dev.13: split in two — this round's own explicit "hauteur
   compacte, aucune zone vide excessive" ask for 768/900px specifically
   (both real test widths this round), and its own equally explicit
   "conserver strictement la version desktop... ne pas modifier au-dessus
   de 1024px" boundary. 108px was measured live to be the dominant factor
   in a 255px-tall header at 768px (row 1 alone: 108px logo + 32px
   padding ≈ 130px, before the full-width search row underneath even
   counts) — confirmed via getBoundingClientRect() on every header grid
   item, not assumed. Shrunk to 72px for 768-1024px only; 1025-1279px
   keeps the exact original 108px below, unchanged. */
@media (min-width: 768px) and (max-width: 1024px) {
	.cristaline-fallback-logo .site-branding .site-title a {
		height: 72px;
		width: 72px;
	}
}

@media (min-width: 1025px) and (max-width: 1279px) {
	.cristaline-fallback-logo .site-branding .site-title a {
		height: 108px;
		width: 108px;
	}
}

/* 0.2.0-dev.5: shrunk again, 108px -> 68px, DESKTOP TIER ONLY. Real
   conflict in this round's own two numbers: a square logo (the source
   file is a 500×500 mark, confirmed in earlier rounds) at the requested
   "105 à 125px de largeur" is ALSO 105-125px tall, which alone exceeds
   the requested "hauteur totale du header : environ 88 à 100 px" before
   counting any padding at all — the two targets can't both hold for a
   square asset. Prioritized the header-height target: it's the one
   backed by an explicit numeric range AND a full validation checklist
   ("le header ne reste pas stable" is the round's own closing bar), while
   the logo range is presented as indicative ("environ"). 68px + 12px
   top/bottom padding (see the desktop header-grid block above) = 92px
   total header height, comfortably inside 88-100px — confirmed live.
   Flagged in this round's own report as a deliberate trade-off, not an
   oversight, in case the client would rather keep a larger logo and
   accept a taller header instead. */
@media (min-width: 1280px) {
	.cristaline-fallback-logo .site-branding .site-title a {
		height: 68px;
		width: 68px;
	}
}

/* Header: social icons + account link — real siblings of #site-navigation
   and #site-header-cart now (0.1.26 — all 5 render inside the same
   ".col-full" grid, see the header-grid block above). */
.cristaline-header-social {
	align-items: center;
	display: flex;
	/*
	 * 0.2.0-dev.49 — client's own explicit "16 à 20px entre Instagram et le
	 * montant CHF" ask. The header row's own grid `column-gap` (10px,
	 * assets/css/layout.css's ≥1280px header-grid block) is shared UNIFORMLY
	 * by every adjacent pair in "logo nav search social cart account" — that
	 * value is the result of this project's own extensively documented,
	 * repeatedly-regressed ≥1280px width budget (see this file's own
	 * "column-gap: 10px" comment), so it is NOT touched here. Instead, a
	 * small, deliberately modest margin widens ONLY the social→cart gap:
	 * 10px (existing grid gap) + 6px (this margin) = 16px, the LOW end of
	 * the requested range — chosen over the full +10px specifically to
	 * minimise the real width this round's own larger circular buttons
	 * (below) already add to this same tight row. Flagged in this round's
	 * own final report as a real, monitored risk to re-check live after
	 * install, per this project's own standing practice for this exact
	 * breakpoint.
	 */
	margin-right: 6px;
	position: relative;
}

/*
 * 0.2.0-dev.49 — the optional thin vertical separator between the social
 * icons and the cart, client's own explicit "éventuellement" ask. A
 * pseudo-element, not a new DOM node or extra grid item — sits inside the
 * gap this rule's own margin-right just created, adding no further width
 * of its own beyond a hairline.
 */
.cristaline-header-social::after {
	background-color: rgba(248, 247, 244, .22);
	content: "";
	height: 22px;
	position: absolute;
	right: -13px;
	top: 50%;
	transform: translateY(-50%);
	width: 1px;
}

/*
 * 0.2.0-dev.50 — "bijou discret" premium redesign: a real, visible circular
 * button with a soft ambient champagne glow even at rest (client's own
 * explicit "léger halo lumineux autour du cercle" ask this round), a subtly
 * gold-tinted glass background (never fully flat/transparent), brightening
 * to a real, brighter halo plus a soft inner highlight on hover — client's
 * own explicit "sans tomber dans un rendu flashy ou kitsch" boundary kept
 * by staying strictly monochrome champagne/ivory (no color, no gradient)
 * and by keeping every glow value soft (small blur radius, moderate
 * opacity) rather than a hard neon ring. Supersedes 0.2.0-dev.49's
 * Facebook-blue/Instagram-gradient hover (removed below) — this round's
 * own explicit palette ("champagne doré #C5AD8A, ivoire #F8F7F4") is a
 * deliberate reversal of that brand-color direction, not an oversight (see
 * this project's own standing precedent for a client legitimately reversing
 * a previous round's explicit spec, e.g. 0.1.30's Marques-link history).
 * The shape itself (border/radius/background/shadow/transition) is shared
 * across EVERY placement (header/footer/mobile drawer) — client's own
 * "cohérence parfaite entre header et footer" ask, extended to the mobile
 * drawer for the same reason — each context below only sets its own SIZE.
 */
.cristaline-social-links a {
	align-items: center;
	background-color: rgba(197, 173, 138, .12);
	border: 1px solid rgba(197, 173, 138, .45);
	border-radius: 50%;
	box-shadow: 0 0 8px rgba(197, 173, 138, .25), 0 2px 5px rgba(0, 0, 0, .15);
	color: var(--color-chrome-text);
	display: inline-flex;
	justify-content: center;
	transition: background-color 260ms ease, border-color 260ms ease, box-shadow 260ms ease, color 260ms ease, transform 260ms ease;
}

/*
 * 0.2.0-dev.50 — the brighter hover state: a real, visible halo (larger
 * blur, higher opacity than the rest state above), a faint inset highlight
 * simulating a soft inner reflection ("éventuellement un très léger reflet
 * intérieur", client's own wording), the border brightening to near-full
 * opacity, and a 1px lift — enough to read as a genuine jewel-like
 * response to the cursor without becoming a distracting animation. Gated
 * to real hover-capable devices only (this project's own standing rule
 * since 0.2.0-dev.3 — a fill that can't be dismissed by anything but a
 * second tap reads as "stuck" on touch) — unchanged reasoning from
 * 0.2.0-dev.49, just a different visual result.
 */
@media (hover: hover) and (pointer: fine) {
	.cristaline-social-links a:hover {
		background-color: rgba(197, 173, 138, .24);
		border-color: rgba(197, 173, 138, .85);
		box-shadow: 0 0 16px rgba(197, 173, 138, .6), inset 0 0 6px rgba(255, 255, 255, .22), 0 2px 6px rgba(0, 0, 0, .2);
		color: #fff;
		transform: translateY(-1px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.cristaline-social-links a {
		transition: none;
	}

	.cristaline-social-links a:hover {
		transform: none;
	}
}

/*
 * Real inline SVGs (inc/header-footer.php's own cristaline_social_links_
 * html()) no longer carry a hardcoded width/height attribute (0.2.0-dev.48)
 * — every placement sizes them via its own modifier class, the ONE place
 * icon size is decided per context.
 */
.cristaline-social-links--header {
	gap: 9px;
}

.cristaline-social-links--header a {
	height: 34px;
	width: 34px;
}

.cristaline-social-links--header svg {
	height: 18px;
	width: 18px;
}

.cristaline-social-links--header a:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

/* 0.2.0-dev.6: real dead-code conflict found and fixed — this rule's own
   "margin-left: var(--space-4)" was silently doubling the account link's
   own spacing, overriding the OTHER ".cristaline-account-link" rule
   (grid-area block, near the top of this file) which explicitly sets
   "margin-left: 0" with a comment explaining why (the grid's own
   column-gap already provides the spacing). Removed here — the grid gap
   is the single source of truth for this spacing now. Also adds a real
   44×44px tap target (client's own explicit accessibility ask) via
   padding, with a matching negative margin so the LARGER click area
   doesn't visually shift the icon's own position or widen the grid
   column beyond what the header's own right-edge padding already
   absorbs. */
.cristaline-account-link {
	align-items: center;
	color: var(--color-chrome-text);
	display: inline-flex;
	justify-content: center;
	margin: -11px;
	padding: 11px;
}

@media (hover: hover) and (pointer: fine) {
	.cristaline-social-links a:hover,
	.cristaline-account-link:hover {
		color: var(--color-chrome-accent);
	}
}

/* Footer — 0.2.0-dev.4: dark "chrome" redesign, matching the header (same
   client brief: header + footer only go dark, everything else on the site
   keeps the light palette). */
.site-footer {
	background-color: var(--color-chrome-bg);
	border-top: 1px solid var(--color-chrome-border);
	color: var(--color-chrome-text);
}

/* 0.2.0-dev.5: real correction to this round's own explicit spec — footer
   links were solid white (opacity 1) by default with a CHAMPAGNE hover;
   the client's own numbers this round ask for the opposite emphasis: links
   sit at ~0.75-0.82 opacity by default (a real secondary tone, distinct
   from full-white titles) and go to PURE white on hover (not champagne —
   that accent stays reserved for the section kickers/numbers elsewhere on
   the page, matching the "champagne discret" framing, not every footer
   hover state).
   0.2.0-dev.7: .78 -> .83 — client's own new explicit range for main
   footer links, "0.80 à 0.86", still reported as "trop gris/peu lisible"
   at .78. Set directly on this rule (not a parent-container opacity), so
   it's a real per-text RGBA value per the client's own explicit constraint
   against opacity inherited by a whole column.
   0.2.0-dev.8: real root cause found and fixed — WordPress/Storefront's own
   inline stylesheet (`<style id="storefront-style-inline-css">`, generated
   from the Customizer's colour settings, output as an inline block tied to
   the `storefront-style` handle, BEFORE this theme's own CSS bundle in the
   real page) contains ".site-footer a:not(.button):not(.components-button)
   { color: #333333 }" — specificity (0,3,1), strictly higher than this
   rule's previous (0,1,1) ".site-footer a", so it was winning regardless of
   load order and silently forcing every footer link back to near-black.
   Confirmed live by walking every loaded stylesheet's cssRules and calling
   element.matches() against the real "Découvrir"/"Nos services" link —
   this exact rule was the only match with a non-default color. This inline
   block also explains why .cristaline-footer__cities/__copyright (non-<a>
   elements, never matched by this Storefront rule at all) were already
   correctly white — only real <a> tags under .site-footer were affected,
   which is exactly what the client reported. Fixed by matching the same
   selector shape (same specificity, later source order in this file wins)
   instead of reaching for !important. Colour literal also switched from
   the --color-bg-derived rgba(248,247,244,…) to a plain rgba(255,255,255,…)
   base per this round's own explicit spec. */
/* 0.2.0-dev.10: .82 -> .80 — this round's own explicit "liens normaux et
   visités : rgba(255,255,255,0.80)" target. Also explicitly re-confirmed
   live as a genuinely signed-out visitor (no session cookie, no admin-bar
   class) that this rule — and the specificity fix it documents above —
   is already winning correctly; no separate "public" rule was found
   overriding it, and this project's own theme files contain zero
   is_user_logged_in()/body.logged-in-conditional logic anywhere (grepped
   before writing anything). If a visitor still sees the old dark grey
   after this ships, the CDN/host cache is the far more likely explanation
   than a code path — this exact project has proven that failure mode
   before (see the 0.1.29 changelog entry, x-hcdn-cache-status: HIT with a
   multi-hour age on a stylesheet that had already been fixed and
   re-verified). */
.site-footer a:not(.button):not(.components-button) {
	color: rgba(255, 255, 255, .80);
	transition: color 150ms ease, text-decoration-color 150ms ease;
}

.site-footer a:not(.button):not(.components-button):visited,
.site-footer a:not(.button):not(.components-button):active {
	color: rgba(255, 255, 255, .80);
}

/* 0.2.0-dev.10: --color-bg (#F8F7F4, warm pearl) -> literal #FFFFFF —
   this round's own explicit "hover et focus-visible : #FFFFFF" target
   (previously used the pearl token, which is close but not literally
   white). */
@media (hover: hover) and (pointer: fine) {
	.site-footer a:hover:not(.button):not(.components-button) {
		color: #FFFFFF;
	}
}

/* 0.1.25: real bug, confirmed live — every footer link (menu items, legal
   links) rendered permanently underlined, since base.css's own "a" rule
   never sets text-decoration at all (only text-decoration-color / offset,
   for whenever an underline IS shown) and nothing here ever opted out —
   so it was just the browser's own default <a> underline, always on,
   client's own "visuellement trop chargé" complaint. Discreet, hover/focus-
   only underline for ordinary links; .cristaline-footer__all-shops ("Voir
   toutes nos boutiques") keeps its own always-on underline unchanged below
   — the one explicit exception the client asked to keep, since it's the
   column's one real action link, not an ordinary nav item. */
.cristaline-footer__menu a,
.cristaline-footer__legal a {
	text-decoration: none;
}

.cristaline-footer__menu a:hover,
.cristaline-footer__menu a:focus-visible,
.cristaline-footer__legal a:hover,
.cristaline-footer__legal a:focus-visible {
	text-decoration: underline;
	text-underline-offset: .2em;
}

/* 0.1.24: explicit weight + a touch larger than the footer links below it
   (.cristaline-footer__menu a, .9rem) — client's own "semi-gras, légèrement
   plus grand" ask. Color/family unchanged (already --color-ink via
   .site-footer's own color rule, already --font-heading).
   0.2.0-dev.8: explicit color added — real root cause found live: this
   rule never set its own color, relying on inheriting .site-footer's
   var(--color-chrome-text). WordPress/Storefront's own inline stylesheet
   (see .site-footer a's own 0.2.0-dev.8 comment above) sets ".site-footer
   h1, h2, h3, h4, h5, h6 { color: #333333 }" — an EXPLICIT rule on the
   element itself always wins over an inherited value regardless of
   specificity, which is why "Découvrir"/"Nos services"/"Nos boutiques"
   (all real <h2 class="widget-title">) rendered near-black despite
   .site-footer's own color rule. Declaring a real color here
   (specificity 0,2,0, already higher than Storefront's 0,1,1 for this
   selector list) fixes all 3 column titles at once, same class. */
/* 0.2.0-dev.10: .96 -> solid #FFFFFF — this round's own explicit "titres
   de colonnes : #FFFFFF" target. */
.site-footer .widget-title {
	color: #FFFFFF;
	font-family: var(--font-heading);
	font-size: 1.05rem;
	font-weight: 600;
	margin-bottom: var(--space-4);
}

/* 0.2.0-dev.5: top/bottom padding (48px/32px) already sat inside the
   client's own "48 à 56px" / "32 à 40px" ranges — kept as-is. The real
   "réduire la hauteur totale du footer d'environ 25 à 35%" ask is met
   below instead: .cristaline-footer__columns' own gap and
   .cristaline-footer__bottom's margin/padding, both trimmed. */
/* 0.2.0-dev.6: trimmed once more — 48px/32px -> 40px/28px, client's own
   "réduire sa hauteur et ses espacements verticaux" ask for this round
   (already trimmed once in 0.2.0-dev.5). */
.cristaline-footer {
	padding: 40px 0 28px;
}

.cristaline-footer__columns {
	display: grid;
	gap: 20px;
	grid-template-columns: 1fr;
}

/* 0.2.0-dev.4: was repeat(3, 1fr) — the new brand column (logo + blurb +
   social) carries more content than the other 3, so it gets a wider
   fraction rather than an equal 1/4 share, same "wide first, narrower rest"
   pattern common to premium footer layouts. */
@media (min-width: 768px) {
	.cristaline-footer__columns--4 {
		grid-template-columns: 1.4fr 1fr 1fr 1fr;
	}
}

.cristaline-footer__col--brand {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
}

.cristaline-footer__logo {
	background-image: url("../images/logo-cristaline.png");
	background-position: left center;
	background-repeat: no-repeat;
	background-size: contain;
	display: inline-block;
	height: 64px;
	overflow: hidden;
	text-indent: -9999px;
	width: 64px;
}

/* 0.2.0-dev.5: opacity .68 -> .78 — client's own explicit "description :
   blanc avec une opacité d'environ 0.78" (a dedicated value rather than
   the shared --color-chrome-text-muted token, which stays at .68 for its
   other uses — header placeholder text, etc. — untouched by this
   footer-specific spec).
   0.2.0-dev.7: .78 -> .82 — client's new explicit "~0.82" target, still
   reported as too gray at .78.
   0.2.0-dev.8: base literal switched to rgba(255,255,255,…) per this
   round's own explicit spec (was --color-bg-derived 248,247,244). This
   element is a <p>, never matched by Storefront's ".site-footer
   a:not(...)" inline rule, so it was already rendering correctly — value
   unchanged at .82, only the literal base colour updated for consistency
   with every other footer text rule this round. */
.cristaline-footer__blurb {
	color: rgba(255, 255, 255, .82);
	font-size: .9rem;
	line-height: 1.6;
	margin: 0;
	max-width: 32ch;
}

/*
 * 0.2.0-dev.48 — "Suivez-nous" + icons, client's own explicit footer spec
 * this round (previously just the bare icon list). Kept inside the SAME
 * brand column (no new footer column, no extra height beyond the label's
 * own line) — client's own "s'intégrer naturellement... ne pas agrandir
 * excessivement le footer" constraint. `--color-chrome-text-muted` is the
 * same muted-white token already used for every other secondary footer
 * text ("Découvrir"/"Nos services" column intros etc.) — reused rather
 * than a new literal opacity value.
 */
.cristaline-footer__social {
	margin-top: var(--space-3);
}

.cristaline-footer__social-label {
	color: var(--color-chrome-text-muted);
	font-size: .78rem;
	letter-spacing: .04em;
	margin: 0 0 var(--space-2);
	text-transform: uppercase;
}

/*
 * 0.2.0-dev.49 — real ~38px circular buttons (client's own explicit "mêmes
 * boutons circulaires que dans le header" ask), replacing the previous
 * invisible-enlarged-tap-target treatment. The shared circular shape,
 * ambient glow AND hover state (border/radius/background/shadow/
 * transition) all live on the generic `.cristaline-social-links a` rule
 * above — 0.2.0-dev.50 removed this block's own separate gold-fill hover
 * entirely, since the shared rule's own premium hover now IS the "cohérence
 * parfaite entre header et footer" the client explicitly asked for this
 * round, rather than a second, independently-tuned footer-only hover.
 * Only size/spacing stay footer-specific here.
 */
.cristaline-social-links--footer {
	gap: 11px;
}

.cristaline-social-links--footer a {
	height: 38px;
	width: 38px;
}

.cristaline-social-links--footer svg {
	height: 18px;
	width: 18px;
}

.cristaline-social-links--footer a:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.cristaline-footer__menu {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

/* 0.2.0-dev.6: font-weight 400 (unset) -> 500 — client's own "rendre les
   colonnes Découvrir et Nos services aussi lisibles que Nos boutiques"
   ask; a touch more weight reads as more substantial next to the
   boutiques column's own always-underlined, visually heavier "Voir
   toutes nos boutiques" action link. */
.cristaline-footer__menu a {
	font-family: var(--font-nav);
	font-size: .9rem;
	font-weight: 500;
}

/* 0.2.0-dev.5: solid white -> --color-chrome-text-muted (.68 opacity) —
   plain city names are secondary information next to the column's own
   white title and the real "Voir toutes nos boutiques" link, matching the
   client's own 3-tier text hierarchy (titles/links/secondary) rather than
   reading at the same weight as a title.
   0.2.0-dev.7: .68 -> a dedicated .88 (no longer the shared muted token,
   which stays .68 for its other uses) — the client's new explicit
   "liste des boutiques : blanc, opacité >= 0.86" target reverses the
   earlier "secondary tier" framing; a real list of 4 shop names reads as
   near-invisible at .68 against the dark footer.
   0.2.0-dev.8: .88 -> .90 (this round's explicit target) + literal base
   switched to rgba(255,255,255,…). This element is a <li>, never matched
   by Storefront's ".site-footer a:not(...)" inline rule (see .site-footer
   a's own 0.2.0-dev.8 comment) — already rendering correctly before this
   round, only the exact value/base literal updated. */
.cristaline-footer__cities {
	color: rgba(255, 255, 255, .90);
	display: flex;
	flex-direction: column;
	font-family: var(--font-nav);
	font-size: .9rem;
	gap: var(--space-1);
	margin-bottom: var(--space-3);
}

/* 0.1.26: real bug, confirmed live — .cristaline-footer__cities already
   had its own margin-bottom (var(--space-3), 12px), but Storefront's own
   auto-enqueued child style.css genuinely loads AFTER this file (checked
   live via the real stylesheet load order, not assumed) and its
   "ul[class],ol[class] { margin: 0 }" reset (same 0,1,0 specificity as
   .cristaline-footer__cities, tied specificity resolved by later source
   order) was winning, silently zeroing that margin back out — only ~3px
   of real gap was left (line-height/font-metrics, not a real margin).
   Fixed here instead, on margin-top of the link itself: "ul[class]"
   structurally can't match this <a>, so there's no cascade fight to lose
   regardless of load order. display:inline-block is needed for a
   margin-top to actually create real vertical space on an element that's
   inline by default (base.css's own "a" rule never changes that). */
/* 0.2.0-dev.7: explicit color added — this link previously just inherited
   ".site-footer a" (.83, a "regular link" tone); the client's own spec
   calls it out as its own tier ("blanc ou champagne clairement visible"),
   so it gets a dedicated, slightly higher value than ordinary footer
   links to read as the column's one real action.
   0.2.0-dev.8: real bug — this rule's bare ".cristaline-footer__all-shops"
   selector (0,1,0) never actually won against WordPress/Storefront's own
   inline ".site-footer a:not(.button):not(.components-button) { color:
   #333333 }" (0,3,1) — confirmed live the link was rendering near-black
   the whole time despite this rule looking correct on paper (same root
   cause as .site-footer a's own 0.2.0-dev.8 fix above). Rescoped to match
   or exceed that selector's specificity; "ou champagne clair" (the
   client's own offered alternative to plain white) used here specifically
   so this one action link keeps reading as visually distinct from the
   ordinary column links around it, now that both tiers are close in
   opacity (.82). */
.site-footer a.cristaline-footer__all-shops:not(.button):not(.components-button) {
	color: color-mix(in srgb, var(--color-gold) 78%, white 22%);
	display: inline-block;
	font-family: var(--font-nav);
	font-size: .9rem;
	margin-top: 16px;
	text-decoration: underline;
	text-underline-offset: .2em;
}

.site-footer a.cristaline-footer__all-shops:not(.button):not(.components-button):visited,
.site-footer a.cristaline-footer__all-shops:not(.button):not(.components-button):active {
	color: color-mix(in srgb, var(--color-gold) 78%, white 22%);
}

/* Needs its own hover rule, not just the shared ".site-footer a:hover"
   above — that rule and this element's own base rule (both 0,4,1 once the
   ":not()" pair is added) tie in specificity, and this element's base rule
   loads LATER in this file, so it would otherwise win over the earlier,
   shared hover rule even on a real :hover. One extra selector level here
   (0,5,1) settles it unambiguously. */
/* 0.2.0-dev.10: --color-bg -> literal #FFFFFF, matching the general
   footer hover target this round (the resting colour stays champagne per
   this round's own "lien principal ... champagne clair" spec — only the
   hover/focus-visible state moves to pure white, same as every other
   footer link). */
@media (hover: hover) and (pointer: fine) {
	.site-footer a.cristaline-footer__all-shops:hover:not(.button):not(.components-button) {
		color: #FFFFFF;
	}
}

/* 0.2.0-dev.5: margin-top 48px -> 24px, padding-top 32px -> 20px — the
   real contributor to "footer trop grand" once the top/bottom section
   padding turned out to already be inside the client's own target range
   (see .cristaline-footer's own comment above): this 80px gap before the
   legal row, combined with the column gap trim above, is what gets the
   whole footer into the client's own "environ 25 à 35%" reduction target. */
/* 0.2.0-dev.6: trimmed once more — margin-top 24px -> 16px, padding-top
   20px -> 16px, same "réduire sa hauteur" ask as .cristaline-footer above. */
.cristaline-footer__bottom {
	align-items: center;
	border-top: 1px solid var(--color-chrome-border);
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	margin-top: 16px;
	padding-top: 16px;
	text-align: center;
}

/* 0.2.0-dev.4: was a color-mix() blend of --color-ink/--color-neutral (the
   0.1.26 fix for low contrast on the old LIGHT footer background) —
   swapped for --color-chrome-text-muted now that the footer itself is
   dark; the old light-mode blend would read as near-invisible on charcoal.
   0.2.0-dev.7: --color-chrome-text-muted (.68) -> a dedicated .82 — the
   client's new explicit "copyright: blanc, opacité ~0.82" target; the
   shared muted token stays .68 for its other, genuinely-secondary uses.
   0.2.0-dev.8: .82 -> .86 (this round's explicit target) + literal base
   switched to rgba(255,255,255,…). This element is a <p>, never matched
   by Storefront's ".site-footer a:not(...)" inline rule — already
   rendering correctly before this round. */
/* 0.2.0-dev.10: .86 -> .85 — this round's own explicit "copyright :
   rgba(255,255,255,0.85)" target. */
.cristaline-footer__copyright {
	color: rgba(255, 255, 255, .85);
	font-size: .85rem;
	margin: 0;
}

.cristaline-footer__legal {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2) var(--space-4);
	justify-content: center;
}

/* 0.1.26: white-space:nowrap keeps each label ("Politique de
   confidentialité", the longest one) as one unbroken unit — combined with
   flex-wrap on the container above, a whole label moves to the next line
   together when it doesn't fit, rather than ever breaking mid-word.
   Checked live at 320/360/390px. */
/* 0.2.0-dev.6: explicit dedicated color — client's own "textes juridiques
   environ 55-65% d'opacité" ask, its own distinct (lower) tier from the
   .78 regular-link default this would otherwise inherit from
   ".site-footer a". Hover still lightens via the shared ".site-footer
   a:hover" rule (pure white) — legal links stay readable/functional on
   focus or hover, just quieter at rest.
   0.2.0-dev.7: .6 -> .72 — client's new explicit "0.68 à 0.75 minimum"
   range, still reported as too gray at .6.
   0.2.0-dev.8: real bug — this rule's ".cristaline-footer__legal a"
   selector (0,2,1) never actually won against WordPress/Storefront's own
   inline ".site-footer a:not(.button):not(.components-button) { color:
   #333333 }" (0,3,1) — same root cause as every other footer <a> fixed
   this round (see .site-footer a's own 0.2.0-dev.8 comment). Rescoped to
   match/exceed that specificity; value .72 unchanged (already inside this
   round's own "0.68 à 0.75" range), literal base switched to
   rgba(255,255,255,…). Needs its own dedicated hover rule below for the
   same reason .cristaline-footer__all-shops does: at tied specificity with
   the shared ".site-footer a:hover" rule, this rule's later position in
   the file would otherwise win even ON hover, silently preventing the
   hover colour from ever showing. */
/* 0.2.0-dev.10: .72 -> .70 — this round's own explicit "liens juridiques :
   rgba(255,255,255,0.70)" target. */
.site-footer .cristaline-footer__legal a:not(.button):not(.components-button) {
	color: rgba(255, 255, 255, .70);
	font-size: .8rem;
	white-space: nowrap;
}

.site-footer .cristaline-footer__legal a:not(.button):not(.components-button):visited,
.site-footer .cristaline-footer__legal a:not(.button):not(.components-button):active {
	color: rgba(255, 255, 255, .70);
}

@media (hover: hover) and (pointer: fine) {
	.site-footer .cristaline-footer__legal a:hover:not(.button):not(.components-button) {
		color: #FFFFFF;
	}
}

/* Homepage-only styles (hero, category tiles, new-arrivals grid, brand
   strip) moved to assets/css/homepage.css in 0.2.0-dev.1 — enqueued only
   on is_front_page() (see inc/enqueue.php), so no other page loads them. */


/* =========================================================
   Compact / mobile navigation (below 1280px)
   Desktop layout, homepage content, colors and WooCommerce
   templates are untouched.

   0.1.27: the "Real structure" diagram and the row1/row2 flex rules this
   comment originally described are GONE — folded into the single shared
   ".site-header" grid near the top of this file (see that block's own
   0.1.26/0.1.27 comments for the current architecture; the historical
   context below — why 1280px, why the 768–1279px tier exists at all — is
   kept because it's still the reason those breakpoints are what they are,
   just no longer describes the literal CSS below this comment). Only the
   menu-toggle/drawer-visibility/breadcrumb rules further down in this
   block are still live code.

   Breakpoint moved from Storefront's own default (768px, "$desktop" in
   their _variables.scss) up to 1280px for the NAV specifically: with 9
   top-level items + cart + account link sharing one row, real widths
   measured live on the actual WordPress site (see
   Decisions-validees.md) didn't reliably fit a single line below that —
   1200px and 1366px-minus-some-margin both still wrapped even after the
   padding/cart/flex-row fixes below; 1280px (which also happens to match
   --container-max) is the first width that consistently held one line
   across repeated live checks.

   0.1.25: this whole block was rebuilt around a real, confirmed-live
   regression in 0.1.24. Storefront's own ".storefront-handheld-footer-bar"
   (the fixed bottom tab bar with Recherche/Panier/Mon compte) is ONLY
   shown below 768px — Storefront's own native CSS sets it
   "display: none" at "(min-width: 768px)" (checked live in the real
   compiled stylesheet, not assumed). 0.1.24 hid this theme's own header
   search/cart/account unconditionally below 1280px, reasoning that the
   bottom bar already covered the same functions — true below 768px, but
   NOT in the real 768–1279px range, which was left with no way at all to
   search, view the cart, or reach the account page. That gap is almost
   certainly what the client's "il existe une largeur intermédiaire où la
   navigation devient incomplète" report was describing.

   Fixed with a real 3rd tier instead of a 2-way switch: a "compact" header
   (768–1279px) that keeps a real, working search field, cart and account
   link — laid out as two ordinary flex rows (never absolute positioning
   for alignment, per the client's own explicit instruction), not a single
   absolutely-positioned 44px corner box the way 0.1.8–0.1.24 did it:
     Row 1 (.site-header > .col-full):            logo (+ search, >=768px)
     Row 2 (.storefront-primary-navigation .col-full): hamburger + cart + account
   Both rows share the exact same container treatment (max-width:
   var(--container-max), margin: 0 auto) as .site-header's branding row and
   .cristaline-mega-menu__inner, so nothing in the header sits at a
   different left/right edge than the mega-menu content below it (see also
   navigation.css's 0.1.25 fix to .storefront-primary-navigation .col-full
   at >=1280px, the same alignment bug one tier up).
   Below 768px, search/cart/account go back to being hidden — the bottom
   bar genuinely does cover them there, reconfirmed live this round.

   Verified against the exact Storefront 4.6.2 tag (matching the
   parent theme installed on WordPress) — not trunk, not assumed:
     https://github.com/woocommerce/storefront/tree/4.6.2
       inc/storefront-template-functions.php
       inc/storefront-template-hooks.php
       inc/woocommerce/storefront-woocommerce-template-functions.php
       inc/woocommerce/storefront-woocommerce-template-hooks.php
       assets/js/navigation.js
       assets/css/base/_layout.scss (menu-toggle/primary-navigation display switch)
       assets/css/woocommerce/woocommerce.scss (.site-header-cart / .cart-contents)
   Also verified: .woocommerce-breadcrumb against WooCommerce's own
   woocommerce_breadcrumb() default wrap_before, and that Storefront
   4.6.2 only repositions that hook (storefront_before_content),
   it does not change the class.

   Real structure:
     .site-header (position:relative — the only ancestor anchor)
       .col-full                          (branding row)
         .site-branding > .site-title
         .site-search                        (>=768px only, see below)
       .storefront-primary-navigation     (nav row, sibling of the above,
                                            normal block flow — no longer
                                            position:absolute, see below)
         .col-full
           #site-navigation.main-navigation   <-- JS adds/removes .toggled HERE
             button.menu-toggle > span        <-- text lives in a real <span>
             .primary-navigation                (the actual menu <ul> wrapper)
             .handheld-navigation               (unused fallback menu)
           #site-header-cart.site-header-cart   <-- cart icon, sibling of the nav
           .cristaline-account-link             <-- sibling of the above

   The real overlay drawer (.cristaline-mobile-drawer) is a SEPARATE
   sibling of .storefront-primary-navigation, position:fixed to the
   viewport (see navigation.css) — it never depended on
   .storefront-primary-navigation being position:absolute (confirmed: no
   ancestor between it and <body> sets transform/filter/will-change/
   perspective, which are the only things that would change a
   position:fixed element's containing block), so switching that ancestor
   to normal flow here has no effect on how the drawer itself renders.
   ========================================================= */

/* Site title: full text, natural wrap, no clip/clamp — applies at every
   width (defensive against text overflow whenever a real Customizer logo
   replaces the image fallback and Storefront falls back to rendering the
   plain site title), not just <768px. */
.site-branding .site-title {
	display: block;
	overflow: visible;
	-webkit-line-clamp: unset;
	margin: 0;
	font-size: clamp(20px, 6vw, 26px);
	line-height: 1.1;
	word-break: normal;
	overflow-wrap: normal;
	hyphens: none;
}

.site-branding .site-title a {
	word-break: normal;
	overflow-wrap: normal;
	hyphens: none;
}

/* 0.2.0-dev.3: REAL root cause of "zone blanche entre le header et le hero
   sur mobile", found by fetching Storefront's own real compiled style.css
   directly (per this project's standing rule to verify against the real
   source, not memory) rather than guessing — confirmed present,
   completely unconditional in Storefront's own file (no @media wrapper at
   all there, so it would affect every width if left unchecked):
     .home.blog .site-header,
     .home.page:not(.page-template-template-homepage) .site-header,
     .home.post-type-archive-product .site-header { margin-bottom: 4.235801032em }
   (≈67.8px). The "Accueil" page is a static front page using the default
   template (no "template-homepage" page template assigned), so its body
   carries "home page" without "page-template-template-homepage" — this
   rule matches. Its specificity (.home.page:not(...) .site-header = 4
   class-level selectors, 0,4,0) beats this theme's own plain
   ".site-header { margin-bottom: 0 }" below (0,1,0) regardless of source
   order — that existing override was never actually winning on the
   homepage specifically, only looked like it worked elsewhere (every
   other page lacks the ".home" class, where Storefront's own rule simply
   doesn't match and was never the problem). Fixed by matching the exact
   same selector Storefront uses (same specificity, this stylesheet loads
   after Storefront's, so source order now correctly decides it). Scoped
   to <1280px on purpose, matching this round's own "sur mobile" framing
   and every other header tier boundary in this file — desktop's existing
   spacing was not reported as a problem this round and is left untouched.
   Set to 48px (var(--space-12)), not 0 — the client asked for a
   deliberate, smaller gap (48–64px on standard mobile, 40–50px on small
   phones), not for the header to touch the hero; 48px satisfies both
   stated ranges at once (it's the shared value where they overlap), so no
   extra breakpoint is needed just for this. */
@media (max-width: 1279px) {
	.home.page:not(.page-template-template-homepage) .site-header {
		margin-bottom: var(--space-12);
	}
}

/* 0.2.0-dev.6: mobile-specific trim — client's own "réduire légèrement...
   l'espace entre le header et le hero" ask for mobile specifically (the
   768-1279px tier wasn't mentioned this round, so it keeps the 48px
   above). 40px still sits inside the "40-50px small phones" range this
   theme already committed to in an earlier round — a real reduction, not
   just a re-statement of the existing value. Same selector/specificity
   match against Storefront's own real rule as the block above, just
   narrowed to <768px so it wins there specifically (later source order,
   tied specificity). */
@media (max-width: 767px) {
	.home.page:not(.page-template-template-homepage) .site-header {
		margin-bottom: 40px;
	}
}

@media (max-width: 1279px) {

	/* 1. Compact header — natural height, no forced minimum */
	.site-header {
		margin-bottom: 0;
		min-height: 0;
	}

	/* 4. Menu toggle: 56x56 (0.2.0-dev.2: bumped from 48x48 — this round's
	   own explicit "zone tactile d'environ 56 à 60 px" ask; 0.1.27's own
	   48px already covered the "au minimum 44×44px" floor still asked for
	   this round, so this is a further increase, not a fix). Pearl/
	   transparent, real 3-bar hamburger built from the button's own <span>
	   (middle bar) plus ::before/::after (top/bottom bars) — no markup
	   changes, native button/JS/aria-expanded untouched. ".site-header
	   .menu-toggle" (rather than plain ".menu-toggle") is used so its
	   specificity beats components.css's global
	   "button:not(.wc-block-components-button)" gold-pill rule. Applies up
	   to 1279px (mobile + the compact/"petite tablette" tier alike) — at
	   the compact tier the header row is already sized by the 96px logo,
	   so this doesn't change that tier's own total height. */
	.site-header .menu-toggle {
		/* 0.1.29: real bug, confirmed live — same root cause as the
		   .cristaline-mobile-drawer__back/close fix in navigation.css
		   (this theme never neutralized -webkit-tap-highlight-color
		   anywhere): the browser's own default gray tap-highlight overlay
		   could render on top of this button's real, always-transparent-
		   or-pearl background, misread as a permanent square. */
		-webkit-tap-highlight-color: transparent;
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		width: 56px;
		height: 56px;
		padding: 0;
		margin: 0;
		background-color: rgba(248, 247, 244, .1);
		border: 1px solid var(--color-chrome-border);
		border-radius: var(--radius-sm);
		flex: none;
	}

	@media (hover: hover) and (pointer: fine) {
		.site-header .menu-toggle:hover {
			background-color: rgba(248, 247, 244, .18);
		}
	}

	/* 0.1.28: real bug, confirmed live — this toggle only ever had a
	   :focus-visible rule, with nothing neutralizing the browser's own
	   default :focus ring for the cases where :focus-visible's keyboard-
	   intent heuristic doesn't suppress it after a real tap/click (the
	   same root cause already fixed for Retour/Fermer/category links in
	   navigation.css back in 0.1.25 — this button was simply missed at the
	   time, since the client's earlier reports were specifically about the
	   drawer's own internal buttons, not the header toggle that opens it).
	   Same accessible pattern: outline:none scoped to plain :focus only,
	   paired with its own :focus-visible rule right below — never a
	   global "outline: none". */
	.site-header .menu-toggle:focus {
		outline: none;
	}

	.site-header .menu-toggle:focus-visible {
		outline: 2px solid var(--color-chrome-accent);
		outline-offset: 2px;
	}

	.site-header .menu-toggle span {
		display: block;
		width: 20px;
		height: 2px;
		background-color: var(--color-chrome-text);
		color: transparent;
		font-size: 0;
		line-height: 0;
		transition: opacity 150ms ease;
	}

	/* left/top recalculated for the 56px box (was 48px): centered
	   horizontally ((56-20)/2 = 18px); bars kept the same 7px bar-center-
	   to-box-center spacing as before (before: 28-7=21 center -> top 20;
	   after: 28+7=35 center -> top 34), just re-based on the new box
	   center (28, was 24) so the 3-bar icon itself stays the same visual
	   size and only re-centers in the bigger tap target. */
	.site-header .menu-toggle::before,
	.site-header .menu-toggle::after {
		content: "";
		position: absolute;
		left: 18px;
		width: 20px;
		height: 2px;
		background-color: var(--color-chrome-text);
		transition: transform 150ms ease, top 150ms ease;
	}

	.site-header .menu-toggle::before {
		top: 20px;
	}

	.site-header .menu-toggle::after {
		top: 34px;
	}

	/* Open state -> X. #site-navigation.toggled is Storefront's real,
	   JS-applied toggle class (confirmed in assets/js/navigation.js,
	   4.6.2 tag). Both bars converge on the box's own true center
	   (28 - 1 half-bar-height = 27, was 23 for the 48px box). */
	#site-navigation.toggled .menu-toggle span {
		opacity: 0;
	}

	#site-navigation.toggled .menu-toggle::before {
		top: 27px;
		transform: rotate(45deg);
	}

	#site-navigation.toggled .menu-toggle::after {
		top: 27px;
		transform: rotate(-45deg);
	}

	/* 5. Visibility switch only — Storefront's own default breakpoint
	   (768px) still needs overriding up to our 1279px one, regardless of
	   what opens when toggled. What OPENS is now assets/js/mobile-
	   drawer.js's own full-viewport ".cristaline-mobile-drawer" overlay
	   (see navigation.css), rendered as a sibling of
	   ".storefront-primary-navigation" — never this ".handheld-navigation"
	   copy of "Menu Cristaline" itself.
	   ".handheld-navigation" is kept, deliberately unstyled beyond a plain
	   block list below, as the no-JS fallback (every top-level link still
	   reachable if assets/js/mobile-drawer.js never runs) — the drawer's
	   own JS hides this plain list once it successfully takes over (see
	   that file's docblock), so a visitor never sees both at once. */
	.primary-navigation {
		display: none;
	}

	#site-navigation:not(.toggled) .handheld-navigation {
		display: none;
	}

	#site-navigation.toggled .handheld-navigation {
		display: block;
	}

	#site-navigation.toggled .handheld-navigation div,
	#site-navigation.toggled .handheld-navigation ul,
	#site-navigation.toggled .handheld-navigation li {
		width: 100%;
		max-width: none;
		margin: 0;
		padding: 0;
		float: none;
		box-sizing: border-box;
		list-style: none;
	}

	#site-navigation.toggled .handheld-navigation a {
		display: block;
		width: 100%;
		min-height: 44px;
		padding: 12px 20px;
		font-size: 16px;
		line-height: 1.35;
		box-sizing: border-box;
		color: var(--color-ink);
		text-decoration: none;
		border-bottom: 1px solid var(--color-accent-soft);
	}

	/* Hidden once assets/js/mobile-drawer.js has taken over (marks
	   <html data-cristaline-drawer-initialized="true">) — prevents the
	   plain no-JS list from showing underneath/behind the real drawer
	   overlay. */
	html[data-cristaline-drawer-initialized="true"] #site-navigation.toggled .handheld-navigation {
		display: none;
	}

	/* 6. Simplify inner pages: hide breadcrumbs, keep titles from
	   overflowing. .woocommerce-breadcrumb verified against
	   WooCommerce's own woocommerce_breadcrumb() defaults. */
	.woocommerce-breadcrumb {
		display: none;
	}

	.entry-title,
	.page-title,
	.woocommerce-products-header__title {
		overflow-wrap: break-word;
		max-width: 100%;
	}

	/* 7. Never allow a horizontal scrollbar in this whole tier — kept
	   unconditional (not scoped to either sub-tier below) as a blanket
	   safety net, same as before. */
	body {
		overflow-x: hidden;
	}
}

/* =========================================================
   0.2.0-dev.6: search rebuilt again, simpler this time — a persistently
   visible compact field (the client's own explicit "réduire le champ à
   environ 145-155px" ask, REVERSING the 0.2.0-dev.4/dev.5 icon-collapse
   approach entirely: no more click-to-open state, no more ".is-open"
   class, no more assets/js/header-search.js toggle logic — dead code
   removed, see that file's own docblock). Expands to ~190px ONLY on
   focus, via position:absolute so the expansion overlays rather than
   reflowing: .site-search itself keeps a fixed 150px box for grid-sizing
   purposes (so logo/nav/social/cart/account never shift), while its real
   content (the WooCommerce search form) becomes an absolutely-positioned
   overlay anchored to the box's own right edge once focused, growing
   LEFTWARD into the nav's own centered whitespace (confirmed there's
   room there now that nav is genuinely centered, see the header-grid
   block's own dev.6 comment above) rather than rightward into the
   cart/account cluster. */
/* 0.2.0-dev.9: real bug found live and fixed — ".site-search" (a CSS grid
   item, "grid-area: search") had no height of its own; its rendered 48px
   came entirely from its single child (".woocommerce-product-search")
   contributing to its auto content-height. The moment that child becomes
   "position: absolute" on focus (below), it's removed from normal flow
   and stops contributing to its parent's height AT ALL — ".site-search"
   itself collapsed to a real, measured 0px height, and the grid row then
   centered that now-empty box within its own (taller) row track, moving
   its top from y=20 to y=44 — the client's own "le champ descend au
   focus" report, confirmed via getBoundingClientRect() before/after a
   real .focus() call, not assumed. An explicit height here removes the
   dependency on the child entirely, so ".site-search" never changes size
   regardless of what its child's own position becomes. align-self:center
   added explicitly too (the client's own ask) so it's never implicitly
   inherited/guessed from the grid container's own align-items. */
@media (min-width: 1280px) {
	.woocommerce-active .site-header .site-search {
		align-self: center;
		height: 42px;
		position: relative;
		width: 150px !important;
	}

	/* 0.2.0-dev.9: real second cause of the same bug, found only after the
	   fix above still left the RESTING (unfocused) input measuring 48px
	   tall, 3px taller than ".site-search" on each side — WooCommerce
	   actually wraps the search form in its own ".widget" div (never
	   visible in this file, since nothing here styles it directly), which
	   sits BETWEEN ".site-search" and ".woocommerce-product-search" and
	   has no height of its own (auto). A percentage height on a normal
	   in-flow child resolves against its OWN parent's height — here, that
	   intermediate ".widget" div, not ".site-search" — so the form's own
	   "height:100%" was silently computing against an auto/content-based
	   box and falling back to its intrinsic ~48px. (Once focused and
	   "position:absolute", percentage resolution instead uses the nearest
	   POSITIONED ancestor's padding box — ".site-search" itself, which
	   HAS "position:relative" — which is why only the focused state
	   measured correctly before this fix.) Giving the real intermediate
	   wrapper a height too closes that gap for the resting state as well. */
	.site-search .widget {
		height: 100%;
	}

	.site-search .woocommerce-product-search {
		height: 100%;
		transition: width 200ms ease;
		width: 100%;
	}

	.site-search:focus-within .woocommerce-product-search {
		background-color: var(--color-chrome-bg);
		position: absolute;
		right: 0;
		top: 0;
		width: 190px;
		z-index: 10;
	}
}

@media (prefers-reduced-motion: reduce) {
	.site-search .woocommerce-product-search {
		transition: none;
	}
}

/* =========================================================
   0.1.26: Compact tier (768–1279px) — MODE B. The search field spans the
   full row width — never hidden at this tier (the real fix for the
   confirmed gap documented in the big comment above: Storefront's own
   bottom bar only covers <768px, so a working search/cart/account here
   can't depend on it). (grid-template-areas/columns themselves now live
   in the shared header-grid block above, 0.1.27.)
   ========================================================= */
@media (min-width: 768px) and (max-width: 1279px) {
	.site-search {
		justify-self: stretch;
		width: 100%;
	}
}

/* =========================================================
   Mobile tier only (<768px) — search/cart/account go back to hidden here;
   Storefront's own ".storefront-handheld-footer-bar" is confirmed live to
   actually cover this range (unlike 768–1279px, see the big comment
   above), so nothing is lost, and this is the one tier that still needs
   its bottom padding reserved for that bar.
   ========================================================= */
@media (max-width: 767px) {
	.site-header .site-search,
	.site-header-cart,
	.cristaline-account-link {
		display: none;
	}

	/* 0.1.26: real bug, confirmed live (twice — same razor-thin buffer as
	   0.1.25's own bottom-bar-visibility fix) — ".storefront-handheld-
	   footer-bar" measures 68.765625px tall live (stable across every
	   width tested, 320–390px), so the previous flat 72px left only ~3px
	   of clearance: enough on this test viewport, not enough margin for
	   any real device to differ even slightly (a taller safe-area, a
	   slightly different font metric) without the footer's last legal
	   link ending up genuinely covered. 69px (the bar's real measured
	   height, rounded up) + a real 24px margin + env(safe-area-inset-
	   bottom) for notched devices — the client's own suggested formula,
	   using this bar's own real height rather than copying their example
	   number blindly. */
	body {
		padding-bottom: calc(69px + env(safe-area-inset-bottom) + 24px);
	}
}
