/**
 * FLUXX — page frame, header, footer, product grid.
 *
 * Reads tokens.css.
 */

/* ------------------------------------------------------------- containers */

.fx-container {
	width: 100%;
	max-width: var(--fx-page-max);
	margin-inline: auto;
	padding-inline: var(--fx-gutter);
}

@media (min-width: 768px) {
	.fx-container {
		padding-inline: var(--fx-gutter-md);
	}
}

/* Full width, no gutter. Hero banners and edge-to-edge product grids. */
.fx-container--bleed {
	max-width: none;
	padding-inline: 0;
}

/* Section rhythm: tight on mobile, generous on desktop. */
.fx-section {
	padding-block: 32px;
}

@media (min-width: 768px) {
	.fx-section {
		padding-block: 56px;
	}
}

/* ------------------------------------------------ announcement / marquee */

.fx-announce {
	height: var(--fx-announce-h);
	background: var(--fx-sand);
	color: var(--fx-ink);
	overflow: hidden;
	display: flex;
	align-items: center;
	position: relative;
}

/*
 * The row travels exactly one group's width and then repeats, by which point
 * the next identical group is sitting where the last one started. That is what
 * makes the loop continuous.
 *
 * The two numbers below are fallbacks for when the script has not run. It
 * measures a group and sets both from the real width, because the duration a
 * readable speed needs depends on how much text there is — and the client can
 * change that whenever they like.
 */
.fx-announce__track {
	display: flex;
	min-width: max-content;
	white-space: nowrap;
	animation: fx-crawl var(--fx-marquee-duration, 40s) linear infinite;
}

/*
 * One group of messages. The trailing padding is the gap that would otherwise
 * be missing at the join: `gap` puts space between items but not after the last
 * one, so without this the seam is one gap tighter than everywhere else.
 */
.fx-announce__set {
	display: flex;
	gap: 48px;
	padding-inline-end: 48px;
}

/* Pause on hover so a message can actually be read. The reference does not. */
.fx-announce:hover .fx-announce__track,
.fx-announce:focus-within .fx-announce__track {
	animation-play-state: paused;
}

@keyframes fx-crawl {
	from { transform: translateX(0); }
	to   { transform: translateX(var(--fx-marquee-shift, -50%)); }
}

/* With motion off the marquee becomes a centred static strip. */
@media (prefers-reduced-motion: reduce) {
	.fx-announce__track {
		animation: none;
		margin-inline: auto;
	}

	.fx-announce__set {
		padding-inline-end: 0;
	}

	.fx-announce__set + .fx-announce__set,
	.fx-announce__item + .fx-announce__item {
		display: none;
	}
}

/* ----------------------------------------------------------------- header */

.fx-header {
	position: sticky;
	top: 0;
	z-index: var(--fx-z-header);
	background: var(--fx-paper);
	border-bottom: 1px solid var(--fx-border);
}

.fx-header__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	height: var(--fx-header-h);
	max-width: var(--fx-page-max);
	margin-inline: auto;
	padding-inline: var(--fx-gutter);
}

@media (min-width: 768px) {
	.fx-header__bar {
		height: var(--fx-header-h-md);
		gap: 24px;
		padding-inline: var(--fx-gutter-md);
	}
}

.fx-header__brand {
	display: flex;
	align-items: center;
	flex-shrink: 0;
}

.fx-header__brand svg,
.fx-header__brand img {
	height: 22px;
	width: auto;
}

@media (min-width: 768px) {
	.fx-header__brand svg,
	.fx-header__brand img {
		height: 26px;
	}
}

.fx-header__nav {
	display: none;
}

@media (min-width: 1024px) {
	.fx-header__nav {
		display: flex;
		align-items: center;
		gap: 28px;
		flex: 1 1 auto;
		justify-content: center;
	}
}

.fx-header__actions {
	display: flex;
	align-items: center;
	gap: 16px;
	flex-shrink: 0;
}

@media (min-width: 768px) {
	.fx-header__actions {
		gap: 24px;
	}
}

.fx-header__action {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var(--fx-ink);
}

/* The bag count. Small, accent, never a large red circle. */
.fx-header__count {
	position: absolute;
	top: -6px;
	inset-inline-end: -8px;
	min-width: 16px;
	height: 16px;
	padding-inline: 4px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--fx-ink);
	color: var(--fx-text-on-dark);
	border-radius: var(--fx-radius-round);
	font-size: 10px;
	font-weight: var(--fx-weight-bold);
	line-height: 1;
}

.fx-header__count[hidden] {
	display: none;
}

/* --------------------------------------------------- mobile bottom tab bar */
/*
 * Part of the app-shell illusion: on mobile the primary navigation sits at the
 * bottom, within thumb reach, as it would in a native app.
 */
.fx-tabbar {
	position: fixed;
	bottom: 0;
	inset-inline: 0;
	z-index: var(--fx-z-header);
	max-width: var(--fx-shell-mobile);
	margin-inline: auto;
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	align-items: center;
	height: 58px;
	background: var(--fx-paper);
	border-top: 1px solid var(--fx-border);
	padding-bottom: env(safe-area-inset-bottom);
}

@media (min-width: 768px) {
	.fx-tabbar {
		display: none;
	}
}

.fx-tabbar__item {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 3px;
	height: 100%;
	color: var(--fx-ink);
	font-size: 10px;
	letter-spacing: var(--fx-tracking-nav);
	text-transform: uppercase;
}

/* The entire active-state mechanism: accent stroke at double weight. */
.fx-tabbar__item.is-active {
	color: var(--fx-accent-alt);
}

.fx-tabbar__item.is-active .fx-icon path {
	stroke-width: 2;
}

/*
 * Clear the tab bar and the sticky add-to-cart bar so the last row of content
 * is never trapped underneath them.
 */
@media (max-width: 767px) {
	.fx-shell {
		padding-bottom: 58px;
	}

	body.fx-has-sticky-cta .fx-shell {
		padding-bottom: 132px;
	}
}

/* ---------------------------------------------------------- product grid */
/*
 * Deliberately dense: 8px horizontal and 2px vertical gutters make the grid
 * read as one editorial sheet rather than a set of cards. This is the single
 * most recognisable thing about the reference's catalogue pages.
 */
.fx-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: var(--fx-grid-gap-x);
	row-gap: var(--fx-grid-gap-y);
}

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

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

/* The compact toggle on catalogue pages. */
.fx-grid--dense {
	grid-template-columns: repeat(3, minmax(0, 1fr));
}

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

@media (min-width: 1024px) {
	.fx-grid--dense {
		grid-template-columns: repeat(5, minmax(0, 1fr));
	}
}

@media (min-width: 1280px) {
	.fx-grid--dense {
		grid-template-columns: repeat(7, minmax(0, 1fr));
	}
}

/*
 * A horizontally scrolling rail of the same cards.
 *
 * Written as `.products.fx-rail` so it outranks the catalogue grid rules in
 * woocommerce.css, which set fixed columns on the same element. The rail and
 * the grid are the same markup in two arrangements; only the axis differs.
 */
.products.fx-rail {
	display: grid;
	grid-auto-flow: column;
	grid-template-columns: none;
	grid-auto-columns: 46%;
	column-gap: var(--fx-grid-gap-x);
	row-gap: 0;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	/* The gutter is scroll padding too, so the first card is not flush against
	   the viewport edge at scroll position zero. */
	padding-inline: var(--fx-gutter);
	scroll-padding-inline: var(--fx-gutter);
	margin: 0;
	list-style: none;
}

.products.fx-rail > * {
	scroll-snap-align: start;
}

@media (min-width: 768px) {
	.products.fx-rail {
		grid-auto-columns: 30%;
		padding-inline: var(--fx-gutter-md);
		scroll-padding-inline: var(--fx-gutter-md);
	}
}

@media (min-width: 1024px) {
	.products.fx-rail {
		grid-auto-columns: 23%;
	}
}

@media (min-width: 1600px) {
	/* Past the page frame the rail centres rather than running to the edges. */
	.products.fx-rail {
		max-width: var(--fx-page-max);
		margin-inline: auto;
	}
}

/* ----------------------------------------------------------------- footer */

.fx-footer {
	background: var(--fx-sand);
	color: var(--fx-ink);
	padding-block: 40px 32px;
	margin-top: 48px;
}

.fx-footer__cols {
	display: grid;
	gap: 28px;
	grid-template-columns: 1fr;
}

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

.fx-footer__list {
	list-style: none;
	margin: 12px 0 0;
	padding: 0;
	display: grid;
	gap: 8px;
}

.fx-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-top: 32px;
	padding-top: 20px;
	border-top: 1px solid rgba(11, 11, 11, .12);
}

/*
 * Contact details are a footer fixture here.
 *
 * The reference publishes no phone number or email anywhere on the site, and
 * its reviews say so repeatedly. This is the cheapest trust win available.
 */
.fx-footer__contact {
	display: grid;
	gap: 6px;
}

.fx-footer__contact a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}
