/**
 * NonStop Ads Manager — frontend.
 *
 * Deliberately minimal and theme-neutral. Colours and fonts inherit rather
 * than being set, so an ad unit looks like it belongs to whatever theme it
 * lands in. Everything tunable is a CSS custom property, so a publisher can
 * restyle without touching this file.
 *
 * Class names avoid "ad", "banner" and "sponsor" — blocklists match those and
 * would hide legitimately purchased advertising along with the layout that
 * reserves its space.
 */

.nsd-nam-zone {
	--nsd-nam-w: 100%;
	--nsd-nam-h: auto;
	--nsd-nam-gap: 0.35em;
	--nsd-nam-label-size: 0.6875rem;
	--nsd-nam-label-opacity: 0.6;

	display: block;
	margin: 0 auto 1.5em;
	max-width: var(--nsd-nam-w);
	text-align: center;
}

/*
 * The stack reserves the zone's height before any creative loads. Without it
 * the ad pops in and pushes the article down, which is the single most
 * complained-about behaviour of every ad plugin.
 */
.nsd-nam-stack {
	position: relative;
	display: block;
	min-height: var(--nsd-nam-h);
}

.nsd-nam-unit {
	display: block;
}

.nsd-nam-unit[hidden] {
	display: none;
}

/* Width modes ------------------------------------------------------------ */

/*
 * Fluid: whatever the container gives it. The base rule already caps at
 * --nsd-nam-w, which defaults to 100%, so this only needs to defeat a width
 * left over from a previous setting.
 */
.nsd-nam-zone-fluid {
	max-width: 100%;
}

/*
 * Edge to edge. The negative margins pull the zone out of whatever content
 * column it was dropped into.
 *
 * The scrollbar correction is not a nicety. `100vw` is the viewport INCLUDING
 * the classic scrollbar gutter, while the page's own 100% excludes it, so the
 * naive version overhangs by the scrollbar width — about 7px each side on
 * Windows — which either clips the banner or trips horizontal scroll. The
 * script measures the gutter once and writes --nsd-nam-sbw; the fallback of 0
 * is correct on every platform with overlay scrollbars, and is also what
 * applies for the moment before the script runs.
 *
 * This works only if no ancestor clips overflow. Nothing here can fix a theme
 * that does, which is why the zone screen says so rather than promising it.
 */
.nsd-nam-zone-full {
	width: calc(100vw - var(--nsd-nam-sbw, 0px));
	max-width: calc(100vw - var(--nsd-nam-sbw, 0px));
	margin-left: calc(50% - 50vw + var(--nsd-nam-sbw, 0px) / 2);
	margin-right: calc(50% - 50vw + var(--nsd-nam-sbw, 0px) / 2);
}

.nsd-nam-zone-full .nsd-nam-creative {
	width: 100%;
}

/* Fader ------------------------------------------------------------------ */

/*
 * Every unit shares one grid cell, so the stack is as tall as the tallest ad
 * and does not collapse when the visible one is transparent. Absolute
 * positioning would need an explicit height on the zone, and a zone left at
 * height 0 would render a strip of nothing with no clue why.
 */
.nsd-nam-fader {
	display: grid;
}

.nsd-nam-fader > .nsd-nam-unit {
	grid-area: 1 / 1;
	/*
	 * visibility, not just opacity: a transparent ad is still in the
	 * accessibility tree and its link is still in the tab order, so a screen
	 * reader would announce every advertiser at once and Tab would land on
	 * links nobody can see. The delayed visibility transition lets the fade
	 * finish before the unit leaves the tree.
	 */
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}

.nsd-nam-fader > .nsd-nam-unit.is-active {
	opacity: 1;
	visibility: visible;
	transition: opacity 0.6s ease, visibility 0s;
}

/*
 * The fader manages its own units, so the one-shot reveal animation used by
 * the single-ad path must not also run on them.
 */
.nsd-nam-fader > .nsd-nam-unit.is-shown {
	animation: none;
}

.nsd-nam-link {
	display: inline-block;
	max-width: 100%;
	text-decoration: none;
	color: inherit;
}

.nsd-nam-creative {
	display: block;
	max-width: 100%;
	height: auto;
	margin: 0 auto;
}

/* Disclosure label ------------------------------------------------------- */

.nsd-nam-label {
	display: block;
	margin-bottom: var(--nsd-nam-gap);
	font-size: var(--nsd-nam-label-size);
	line-height: 1.4;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	opacity: var(--nsd-nam-label-opacity);
}

/*
 * The plugin's own visually-hidden helper. Deliberately not .screen-reader-text
 * — themes are not required to define that, and relying on it means the
 * disclosure silently becomes visible on the ones that don't.
 */
.nsd-nam-sr {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Text ads --------------------------------------------------------------- */

.nsd-nam-headline {
	display: block;
	font-weight: 600;
	line-height: 1.3;
	margin-bottom: 0.25em;
}

.nsd-nam-body {
	display: block;
	font-size: 0.9375em;
	line-height: 1.5;
}

.nsd-nam-link:hover .nsd-nam-headline {
	text-decoration: underline;
}

/* House ad --------------------------------------------------------------- */

.nsd-nam-zone-empty .nsd-nam-house {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: var(--nsd-nam-h);
}

/* Featured directory listings -------------------------------------------- */

/*
 * Themes are expected to restyle these. The defaults exist so a paid featured
 * listing is visibly distinct with no theme work at all — an advertiser who
 * paid for prominence and got none has a legitimate complaint.
 */
.nsd-nam-featured-badge {
	display: inline-block;
	padding: 0.15em 0.6em;
	font-size: 0.6875rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: #fff;
	background: #2271b1;
	border-radius: 999px;
	vertical-align: middle;
}

/* Sponsored content disclosure ------------------------------------------- */

.nsd-nam-sponsored-notice {
	font-size: 0.9375em;
}

/* Motion ----------------------------------------------------------------- */

.nsd-nam-unit.is-shown {
	animation: nsd-nam-in 0.2s ease-out;
}

@keyframes nsd-nam-in {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.nsd-nam-unit.is-shown {
		animation: none;
	}

	/*
	 * The cross-fade is the part that causes trouble, not the change itself.
	 * Swapping instantly keeps every advertiser in the rotation they paid for
	 * while removing the movement. The script also honours this setting and
	 * lengthens its timer, so the banner still changes but far less often.
	 */
	.nsd-nam-fader > .nsd-nam-unit,
	.nsd-nam-fader > .nsd-nam-unit.is-active {
		transition: none;
	}
}

/* Corner ribbon ---------------------------------------------------------- */

/*
 * A diagonal flash across one corner of an ad, for a coupon code.
 */

/*
 * The frame is what the ribbon is positioned against, and it exists because
 * the unit is the wrong shape: a full-width block wrapping a centred image.
 * Anchoring to the unit put the ribbon on the corner of the empty box around
 * the ad rather than on the ad, which on a short wide banner is outside the
 * artwork entirely.
 *
 * inline-block so it shrink-wraps the creative, and overflow:hidden so the
 * ribbon is cut flush with the artwork edges instead of hanging past them.
 */
.nsd-nam-frame {
	position: relative;
	display: inline-block;
	max-width: 100%;
	overflow: hidden;
	vertical-align: top;
}

/*
 * vertical-align on the child rather than line-height:0 on the frame. Zeroing
 * the line height would close the baseline gap under an inline-block image,
 * but it also collapses the lines of a TEXT ad wrapped in the same frame.
 */
.nsd-nam-frame > .nsd-nam-link {
	vertical-align: top;
}

/*
 * The ribbon is a square clipping box pinned to one corner; the text inside is
 * a wide bar rotated through 45 degrees, and the box's overflow cuts its ends
 * off flush with the two edges. Rotating the bar alone would leave its corners
 * poking out past the artwork.
 *
 * pointer-events: none matters. The ribbon sits on top of the ad's link, and
 * without this a click landing on the coupon would hit the ribbon and go
 * nowhere — costing the advertiser the click they are paying for.
 */
.nsd-nam-ribbon {
	--nsd-nam-ribbon-size: 110px;
	--nsd-nam-ribbon-bg: #d63638;
	--nsd-nam-ribbon-fg: #ffffff;
	--nsd-nam-ribbon-font: 0.75rem;

	position: absolute;
	z-index: 2;
	width: var(--nsd-nam-ribbon-size);
	height: var(--nsd-nam-ribbon-size);
	overflow: hidden;
	pointer-events: none;
}

.nsd-nam-ribbon-text {
	position: absolute;
	display: block;
	/*
	 * The bar must OVER-span the box's diagonal, which is size × 1.414. At
	 * 1.45 the margin was three pixels, so rounding could leave the ends a
	 * hair short of the edges and the ribbon read as floating in the corner
	 * rather than cut into it. 1.7 guarantees both ends are clipped by the
	 * artwork edge at every size.
	 */
	width: calc(var(--nsd-nam-ribbon-size) * 1.7);
	padding: 0.4em 0;
	background: var(--nsd-nam-ribbon-bg);
	color: var(--nsd-nam-ribbon-fg);
	font-size: var(--nsd-nam-ribbon-font);
	font-weight: 700;
	line-height: 1.35;
	letter-spacing: 0.04em;
	text-align: center;
	text-transform: uppercase;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.28);
}

/* Sizes ------------------------------------------------------------------ */

.nsd-nam-ribbon-small {
	--nsd-nam-ribbon-size: 82px;
	--nsd-nam-ribbon-font: 0.625rem;
}

.nsd-nam-ribbon-large {
	--nsd-nam-ribbon-size: 145px;
	--nsd-nam-ribbon-font: 0.875rem;
}

/* Corners ---------------------------------------------------------------- */

/*
 * Each corner needs its own rotation direction and offsets. The 22% inset
 * places the bar far enough down the diagonal that it reads as a corner
 * ribbon rather than a clipped triangle.
 */
.nsd-nam-ribbon-tr {
	top: 0;
	right: 0;
}

.nsd-nam-ribbon-tr .nsd-nam-ribbon-text {
	top: 22%;
	right: -35%;
	transform: rotate(45deg);
}

.nsd-nam-ribbon-tl {
	top: 0;
	left: 0;
}

.nsd-nam-ribbon-tl .nsd-nam-ribbon-text {
	top: 22%;
	left: -35%;
	transform: rotate(-45deg);
}

.nsd-nam-ribbon-br {
	right: 0;
	bottom: 0;
}

.nsd-nam-ribbon-br .nsd-nam-ribbon-text {
	right: -35%;
	bottom: 22%;
	transform: rotate(-45deg);
}

.nsd-nam-ribbon-bl {
	bottom: 0;
	left: 0;
}

.nsd-nam-ribbon-bl .nsd-nam-ribbon-text {
	bottom: 22%;
	left: -35%;
	transform: rotate(45deg);
}

/*
 * On a narrow screen a fixed ribbon eats a phone banner. Step it down rather
 * than hiding it — the coupon is the point of the placement.
 */
@media (max-width: 480px) {
	.nsd-nam-ribbon {
		--nsd-nam-ribbon-size: 76px;
		--nsd-nam-ribbon-font: 0.5625rem;
	}
}

/* Scrolling logo ribbon -------------------------------------------------- */

/*
 * A strip of sponsor logos that scrolls sideways. Unlike every other rotation
 * mode, all booked campaigns are on screen at once — set the zone's Concurrent
 * campaigns to however many logos belong in the strip.
 */
.nsd-nam-marquee {
	--nsd-nam-logo-h: 40px;
	--nsd-nam-logo-gap: 64px;

	overflow: hidden;
	/*
	 * The strip runs full width, so its edges meet whatever is beside it. A
	 * mask fades logos out as they arrive and leave instead of clipping them
	 * mid-letter. -webkit- included: Safari has not unprefixed mask-image.
	 */
	-webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
	mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}

.nsd-nam-marquee-track {
	display: flex;
	align-items: center;
	gap: var(--nsd-nam-logo-gap);
	/*
	 * max-content so the track is as wide as its contents rather than the
	 * container — without it every logo would be squeezed into one screen and
	 * there would be nothing to scroll.
	 */
	width: max-content;
	will-change: transform;
}

/*
 * The animation is added by the script, not here, because its duration depends
 * on how wide the assembled strip turns out to be. A fixed duration would make
 * a strip of twelve logos scroll twice as fast as a strip of six.
 */
@keyframes nsd-nam-marquee {
	from {
		transform: translateX(0);
	}

	to {
		/*
		 * Exactly half: the script duplicates the set of logos once, so
		 * travelling one set-width lands on an identical frame and the restart
		 * is invisible.
		 */
		transform: translateX(-50%);
	}
}

.nsd-nam-marquee .nsd-nam-unit {
	flex: 0 0 auto;
	display: block;
}

/* A marquee shows every unit; nothing is hidden waiting to be chosen. */
.nsd-nam-marquee .nsd-nam-unit[hidden] {
	display: block;
}

.nsd-nam-marquee .nsd-nam-creative {
	height: var(--nsd-nam-logo-h);
	width: auto;
	max-width: none;
}

/*
 * Pause on hover and on keyboard focus. Not decoration: a moving target is
 * hard to click, and for someone with a motor impairment it can be impossible.
 * focus-within covers tabbing to a logo's link.
 */
.nsd-nam-marquee-pause:hover .nsd-nam-marquee-track,
.nsd-nam-marquee-pause:focus-within .nsd-nam-marquee-track {
	animation-play-state: paused;
}

/* Logo treatments -------------------------------------------------------- */

/*
 * A row of logos in a dozen brand colours reads as noise, so flattening them
 * to one tone is the convention. Colour returns on hover, which also gives a
 * useful hint that the logo is a link.
 */
.nsd-nam-marquee-grey .nsd-nam-creative {
	filter: grayscale(1);
	opacity: 0.75;
	transition: filter 0.2s ease, opacity 0.2s ease;
}

.nsd-nam-marquee-white .nsd-nam-creative {
	filter: brightness(0) invert(1);
	opacity: 0.85;
	transition: filter 0.2s ease, opacity 0.2s ease;
}

.nsd-nam-marquee-black .nsd-nam-creative {
	filter: brightness(0);
	opacity: 0.75;
	transition: filter 0.2s ease, opacity 0.2s ease;
}

.nsd-nam-marquee-grey .nsd-nam-unit:hover .nsd-nam-creative,
.nsd-nam-marquee-white .nsd-nam-unit:hover .nsd-nam-creative,
.nsd-nam-marquee-black .nsd-nam-unit:hover .nsd-nam-creative {
	filter: none;
	opacity: 1;
}

/*
 * Reduced motion stops the scroll rather than hiding the strip: the sponsors
 * were paid for and must still be visible. The row becomes a normal
 * horizontally scrollable list the reader moves themselves.
 */
@media (prefers-reduced-motion: reduce) {
	.nsd-nam-marquee-track {
		animation: none !important;
		transform: none !important;
	}

	.nsd-nam-marquee {
		overflow-x: auto;
		-webkit-mask-image: none;
		mask-image: none;
	}
}
