/*
 * Home page: hero, collection carousel, category pebbles, featured grid, CTA.
 *
 * Loads only on the front page.
 */

/* ----------------------------------------------------------------- Hero -- */

.lb-hero {
	padding-block: var(--lb-s5) 0;
}

.lb-hero__panel {
	position: relative;
	display: flex;
	align-items: flex-end;
	overflow: hidden;
	border-radius: var(--lb-r-hero);
	background: var(--lb-well);
	min-height: clamp(420px, 62vh, 660px);
}

.lb-hero__media {
	position: absolute;
	inset: 0;
}

/*
 * Slides stack in the same box and cross-fade. The template marks the first one
 * active, so the hero is already showing an image before hero-slider.js runs -
 * and still is if it never does.
 */
.lb-hero__slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity var(--lb-dur-slide) var(--lb-ease);
}

.lb-hero__slide.is-active { opacity: 1; }

.lb-hero__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Scoped because the parent theme paints every button on hover; an unscoped
   single class loses to its `button:hover`. */
.lb-hero__dots {
	position: absolute;
	right: clamp(var(--lb-s5), 4vw, var(--lb-s7));
	bottom: clamp(var(--lb-s5), 4vw, var(--lb-s7));
	z-index: 2;
	display: flex;
	gap: var(--lb-s2);
}

.lb-scope .lb-hero__dot {
	width: 9px;
	height: 9px;
	min-height: 0;
	padding: 0;
	border: 0;
	border-radius: var(--lb-r-pill);
	background: rgba(251, 249, 246, .45);
	cursor: pointer;
	transition: background var(--lb-dur) var(--lb-ease),
	            width var(--lb-dur) var(--lb-ease);
}

.lb-scope .lb-hero__dot:hover { background: rgba(251, 249, 246, .8); }

.lb-scope .lb-hero__dot.is-active {
	width: 26px;
	background: var(--lb-sand);
}

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

.lb-hero__body {
	position: relative;
	z-index: 1;
	max-width: 640px;
	padding: clamp(var(--lb-s6), 5vw, var(--lb-s8));
	color: var(--lb-paper);
}

.lb-hero__title {
	color: var(--lb-paper);
}

.lb-hero__text {
	margin-top: var(--lb-s5);
	color: rgba(251, 249, 246, .82);
}

.lb-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lb-s3);
	margin-top: var(--lb-s6);
}

/* The secondary hero button sits on a dark panel, so it inverts. */
.lb-hero__cta2 {
	background: rgba(251, 249, 246, .12);
	color: var(--lb-paper);
	border-color: rgba(251, 249, 246, .34);
}

.lb-hero__cta2:hover,
.lb-hero__cta2:focus-visible {
	background: var(--lb-paper);
	color: var(--lb-ink);
	border-color: var(--lb-paper);
}

@media (max-width: 599px) {
	.lb-hero__panel { min-height: 480px; }
	.lb-hero__body { padding: var(--lb-s5); }
}

/* ---------------------------------------------------------- Collections -- */

.lb-collections__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--lb-s6);
	margin-bottom: var(--lb-s7);
}

.lb-collections__aside {
	display: flex;
	align-items: flex-end;
	gap: var(--lb-s6);
	flex: 1 1 380px;
	justify-content: flex-end;
}

.lb-collections__arrows {
	display: flex;
	gap: var(--lb-s2);
	flex-shrink: 0;
}

/* The track is a native scroller so touch and keyboard work without JS. */
.lb-collections__track {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 340px;
	gap: 20px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-block: var(--lb-s2);

	/*
	 * Line the first slide up with the heading above it while letting the rest
	 * bleed to the edge. This repeats what .lb-wrap does - centre at --lb-maxw,
	 * then step in by the gutter - so the two have to be measuring the same box.
	 * 100% is the track's own containing block, which is the one .lb-wrap is
	 * centred in; 100vw is the viewport, and the two differ by whatever padding
	 * sits between them, which put the cards a few pixels off the heading.
	 */
	--lb-track-gutter: calc(var(--lb-gutter) + max(0px, (100% - var(--lb-maxw)) / 2));
	padding-inline: var(--lb-track-gutter);

	/*
	 * scroll-snap-align: start snaps a slide to the snapport's start edge, and
	 * that edge is the padding box - inside the padding, not outside it. Without
	 * this, mandatory snapping pulls the first slide flush against the viewport
	 * as soon as the page loads: the track comes to rest at
	 * scrollLeft == padding-left, the left gutter becomes dead space you cannot
	 * stop on, and the first card is clipped by the edge of the screen.
	 *
	 * Insetting the snapport by the same amount as the padding puts the resting
	 * position back at 0 with the gutter visible, so the first card lines up
	 * with the heading above it.
	 */
	scroll-padding-inline: var(--lb-track-gutter);
}

.lb-collections__track::-webkit-scrollbar { display: none; }

.lb-collections__track:focus-visible {
	outline: 2px solid var(--lb-violet);
	outline-offset: 4px;
	border-radius: var(--lb-r-panel);
}

.lb-slide { scroll-snap-align: start; }

.lb-slide__link { display: block; }

.lb-slide__well {
	border-radius: var(--lb-r-panel);
	height: 520px;
	box-shadow: var(--lb-sh-rest);
	transition: box-shadow var(--lb-dur) var(--lb-ease),
	            transform var(--lb-dur) var(--lb-ease);
}

.lb-slide__link:hover .lb-slide__well {
	box-shadow: var(--lb-sh-hover);
	transform: translateY(-3px);
}

.lb-slide__body {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: var(--lb-s2);
	padding: var(--lb-s5);
	color: var(--lb-paper);
}

.lb-slide__name { color: var(--lb-paper); font-size: 28px; }

.lb-slide__note,
.lb-slide__count {
	font-size: 13px;
	color: rgba(251, 249, 246, .78);
}

.lb-slide__count { color: var(--lb-sand); }

.lb-collections__foot {
	display: flex;
	align-items: center;
	gap: var(--lb-s4);
	margin-top: var(--lb-s5);
}

@media (max-width: 899px) {
	.lb-collections__track { grid-auto-columns: 74vw; }
	.lb-slide__well { height: 440px; }
	.lb-collections__aside { justify-content: flex-start; }
}

/* ------------------------------------------------------- Category grid --- */

/*
 * The same card the carousel uses, laid out as a grid. Only the sizing
 * differs: the track fixes a slide height because it scrolls sideways, while
 * here the well's portrait ratio decides the height, so the cards stay square
 * with the column width whatever it is.
 */
.lb-pebbles__title { margin-bottom: var(--lb-s7); }

.lb-pebbles__grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: var(--lb-s5);
}

.lb-pebbles__grid .lb-slide__well { height: auto; }

/* ------------------------------------------------------------ Featured --- */

.lb-featured { margin-top: var(--lb-s8); }

.lb-featured__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--lb-s5);
	margin-bottom: var(--lb-s7);
}

.lb-featured__text { margin-top: var(--lb-s5); }

.lb-grid--featured {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: 26px 22px;
}

/* ------------------------------------------------------------------ CTA -- */

.lb-cta { padding-bottom: var(--lb-s8); }

.lb-cta__panel {
	position: relative;
	overflow: hidden;
	border-radius: var(--lb-r-hero);
	background: var(--lb-violet);
	color: #fff;
	padding: clamp(var(--lb-s7), 6vw, var(--lb-s9));
}

/* One oversized translucent circle bleeding off the top-right corner. */
.lb-cta__orb {
	position: absolute;
	top: -38%;
	right: -12%;
	width: 560px;
	height: 560px;
	border-radius: var(--lb-r-pill);
	background: rgba(255, 255, 255, .1);
	pointer-events: none;
}

.lb-cta__body {
	position: relative;
	z-index: 1;
	max-width: 640px;
}

.lb-cta__title { color: #fff; }

.lb-cta__text {
	margin-top: var(--lb-s5);
	color: rgba(255, 255, 255, .84);
}

.lb-cta__button {
	background: var(--lb-paper);
	color: var(--lb-ink);
}

.lb-cta__button:hover,
.lb-cta__button:focus-visible {
	background: var(--lb-ink);
	color: var(--lb-paper);
	transform: translateY(-2px);
}

/* ---------------------------------------------------------- Breakpoints -- */

@media (max-width: 599px) {
	/* One slide plus a clear peek at the next, so the track reads as scrollable. */
	.lb-collections__track { grid-auto-columns: 78vw; }
	.lb-slide__well { height: 380px; }
	.lb-slide__name { font-size: 23px; }

	.lb-pebbles__grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--lb-s3); }

	/* A grid card is a fraction of a carousel slide's width, so the name and
	   the padding step down with it. */
	.lb-pebbles__grid .lb-slide__name { font-size: 18px; }
	.lb-pebbles__grid .lb-slide__body { padding: var(--lb-s3); }

	.lb-grid--featured { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 22px 14px; }

	.lb-cta__orb { width: 320px; height: 320px; }
}

/* ---------------------------------------------------------------- Story -- */

/*
 * The marketing block: who the business is, its divisions, its certifications.
 * Intro on the left at reading width, the divisions as a trio beneath it, and
 * the certifications as a quiet strip at the foot. Every part is optional in
 * the template, so the rules below have to survive any of them being absent -
 * which is why the spacing is on the children rather than between siblings.
 */
.lb-story__intro { max-width: 720px; }

.lb-story__title { margin-block: var(--lb-s3) var(--lb-s5); }

.lb-story__text { margin: 0; }

.lb-story__link {
	display: inline-flex;
	align-items: center;
	gap: var(--lb-s2);
	margin-top: var(--lb-s5);
	font-size: var(--lb-fs-control);
	font-weight: 500;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--lb-violet-ink);
}

.lb-story__link:hover { color: var(--lb-ink); }

.lb-story__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: var(--lb-s6);
	margin-top: var(--lb-s7);
}

/* A hairline between the columns, drawn on the column so it disappears with it
   when a division is left blank. */
.lb-story__col {
	padding-top: var(--lb-s5);
	border-top: 1px solid var(--lb-line);
}

.lb-story__num {
	display: block;
	font-family: var(--lb-font-serif);
	font-size: 15px;
	color: var(--lb-sand);
}

.lb-story__col-title {
	margin: var(--lb-s3) 0 var(--lb-s2);
	font-family: var(--lb-font-serif);
	font-size: 22px;
	font-weight: 400;
	line-height: 1.2;
	color: var(--lb-ink);
}

.lb-story__col-text {
	margin: 0;
	font-size: 15px;
	line-height: 1.65;
	color: var(--lb-ink-2);
}

.lb-story__badges {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--lb-s3);
	margin-top: var(--lb-s7);
	padding-top: var(--lb-s5);
	border-top: 1px solid var(--lb-line);
}

.lb-story__badges-label { margin-right: var(--lb-s2); }

.lb-story__badge {
	padding: 7px 14px;
	border: 1px solid var(--lb-line);
	border-radius: var(--lb-r-pill);
	background: var(--lb-surface);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: .08em;
	color: var(--lb-ink-2);
}

/* ------------------------------------------------------- CTA, contact ---- */

.lb-cta__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lb-s3);
	margin-top: var(--lb-s6);
}

/*
 * From 900px the panel reads as two columns: the sentence on the left at
 * reading width, the actions and the contact line on the right. Below that they
 * stack. The children are placed explicitly because the text is optional - the
 * grid must not collapse into the wrong column when it is absent.
 */
@media (min-width: 900px) {
	.lb-cta__body {
		max-width: none;
		display: grid;
		grid-template-columns: minmax(0, 1.2fr) minmax(260px, .8fr);
		column-gap: var(--lb-s8);
		align-items: start;
	}

	.lb-cta__title,
	.lb-cta__text { grid-column: 1; }

	.lb-cta__actions,
	.lb-cta__reach { grid-column: 2; }

	.lb-cta__actions {
		flex-direction: column;
		align-items: stretch;
		margin-top: var(--lb-s2);
	}

	.lb-cta__reach { text-align: center; }
}

/* The second button is the quiet one: outlined on the violet panel so the
   primary action keeps the only filled treatment. */
.lb-scope .lb-cta__button2 {
	background: transparent;
	border-color: rgba(251, 249, 246, .55);
	color: var(--lb-paper);
}

.lb-scope .lb-cta__button2:hover {
	background: rgba(251, 249, 246, .12);
	border-color: var(--lb-paper);
	color: var(--lb-paper);
}

.lb-cta__reach {
	margin: var(--lb-s5) 0 0;
	font-size: 14px;
	color: rgba(251, 249, 246, .82);
}

.lb-cta__reach a {
	color: var(--lb-paper);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.lb-cta__reach-sep { padding-inline: var(--lb-s2); }

@media (max-width: 767px) {
	.lb-story__grid { gap: var(--lb-s5); margin-top: var(--lb-s6); }
	.lb-story__col-title { font-size: 20px; }
	.lb-story__badges { margin-top: var(--lb-s6); }
}

/* Carousel with nothing to scroll: carousel.js marks the section and the
   controls go, rather than sitting there permanently disabled. */
.lb-collections.is-static .lb-collections__arrows,
.lb-collections.is-static .lb-collections__foot { display: none; }

/* --------------------------------------------------------- How it works -- */

/*
 * Three numbered steps on the paper ground, between the occasions and the
 * catalogue. The rule sits on the step rather than between steps so a section
 * configured with two still looks deliberate.
 */
.lb-how__head { max-width: 720px; }

.lb-how__text { margin: var(--lb-s5) 0 0; }

.lb-how__steps {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: var(--lb-s6);
	margin: var(--lb-s7) 0 0;
	padding: 0;
	list-style: none;
	counter-reset: none;
}

.lb-how__step {
	padding-top: var(--lb-s5);
	border-top: 1px solid var(--lb-line);
}

/* The number is the only sand element in the row, so the eye follows the
   sequence before it reads any of the copy. */
.lb-how__num {
	display: block;
	font-family: var(--lb-font-serif);
	font-size: 34px;
	line-height: 1;
	color: var(--lb-sand);
}

.lb-how__step-title {
	margin: var(--lb-s4) 0 var(--lb-s2);
	font-family: var(--lb-font-serif);
	font-size: 22px;
	font-weight: 400;
	line-height: 1.2;
	color: var(--lb-ink);
}

.lb-how__step-text {
	margin: 0;
	font-size: 15px;
	line-height: 1.65;
	color: var(--lb-ink-2);
}

@media (max-width: 767px) {
	.lb-how__steps { gap: var(--lb-s5); margin-top: var(--lb-s6); }
	.lb-how__num { font-size: 28px; }
	.lb-how__step-title { font-size: 20px; }
}

/* A category or occasion with no picture still has to look deliberate. The
   scrim is not rendered for these, so the type sets in ink on the warm well
   rather than in paper-white on a muddied gradient. */
.lb-slide--flat .lb-slide__kicker { color: var(--lb-mute); }
.lb-slide--flat .lb-slide__name { color: var(--lb-ink); }
.lb-slide--flat .lb-slide__note { color: var(--lb-ink-2); }
.lb-slide--flat .lb-slide__count { color: var(--lb-mute); }

/* ------------------------------------------------------------- Parallax -- */

/*
 * The band paints its own picture and positions it against the viewport rather
 * than against itself, so the image holds still while the section scrolls over
 * it. That is the whole effect - no script, no second layer to keep in sync,
 * and nothing to recalculate on resize.
 *
 * Only applied when the client has actually set an image. With none set the
 * section keeps its ink-on-paper look and none of these rules match.
 */
.lb-parallax {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	padding-block: calc(var(--lb-s7) * 2);
}

.lb-parallax__bg {
	position: absolute;
	inset: 0;
	z-index: -2;
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
	background-attachment: fixed;
}

/*
 * iOS sizes a fixed background against the whole document instead of the
 * viewport, which leaves the picture zoomed in and off-centre, and there is no
 * way to correct for it. Touch devices get the same image scrolling with the
 * section, which is the honest version of the effect rather than a broken one.
 */
@media (hover: none), (prefers-reduced-motion: reduce) {
	.lb-parallax__bg { background-attachment: scroll; }
}

/*
 * The client picks the picture, so the copy cannot assume anything about what
 * is behind it. The veil is what guarantees the text stays readable over a
 * bright image, and it is darkest top and bottom where the type sits.
 */
.lb-parallax__veil {
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(
		180deg,
		rgba(26, 22, 32, .84),
		rgba(26, 22, 32, .66) 45%,
		rgba(26, 22, 32, .88)
	);
}

.lb-parallax__fg { position: relative; }

/* Ink-on-paper inverts to paper-on-ink for the whole band. */
.lb-parallax .lb-h2,
.lb-parallax .lb-how__step-title { color: var(--lb-paper); }

.lb-parallax .lb-lede,
.lb-parallax .lb-how__step-text { color: rgba(251, 249, 246, .78); }

.lb-parallax .lb-how__step { border-top-color: rgba(251, 249, 246, .22); }

/*
 * The foreground drifts against the still background as the band crosses the
 * screen. This is the decorative half of the effect, so it is behind both a
 * support check and a motion preference - where either fails the copy simply
 * scrolls with the page and the fixed background carries the section on its own.
 */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.lb-parallax__fg {
			animation: lb-parallax-drift linear both;
			animation-timeline: view();
			animation-range: entry 0% exit 100%;
		}

		.lb-parallax .lb-how__num {
			animation: lb-parallax-lift linear both;
			animation-timeline: view();
			animation-range: entry 0% exit 100%;
		}
	}
}

@keyframes lb-parallax-drift {
	from { transform: translateY(34px); }
	to   { transform: translateY(-34px); }
}

@keyframes lb-parallax-lift {
	from { transform: translateY(14px); opacity: .55; }
	to   { transform: translateY(-14px); opacity: 1; }
}

@media (max-width: 767px) {
	.lb-parallax { padding-block: var(--lb-s7); }
}
