/* =========================================================================
   Homepage sections
   Loaded only on the front page (see inc/enqueue.php).

   Contents
     1. Hero
     2. Marquee
     3. Category tiles
     4. Carousel (shared by Bestsellers and Shop the look)
     5. Bestsellers
     6. Shop the look
     7. Our mission
     8. Promise
     9. Lifestyle images
     10. Newsletter
   ====================================================================== */

/* -------------------------------------------------------------------------
   1. Hero

   A carousel of up to 5 slides — see t42_hero_slide_subfields() in
   inc/fields.php and template-parts/home/hero.php for why it stops at 5
   (free-tier ACF/SCF has no Repeater) and how a slide's fields resolve.

   BELOW 62rem each slide is a full-bleed photo or video, the header sitting
   transparent over it (see .has-transparent-header in main.css) and a
   minimal caption in the lower corner, scrim'd for legibility — the
   photograph carries the slide, the type is a caption on it.

   FROM 62rem the slide becomes two columns, photo beside caption, no scrim.
   Not a cosmetic choice: the source photography here is portrait, and a
   portrait image forced full-bleed across a wide desktop viewport means
   cropping most of the shot away or blurring it — see
   t42_gallery_image_size() in inc/woocommerce.php for the earlier fix this
   would otherwise repeat. Side by side keeps the whole photo. See main.css,
   ".has-transparent-header", for the header's half of this same switch —
   white nav text stops making sense once only half the slide is a photo.

   Navigation is the same [data-carousel] convention Bestsellers and Shop
   the look already use (see carousels() in app.js): a native horizontal
   scroll-snap track, arrows as an optional enhancement on top of it, so
   swipe/trackpad/wheel scrolling all work with no script at all. The dots
   are new — see heroDots() in app.js.
   ---------------------------------------------------------------------- */

/* The header is position:sticky, which still occupies its own space at the
   top of normal flow — without this, it would render as a plain solid bar
   above the image instead of floating transparently over it (and, worse, an
   invisible one: white text on the white body background behind it).
   Pulling the hero up by exactly the header's height slides it underneath
   the header, which — being sticky and positioned — paints above it. As the
   page scrolls, sticky keeps the header pinned at the top while the hero
   scrolls normally past/under it, so the overlay holds throughout. */
.hero {
	position: relative;
	margin-top: calc(-1 * var(--header-h));
}

.hero__carousel {
	position: relative;
}

/*
 * A plain horizontal scroll-snap row, the same mechanics as the shared
 * carousel (see "Carousel" further down and carousels() in app.js) — kept
 * separate rather than reusing that class because a hero slide is full
 * width, not a peeking multi-card row, and needed none of that version's
 * per-card sizing.
 */
.hero__track {
	display: flex;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

.hero__track::-webkit-scrollbar {
	display: none;
}

.hero__slide {
	position: relative;
	flex: 0 0 100%;
	scroll-snap-align: start;
	scroll-snap-stop: always;
}

.hero__media {
	position: relative;
	overflow: hidden;
	background: var(--bg-soft);
}

/*
 * Same box for both: in Video mode the <video> sits here instead of the
 * <img> (see hero.php), never both at once, so one shared rule is enough.
 * Autoplaying background video is exactly the kind of motion
 * prefers-reduced-motion exists for — see heroVideo() in app.js, which
 * pauses every slide's video on load rather than never starting them, so
 * the poster frame (the same image Image mode uses) is what a shopper who
 * asked for less motion actually sees, frozen, not a black box.
 */
.hero__image,
.hero__video {
	width: 100%;
	/*
	 * 100vh first as the fallback, 100dvh after to override it wherever a
	 * browser actually understands it: on mobile, 100vh is measured against
	 * the browser chrome's collapsed state, so a shopper starts the page
	 * taller than the screen actually shows and has to scroll a sliver just
	 * to see the fold — 100dvh (dynamic viewport height) tracks the chrome
	 * as it shows and hides instead, which is what "full height" is
	 * actually asking for on a phone.
	 */
	height: 100vh;
	height: 100dvh;
	object-fit: cover;
}

/* A bottom-anchored scrim, not a flat tint over the whole photograph — this
   keeps the top two-thirds of the image, and the header sitting on it, true
   to the original exposure. Below 62rem only — see the desktop override
   further down, where there is no text sitting on the photo left to protect. */
.hero__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 42%);
	pointer-events: none;
}

.hero__caption {
	position: absolute;
	left: 0;
	right: 0;
	bottom: clamp(1.75rem, 5vw, 3.5rem);
	z-index: 1;
	color: var(--white);
}

.hero__title {
	max-width: 14ch;
	font-size: var(--fs-900);
}

.hero__subtitle {
	max-width: 36ch;
	margin-top: var(--sp-3);
	color: rgba(255, 255, 255, 0.86);
	font-size: var(--fs-500);
}

/*
 * Coloured here rather than by handing hero.php a --invert modifier class:
 * this link's colour depends on which of two layouts is active, not on a
 * fixed choice made once in PHP, so it belongs in CSS where the breakpoint
 * that decides it already lives — see the desktop override below.
 */
.hero__caption .link-arrow {
	margin-top: var(--sp-5);
	color: var(--white);
	text-decoration-color: rgba(255, 255, 255, 0.5);
}

.hero__caption .link-arrow:hover {
	text-decoration-color: var(--white);
}

/*
 * Arrows + dots. Sits below the slide on mobile (there is no empty space on
 * top of a full-bleed photo to put it in without covering the caption) and
 * moves to an overlay in the desktop override below, where the two-column
 * layout leaves room for it over the image half instead.
 */
.hero__nav {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-4);
	padding-block: var(--sp-4);
}

.hero__arrow {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	border: 0;
	border-radius: 50%;
	background: none;
	color: var(--ink);
	transition: background-color var(--dur-fast) var(--ease);
}

.hero__arrow:hover {
	background: var(--bg-soft);
}

.hero__dots {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
}

.hero__dot {
	width: 0.5rem;
	height: 0.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--line-strong);
	transition: background-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.hero__dot.is-active {
	background: var(--ink);
	transform: scale(1.3);
}

@media (min-width: 62rem) {
	.hero__slide {
		display: grid;
		grid-template-columns: 1fr 1fr;
		align-items: stretch;
	}

	.hero__media {
		height: 100vh;
		height: 100dvh;
	}

	.hero__image,
	.hero__video {
		height: 100%;
	}

	/* No text sits on the photo in this layout, so nothing needs protecting. */
	.hero__media::after {
		content: none;
	}

	.hero__caption {
		position: static;
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding-inline: clamp(2rem, 5vw, 5rem);
		color: var(--ink);
	}

	.hero__subtitle {
		color: var(--ink-soft);
	}

	.hero__caption .link-arrow {
		color: var(--ink);
		text-decoration-color: var(--line-strong);
	}

	.hero__caption .link-arrow:hover {
		text-decoration-color: var(--ink);
	}

	/* Overlaid on the image half, bottom-left, rather than its own row below
	   the slide — there is no photo-less strip left to put it in once the
	   caption has a whole column of its own. */
	.hero__nav {
		position: absolute;
		left: 0;
		bottom: var(--sp-5);
		width: 50%;
		padding-block: 0;
		padding-inline: var(--sp-5);
		justify-content: flex-start;
	}

	.hero__arrow {
		background: rgba(255, 255, 255, 0.85);
	}

	.hero__arrow:hover {
		background: var(--white);
	}

	.hero__dot {
		background: rgba(255, 255, 255, 0.6);
	}

	.hero__dot.is-active {
		background: var(--white);
	}
}

/* -------------------------------------------------------------------------
   2. Marquee

   Two identical tracks scrolling as one continuous loop. The animation moves
   the flex container by exactly one track width, so the seam is invisible.
   Pure CSS — no measurement, no scroll listener, no JavaScript at all.
   ---------------------------------------------------------------------- */

/* overflow: hidden is load-bearing here, not decorative: .marquee__viewport is
   deliberately wider than the page (two duplicated tracks, so the loop has no
   visible seam — see the animation below), and this is what turns that into a
   windowed ticker instead of genuine horizontal page overflow. It used to be
   masked as a side effect of overflow-x:hidden on <body>; removing that (see
   main.css, section 2 — it was breaking sticky positioning on the product
   page) exposed the marquee never had its own clipping and needed one. */
.marquee {
	overflow: hidden;
	padding-block: var(--sp-4);
	border-block: 1px solid var(--line);
}

.marquee__viewport {
	display: flex;
	width: max-content;
	animation: t42-marquee 34s linear infinite;
}

.marquee__track {
	display: flex;
	align-items: center;
	gap: var(--sp-6);
	padding-right: var(--sp-6);
}

.marquee__item {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	white-space: nowrap;
	font-size: var(--fs-300);
	font-weight: 500;
	letter-spacing: var(--tracking-wide);
	text-transform: uppercase;
	color: var(--ink-soft);
}

.marquee__dot {
	width: 4px;
	height: 4px;
	border-radius: 50%;
	background: var(--ink);
}

@keyframes t42-marquee {
	from {
		transform: translateX(0);
	}

	to {
		transform: translateX(-50%);
	}
}

/* Continuous horizontal motion is a real trigger for vestibular disorders, so
   under reduced-motion the marquee stops dead and becomes a static, wrapping
   row that is still fully readable. */
@media (prefers-reduced-motion: reduce) {
	.marquee__viewport {
		animation: none;
		width: 100%;
		flex-wrap: wrap;
		justify-content: center;
	}

	.marquee__viewport > [aria-hidden="true"] {
		display: none;
	}

	.marquee__track {
		flex-wrap: wrap;
		justify-content: center;
		row-gap: var(--sp-3);
		padding-right: 0;
	}
}

/* -------------------------------------------------------------------------
   3. Category tiles
   ---------------------------------------------------------------------- */

.tiles {
	display: grid;
	gap: var(--sp-5);
}

.tile {
	display: block;
	height: 100%;
	text-decoration: none;
	color: inherit;
}

.tile__media {
	position: relative;
	overflow: hidden;
	background: var(--bg-soft);
}

/*
 * contain, not cover: these tiles reuse the same product photography as the
 * shop grid (see .card__image, main.css), which runs closer to 3:4 than
 * square — cover was cropping off the top of the garment (a jacket's
 * shoulders, a tee's collar) to fill the 1:1 box. contain letterboxes the
 * whole photo into the square instead, against .tile__media's own
 * background above, matching the same fix made there.
 */
.tile__image {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: contain;
	transition: transform var(--dur-slow) var(--ease);
}

a.tile:hover .tile__image {
	transform: scale(1.04);
}

.tile__body {
	padding-top: var(--sp-4);
}

.tile__title {
	font-size: var(--fs-500);
	font-weight: 600;
}

.tile__caption {
	margin-top: var(--sp-1);
	color: var(--muted);
	font-size: var(--fs-300);
}

.tile__cue {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	margin-top: var(--sp-3);
	font-size: var(--fs-200);
	font-weight: 500;
	letter-spacing: var(--tracking-wide);
	text-transform: uppercase;
}

.tile__cue .icon {
	width: 1rem;
	height: 1rem;
	transition: transform var(--dur) var(--ease);
}

a.tile:hover .tile__cue .icon {
	transform: translateX(4px);
}

@media (min-width: 44rem) {
	.tiles {
		grid-template-columns: repeat(3, 1fr);
	}
}

@media (prefers-reduced-motion: reduce) {
	.tile__image,
	.tile__cue .icon {
		transition: none;
	}

	a.tile:hover .tile__image {
		transform: none;
	}
}

/* -------------------------------------------------------------------------
   4. Carousel

   Shared scroll-snap infrastructure for Bestsellers and Shop the look. A
   native horizontally-scrolling row: swipeable on touch and scrollable with a
   trackpad or wheel with no script at all. app.js only adds the optional
   prev/next buttons on top of that — nothing here depends on JavaScript.
   ---------------------------------------------------------------------- */

.carousel-head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-4);
	margin-bottom: var(--sp-5);
}

.carousel-head__intro {
	flex-basis: 100%;
	order: 3;
	max-width: 58ch;
	color: var(--muted);
	font-size: var(--fs-400);
}

.carousel-head__end {
	display: flex;
	align-items: center;
	gap: var(--sp-5);
	margin-left: auto;
}

.carousel__nav {
	display: none;
}

.carousel__btn {
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	border: 1px solid var(--line-strong);
	border-radius: 50%;
	background: var(--bg);
	color: var(--ink);
	transition: border-color var(--dur-fast) var(--ease);
}

.carousel__btn:hover {
	border-color: var(--ink);
}

.carousel__btn .icon {
	width: 1rem;
	height: 1rem;
}

.carousel__track {
	display: flex;
	gap: var(--sp-4);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
	padding-inline: var(--gutter);
}

.carousel__track::-webkit-scrollbar {
	display: none;
}

.carousel__item {
	flex: 0 0 auto;
	width: 68%;
	scroll-snap-align: start;
}

@media (min-width: 36rem) {
	.carousel__item {
		width: 40%;
	}
}

@media (min-width: 56rem) {
	.carousel__nav {
		display: flex;
		gap: var(--sp-2);
	}

	.carousel__item {
		width: 27%;
	}
}

@media (min-width: 78rem) {
	.carousel__item {
		width: 21.5%;
	}
}

/* -------------------------------------------------------------------------
   5. Bestsellers

   Uses the carousel shell above with the shared product card
   (template-parts/shop/product-card.php, styled in main.css).
   ---------------------------------------------------------------------- */

.featured {
	padding-bottom: clamp(2.5rem, 5vw, 4rem);
}

.featured .carousel-head {
	margin-bottom: var(--sp-4);
}

/*
 * Four items or fewer (see $scrolls in featured.php) render here instead of
 * scrolling — wrapped into a plain two-up/four-up grid so the row fills the
 * full width edge to edge rather than leaving unused space where a fifth
 * card would have peeked in.
 */
.carousel__track--fill {
	flex-wrap: wrap;
	overflow: visible;
	scroll-snap-type: none;
}

.carousel__track--fill .carousel__item {
	width: calc(50% - var(--sp-4) / 2);
	scroll-snap-align: none;
}

@media (min-width: 56rem) {
	.carousel__track--fill .carousel__item {
		width: calc(25% - (var(--sp-4) * 3 / 4));
	}
}

/* -------------------------------------------------------------------------
   6. Shop the look

   The first product chosen renders broad, as a spotlight; every other
   product renders smaller, in its own horizontally-scrolling row beside it.
   Both use the ordinary product card (main.css) — only the column width
   they sit in differs, so nothing needs a "large" card variant.
   ---------------------------------------------------------------------- */

.shop-look__inner {
	display: grid;
	gap: var(--sp-6);
}

.shop-look__spotlight .card__title {
	font-size: var(--fs-300);
}

.shop-look .carousel__track {
	padding-inline: 0;
}

/* Two-thirds smaller than the mobile Bestsellers card, since this row is
   explicitly the "smaller, secondary" set beside the spotlight. */
.shop-look .carousel__item {
	width: 46%;
}

@media (min-width: 30rem) {
	.shop-look .carousel__item {
		width: 34%;
	}
}

@media (min-width: 56rem) {
	.shop-look__inner {
		grid-template-columns: 1.4fr 1fr;
		align-items: start;
		gap: var(--sp-7);
	}

	.shop-look .carousel__item {
		width: 62%;
	}
}

@media (min-width: 78rem) {
	.shop-look .carousel__item {
		width: 46%;
	}
}

/* -------------------------------------------------------------------------
   7. Our mission
   ---------------------------------------------------------------------- */

.mission {
	background: var(--bg-soft);
}

.mission__inner {
	display: grid;
	gap: clamp(2rem, 5vw, 3.5rem);
	align-items: center;
}

.mission__figure {
	background: var(--bg);
	overflow: hidden;
}

/*
 * max-height is a safety cap left over from a taller aspect-ratio, kept for
 * the same reason it was added: below the 56rem breakpoint the grid drops to
 * a single stacked column, so this image takes the full container width, and
 * without a cap a very wide column could still make a tall image. At 1:1 it
 * rarely binds, but costs nothing to keep. object-fit: cover means the cap
 * only changes how much of a photo shows, never distorts it.
 */
.mission__image {
	width: 100%;
	aspect-ratio: 1 / 1;
	max-height: 34rem;
	object-fit: cover;
}

@media (min-width: 56rem) {
	.mission__image {
		max-height: 42rem;
	}
}

.mission__title {
	max-width: 18ch;
}

.mission__body {
	margin-top: var(--sp-4);
	max-width: 48ch;
	color: var(--ink-soft);
}

.mission__cta {
	margin-top: var(--sp-6);
}

@media (min-width: 56rem) {
	.mission__inner {
		grid-template-columns: 0.9fr 1.1fr;
	}
}

/* -------------------------------------------------------------------------
   8. Promise
   ---------------------------------------------------------------------- */

.promise__grid {
	display: grid;
	gap: var(--sp-6);
}

.promise__item {
	padding: var(--sp-6) var(--sp-5);
	border: 1px solid var(--line);
}

.promise__icon {
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	margin-bottom: var(--sp-5);
	border: 1px solid var(--ink);
	border-radius: 50%;
	color: var(--ink);
}

.promise__icon .icon {
	width: 1.35rem;
	height: 1.35rem;
}

.promise__title {
	font-size: var(--fs-500);
	font-weight: 600;
	max-width: 22ch;
}

.promise__text {
	margin-top: var(--sp-3);
	color: var(--ink-soft);
	font-size: var(--fs-400);
}

@media (min-width: 52rem) {
	.promise__grid {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--sp-5);
	}
}

/* -------------------------------------------------------------------------
   9. Lifestyle images

   Two full-bleed photographs side by side, each with a small caption pinned
   to the lower-left corner — the pairing that sits under Bestsellers in the
   reference ("From creators to creators" beside a studio shot).
   ---------------------------------------------------------------------- */

.lifestyle__grid {
	display: grid;
	gap: 2px;
	background: var(--line);
}

.lifestyle__cell {
	position: relative;
	overflow: hidden;
	background: var(--bg-soft);
}

.lifestyle__link {
	display: block;
	height: 100%;
	color: inherit;
	text-decoration: none;
}

.lifestyle__image {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	transition: transform var(--dur-slow) var(--ease);
}

.lifestyle__cell:hover .lifestyle__image {
	transform: scale(1.03);
}

.lifestyle__caption {
	position: absolute;
	left: var(--sp-5);
	bottom: var(--sp-5);
	color: var(--white);
	font-size: var(--fs-300);
}

.lifestyle__caption .link-arrow {
	margin-top: var(--sp-1);
}

@media (min-width: 44rem) {
	.lifestyle__grid {
		grid-template-columns: repeat(2, 1fr);
	}

	.lifestyle__image {
		aspect-ratio: 1 / 1;
	}
}

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

	.lifestyle__cell:hover .lifestyle__image {
		transform: none;
	}
}

/* -------------------------------------------------------------------------
   10. Newsletter
   ---------------------------------------------------------------------- */

.newsletter {
	background: var(--bg-soft);
}

.newsletter__inner {
	display: grid;
	gap: var(--sp-6);
	align-items: center;
}

.newsletter__title {
	max-width: 22ch;
}

.newsletter__body {
	max-width: 48ch;
	margin-top: var(--sp-4);
	color: var(--ink-soft);
	font-size: var(--fs-500);
}

.newsletter__note {
	margin-top: var(--sp-3);
	color: var(--muted);
	font-size: var(--fs-300);
}

@media (min-width: 62rem) {
	.newsletter__inner {
		grid-template-columns: 1.1fr 0.9fr;
		gap: var(--sp-9);
	}
}
