/*
 * Sticky header, cart control, account link.
 *
 * Loaded on every page (functions.php), unlike homepage.css / catalogue.css /
 * product.css which are template-scoped — the header is the one component that
 * is genuinely global.
 */

/* ── Sticky behaviour ──────────────────────────────────────────────
   `position: sticky` rather than `fixed` on purpose: a sticky element keeps
   its box in normal flow, so the page below it does not jump upward by the
   header's height the moment it sticks. `fixed` removes it from flow and
   would need a compensating spacer to avoid exactly that shift. */

#site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	transition: box-shadow 200ms ease, border-color 200ms ease;
}

/*
 * IMPORTANT: the stuck state changes shadow and border only — never padding,
 * height, or font size.
 *
 * A sticky element is still in flow, so its box still occupies its slot in the
 * document. Shrinking the header on scroll therefore reflows everything below
 * it, which is the layout shift this task exists to avoid. Shadow and colour
 * are composited, cost no reflow, and produce the same "lifted" read.
 */
#site-header.is-stuck {
	box-shadow: var(--kyrex-shadow-sm);
	border-bottom-color: transparent;
}

/* The observer target. Zero height, no visual presence — assets/header.js
   watches it leave the viewport to know the header has begun sticking. */
.site-header__sentinel {
	height: 0;
}

/*
 * The admin bar is `position: fixed`, so a header stuck at `top: 0` slides
 * underneath it. Offset by the admin bar's own height at each of its two
 * breakpoints — WordPress switches it from 32px to 46px at 782px.
 */
body.admin-bar #site-header {
	top: 32px;
}

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


/* ── Header actions ────────────────────────────────────────────────
   Account link and cart control, grouped so they stay together as one unit
   when the header wraps at narrow widths. */

.site-header__actions {
	display: flex;
	align-items: center;
	gap: 1.25rem;
	margin-left: auto;
}

.kyrex-account-link,
.kyrex-cart-link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	color: var(--kyrex-charcoal);
	font-family: var(--kyrex-font-body);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-decoration: none;
	padding: 0.375rem;
	border-radius: var(--kyrex-radius-sm);
	transition: color 200ms ease;
}

.kyrex-account-link:hover,
.kyrex-cart-link:hover {
	color: var(--kyrex-gold-deep);
}

/* Visible focus ring — keyboard users must be able to see where they are.
   `:focus-visible` rather than `:focus` so a mouse click does not leave a
   ring behind. */
.kyrex-account-link:focus-visible,
.kyrex-cart-link:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 2px;
}


/* ── Cart count badge ──────────────────────────────────────────────
   Positioned against the icon rather than sitting inline, so the control's
   width does not change as the count goes from 1 to 2 digits — which would
   otherwise nudge the whole header layout on every add to cart. */

.kyrex-cart-link {
	position: relative;
}

.kyrex-cart-count {
	position: absolute;
	top: -0.125rem;
	left: 1.0625rem;
	min-width: 1.125rem;
	height: 1.125rem;
	padding: 0 0.25rem;
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background-color: var(--kyrex-wine);
	color: var(--kyrex-ivory);
	border-radius: var(--kyrex-radius-pill);
	font-size: 0.625rem;
	font-weight: 600;
	letter-spacing: 0;
	line-height: 1;
}

/*
 * An empty cart shows no badge at all rather than a "0".
 *
 * `display: none` and NOT removing the element: WooCommerce's cart fragments
 * replace this control by selector, so the node has to stay in the DOM for the
 * count to ever come back. Rendering nothing when empty would mean the first
 * add to cart had nothing to replace.
 */
.kyrex-cart-count--empty {
	display: none;
}

/* ── Header search ─────────────────────────────────────────────────
   Collapsed behind a magnifier at every width. One form in the DOM, opening
   into a panel below the header — rather than a second copy inside the mobile
   drawer, which would be two forms to keep in step for no gain. */

/* Deliberately NOT position:relative. The panel below spans the full header
   width, which means its containing block has to be #site-header — already
   positioned, because it is sticky — rather than this little flex wrapper. */
.kyrex-header-search {
	display: flex;
	align-items: center;
}

.kyrex-header-search__toggle {
	display: none;
	align-items: center;
	justify-content: center;
	padding: 0.375rem;
	background: none;
	border: 0;
	border-radius: var(--kyrex-radius-sm);
	color: var(--kyrex-charcoal);
	cursor: pointer;
	transition: color 200ms ease;
}

.kyrex-header-search__toggle:hover {
	color: var(--kyrex-gold-deep);
}

.kyrex-header-search__toggle:focus-visible,
.kyrex-search-form__submit:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 2px;
}

.kyrex-search-form {
	display: flex;
	align-items: center;
	gap: 0.375rem;
	background-color: var(--kyrex-surface);
	border: 1px solid var(--kyrex-border);
	border-radius: var(--kyrex-radius-pill);
	padding: 0.25rem 0.25rem 0.25rem 0.875rem;
}

.kyrex-search-form__field {
	flex: 1;
	min-width: 0;
	background: none;
	border: 0;
	color: var(--kyrex-charcoal);
	font-family: var(--kyrex-font-body);
	font-size: 0.875rem;
	padding: 0.375rem 0;
}

.kyrex-search-form__field::placeholder {
	color: var(--kyrex-charcoal-muted);
}

/* The field sits inside a bordered pill, so the focus ring goes on the pill
   rather than the input — an outline on the input alone would draw a second
   rectangle inside the first. */
.kyrex-search-form__field:focus {
	outline: none;
}

.kyrex-search-form:focus-within {
	border-color: var(--kyrex-gold-deep);
	box-shadow: 0 0 0 1px var(--kyrex-gold-deep);
}

/* Brass, not near-black. A charcoal disc is the heaviest thing in a header
   built out of hairlines and ivory, and it pulled the eye to a control
   nobody needs to press — pressing Enter, or picking a result, is the
   actual path. */
.kyrex-search-form__submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.875rem;
	height: 1.875rem;
	flex: none;
	background-color: var(--kyrex-gold);
	color: var(--kyrex-charcoal);
	border: 0;
	border-radius: var(--kyrex-radius-pill);
	cursor: pointer;
	transition: background-color 200ms ease;
}

.kyrex-search-form__submit:hover {
	background-color: var(--kyrex-gold-soft);
	color: var(--kyrex-charcoal);
}

/* The browser's own clear button, removed.
   Chrome draws an unstyleable grey ✕ inside every input[type="search"], and
   with the panel's own close button beside it that put two ✕ controls a
   few pixels apart doing completely different things — one clears the
   query, one dismisses the panel. Ambiguous, and it looked like a bug. The
   panel's close is the one that stays, because it is the one that is
   styled and labelled. */
.kyrex-search-form__field::-webkit-search-cancel-button,
.kyrex-search-form__field::-webkit-search-decoration {
	-webkit-appearance: none;
	appearance: none;
}


/*
 * Visibility is decided here, not by a script.
 *
 * These controls previously shipped the `hidden` attribute and were unhidden by
 * assets/header.js. That produced an intermittent layout shift: until the script
 * ran, the no-JS fallback below rendered the search field inline, so the header
 * was 366px wide and 42px tall at first paint and then collapsed to 213x32 —
 * roughly 0.1 CLS on half of cold loads, which is the whole "good" budget spent
 * on a flash.
 *
 * `html.no-js` is swapped to `js` by an inline head script before first paint,
 * so the browser knows which state to render on the very first pass. It also
 * keeps the semantics honest: nothing is visible while still carrying `hidden`,
 * which would show a control to sighted users that assistive technology is told
 * does not exist.
 */
.kyrex-header-search__toggle {
	display: inline-flex;
}

html.no-js .kyrex-header-search__toggle {
	display: none;
}

/* ── Search panel ──────────────────────────────────────────────────
   Full width, anchored under the header. The previous version was a 26rem
   pill floating over the occasion chips with no ground of its own; it read
   as a rendering fault, and there was nowhere to put anything but a bare
   list of names.

   Full width buys the two-column layout — occasion shortcuts on the left,
   live results on the right — which is what makes the panel useful the
   moment it opens rather than only after typing. */

.kyrex-header-search__panel {
	display: none;
	position: absolute;
	left: 0;
	right: 0;
	top: 100%;
	z-index: 30;
	background-color: var(--kyrex-surface);
	border-top: 1px solid var(--kyrex-border);
	border-bottom: 1px solid var(--kyrex-border);
	box-shadow: 0 18px 40px rgb(42 38 34 / 12%);
}

.kyrex-header-search.is-open .kyrex-header-search__panel {
	display: block;
}

.kyrex-header-search__inner {
	padding-block: 1.5rem 1.75rem;
}

.kyrex-header-search__field {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

.kyrex-header-search__field form,
.kyrex-header-search__field .search-form {
	flex: 1;
	min-width: 0;
}

.kyrex-header-search__close {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--kyrex-radius-sm);
	color: var(--kyrex-charcoal-muted);
	cursor: pointer;
}

.kyrex-header-search__close:hover {
	color: var(--kyrex-charcoal);
}

.kyrex-header-search__close:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 2px;
}

/* Shortcuts | results. One column on a phone, with the results first —
   somebody who has typed wants to see what they found, not scroll past a
   list of occasions to reach it. */
.kyrex-header-search__body {
	display: grid;
	grid-template-columns: 1fr;
	gap: 1.5rem;
	margin-top: 1.5rem;
}

@media (min-width: 48rem) {
	.kyrex-header-search__body {
		grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
		gap: 3rem;
	}
}

@media (max-width: 47.999rem) {
	.kyrex-header-search__results {
		order: 1;
	}

	.kyrex-header-search__shortcuts {
		order: 2;
		padding-top: 1.25rem;
		border-top: 1px solid var(--kyrex-border);
	}
}

.kyrex-header-search__label {
	font-family: var(--kyrex-font-body);
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--kyrex-charcoal-muted);
	margin: 0 0 0.75rem;
}

.kyrex-header-search__links {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.125rem;
}

.kyrex-header-search__links a {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
	padding: 0.4375rem 0.5rem;
	border-radius: var(--kyrex-radius-sm);
	font-family: var(--kyrex-font-body);
	font-size: 0.875rem;
	color: var(--kyrex-charcoal);
	text-decoration: none;
}

.kyrex-header-search__links a:hover {
	background-color: var(--kyrex-ivory);
	color: var(--kyrex-gold-deep);
}

.kyrex-header-search__links a:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 1px;
}

.kyrex-header-search__links span {
	font-size: 0.75rem;
	color: var(--kyrex-charcoal-muted);
	font-variant-numeric: tabular-nums;
}

.kyrex-header-search__hint {
	font-family: var(--kyrex-font-body);
	font-size: 0.875rem;
	color: var(--kyrex-charcoal-muted);
	margin: 0;
	padding: 0.5rem 0;
}

/* Dimmed while a request is in flight. Opacity only — anything that moves
   the list would register as layout shift, and this build measured 0.3595
   once already. */
.kyrex-header-search__results[aria-busy="true"] {
	opacity: 0.6;
	transition: opacity 120ms ease;
}

@media (prefers-reduced-motion: reduce) {
	.kyrex-header-search__results[aria-busy="true"] {
		transition: none;
	}
}

.kyrex-search-results__note {
	font-family: var(--kyrex-font-body);
	font-size: 0.8125rem;
	font-style: italic;
	color: var(--kyrex-charcoal-muted);
	margin: 0 0 0.75rem;
}

.kyrex-search-results__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.25rem;
	max-height: min(24rem, 55vh);
	overflow-y: auto;
}

@media (min-width: 62rem) {
	/* Two-up once there is room, so six results do not become a long scroll. */
	.kyrex-search-results__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 0.25rem 1rem;
	}

	.kyrex-search-result--all {
		grid-column: 1 / -1;
	}
}

.kyrex-search-result__link {
	display: grid;
	grid-template-columns: 3.5rem 1fr;
	gap: 0.875rem;
	align-items: center;
	padding: 0.5rem;
	border-radius: var(--kyrex-radius-sm);
	text-decoration: none;
	color: var(--kyrex-charcoal);
}

/* Hover and the arrow-key cursor look identical on purpose: there is one
   notion of "the result you are on", however you arrived at it. */
.kyrex-search-result.is-active .kyrex-search-result__link,
.kyrex-search-result__link:hover {
	background-color: var(--kyrex-ivory);
}

.kyrex-search-result__media {
	display: block;
	width: 3.5rem;
	height: 3.5rem;
	border-radius: var(--kyrex-radius-sm);
	overflow: hidden;
	background-color: var(--kyrex-ivory);
	border: 1px solid var(--kyrex-border);
	position: relative;
}

.kyrex-search-result__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Photography is outstanding for most of the catalogue, so the no-image
   case is the common one. The same plus mark the product cards use, so a
   missing photograph looks intentional rather than broken. */
.kyrex-search-result__media--empty::before,
.kyrex-search-result__media--empty::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	background-color: var(--kyrex-gold-soft);
	transform: translate(-50%, -50%);
}

.kyrex-search-result__media--empty::before {
	width: 0.875rem;
	height: 1px;
}

.kyrex-search-result__media--empty::after {
	width: 1px;
	height: 0.875rem;
}

.kyrex-search-result__body {
	display: block;
	min-width: 0;
}

.kyrex-search-result__name {
	display: block;
	font-family: var(--kyrex-font-body);
	font-size: 0.9375rem;
	font-weight: 500;
	line-height: 1.3;
	/* A long package name must not push the price out of the panel. */
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.kyrex-search-result__meta {
	display: block;
	font-family: var(--kyrex-font-body);
	font-size: 0.8125rem;
	color: var(--kyrex-charcoal-muted);
	margin-top: 0.1875rem;
}

.kyrex-search-result--all .kyrex-search-result__link {
	grid-template-columns: 1fr;
	justify-items: start;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--kyrex-gold-deep);
	margin-top: 0.5rem;
	padding-top: 0.875rem;
	border-top: 1px solid var(--kyrex-border);
	border-radius: 0;
}

/*
 * No-JS fallback: without script the toggle can never be pressed, so a
 * permanently collapsed panel would mean no search at all. The field goes back
 * inline, and the panel's chrome comes off with it.
 */
html.no-js .kyrex-header-search__panel {
	display: block;
	position: static;
	background: none;
	border: 0;
	box-shadow: none;
}

html.no-js .kyrex-header-search__inner {
	padding: 0;
}

html.no-js .kyrex-header-search__body,
html.no-js .kyrex-header-search__close {
	display: none;
}

/* ── Occasion chip row ─────────────────────────────────────────────
   Pills, horizontally scrollable. Lives here rather than in homepage.css
   because header.php renders this row on every page — see the note left in
   homepage.css. */

.kyrex-chip:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 2px;
	box-shadow: 0 0 0 4px var(--kyrex-ivory);
	border-radius: var(--kyrex-radius-sm);
}

/* ── 1. Occasion chip row — pills, horizontally scrollable ───────────── */

.kyrex-chip-row {
	background-color: var(--kyrex-ivory);
	border-bottom: 1px solid var(--kyrex-border);
	padding-block: 1rem;
}

.kyrex-chip-row__scroll {
	overflow-x: auto;
	scrollbar-width: thin;
	-webkit-overflow-scrolling: touch;
}

.kyrex-chip-row__list {
	display: flex;
	flex-wrap: nowrap;
	gap: 0.75rem;
	list-style: none;
	margin: 0;
	padding: 0.25rem 0;
	width: max-content;
	min-width: 100%;
}

.kyrex-chip-row__item {
	flex: 0 0 auto;
}

.kyrex-chip {
	display: inline-flex;
	align-items: center;
	white-space: nowrap;
	font-family: var(--kyrex-font-body);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--kyrex-charcoal);
	background-color: var(--kyrex-ivory);
	border: 1px solid var(--kyrex-gold-soft);
	border-radius: var(--kyrex-radius-pill);
	padding: 0.5rem 1.125rem;
	transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;
}

.kyrex-chip:hover {
	background-color: var(--kyrex-gold-soft);
	border-color: var(--kyrex-gold-soft);
	color: var(--kyrex-charcoal);
}

/* ── Breadcrumbs ───────────────────────────────────────────────────
   Quiet by design: a wayfinding aid, not a feature. Muted until hovered. */

.kyrex-breadcrumb {
	padding-block: 1rem 0;
}

.kyrex-breadcrumb__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	list-style: none;
	margin: 0;
	padding: 0;
	font-family: var(--kyrex-font-body);
	font-size: 0.75rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--kyrex-charcoal-muted);
}

.kyrex-breadcrumb__item {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
}

.kyrex-breadcrumb__link {
	color: var(--kyrex-charcoal-muted);
	text-decoration: none;
	border-bottom: 1px solid transparent;
	transition: color 200ms ease, border-color 200ms ease;
}

.kyrex-breadcrumb__link:hover,
.kyrex-breadcrumb__link:focus-visible {
	color: var(--kyrex-charcoal);
	border-bottom-color: var(--kyrex-gold);
}

.kyrex-breadcrumb__current {
	color: var(--kyrex-charcoal);
}

.kyrex-breadcrumb__sep {
	color: var(--kyrex-charcoal-muted);
}


/* ── Drawer toggle and close ───────────────────────────────────────
   Both ship `hidden` for the same reason as the search toggle, and both need
   the same `:not([hidden])` guard so the attribute keeps winning until JS
   removes it. */

.site-header__menu-toggle,
.site-header__drawer-close {
	display: none;
	align-items: center;
	justify-content: center;
	padding: 0.375rem;
	background: none;
	border: 0;
	border-radius: var(--kyrex-radius-sm);
	color: var(--kyrex-charcoal);
	cursor: pointer;
}

.site-header__menu-toggle:focus-visible,
.site-header__drawer-close:focus-visible {
	outline: 2px solid var(--kyrex-charcoal);
	outline-offset: 2px;
}

/* ── Backdrop ──────────────────────────────────────────────────────
   Sits under the drawer and over everything else. `hidden` is toggled by JS;
   the `:not([hidden])` guard is what actually reveals it. */

.site-header__backdrop:not([hidden]) {
	display: block;
	position: fixed;
	inset: 0;
	z-index: 200;
	background-color: rgb(42 38 34 / 45%);
}

/* Scroll lock — without this the page behind the drawer scrolls under it. */
body.kyrex-drawer-open {
	overflow: hidden;
}

/* ── Narrow widths ─────────────────────────────────────────────────
   The nav becomes an off-canvas drawer. Same element, same links — only the
   presentation changes, so nothing is rendered twice. */

@media (max-width: 782px) {
	.site-header__menu-toggle,
	.site-header__drawer-close {
		display: inline-flex;
	}

	html.no-js .site-header__menu-toggle,
	html.no-js .site-header__drawer-close {
		display: none;
	}

	.site-header__actions {
		gap: 0.5rem;
	}

	.site-header__drawer {
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		width: min(20rem, 82vw);
		z-index: 300;
		display: flex;
		flex-direction: column;
		gap: 1.5rem;
		padding: 1.25rem;
		background-color: var(--kyrex-ivory);
		border-left: 1px solid var(--kyrex-border);
		overflow-y: auto;

		/*
		 * Off-canvas via transform, not `display: none` — a display-none
		 * element cannot be transitioned, and its children are not focusable,
		 * which would make the focus trap's job ambiguous. `visibility`
		 * carries the "not reachable while closed" part.
		 *
		 * THE `0s` TIMINGS ARE LOAD-BEARING. This was written as
		 * `transition: transform 240ms ease, visibility 240ms`, and that broke
		 * the drawer for keyboard users: a transitioning `visibility` keeps its
		 * computed value at `hidden` for the whole 240ms, and a
		 * visibility:hidden element cannot receive focus, so the `focus()` call
		 * on open was a silent no-op. Focus stayed on the toggle, the trap
		 * never engaged, and Tab walked straight out into the page behind the
		 * drawer. Caught by the Task 7 keyboard pass, not by reading the code.
		 *
		 * So: flip visibility instantly when opening (`0s` delay, below), and
		 * delay it until the slide has finished when closing (`0s 240ms`, here)
		 * so the drawer does not vanish mid-animation.
		 */
		transform: translateX(100%);
		visibility: hidden;
		transition: transform 240ms ease, visibility 0s 240ms;
	}

	body.kyrex-drawer-open .site-header__drawer {
		transform: translateX(0);
		visibility: visible;
		transition: transform 240ms ease, visibility 0s 0s;
	}

	.site-header__drawer-close {
		align-self: flex-end;
	}

	/* Stacked, generously spaced links — a drawer is touched, not pointed at. */
	.site-navigation ul.menu {
		flex-direction: column;
		align-items: flex-start;
		gap: 1.25rem;
	}

	/* Icon-only at narrow widths. This is the visually-hidden pattern, not
	   `display: none` — the word stays in the accessibility tree, so the link
	   is still announced as "Account" even though it reads as a bare icon. */
	.kyrex-account-link__label {
		border: 0;
		clip-path: inset(50%);
		height: 1px;
		overflow: hidden;
		position: absolute;
		width: 1px;
	}
}

/*
 * No-JS fallback for the drawer.
 *
 * Without JS the toggle can never be pressed, so an off-canvas drawer would
 * put the entire primary navigation permanently out of reach — a real
 * accessibility failure, not a cosmetic one. Here it stays in the normal flow
 * of the header as a plain wrapped nav row.
 *
 * Keyed off `html.no-js` rather than the toggle's `[hidden]` attribute
 * (the trick the search control uses) because the toggle is not a sibling of
 * the drawer — it sits inside `.site-header__actions` — so no sibling
 * combinator can reach it. `:has()` would work but takes the whole rule down
 * with it in any browser that cannot parse it. The class is swapped to `js` by
 * an inline script in the head, before first paint, so nothing flashes.
 */
@media (max-width: 782px) {
	html.no-js .site-header__drawer {
		position: static;
		width: 100%;
		transform: none;
		visibility: visible;
		border-left: 0;
		padding: 0;
		background: none;
	}
}
