/**
 * Northline — components: frames, cards, carousels, homepage sections.
 */

/* =============================================================================
   The frame — product photography never sits on a hard corner or full bleed.
   ========================================================================== */

/*
 * `overflow: clip` crops exactly as `hidden` does but, unlike it, does not
 * turn the frame into a scroll container — and a scroll container between
 * an image and the page would capture its scroll-driven animation and leave
 * it inert (see "Scroll-linked depth" below). `hidden` stays as the fallback
 * for browsers without `clip`. The same pair is used on every container
 * that holds scroll-linked imagery.
 */
.nl-frame {
	position: relative;
	overflow: hidden;
	overflow: clip;
	border-radius: var(--nl-radius-lg);
	background: var(--nl-surface);
	box-shadow: var(--nl-shadow-inset-frame);
	isolation: isolate;
}

.nl-frame::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(160deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 42%);
	mix-blend-mode: soft-light;
}

.nl-on-dark .nl-frame::after {
	background: linear-gradient(160deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0) 45%);
}

.nl-frame__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: opacity var(--nl-dur-quick) var(--nl-ease-out);
}

/* A slow cross-fade to a second angle — the only motion a product image makes. */
.nl-frame__img--hover {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity var(--nl-dur-slow) var(--nl-ease-out);
}

.nl-frame--has-hover:hover .nl-frame__img--hover,
a:focus-visible .nl-frame--has-hover .nl-frame__img--hover {
	opacity: 1;
}

.nl-placeholder {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	background: var(--nl-surface-sunken);
	color: var(--nl-ink-muted);
	/* Visible enough to read as "no image yet" rather than a broken frame. */
	opacity: 1;
}

.nl-placeholder svg {
	opacity: 0.55;
}

.nl-placeholder svg {
	width: 44%;
	max-width: 120px;
	height: auto;
}

/* Full-bleed is reserved for hero and lifestyle imagery. */
.nl-bleed {
	border-radius: 0;
}

/* =============================================================================
   Badges, stars
   ========================================================================== */

.nl-badge {
	position: absolute;
	top: var(--nl-space-2xs);
	left: var(--nl-space-2xs);
	z-index: 2;
	padding: 3px 10px;
	border-radius: var(--nl-radius-pill);
	background: var(--nl-ink);
	color: var(--nl-base);
	font-size: var(--nl-size-micro);
	font-weight: var(--nl-weight-medium);
	letter-spacing: 0.02em;
}

.nl-badge--sale {
	background: var(--nl-accent);
	color: var(--nl-accent-ink);
}

.nl-stars {
	position: relative;
	display: inline-block;
	font-size: 0.95rem;
	line-height: 1;
	letter-spacing: 1px;
	color: var(--nl-line-strong);
	white-space: nowrap;
}

.nl-stars__fill {
	position: absolute;
	inset: 0;
	overflow: hidden;
	color: var(--nl-accent);
}

/* =============================================================================
   Product card
   ========================================================================== */

.nl-product-card {
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-xs);
	height: 100%;
	/* The wishlist heart is positioned against this. */
	position: relative;
	padding: var(--nl-space-xs);
	border-radius: var(--nl-radius-xl);
	background: transparent;
	transform: translateY(var(--nl-lift, 0px));
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

/* Quiet hover: a 3px lift and a softer shadow. Never a scale or a colour shift. */
.nl-product-card:hover,
.nl-product-card:focus-within {
	--nl-lift: -3px;
	box-shadow: var(--nl-shadow-lift);
	background: var(--nl-surface);
}

.nl-product-card--dark:hover,
.nl-product-card--dark:focus-within {
	background: var(--nl-dark-surface);
}

.nl-product-card__media {
	position: relative;
	display: block;
}

.nl-product-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-3xs);
	padding-inline: var(--nl-space-3xs);
	flex: 1 1 auto;
}

/*
 * Descriptions differ in length, so the copy absorbs the slack. Without this
 * the price and the calls to action sit at a different height on every card in
 * a row, which reads as sloppy even when nothing is broken.
 */
.nl-product-card__copy {
	flex: 1 1 auto;
}

.nl-product-card__title {
	font-size: 1.0625rem;
	margin: 0;
}

.nl-product-card__title a {
	color: var(--nl-ink);
	text-decoration: none;
}

.nl-product-card__title a:hover {
	text-decoration: underline;
}

.nl-product-card__copy {
	margin: 0;
	font-size: var(--nl-size-small);
	color: var(--nl-ink-muted);
}

.nl-product-card__price {
	margin: 0;
	font-weight: var(--nl-weight-medium);
}

.nl-product-card__price del {
	color: var(--nl-ink-muted);
	font-weight: var(--nl-weight-regular);
	margin-right: 6px;
}

.nl-product-card__rating {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: var(--nl-size-micro);
	color: var(--nl-ink-muted);
}

.nl-product-card__ctas {
	margin-top: var(--nl-space-3xs);
}

.nl-product-card__ctas .nl-btn {
	padding: 0.5rem 1.1rem;
	font-size: var(--nl-size-small);
}

.nl-compare-toggle {
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 4px 10px;
	background: none;
	border: 1px solid transparent;
	border-radius: var(--nl-radius-pill);
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-micro);
	cursor: pointer;
}

.nl-compare-toggle:hover {
	border-color: var(--nl-line-strong);
	color: var(--nl-ink);
	box-shadow: none;
}

.nl-compare-toggle[aria-pressed="true"] {
	border-color: var(--nl-accent);
	color: var(--nl-accent);
}

.nl-compare-toggle--single {
	margin-top: var(--nl-space-2xs);
	border-color: var(--nl-line-strong);
	font-size: var(--nl-size-small);
	padding: 7px 14px;
}

.nl-icon {
	width: 1.15em;
	height: 1.15em;
	flex: 0 0 auto;
}

/* =============================================================================
   Category tile
   ========================================================================== */

/*
 * Bento tile. The collection is named on the image with a corner affordance,
 * rather than captioned beneath it, so a row of tiles reads as one surface.
 * Text sits on a scrim, not on the photograph directly — see the gradient on
 * __overlay, which is what keeps the label legible over any image a buyer
 * uploads, light or dark.
 */
.nl-tile {
	position: relative;
	display: block;
	overflow: hidden;
	overflow: clip;
	color: #fff;
	text-decoration: none;
	border-radius: var(--nl-radius-xl);
	background: var(--nl-surface-sunken);
	transform: translateY(var(--nl-lift, 0px));
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

.nl-tile:hover,
.nl-tile:focus-visible {
	--nl-lift: -3px;
	box-shadow: var(--nl-shadow-lift);
	text-decoration: none;
}

.nl-tile .nl-tile__frame {
	border-radius: 0;
	height: 100%;
}

/*
 * Below the bento breakpoint a tile is one column wide, so its 16/10 frame is
 * only a couple of hundred pixels tall and the label chip — which does not
 * shrink, because the text in it does not — covered half the product. A floor
 * on the height gives the product room to be seen above the chip; the aspect
 * ratio still governs once the tile is wide enough to beat it.
 */
@media (max-width: 899px) {
	.nl-tile .nl-tile__frame {
		/*
		 * width is pinned as well as the height floor: aspect-ratio resolves
		 * width from height when the height is the constrained axis, so the
		 * floor alone made the frame wider than its tile and left the parent's
		 * overflow to clip it — which crops the product sideways instead of
		 * giving it room.
		 */
		width: 100%;
		min-height: 20rem;
	}
}

.nl-tile__overlay {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--nl-space-sm);
	padding: var(--nl-space-sm);
	pointer-events: none;
}

/*
 * The chip carries its own surface, so the label never depends on what is in
 * the photograph behind it. That is what makes this safe for a buyer's own
 * imagery: a scrim dark enough for white text on a light product shot would
 * muddy the bottom third of every tile.
 */
.nl-tile__chip {
	min-width: 0;
	max-width: 30ch;
	padding: var(--nl-space-2xs) var(--nl-space-sm);
	border-radius: var(--nl-radius-lg);
	background: rgba(255, 255, 255, 0.92);
	-webkit-backdrop-filter: saturate(1.6) blur(12px);
	backdrop-filter: saturate(1.6) blur(12px);
	box-shadow: 0 1px 2px rgba(10, 10, 12, 0.06);
}

.nl-tile__title {
	font-size: 1.0625rem;
	font-weight: var(--nl-weight-bold);
	letter-spacing: var(--nl-tracking-headline);
	margin: 0;
	color: var(--nl-ink);
}

.nl-tile__copy {
	margin: 2px 0 0;
	font-size: var(--nl-size-small);
	color: var(--nl-ink-muted);
}

.nl-tile__price {
	margin: 2px 0 0;
	font-size: var(--nl-size-small);
	color: var(--nl-ink);
	font-weight: var(--nl-weight-medium);
}

/* The corner affordance: present at rest, so the tile reads as a link. */
.nl-tile__go {
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.92);
	-webkit-backdrop-filter: saturate(1.6) blur(12px);
	backdrop-filter: saturate(1.6) blur(12px);
	box-shadow: 0 1px 2px rgba(10, 10, 12, 0.06);
	color: var(--nl-ink);
	transition: background-color var(--nl-dur-base) var(--nl-ease-out);
}

.nl-tile:hover .nl-tile__go,
.nl-tile:focus-visible .nl-tile__go {
	background: #fff;
}

/* =============================================================================
   Hero carousel
   ========================================================================== */

.nl-hero {
	position: relative;
	overflow: hidden;
	background: var(--nl-ink);
}

.nl-hero__track {
	display: grid;
}

.nl-hero__slide {
	grid-area: 1 / 1;
	position: relative;
	display: flex;
	align-items: center;
	/*
	 * The hero is the first thing a visitor sees and the only full-bleed
	 * moment on the page, so it takes most of the first screen rather than
	 * sitting as a band above the fold.
	 */
	min-height: clamp(520px, 84vh, 900px);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--nl-dur-slow) var(--nl-ease-decel), visibility var(--nl-dur-slow);
}

.nl-hero__slide.is-active {
	opacity: 1;
	visibility: visible;
}

.nl-hero__media {
	position: absolute;
	inset: 0;
	overflow: hidden;
}

/*
 * Two scrims, not one. The vertical pass keeps the rail legible at the foot of
 * the frame; the horizontal pass holds the left back so the headline never
 * has to fight the product group on the right.
 */
.nl-hero__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(90deg, rgba(8, 8, 11, 0.78) 0%, rgba(8, 8, 11, 0.28) 46%, rgba(8, 8, 11, 0) 70%),
		linear-gradient(180deg, rgba(8, 8, 11, 0.2) 0%, rgba(8, 8, 11, 0.16) 52%, rgba(8, 8, 11, 0.76) 100%);
}

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

/*
 * What a buyer sees before setting a hero image, so it has to look chosen
 * rather than failed. The old fill was a flat cool-grey gradient in literal
 * hex, which read as a dead frame against a warm palette. This builds from
 * the dark tokens and adds a soft off-centre glow, so the empty state has a
 * light source and some depth.
 */
.nl-hero__img--empty {
	display: block;
	width: 100%;
	height: 100%;
	background:
		radial-gradient(
			70% 90% at 72% 18%,
			color-mix(in srgb, var(--nl-accent) 16%, transparent),
			transparent 62%
		),
		radial-gradient(
			90% 120% at 18% 92%,
			color-mix(in srgb, var(--nl-dark-surface) 90%, white),
			transparent 58%
		),
		linear-gradient(145deg, var(--nl-dark-surface), var(--nl-dark) 62%);
}

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
	.nl-hero__img--empty {
		background: linear-gradient(145deg, var(--nl-dark-surface), var(--nl-dark) 62%);
	}
}

.nl-hero__inner {
	position: relative;
	z-index: 1;
	width: 100%;
	padding-block: var(--nl-space-2xl);
}

/* Slide rail — names the slides instead of counting them. */
.nl-hero__rail {
	position: absolute;
	left: 0;
	right: 0;
	bottom: var(--nl-space-xl);
	z-index: 2;
	pointer-events: none;
	display: none;
}

.nl-hero__rail-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
	max-width: 22rem;
}

.nl-hero__rail-button {
	pointer-events: auto;
	display: block;
	width: 100%;
	text-align: left;
	background: none;
	border: 0;
	border-left: 2px solid transparent;
	border-radius: 0;
	/* 7px of padding left these 32px tall, under the touch minimum. */
	padding: var(--nl-space-2xs) 0 var(--nl-space-2xs) var(--nl-space-2xs);
	min-height: 44px;
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-regular);
	color: rgba(255, 255, 255, 0.58);
	cursor: pointer;
	transition: color var(--nl-dur-quick) var(--nl-ease-out), border-color var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-hero__rail-button:hover {
	color: rgba(255, 255, 255, 0.86);
}

.nl-hero__rail-button.is-active {
	color: #fff;
	border-left-color: #fff;
}

.nl-hero__text {
	max-width: 34rem;
	color: #fff;
}

.nl-hero__headline {
	font-size: var(--nl-size-display);
	font-weight: var(--nl-weight-bold);
	line-height: var(--nl-leading-tight);
	letter-spacing: var(--nl-tracking-display);
	color: inherit;
	margin: 0 0 var(--nl-space-sm);
	max-width: 14ch;
	text-wrap: balance;
}

.nl-hero__copy {
	font-size: var(--nl-size-subhead);
	color: rgba(255, 255, 255, 0.84);
	margin-bottom: var(--nl-space-lg);
	max-width: 38ch;
}

.nl-hero__ctas .nl-btn {
	padding: 0.9rem 1.75rem;
	font-size: var(--nl-size-body);
}

.nl-hero__ctas .nl-btn--quiet {
	color: #fff;
	border-color: rgba(255, 255, 255, 0.5);
}

.nl-hero__ctas .nl-btn--quiet:hover {
	border-color: #fff;
	color: #fff;
}

.nl-hero__controls {
	position: absolute;
	left: 0;
	right: 0;
	bottom: var(--nl-space-md);
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: var(--nl-space-2xs);
	pointer-events: none;
}

.nl-hero__controls > * {
	pointer-events: auto;
}

.nl-hero__arrow {
	width: 40px;
	height: 40px;
	padding: 0;
	border-radius: var(--nl-radius-pill);
	background: rgba(255, 255, 255, 0.16);
	border: 1px solid rgba(255, 255, 255, 0.3);
	color: #fff;
	backdrop-filter: blur(8px);
}

.nl-hero__arrow:hover {
	background: rgba(255, 255, 255, 0.28);
	color: #fff;
	box-shadow: none;
}

.nl-hero__arrow--prev .nl-icon {
	transform: rotate(180deg);
}

.nl-hero__dots {
	display: flex;
	gap: 6px;
	margin-inline: var(--nl-space-2xs);
}

.nl-hero__dot {
	width: 8px;
	height: 8px;
	padding: 0;
	border-radius: var(--nl-radius-pill);
	border: 0;
	background: rgba(255, 255, 255, 0.4);
	transition: width var(--nl-dur-base) var(--nl-ease-out), background-color var(--nl-dur-base) var(--nl-ease-out);
}

.nl-hero__dot.is-active {
	width: 22px;
	background: #fff;
}

.nl-hero__dot:hover {
	box-shadow: none;
	background: rgba(255, 255, 255, 0.75);
}

/*
 * The rail needs vertical room and a quiet left edge to sit against, so it is
 * a wide-screen control. Below that the dots do the same job in less space.
 * Declared after the dot rules so it wins on order rather than on specificity.
 */
@media (min-width: 900px) {
	.nl-hero__rail {
		display: block;
	}

	.nl-hero__dots {
		display: none;
	}

	/*
	 * Reserve the rail's strip so the centred slide copy is centred in what
	 * is left rather than running into it. 46px is one rail row: the 44px
	 * touch minimum plus the 2px list gap. The count comes from the template,
	 * so a hero with fewer slides gives back the room.
	 */
	.nl-hero__slide {
		padding-bottom: calc(var(--nl-hero-rail-rows, 0) * 46px + var(--nl-space-xl));
	}
}

/* =============================================================================
   "The latest" grid — calm, no motion beyond the single reveal
   ========================================================================== */

/*
 * Bento grid. Tiles carry their own column span, planned by
 * northline_bento_spans() so every row fills exactly; the grid only has to
 * provide the twelve columns to span across. Below the breakpoint the spans
 * are ignored and tiles stack one per row, because a three-up bento at phone
 * width is just three small photographs.
 */
.nl-latest__grid {
	display: grid;
	gap: var(--nl-space-md);
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
	.nl-latest__grid {
		grid-template-columns: repeat(12, minmax(0, 1fr));
	}

	.nl-tile--span-3 { grid-column: span 6; }
	.nl-tile--span-4 { grid-column: span 6; }
	.nl-tile--span-6 { grid-column: span 6; }
	.nl-tile--span-12 { grid-column: span 12; }
}

@media (min-width: 900px) {
	.nl-tile--span-3 { grid-column: span 3; }
	.nl-tile--span-4 { grid-column: span 4; }
}

/* =============================================================================
   Carousel — soft deceleration, never a hard snap
   ========================================================================== */

.nl-carousel {
	position: relative;
}

/*
 * Progress rail. It reports both how far along the run is and how much of it
 * fits, which a row of dots cannot do for a track that scrolls continuously.
 */
.nl-carousel__progress {
	flex: 1 1 auto;
	max-width: 12rem;
	height: 2px;
	margin-right: auto;
	border-radius: 2px;
	background: var(--nl-line);
	overflow: hidden;
}

.nl-carousel__progress-bar {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: inherit;
	background: var(--nl-ink);
	transform-origin: 0 50%;
	transition: transform var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-carousel__track {
	display: flex;
	gap: var(--nl-space-md);
	overflow-x: auto;
	scroll-snap-type: x proximity;
	scroll-behavior: smooth;
	scrollbar-width: none;
	padding-block: var(--nl-space-3xs) var(--nl-space-sm);
	margin-inline: calc(var(--nl-gutter) * -1);
	padding-inline: var(--nl-gutter);
	/*
	 * Snap positions are measured from the scrollport edge, not from the
	 * padding box, so without this the first item snapped under the gutter
	 * the negative margin opens up: the track settled at scrollLeft 32 and
	 * the whole row sat a gutter to the left of the heading above it.
	 */
	scroll-padding-inline: var(--nl-gutter);
}

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

.nl-carousel__item {
	flex: 0 0 72%;
	scroll-snap-align: start;
	min-width: 0;
}

@media (min-width: 640px) {
	.nl-carousel__item {
		flex-basis: 44%;
	}
}

@media (min-width: 900px) {
	.nl-carousel__item {
		flex-basis: 30%;
	}
}

@media (min-width: 1200px) {
	.nl-carousel__item {
		flex-basis: 23%;
	}
}

.nl-carousel__controls {
	display: none;
	align-items: center;
	gap: var(--nl-space-3xs);
	justify-content: flex-end;
	margin-top: var(--nl-space-sm);
}

@media (min-width: 900px) {
	.nl-carousel__controls {
		display: flex;
	}
}

.nl-carousel__arrow {
	width: 36px;
	height: 36px;
	padding: 0;
	border-radius: var(--nl-radius-pill);
	background: transparent;
	border: 1px solid var(--nl-line-strong);
	color: var(--nl-ink);
}

.nl-carousel__arrow:hover:not([disabled]) {
	border-color: var(--nl-ink);
	color: var(--nl-ink);
	box-shadow: none;
}

.nl-carousel__arrow[disabled] {
	opacity: 0.35;
}

.nl-carousel__arrow:first-child .nl-icon {
	transform: rotate(180deg);
}

.nl-carousel-section__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--nl-space-sm);
}

.nl-carousel-section__head .nl-section__head {
	margin-bottom: var(--nl-space-md);
}

.nl-carousel-section__all {
	margin-bottom: var(--nl-space-md);
	white-space: nowrap;
}

/* =============================================================================
   Dark cinematic reveal — the one bold moment
   ========================================================================== */

.nl-dark {
	background: var(--nl-dark);
	padding-block: var(--nl-space-3xl);
}

.nl-dark__grid {
	display: grid;
	gap: var(--nl-space-xl);
	grid-template-columns: 1fr;
	align-items: center;
}

@media (min-width: 900px) {
	.nl-dark__grid {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		gap: var(--nl-space-2xl);
	}

	/*
	 * The pinned component lays itself out in two columns — sticky frame beside
	 * the lines — so it needs the full width. Nested inside the dark section's
	 * own two-column grid it was halving an already-halved column, which left
	 * the frame at 210px: a thumbnail stranded in a band over a thousand pixels
	 * tall. When this section is the pinned moment, the grid gives way and the
	 * text simply stacks above it.
	 */
	.nl-dark__grid--pinned {
		align-items: start;
		grid-template-columns: minmax(0, 1fr);
	}
}

.nl-dark__title {
	font-size: var(--nl-size-headline);
	font-weight: var(--nl-weight-bold);
	line-height: var(--nl-leading-tight);
	letter-spacing: var(--nl-tracking-display);
	margin-bottom: var(--nl-space-md);
	max-width: 16ch;
	text-wrap: balance;
}

.nl-dark__copy {
	font-size: var(--nl-size-subhead);
	color: var(--nl-ink-muted);
	max-width: 42ch;
	margin-bottom: var(--nl-space-md);
}

/* =============================================================================
   Pinned scroll reveal — used exactly once on the site
   ========================================================================== */

.nl-pinned {
	display: grid;
	gap: var(--nl-space-lg);
	grid-template-columns: 1fr;
}

.nl-pinned__sticky {
	align-self: start;
}

/*
 * The frame had no size of its own, so it collapsed to the intrinsic size of
 * whatever was inside it — a 210px placeholder stranded in a column more than
 * a thousand pixels tall. It is the anchor the whole pinned moment holds on,
 * so it takes the column and a generous share of the viewport height.
 */
.nl-pinned__frame {
	width: 100%;
	border-radius: var(--nl-radius-xl);
	overflow: hidden;
}

.nl-pinned__frame img,
.nl-pinned__frame .nl-placeholder {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media (min-width: 900px) {
	.nl-pinned__frame {
		max-height: 74vh;
	}
}

.nl-pinned__heading {
	font-size: 1.25rem;
	margin-bottom: var(--nl-space-md);
}

.nl-pinned__lines {
	display: grid;
	gap: var(--nl-space-xl);
}

.nl-pinned__line {
	font-size: var(--nl-size-subhead);
	line-height: var(--nl-leading-snug);
	color: var(--nl-ink-muted);
	opacity: 0.45;
	transition: opacity var(--nl-dur-slow) var(--nl-ease-out), color var(--nl-dur-slow) var(--nl-ease-out);
	margin: 0;
	max-width: 34ch;
}

.nl-pinned__line.is-active {
	opacity: 1;
	color: var(--nl-ink);
}

@media (min-width: 900px) {
	.nl-pinned {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		gap: var(--nl-space-2xl);
	}

	.nl-pinned__sticky {
		position: sticky;
		top: calc(var(--nl-header-offset) + var(--nl-space-lg));
	}

	.nl-pinned__lines {
		padding-block: 22vh;
		gap: 38vh;
	}
}

.nl-product-pinned {
	margin-top: var(--nl-space-2xl);
	border-radius: var(--nl-radius-xl);
}

/* =============================================================================
   UGC reviews
   ========================================================================== */

.nl-ugc__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--nl-space-md);
	margin-bottom: var(--nl-space-lg);
}

.nl-ugc__aggregate {
	display: flex;
	align-items: center;
	gap: var(--nl-space-2xs);
	margin: var(--nl-space-2xs) 0 0;
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

.nl-ugc__filters {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.nl-ugc__filter {
	padding: 6px 14px;
	border-radius: var(--nl-radius-pill);
	border: 1px solid var(--nl-line-strong);
	background: transparent;
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

.nl-ugc__filter:hover {
	border-color: var(--nl-ink);
	color: var(--nl-ink);
	box-shadow: none;
}

.nl-ugc__filter.is-active {
	background: var(--nl-ink);
	border-color: var(--nl-ink);
	color: var(--nl-base);
}

.nl-ugc__item {
	flex-basis: 78%;
}

@media (min-width: 640px) {
	.nl-ugc__item {
		flex-basis: 46%;
	}
}

@media (min-width: 900px) {
	.nl-ugc__item {
		flex-basis: 31%;
	}
}

@media (min-width: 1200px) {
	.nl-ugc__item {
		flex-basis: 24%;
	}
}

.nl-ugc__item[hidden] {
	display: none;
}

.nl-ugc__no-match {
	padding: var(--nl-space-lg) 0;
	color: var(--nl-ink-muted);
}

.nl-ugc-card {
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-xs);
	height: 100%;
	padding: var(--nl-space-sm);
	background: var(--nl-surface);
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-xl);
	transform: translateY(var(--nl-lift, 0px));
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

.nl-ugc-card:hover {
	--nl-lift: -2px;
	box-shadow: var(--nl-shadow-lift);
}

.nl-ugc-card__media {
	position: relative;
	border-radius: var(--nl-radius-lg);
	overflow: hidden;
}

.nl-ugc-card__video {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 5;
	object-fit: cover;
	background: var(--nl-surface-sunken);
}

.nl-ugc-card__sound {
	position: absolute;
	right: var(--nl-space-2xs);
	bottom: var(--nl-space-2xs);
	width: 34px;
	height: 34px;
	padding: 0;
	border-radius: var(--nl-radius-pill);
	background: rgba(10, 10, 12, 0.6);
	border: 0;
	color: #fff;
	backdrop-filter: blur(6px);
}

.nl-ugc-card__sound:hover {
	background: rgba(10, 10, 12, 0.8);
	color: #fff;
	box-shadow: none;
}

.nl-ugc-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-2xs);
	flex: 1 1 auto;
}

.nl-ugc-card__quote {
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-size: var(--nl-size-small);
	line-height: var(--nl-leading-body);
	color: var(--nl-ink);
	border-radius: 0;
}

.nl-ugc-card__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	font-size: var(--nl-size-micro);
	color: var(--nl-ink-muted);
	margin-top: auto;
}

.nl-ugc-card__name {
	font-weight: var(--nl-weight-medium);
	color: var(--nl-ink);
}

.nl-ugc-card__verified {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	align-self: flex-start;
	margin: 0;
	padding: 3px 10px;
	border-radius: var(--nl-radius-pill);
	background: var(--nl-accent-soft);
	color: var(--nl-ink);
	font-size: var(--nl-size-micro);
}

.nl-ugc-card__verified .nl-icon {
	width: 0.95em;
	height: 0.95em;
	color: var(--nl-accent);
}

/* =============================================================================
   "Why shop with us" — big cards
   ========================================================================== */

.nl-why__grid {
	display: flex;
	gap: var(--nl-space-md);
	overflow-x: auto;
	scroll-snap-type: x proximity;
	scrollbar-width: none;
	margin-inline: calc(var(--nl-gutter) * -1);
	padding-inline: var(--nl-gutter);
	padding-bottom: var(--nl-space-sm);
}

.nl-why__grid::-webkit-scrollbar {
	display: none;
}

.nl-why__grid > * {
	flex: 0 0 82%;
	scroll-snap-align: start;
}

@media (min-width: 900px) {
	.nl-why__grid {
		display: grid;
		grid-template-columns: repeat(3, minmax(0, 1fr));
		overflow: visible;
		margin-inline: 0;
		padding-inline: 0;
	}

	.nl-why__grid > * {
		flex: initial;
	}
}

.nl-feature-card {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	overflow: clip;
	border-radius: var(--nl-radius-xl);
	background: var(--nl-surface);
	border: 1px solid var(--nl-line);
	color: inherit;
	text-decoration: none;
	transform: translateY(var(--nl-lift, 0px));
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

a.nl-feature-card:hover,
a.nl-feature-card:focus-visible {
	--nl-lift: -4px;
	box-shadow: var(--nl-shadow-lift);
	text-decoration: none;
}

.nl-feature-card__media {
	width: 100%;
}

.nl-feature-card__media .nl-frame {
	border-radius: 0;
	box-shadow: none;
}

.nl-feature-card__video {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	background: var(--nl-surface-sunken);
}

.nl-feature-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-3xs);
	padding: var(--nl-space-md);
	flex: 1 1 auto;
}

.nl-feature-card__title {
	font-size: 1.1875rem;
	margin: 0;
	max-width: 22ch;
}

.nl-feature-card__copy {
	margin: 0;
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

.nl-feature-card__more {
	margin-top: auto;
	padding-top: var(--nl-space-2xs);
	color: var(--nl-accent);
}

/* =============================================================================
   Compare teaser, editorial strip
   ========================================================================== */

.nl-compare-teaser__panel {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nl-space-md);
	padding: var(--nl-space-lg);
	border-radius: var(--nl-radius-xl);
	background: var(--nl-surface);
	border: 1px solid var(--nl-line);
}

.nl-compare-teaser__mark {
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	border-radius: var(--nl-radius-pill);
	background: var(--nl-accent-soft);
	color: var(--nl-accent);
	flex: 0 0 auto;
}

.nl-compare-teaser__text {
	flex: 1 1 18rem;
}

.nl-compare-teaser__title {
	font-size: 1.375rem;
	margin: 0 0 2px;
}

.nl-compare-teaser__copy {
	margin: 0;
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

/*
 * Editorial bento. Cards share the collection grid's span planner, so the two
 * sections read as one system. A card with an image becomes a picture card; one
 * without stays a quiet typographic panel, which keeps the section usable for a
 * buyer who has links to offer but no art to put behind them.
 */
.nl-editorial__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--nl-space-sm);
	grid-template-columns: minmax(0, 1fr);
}

.nl-editorial__item {
	min-width: 0;
}

.nl-editorial__link {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-2xs);
	height: 100%;
	padding: var(--nl-space-md);
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-xl);
	background: var(--nl-surface);
	color: var(--nl-ink);
	text-decoration: none;
	overflow: hidden;
	overflow: clip;
	transform: translateY(var(--nl-lift, 0px));
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

a.nl-editorial__link:hover,
a.nl-editorial__link:focus-visible {
	text-decoration: none;
	--nl-lift: -3px;
	box-shadow: var(--nl-shadow-lift);
}

/* The image bleeds to the card edges; the padding lives on the body instead. */
.nl-editorial__item--has-image .nl-editorial__link {
	padding: 0;
}

.nl-editorial__media {
	display: block;
	overflow: hidden;
	overflow: clip;
}

.nl-editorial__img {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 10;
	object-fit: cover;
}

.nl-editorial__body {
	display: block;
	padding: var(--nl-space-md);
}

.nl-editorial__item:not(.nl-editorial__item--has-image) .nl-editorial__body {
	padding: 0;
}

.nl-editorial__label {
	display: block;
	font-size: 1.0625rem;
	font-weight: var(--nl-weight-semibold);
	letter-spacing: var(--nl-tracking-headline);
}

.nl-editorial__copy {
	display: block;
	margin-top: 4px;
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

.nl-editorial__arrow {
	position: absolute;
	right: var(--nl-space-md);
	bottom: var(--nl-space-md);
	display: grid;
	place-items: center;
	width: 34px;
	height: 34px;
	border-radius: 50%;
	border: 1px solid var(--nl-line);
	background: var(--nl-surface);
	color: var(--nl-ink);
	transition: background-color var(--nl-dur-base) var(--nl-ease-out);
}

a.nl-editorial__link:hover .nl-editorial__arrow {
	background: var(--nl-surface-sunken);
}

/* Room for the corner arrow so long copy never runs under it. */
.nl-editorial__copy {
	padding-right: 2.75rem;
}

@media (min-width: 640px) {
	.nl-editorial__list {
		grid-template-columns: repeat(12, minmax(0, 1fr));
	}

	.nl-editorial__item--span-3,
	.nl-editorial__item--span-4,
	.nl-editorial__item--span-6 {
		grid-column: span 6;
	}

	.nl-editorial__item--span-12 {
		grid-column: span 12;
	}
}

@media (min-width: 900px) {
	.nl-editorial__item--span-3 {
		grid-column: span 3;
	}

	.nl-editorial__item--span-4 {
		grid-column: span 4;
	}
}

/* =============================================================================
   Newsletter band and store locator
   ========================================================================== */

.nl-newsletter {
	background: var(--nl-ink);
	color: var(--nl-ink-on-dark);
	padding-block: var(--nl-space-xl);
}

.nl-newsletter__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--nl-space-md);
}

.nl-newsletter__heading {
	color: inherit;
	font-size: 1.5rem;
	margin: 0 0 4px;
}

.nl-newsletter__copy {
	margin: 0;
	color: var(--nl-ink-on-dark-muted);
	font-size: var(--nl-size-small);
}

.nl-newsletter__form {
	display: flex;
	gap: var(--nl-space-2xs);
	flex: 1 1 22rem;
	max-width: 30rem;
}

/*
 * Scoped through .nl-newsletter on purpose. The base form styles match on
 * `input[type="email"]`, and an attribute selector carries the same weight as a
 * class — so a single-class rule here loses and the field keeps the light-theme
 * white background while the placeholder below turns white on it. Two classes
 * put this ahead of the base rule.
 */
.nl-newsletter .nl-newsletter__field {
	flex: 1 1 auto;
	background: rgba(255, 255, 255, 0.08);
	border-color: rgba(255, 255, 255, 0.25);
	color: #fff;
}

.nl-newsletter .nl-newsletter__field::placeholder {
	color: rgba(255, 255, 255, 0.72);
	opacity: 1;
}

.nl-newsletter__submit {
	flex: 0 0 auto;
}

.nl-locator {
	padding: var(--nl-space-md);
	border-radius: var(--nl-radius-xl);
	background: var(--nl-surface);
	border: 1px solid var(--nl-line);
}

/*
 * On a dark ground the surface and line tokens sit within about 1.4:1 of the
 * base behind them, so the card all but vanished in the dark footer — its text
 * was legible but the panel holding it was not. A translucent lift reads on any
 * dark background rather than depending on one particular base colour.
 */
.nl-on-dark .nl-locator {
	background: rgba(255, 255, 255, 0.05);
	border-color: rgba(255, 255, 255, 0.14);
}

.nl-locator__mark {
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border-radius: var(--nl-radius-pill);
	background: var(--nl-accent-soft);
	color: var(--nl-accent);
	margin-bottom: var(--nl-space-2xs);
}

.nl-locator__heading {
	font-size: 1.125rem;
	margin: 0 0 4px;
}

.nl-locator__copy {
	margin: 0 0 var(--nl-space-sm);
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-small);
}

/* =============================================================================
   Compare table and tray
   ========================================================================== */

.nl-compare__scroll {
	overflow-x: auto;
}

.nl-compare__columns,
.nl-spec-row {
	display: grid;
	grid-template-columns: minmax(120px, 0.7fr) repeat(var(--nl-compare-count, 3), minmax(180px, 1fr));
	gap: var(--nl-space-md);
	align-items: start;
}

.nl-compare__columns {
	padding-bottom: var(--nl-space-lg);
	border-bottom: 1px solid var(--nl-line);
	margin-bottom: var(--nl-space-md);
}

.nl-compare__column {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--nl-space-2xs);
}

.nl-compare__remove {
	position: absolute;
	top: 6px;
	right: 6px;
	z-index: 2;
	width: 28px;
	height: 28px;
	padding: 0;
	border-radius: var(--nl-radius-pill);
	background: var(--nl-surface);
	border: 1px solid var(--nl-line);
	color: var(--nl-ink-muted);
}

.nl-compare__remove:hover {
	color: var(--nl-ink);
	box-shadow: none;
}

.nl-compare__name {
	font-size: 1rem;
	margin: 0;
}

.nl-compare__name a {
	color: var(--nl-ink);
	text-decoration: none;
}

.nl-compare__price {
	margin: 0;
	font-weight: var(--nl-weight-medium);
}

.nl-spec-group {
	border-bottom: 1px solid var(--nl-line);
}

.nl-spec-group__head {
	margin: 0;
	font-size: 1rem;
}

.nl-spec-group__toggle {
	display: flex;
	width: 100%;
	align-items: center;
	justify-content: space-between;
	gap: var(--nl-space-2xs);
	padding: var(--nl-space-sm) 0;
	background: none;
	border: 0;
	border-radius: 0;
	color: var(--nl-ink);
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-semibold);
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

.nl-spec-group__toggle:hover {
	box-shadow: none;
	color: var(--nl-accent);
}

.nl-spec-group__chevron {
	transition: transform var(--nl-dur-base) var(--nl-ease-out);
	color: var(--nl-ink-muted);
}

.nl-spec-group.is-open .nl-spec-group__chevron {
	transform: rotate(180deg);
}

.nl-spec-group__body {
	padding-bottom: var(--nl-space-sm);
}

.nl-spec-row {
	padding-block: var(--nl-space-2xs);
	border-top: 1px solid var(--nl-line);
	font-size: var(--nl-size-small);
}

.nl-spec-row__label {
	color: var(--nl-ink-muted);
}

.nl-spec-row__empty {
	color: var(--nl-line-strong);
}

.nl-compare__rating-count {
	color: var(--nl-ink-muted);
	font-size: var(--nl-size-micro);
	margin-left: 4px;
}

.nl-compare-tray {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 60;
	background: var(--nl-ink);
	color: var(--nl-ink-on-dark);
	padding-block: var(--nl-space-2xs);
	transform: translateY(100%);
	transition: transform var(--nl-dur-base) var(--nl-ease-decel);
}

.nl-compare-tray.is-visible {
	transform: translateY(0);
}

.nl-compare-tray__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--nl-space-2xs);
}

.nl-compare-tray__count {
	margin: 0;
	font-size: var(--nl-size-small);
}

.nl-compare-tray__actions {
	display: flex;
	gap: var(--nl-space-2xs);
}

.nl-compare-tray .nl-btn--quiet {
	color: #fff;
	border-color: rgba(255, 255, 255, 0.35);
}

/* =============================================================================
   Quantity stepper and account pills
   ========================================================================== */

.nl-stepper {
	display: inline-flex;
	align-items: center;
	border: 1px solid var(--nl-line-strong);
	border-radius: var(--nl-radius-pill);
	overflow: hidden;
	background: var(--nl-surface);
}

.nl-stepper__btn {
	width: 38px;
	height: 38px;
	padding: 0;
	background: none;
	border: 0;
	border-radius: 0;
	color: var(--nl-ink);
}

.nl-stepper__btn:hover {
	background: var(--nl-surface-sunken);
	box-shadow: none;
	color: var(--nl-ink);
}

.nl-stepper input.qty,
.nl-stepper .nl-stepper__input {
	width: 3.2rem;
	border: 0;
	border-radius: 0;
	text-align: center;
	padding: 0;
	background: transparent;
	-moz-appearance: textfield;
}

/*
 * The field inside drops its own ring because the pill is the control the
 * eye sees; the pill takes the focus state instead, so a keyboard user never
 * loses track of where they are.
 */
.nl-stepper input.qty:focus {
	box-shadow: none;
}

.nl-stepper {
	transition: border-color var(--nl-dur-quick) var(--nl-ease-out), box-shadow var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-stepper:focus-within {
	border-color: var(--nl-accent);
	box-shadow: 0 0 0 3px var(--nl-accent-soft);
}

.nl-stepper__btn:active {
	transform: scale(0.92);
}

.nl-stepper input::-webkit-outer-spin-button,
.nl-stepper input::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.nl-account-nav__pills {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: var(--nl-space-lg);
}

.nl-account-pill {
	display: inline-block;
	padding: 7px 16px;
	border-radius: var(--nl-radius-pill);
	border: 1px solid var(--nl-line-strong);
	color: var(--nl-ink);
	font-size: var(--nl-size-small);
	text-decoration: none;
	transition: border-color var(--nl-dur-quick) var(--nl-ease-out), background-color var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-account-pill:hover {
	border-color: var(--nl-ink);
	text-decoration: none;
}

.nl-account-pill.is-current {
	background: var(--nl-ink);
	border-color: var(--nl-ink);
	color: var(--nl-base);
}

/* =============================================================================
   Scroll reveal
   ========================================================================== */

/*
 * Keyed on .js so content is never left invisible when scripts fail.
 *
 * The reveal and the hover lift both want the same transform, and the reveal
 * selector wins on specificity and on order — so a plain `transform: none`
 * here silently cancelled every card's hover lift. Both now travel through
 * --nl-lift, which composes them: the reveal owns the 16px entry offset, a
 * hover adds its own few pixels on top, and neither has to out-specify the
 * other.
 */
.js [data-nl-reveal] {
	opacity: 0;
	transform: translateY(calc(16px + var(--nl-lift, 0px)));
}

.js [data-nl-reveal].is-revealed {
	opacity: 1;
	transform: translateY(var(--nl-lift, 0px));
	transition: opacity var(--nl-dur-slow) var(--nl-ease-out), transform var(--nl-dur-slow) var(--nl-ease-out);
}

/* The dark reveal's optional flagship card sits a little larger than a grid card. */
.nl-dark__media--card .nl-product-card {
	padding: 0;
	max-width: 30rem;
}

.nl-dark__media--card .nl-product-card:hover,
.nl-dark__media--card .nl-product-card:focus-within {
	background: transparent;
	box-shadow: none;
	transform: none;
}

.nl-dark__media--card .nl-product-card__title {
	font-size: 1.25rem;
}

/* =============================================================================
   Trust strip — proof points, set as type rather than a row of logos
   ========================================================================== */

/*
 * Typographic on purpose. A buyer's award marks and certification logos arrive
 * at wildly different aspect ratios and weights, and a strip of those never
 * lines up; a label and a line of detail always does. The optional mark sits
 * above the label, at a fixed height, for the buyers who do have one.
 */
.nl-trust__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--nl-space-md);
	grid-template-columns: minmax(0, 1fr);
	border-top: 1px solid var(--nl-line);
	padding-top: var(--nl-space-lg);
}

.nl-trust__item {
	min-width: 0;
}

.nl-trust__mark {
	display: block;
	margin-bottom: var(--nl-space-2xs);
}

.nl-trust__img {
	display: block;
	width: auto;
	height: 32px;
	object-fit: contain;
	object-position: left center;
}

.nl-trust__label {
	margin: 0;
	font-size: 1.0625rem;
	font-weight: var(--nl-weight-semibold);
	letter-spacing: var(--nl-tracking-headline);
	color: var(--nl-ink);
}

.nl-trust__note {
	margin: 4px 0 0;
	font-size: var(--nl-size-small);
	color: var(--nl-ink-muted);
	max-width: 32ch;
}

@media (min-width: 640px) {
	.nl-trust__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 900px) {
	.nl-trust__list {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: var(--nl-space-lg);
	}
}

/* =============================================================================
   Collection tabs
   ========================================================================== */

.nl-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--nl-space-3xs);
	margin-bottom: var(--nl-space-md);
}

.nl-tabs__tab {
	padding: 8px 16px;
	border: 1px solid var(--nl-line-strong);
	border-radius: var(--nl-radius-pill);
	background: none;
	color: var(--nl-ink);
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-regular);
	cursor: pointer;
	transition: background-color var(--nl-dur-quick) var(--nl-ease-out), color var(--nl-dur-quick) var(--nl-ease-out), border-color var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-tabs__tab:hover {
	background: var(--nl-surface-sunken);
}

.nl-tabs__tab.is-active {
	background: var(--nl-ink);
	border-color: var(--nl-ink);
	color: var(--nl-base);
}

/* -------------------------------------------------------------------------
   Colour switcher — the shopper's own accent, kept on their device
   ------------------------------------------------------------------------- */

/*
 * Bottom-left, because the cart drawer owns the right edge and a chat widget
 * usually owns the bottom-right corner of a live shop. Below the drawer (70)
 * and the compare tray (60) in the stack: when either is up, the launcher
 * either lifts clear of it or steps out of the way entirely.
 */
.nl-scheme {
	position: fixed;
	left: var(--nl-space-md);
	bottom: var(--nl-space-md);
	z-index: 55;
	transition: transform var(--nl-dur-base) var(--nl-ease-decel),
		opacity var(--nl-dur-quick) var(--nl-ease-out),
		visibility var(--nl-dur-quick) var(--nl-ease-out);
}

/* The tray slides up over the same corner, so the launcher rides above it. */
html.nl-tray-open .nl-scheme {
	transform: translateY(calc(-1 * var(--nl-tray-height, 56px)));
}

/*
 * The drawer traps focus and dims the page behind it. A button still floating
 * over that dimming reads as reachable when it is not.
 */
html.nl-drawer-open .nl-scheme {
	opacity: 0;
	visibility: hidden;
}

.nl-scheme__launcher {
	width: 48px;
	height: 48px;
	display: grid;
	place-items: center;
	padding: 0;
	border: 1px solid var(--nl-line);
	border-radius: 50%;
	background: var(--nl-surface);
	color: var(--nl-accent);
	box-shadow: var(--nl-shadow-rest);
	cursor: pointer;
	transition: transform var(--nl-dur-base) var(--nl-ease-out),
		box-shadow var(--nl-dur-base) var(--nl-ease-out),
		border-color var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-scheme__launcher:hover {
	/* The house hover: a small lift, no scale and no colour shift. */
	transform: translateY(-2px);
	border-color: var(--nl-line-strong);
	box-shadow: var(--nl-shadow-lift);
	color: var(--nl-accent);
	background: var(--nl-surface);
}

.nl-scheme__launcher-icon {
	display: grid;
	place-items: center;
}

.nl-scheme__launcher svg {
	width: 22px;
	height: 22px;
}

.nl-scheme__panel {
	position: absolute;
	left: 0;
	bottom: calc(48px + var(--nl-space-2xs));
	width: 19rem;
	max-width: calc(100vw - (2 * var(--nl-space-md)));
	/* A short viewport — a phone held sideways — must not push the top off. */
	max-height: calc(100vh - 6rem);
	overflow-y: auto;
	padding: var(--nl-space-md);
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-lg);
	background: var(--nl-surface);
	box-shadow: var(--nl-shadow-lift);
}

.nl-scheme__panel:not([hidden]) {
	animation: nl-scheme-in var(--nl-dur-base) var(--nl-ease-decel) both;
}

@keyframes nl-scheme-in {
	from {
		opacity: 0;
		transform: translateY(8px);
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

.nl-scheme__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--nl-space-2xs);
	margin-bottom: var(--nl-space-3xs);
}

.nl-scheme__title {
	margin: 0;
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-semibold);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--nl-ink);
}

.nl-scheme__close {
	width: 32px;
	height: 32px;
	display: grid;
	place-items: center;
	margin-right: calc(-1 * var(--nl-space-3xs));
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--nl-ink-muted);
	cursor: pointer;
}

.nl-scheme__close:hover {
	background: var(--nl-surface-sunken);
	color: var(--nl-ink);
}

.nl-scheme__close svg {
	width: 16px;
	height: 16px;
}

.nl-scheme__note,
.nl-scheme__custom-note {
	margin: 0 0 var(--nl-space-sm);
	font-size: var(--nl-size-micro);
	line-height: 1.45;
	color: var(--nl-ink-muted);
}

/*
 * Fixed 44px columns rather than fractions: a stretched column would make the
 * last row's lone swatch twice the width of the others, and anything narrower
 * than 44px is under the smallest target a finger can be asked to hit.
 */
.nl-scheme__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, 44px);
	justify-content: start;
	gap: var(--nl-space-2xs);
	margin: 0 0 var(--nl-space-md);
	padding: 0;
	list-style: none;
}

.nl-scheme__cell {
	margin: 0;
	padding: 0;
}

.nl-scheme__swatch {
	width: 100%;
	/* 44px: the smallest a target may be under a finger. */
	height: 44px;
	padding: 0;
	border: 1px solid rgba(0, 0, 0, 0.14);
	border-radius: var(--nl-radius-sm);
	background: var(--nl-swatch, var(--nl-accent));
	cursor: pointer;
	transition: transform var(--nl-dur-base) var(--nl-ease-out),
		box-shadow var(--nl-dur-quick) var(--nl-ease-out);
}

.nl-scheme__swatch:hover {
	transform: translateY(-2px);
	background: var(--nl-swatch, var(--nl-accent));
}

/*
 * Selected reads as a dark ring with a white gap, not as a colour change: the
 * swatch's whole job is to be a colour, so the state cannot be carried by one.
 */
.nl-scheme__swatch[aria-pressed="true"] {
	box-shadow: 0 0 0 2px var(--nl-surface), 0 0 0 4px var(--nl-ink);
}

.nl-scheme__custom {
	margin-bottom: var(--nl-space-sm);
}

.nl-scheme__custom-label {
	display: block;
	margin-bottom: var(--nl-space-3xs);
	font-size: var(--nl-size-micro);
	font-weight: var(--nl-weight-medium);
	color: var(--nl-ink);
}

.nl-scheme__custom-input {
	width: 100%;
	height: 44px;
	padding: 4px;
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-sm);
	background: var(--nl-surface);
	cursor: pointer;
}

.nl-scheme__custom-input::-webkit-color-swatch-wrapper {
	padding: 0;
}

.nl-scheme__custom-input::-webkit-color-swatch {
	border: 0;
	border-radius: calc(var(--nl-radius-sm) - 3px);
}

.nl-scheme__custom-input::-moz-color-swatch {
	border: 0;
	border-radius: calc(var(--nl-radius-sm) - 3px);
}

.nl-scheme__custom-note {
	margin-top: var(--nl-space-3xs);
	margin-bottom: 0;
}

.nl-scheme__reset {
	width: 100%;
	justify-content: center;
}

@media (pointer: coarse) {
	.nl-scheme__close {
		width: 44px;
		height: 44px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.nl-scheme,
	.nl-scheme__launcher,
	.nl-scheme__swatch {
		transition: none;
	}

	.nl-scheme__panel:not([hidden]) {
		animation: none;
	}

	.nl-scheme__launcher:hover,
	.nl-scheme__swatch:hover {
		transform: none;
	}
}

/* =============================================================================
   Variant swatches — colour dots and size pills shared by the product card's
   quick colour pick and the single product's variation form.
   ========================================================================== */

.nl-swatches {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nl-space-2xs);
}

.nl-swatch {
	position: relative;
	display: inline-grid;
	place-items: center;
	margin: 0;
	padding: 0;
	border: 1px solid var(--nl-line-strong);
	border-radius: var(--nl-radius-pill);
	background: var(--nl-surface);
	color: var(--nl-ink);
	font: inherit;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: border-color var(--nl-dur-quick) var(--nl-ease-out),
		background-color var(--nl-dur-quick) var(--nl-ease-out),
		color var(--nl-dur-quick) var(--nl-ease-out),
		box-shadow var(--nl-dur-quick) var(--nl-ease-out),
		opacity var(--nl-dur-quick) var(--nl-ease-out),
		transform var(--nl-dur-quick) var(--nl-ease-out);
}

/* The global button:hover paints white accent ink and a shadow; a swatch is
   neither a filled button nor elevated. */
.nl-swatch:hover,
.nl-swatch:focus {
	box-shadow: none;
	color: var(--nl-ink);
}

.nl-swatch:hover:not(:disabled) {
	border-color: var(--nl-ink-muted);
}

/* A press is felt, not seen: the control gives by a hair and comes back. */
.nl-swatch:active:not(:disabled) {
	transform: scale(0.96);
}

.nl-swatch:focus-visible {
	outline: 2px solid var(--nl-accent);
	outline-offset: 3px;
}

/* Size pills: the whole button is the visible control, 44px tall to touch. */
.nl-swatch--text {
	min-width: 3.25rem;
	min-height: 44px;
	padding: 0 var(--nl-space-sm);
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-medium);
	font-variant-numeric: tabular-nums;
}

.nl-swatch--text[aria-checked="true"] {
	border-color: var(--nl-ink);
	background: var(--nl-ink);
	color: var(--nl-base);
}

.nl-swatch--text[aria-checked="true"]:hover,
.nl-swatch--text[aria-checked="true"]:focus {
	color: var(--nl-base);
}

/*
 * Colour dots: the button is a ring, the dot inside carries the colour. The
 * ring is transparent at rest and draws in, with a gap, when chosen — the
 * colour itself is never covered or tinted by the state.
 */
.nl-swatch--color {
	width: 44px;
	height: 44px;
	border-color: transparent;
	background: transparent;
}

.nl-swatch__dot {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	background: var(--nl-swatch-bg, var(--nl-line-strong));
	/* A hairline keeps white and cream dots from dissolving into the page. */
	box-shadow: inset 0 0 0 1px rgba(17, 18, 20, 0.12);
}

.nl-swatch--color:hover:not(:disabled) {
	border-color: var(--nl-line-strong);
}

.nl-swatch--color[aria-checked="true"],
.nl-swatch--color[aria-checked="true"]:hover {
	border-color: var(--nl-ink);
	box-shadow: inset 0 0 0 2px var(--nl-base);
}

/*
 * Out of stock in the current combination: still choosable, so WooCommerce
 * can say so in words, but struck through so it reads as unavailable before
 * anyone clicks. Unreachable (no such variation at all): disabled outright.
 */
.nl-swatch--oos {
	color: var(--nl-ink-muted);
}

.nl-swatch--oos::after,
.nl-swatch:disabled::after {
	content: "";
	position: absolute;
	inset: 22% 10%;
	background: linear-gradient(
		to top right,
		transparent calc(50% - 0.75px),
		var(--nl-ink-muted) calc(50% - 0.75px),
		var(--nl-ink-muted) calc(50% + 0.75px),
		transparent calc(50% + 0.75px)
	);
	pointer-events: none;
}

.nl-swatch--color.nl-swatch--oos::after,
.nl-swatch--color:disabled::after {
	inset: 6px;
	border-radius: 50%;
}

.nl-swatch:disabled {
	cursor: not-allowed;
	opacity: 0.38;
}

/* The chosen value, set beside the attribute's name: "Colour  Deep Navy". */
.nl-variation-current {
	margin-left: var(--nl-space-2xs);
	font-weight: var(--nl-weight-regular);
	color: var(--nl-ink-muted);
}

/*
 * The card's quick pick. Small dots so the row reads as a hint, not a form —
 * but each carries a 32px hit area through an invisible halo, so a finger
 * still lands on the right one.
 */
.nl-card-swatches {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--nl-space-3xs);
	margin-top: var(--nl-space-3xs);
}

.nl-swatch--mini {
	width: 24px;
	height: 24px;
}

.nl-swatch--mini::before {
	content: "";
	position: absolute;
	inset: -4px;
	border-radius: 50%;
}

.nl-swatch--mini .nl-swatch__dot {
	width: 16px;
	height: 16px;
}

.nl-swatch--mini[aria-checked="true"],
.nl-swatch--mini[aria-checked="true"]:hover {
	box-shadow: inset 0 0 0 2px var(--nl-base);
}

.nl-product-card:hover .nl-swatch--mini[aria-checked="true"] {
	box-shadow: inset 0 0 0 2px var(--nl-surface);
}

.nl-card-swatches__more {
	margin-left: var(--nl-space-3xs);
	font-size: var(--nl-size-micro);
	color: var(--nl-ink-muted);
	text-decoration: none;
}

.nl-card-swatches__more:hover {
	color: var(--nl-ink);
}

/* A picked colour owns the frame; the default colour's second angle would
   contradict it on hover. */
.nl-frame.is-swatched .nl-frame__img--hover {
	display: none;
}

/* The incoming photo during a swatch cross-fade, laid over the outgoing one. */
.nl-frame__img--swap {
	position: absolute;
	inset: 0;
	z-index: 1;
	opacity: 0;
	transition: opacity var(--nl-dur-base) var(--nl-ease-out);
}

.nl-frame__img--swap.is-in {
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.nl-swatch:active:not(:disabled) {
		transform: none;
	}
}

/* =============================================================================
   Scroll-linked depth — the hero and the large lifestyle imagery
   -------------------------------------------------------------------------
   The photograph moves a little slower than the page around it, inside a
   frame that stays put. Four surfaces only: the hero as it leaves, and the
   editorial, category and feature imagery as it passes. Product photography
   never drifts — a product shot has to hold still to be judged — and the
   pinned dark section keeps its own single idea.

   Where the browser has scroll-driven animations these run on the
   compositor with no script at all. Elsewhere theme.js drives the same two
   custom properties from a passive, frame-throttled scroll handler, and only
   for images currently on screen. Nothing here changes layout, so none of
   it can shift the page.

   The image is scaled up by just over twice its travel, so its edges never
   show inside the frame at either end of the range.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
	.js .nl-hero__img {
		scale: calc(1 + var(--nl-parallax-hero) * 2);
		translate: 0 calc(var(--nl-depth, 0) * var(--nl-parallax-hero) * 100%);
	}

	.js .nl-editorial__img,
	.js .nl-tile .nl-tile__frame .nl-frame__img,
	.js .nl-feature-card__media .nl-frame__img {
		scale: calc(1 + var(--nl-parallax-band) * 2.2);
		translate: 0 calc(var(--nl-depth, 0) * var(--nl-parallax-band) * 100%);
	}

	/*
	 * The hero's copy gives way as the image does: it lifts a little and
	 * fades over the first part of the hero leaving, so the next section
	 * arrives into a quiet frame rather than under a headline.
	 */
	.js .nl-hero__slide.is-active .nl-hero__text {
		opacity: calc(1 - var(--nl-hero-exit, 0) * 1.6);
		translate: 0 calc(var(--nl-hero-exit, 0) * -4rem);
	}
}

/*
 * Every frame here clips with overflow: hidden, which also makes it a
 * scroll container — and an anonymous view() timeline binds to the nearest
 * one, which never scrolls, so the animation would sit inert. Each surface
 * names a timeline on the frame itself and its image follows that name,
 * which ties the progress to the page's scroll instead.
 */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.js .nl-hero {
			view-timeline: --nl-hero block;
		}

		.js .nl-editorial__media,
		.js .nl-tile .nl-tile__frame,
		.js .nl-feature-card__media .nl-frame {
			view-timeline: --nl-band block;
		}

		/* 0 while the hero fills the screen, 1 once it has scrolled away. */
		.js .nl-hero__img {
			animation: nl-depth-exit linear both;
			animation-timeline: --nl-hero;
			animation-range: exit 0% exit 100%;
		}

		.js .nl-hero__slide.is-active .nl-hero__text {
			animation: nl-hero-exit linear both;
			animation-timeline: --nl-hero;
			animation-range: exit 0% exit 100%;
		}

		/* -1 as the image enters at the bottom, +1 as it leaves at the top. */
		.js .nl-editorial__img,
		.js .nl-tile .nl-tile__frame .nl-frame__img,
		.js .nl-feature-card__media .nl-frame__img {
			animation: nl-depth-cover linear both;
			animation-timeline: --nl-band;
			animation-range: cover 0% cover 100%;
		}
	}
}

@property --nl-depth {
	syntax: "<number>";
	inherits: false;
	initial-value: 0;
}

@property --nl-hero-exit {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@keyframes nl-depth-exit {
	from { --nl-depth: 0; }
	to { --nl-depth: 1; }
}

@keyframes nl-depth-cover {
	from { --nl-depth: -1; }
	to { --nl-depth: 1; }
}

@keyframes nl-hero-exit {
	from { --nl-hero-exit: 0; }
	to { --nl-hero-exit: 1; }
}

/* =============================================================================
   Product photography settling into its frame
   -------------------------------------------------------------------------
   As a card reveals, its photo eases from very slightly oversized to rest.
   The frame does not move or grow — only the picture inside it settles —
   which is why this sits comfortably beside the rule that hovers never
   scale: nothing the shopper is pointing at changes size.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
	.js [data-nl-reveal] .nl-product-card__frame .nl-frame__img,
	.js [data-nl-reveal] .nl-ugc-card__media .nl-frame__img {
		scale: 1.06;
		transition:
			scale var(--nl-dur-settle) var(--nl-ease-decel),
			opacity var(--nl-dur-quick) var(--nl-ease-out);
	}

	.js [data-nl-reveal].is-revealed .nl-product-card__frame .nl-frame__img,
	.js [data-nl-reveal].is-revealed .nl-ugc-card__media .nl-frame__img {
		scale: 1;
	}

	/* The hover angle keeps its own slow cross-fade. */
	.js [data-nl-reveal] .nl-product-card__frame .nl-frame__img--hover {
		transition:
			scale var(--nl-dur-settle) var(--nl-ease-decel),
			opacity var(--nl-dur-slow) var(--nl-ease-out);
	}
}

/* =============================================================================
   Storefront skin — the reference layout
   -------------------------------------------------------------------------
   Cool white and pale blue surfaces, sans headings set small and flush left,
   product photography on soft blue panels, labels in the top corner of the
   category bento, an awards row of equal cards, and a light gradient
   newsletter panel. Built on the existing tokens; nothing here changes
   markup or behaviour.
   ========================================================================== */

:root {
	--nl-panel: linear-gradient(160deg, #f2f6fc 0%, #e4ecf7 100%);
}

/* Section heads: a small, confident label, not a display line. */
.nl-section__title,
.nl-carousel-section__head .nl-section__title {
	font-size: clamp(1.375rem, 2vw, 1.75rem);
	font-weight: var(--nl-weight-semibold);
	letter-spacing: var(--nl-tracking-headline);
	max-width: none;
}

.nl-section__head {
	margin-bottom: var(--nl-space-md);
}

.nl-section__lede {
	font-size: var(--nl-size-small);
	margin-top: var(--nl-space-3xs);
}

.nl-section__eyebrow {
	margin-bottom: var(--nl-space-2xs);
	color: var(--nl-accent);
}

/* On a dark section the accent is too dark to read; the muted ink carries it. */
.nl-on-dark .nl-section__eyebrow,
.nl-dark .nl-section__eyebrow {
	color: var(--nl-ink-muted);
}

/* Product family bento: pale panels, the label chip top-right, the
   arrow bottom-right. */
.nl-tile {
	border-radius: var(--nl-radius-lg);
	background: var(--nl-panel);
}

.nl-tile__overlay {
	flex-direction: column;
	align-items: flex-end;
	justify-content: space-between;
	padding: var(--nl-space-sm);
}

.nl-tile__chip {
	padding: 6px var(--nl-space-sm);
	border-radius: var(--nl-radius-pill);
	background: rgba(255, 255, 255, 0.86);
	box-shadow: none;
	text-align: right;
}

.nl-tile__title {
	font-size: var(--nl-size-small);
	font-weight: var(--nl-weight-semibold);
	letter-spacing: 0;
}

.nl-tile__copy,
.nl-tile__price {
	display: none;
}

.nl-tile__go {
	width: 32px;
	height: 32px;
}

/* Product cards: the photo on a soft blue panel, text centred in rails. */
.nl-product-card .nl-frame {
	background: var(--nl-panel);
	box-shadow: none;
	border-radius: var(--nl-radius-lg);
}

.nl-product-card .nl-frame::after {
	display: none;
}

.nl-product-card {
	border-radius: var(--nl-radius-lg);
}

.nl-product-card__title {
	font-size: 1rem;
	font-weight: var(--nl-weight-semibold);
}

.nl-carousel .nl-product-card__body {
	align-items: center;
	text-align: center;
}

.nl-carousel .nl-product-card__ctas {
	justify-content: center;
}

.nl-badge {
	background: var(--nl-accent);
	color: var(--nl-accent-ink);
	border-radius: 6px;
	padding: 2px 8px;
}

/* Tabs above a rail: small pills, the active one filled blue. */
.nl-tabs__tab {
	padding: 5px 14px;
	font-size: var(--nl-size-micro);
}

.nl-tabs__tab.is-active,
.nl-tabs__tab[aria-selected="true"] {
	background: var(--nl-accent);
	border-color: var(--nl-accent);
	color: var(--nl-accent-ink);
}

/* Awards / proof row: equal pale cards, centred. */
.nl-trust__list {
	gap: var(--nl-space-sm);
}

.nl-trust__item {
	padding: var(--nl-space-lg) var(--nl-space-md);
	border-radius: var(--nl-radius-md);
	background: var(--nl-surface-sunken);
	text-align: center;
	justify-items: center;
}

/* Newsletter: a light gradient panel inside the page width. */
.nl-newsletter {
	background: transparent;
	color: var(--nl-ink);
}

.nl-newsletter .nl-newsletter__copy {
	color: var(--nl-ink-muted);
}

.nl-newsletter .nl-newsletter__field {
	background: var(--nl-surface);
	border-color: var(--nl-line-strong);
	color: var(--nl-ink);
}

.nl-newsletter .nl-newsletter__field::placeholder {
	color: var(--nl-ink-muted);
}

.nl-newsletter > .nl-container {
	padding: var(--nl-space-xl) var(--nl-space-lg);
	border-radius: var(--nl-radius-xl);
	background: linear-gradient(120deg, #eaf2fd 0%, #f6f9fe 55%, #e3eefc 100%);
}

.nl-newsletter__heading {
	font-size: clamp(1.25rem, 2vw, 1.625rem);
}

/* Buttons a notch smaller, as in the reference. */
.nl-btn {
	padding: 0.625rem 1.25rem;
	font-size: var(--nl-size-small);
}

.nl-hero__ctas .nl-btn {
	padding: 0.8rem 1.6rem;
	font-size: var(--nl-size-body);
}

@media (max-width: 767px) {
	.nl-newsletter > .nl-container {
		padding: var(--nl-space-lg) var(--nl-space-md);
		border-radius: var(--nl-radius-lg);
		margin-inline: var(--nl-gutter);
		width: auto;
	}

	.nl-trust__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.nl-hero__slide {
		min-height: clamp(440px, 72vh, 640px);
	}

	.nl-hero__headline {
		font-size: clamp(2rem, 9vw, 2.75rem);
	}
}

/* Phones: the product family as a two-up grid, as in the reference, with
   the first collection across the full width. */
@media (max-width: 767px) {
	.nl-latest__grid {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--nl-space-xs);
	}

	.nl-latest__grid > * {
		grid-column: auto;
		grid-row: auto;
		min-width: 0;
	}

	.nl-latest__grid > :first-child {
		grid-column: 1 / -1;
	}

	.nl-latest__grid .nl-tile .nl-tile__frame {
		min-height: 0;
		aspect-ratio: 1 / 1;
	}

	.nl-latest__grid > :first-child .nl-tile .nl-tile__frame,
	.nl-latest__grid > .nl-tile:first-child .nl-tile__frame {
		aspect-ratio: 16 / 10;
	}

	.nl-tile__overlay {
		padding: var(--nl-space-2xs);
	}

	.nl-tile__chip {
		padding: 4px 10px;
	}

	.nl-tile__title {
		font-size: var(--nl-size-micro);
	}
}


/* Hero image placement, from Theme Options → Hero Carousel. */
.nl-hero__slide {
	min-height: var(--nl-hero-min-height, clamp(480px, 78vh, 860px));
}

.nl-hero__img {
	object-fit: var(--nl-hero-fit, cover);
	object-position: var(--nl-hero-focus, center);
	background: var(--nl-dark);
}

@media (max-width: 767px) {
	.nl-hero__slide {
		min-height: min(var(--nl-hero-min-height, 72vh), 72vh);
	}
}


/* A custom HTML banner in the hero's place: full width, nothing imposed. */
.nl-hero-html {
	position: relative;
	width: 100%;
	overflow: hidden;
}

.nl-hero-html img,
.nl-hero-html video {
	max-width: 100%;
	height: auto;
}

/* =============================================================================
   Text-only cards — "Why shop with us" and the editorial strip without photos
   -------------------------------------------------------------------------
   A card with no image is designed as a text card, not left as an empty
   frame: a pale panel, a small accent mark, the title and copy, and — when
   it links somewhere — an arrow in the corner saying so. Equal heights,
   equal columns.
   ========================================================================== */

.nl-feature-card--text {
	position: relative;
	display: flex;
	flex-direction: column;
	min-height: 11rem;
	padding: var(--nl-space-lg) var(--nl-space-md) var(--nl-space-md);
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-lg);
	background: var(--nl-panel, var(--nl-surface-sunken));
	text-decoration: none;
	color: var(--nl-ink);
}

.nl-feature-card--text::before {
	content: "";
	display: block;
	width: 28px;
	height: 3px;
	margin-bottom: var(--nl-space-md);
	border-radius: 3px;
	background: var(--nl-accent);
}

.nl-feature-card--text .nl-feature-card__body {
	padding: 0;
}

a.nl-feature-card--text::after,
a.nl-editorial__link:not(:has(.nl-editorial__media))::after {
	content: "";
	position: absolute;
	right: var(--nl-space-md);
	bottom: var(--nl-space-md);
	width: 32px;
	height: 32px;
	border-radius: 50%;
	background:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23111827' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 17L17 7M9 7h8v8'/%3E%3C/svg%3E") center / 14px no-repeat,
		var(--nl-surface);
	box-shadow: var(--nl-shadow-rest);
}

/* Editorial strip: text cards in an even row of four (two on tablets, one
   on phones), whatever column spans the photo layout would use. */
.nl-editorial__list:not(:has(.nl-editorial__media)) {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--nl-space-sm);
}

.nl-editorial__list:not(:has(.nl-editorial__media)) > .nl-editorial__item {
	grid-column: auto;
}

.nl-editorial__item:not(.nl-editorial__item--has-image) .nl-editorial__link {
	position: relative;
	display: flex;
	flex-direction: column;
	height: 100%;
	min-height: 10rem;
	padding: var(--nl-space-md) var(--nl-space-md) calc(var(--nl-space-md) + 40px);
	border: 1px solid var(--nl-line);
	border-radius: var(--nl-radius-lg);
	background: var(--nl-panel, var(--nl-surface-sunken));
}

@media (max-width: 1023px) {
	.nl-editorial__list:not(:has(.nl-editorial__media)) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 599px) {
	.nl-editorial__list:not(:has(.nl-editorial__media)) {
		grid-template-columns: 1fr;
	}
}

/* =============================================================================
   Colour tints — Apple-style tinted icon tiles for trust and "why" cards
   ========================================================================== */
.nl-tint-0 { --nl-tint: #0a7cff; --nl-tint-soft: #e6f1ff; }
.nl-tint-1 { --nl-tint: #1f9d55; --nl-tint-soft: #e5f6ec; }
.nl-tint-2 { --nl-tint: #e8590c; --nl-tint-soft: #fff0e6; }
.nl-tint-3 { --nl-tint: #8b3dff; --nl-tint-soft: #f2eaff; }
.nl-tint-4 { --nl-tint: #d6336c; --nl-tint-soft: #fde8ef; }
.nl-tint-5 { --nl-tint: #0c8599; --nl-tint-soft: #e3f6f8; }

.nl-icon-tile {
	display: inline-grid;
	place-items: center;
	width: 52px;
	height: 52px;
	border-radius: 16px;
	background: linear-gradient(145deg, var(--nl-tint, var(--nl-accent)), color-mix(in srgb, var(--nl-tint, var(--nl-accent)) 70%, #000));
	color: #fff;
	box-shadow: 0 8px 20px -8px var(--nl-tint, var(--nl-accent));
}

.nl-icon-tile .nl-icon {
	width: 26px;
	height: 26px;
	stroke-width: 1.8;
}

.nl-icon-tile--lg {
	width: 64px;
	height: 64px;
	border-radius: 20px;
	margin-bottom: var(--nl-space-sm);
}

.nl-icon-tile--lg .nl-icon {
	width: 32px;
	height: 32px;
}

/* Trust strip: four little tinted cards. */
.nl-trust__list {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--nl-space-sm);
}

.nl-trust .nl-trust__item {
	display: grid;
	gap: 8px;
	justify-items: center;
	align-content: start;
	padding: var(--nl-space-lg) var(--nl-space-md);
	border-radius: 22px;
	background: var(--nl-tint-soft, var(--nl-surface-sunken));
	text-align: center;
	transition: transform var(--nl-dur-base) var(--nl-ease-out), box-shadow var(--nl-dur-base) var(--nl-ease-out);
}

.nl-trust .nl-trust__item:hover {
	transform: translateY(-3px);
	box-shadow: 0 14px 30px -18px var(--nl-tint, rgba(0, 0, 0, 0.3));
}

.nl-trust .nl-trust__label {
	margin-top: 4px;
	font-size: 1.0625rem;
	font-weight: 600;
	color: var(--nl-ink);
}

.nl-trust .nl-trust__note {
	font-size: var(--nl-size-small);
	color: var(--nl-ink-muted);
}

/* "Why shop with us": big text cards with a large tile. */
.nl-feature-card--text {
	background: linear-gradient(160deg, var(--nl-tint-soft, var(--nl-surface-sunken)) 0%, var(--nl-surface) 85%);
	border: 1px solid var(--nl-line);
	border-radius: 28px;
}

.nl-feature-card.nl-feature-card--text::before {
	display: none;
}

.nl-feature-card--text .nl-feature-card__body {
	padding: 0;
}

.nl-feature-card--text .nl-feature-card__title {
	font-size: clamp(1.25rem, 2vw, 1.5rem);
	letter-spacing: -0.01em;
}

/* Reviews: avatar, name and city in a tidy footer. */
.nl-ugc-card--text {
	padding: var(--nl-space-md);
	border-radius: 24px;
}

.nl-ugc-card--text .nl-ugc-card__quote {
	font-size: var(--nl-size-body);
	line-height: 1.55;
}

.nl-ugc-card__meta {
	align-items: center;
	flex-wrap: nowrap;
	gap: 10px;
	padding-top: var(--nl-space-sm);
	border-top: 1px solid var(--nl-line);
}

.nl-ugc-card__avatar {
	display: grid;
	flex: none;
	place-items: center;
	width: 38px;
	height: 38px;
	border-radius: 50%;
	background: linear-gradient(145deg, #0a7cff, #8b3dff);
	color: #fff;
	font-weight: 600;
	font-size: 0.95rem;
}

.nl-ugc-card__who {
	display: grid;
	line-height: 1.3;
}

.nl-ugc-card .nl-stars__fill {
	color: #f5a623;
}

@media (max-width: 767px) {
	.nl-trust__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.nl-trust .nl-trust__item {
		padding: var(--nl-space-md) var(--nl-space-sm);
	}

	.nl-icon-tile {
		width: 44px;
		height: 44px;
		border-radius: 13px;
	}
}

@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) .nl-trust .nl-trust__item {
		background: color-mix(in srgb, var(--nl-tint) 16%, var(--nl-surface));
	}
}
