/**
 * Notice Board.
 *
 * The flyer is the design. A church has usually paid a designer for that
 * artwork, so the plugin frames it and gets out of the way: no text overlaid
 * on the image, no filters, no crop that cuts someone's face off.
 *
 * Flat colour throughout, no gradients. Everything scoped under .nb so it
 * survives whatever theme it lands in.
 */

.nb {
	--nb-ink: #111111;
	--nb-primary: #0862db;
	--nb-accent: #028b2c;

	/* Derived. The brand green measures 4.44:1 on white, a hair under what
	   body text needs, so small green type uses the deepened value. */
	--nb-primary-deep: #0044bd;
	--nb-accent-deep: #007718;

	--nb-paper: #ffffff;
	--nb-wash: #f4f7fb;
	--nb-rule: #e2e8f2;
	--nb-muted: #5b6472;
	--nb-bad: #c4362b;

	--nb-aspect: 16 / 10;
	--nb-btn-radius: 9px;
	--nb-max: 72rem;
	--nb-ease: cubic-bezier(.22, 1, .36, 1);

	box-sizing: border-box;
	position: relative;

	/* Everything the board stacks — the active slide, the arrows — is given
	   a z-index. Without a stacking context of its own those indexes live in
	   the page's root, and the board paints over whatever section follows it
	   unless that section happens to set a z-index too. This confines them.  */
	isolation: isolate;

	/* And it is a block in the flow, whatever the theme does to divs. */
	display: block;
	float: none;
	clear: both;

	max-width: var(--nb-max);
	margin-inline: auto;
	scroll-margin-top: 7rem;
	font-family: inherit;
	color: var(--nb-ink);
}

/* Nothing inside is positioned against anything outside: the arrows anchor
   to the stage and the button bar to its own slide, both of which are inside
   the board. The only exception is the registration dialog, which is meant
   to cover the page. */
.nb-stage,
.nb-slide { contain: layout; }

.nb *,
.nb *::before,
.nb *::after { box-sizing: inherit; }

.nb img { max-width: 100%; height: auto; display: block; }

/* Themes style every button on the site, and a notice board's controls are
   buttons. Without resetting them here, a theme's own button rules turn the
   progress marks into large pills and the arrows into blocks. Stated
   explicitly rather than assumed. */
:where(.nb) button {
	box-sizing: border-box;
	width: auto;
	min-width: 0;
	min-height: 0;
	max-width: none;
	height: auto;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	box-shadow: none;
	font-family: inherit;
	font-size: 100%;
	font-weight: inherit;
	letter-spacing: normal;
	line-height: normal;
	text-transform: none;
	text-shadow: none;
	color: inherit;
	-webkit-appearance: none;
	appearance: none;
}

:where(.nb) button::before,
:where(.nb) button::after { content: none; }

/* ---- Stage ----
   Slides share one grid cell rather than being absolutely positioned. That
   single change is what stops the buttons overlapping the artwork: a slide
   now has a real height, so anything after the flyer flows beneath it
   instead of being laid on top of it. It also means a flyer with buttons and
   one without can sit in the same board without either being clipped. */

.nb-stage {
	position: relative;
	border-radius: 14px;
	background: var(--nb-wash);

	/* So the arrows can be placed against the flyer's height rather than the
	   whole stage. */
	container-type: inline-size;
}

.nb-track {
	display: grid;
	width: 100%;
	border-radius: 14px;
	overflow: hidden;
}

.nb-slide {
	/* Every slide occupies the same cell, so the track is as tall as the
	   tallest and nothing is ever cut off. */
	grid-area: 1 / 1;
	position: relative;
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.nb-flyer {
	position: relative;
	width: 100%;
	overflow: hidden;
}

.nb--solo .nb-flyer { background: transparent; }

/* In normal flow, so the flyer is exactly as tall as the artwork and the
   board is exactly as tall as its contents. Forcing a ratio meant guessing
   the shape of a file the church had already made — which produced black
   bands above and below it, and a board whose height had nothing to do with
   what was in it. That mismatch is where the section below started riding
   over the buttons. */
.nb-image {
	position: relative;
	display: block;
	width: 100%;
	height: auto;

	object-fit: contain;
	object-position: center;
}

/* Every slide shares one grid cell, so a shorter flyer is centred against
   the tallest rather than pinned to the top. */
.nb-slide { align-content: start; }

/* One flyer or ten, the sizing is now identical: the artwork decides. */

/* ==========================================================================
   Carousel transitions. Each is flat and short. A notice board should read
   as a poster wall, not a slideshow: nothing spins, nothing bounces.
   ========================================================================== */

.nb-slide {
	opacity: 0;
	visibility: hidden;
	transition:
		opacity var(--nb-speed, .6s) var(--nb-ease),
		transform var(--nb-speed, .6s) var(--nb-ease),
		visibility 0s linear var(--nb-speed, .6s);
}

.nb-slide.is-on {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition-delay: 0s;
	z-index: 2;
}

/* Slide sideways */
.nb-fx--slide .nb-slide { transform: translateX(100%); }
.nb-fx--slide .nb-slide.is-before { transform: translateX(-100%); }

/* Slide upward */
.nb-fx--slide-up .nb-slide { transform: translateY(100%); }
.nb-fx--slide-up .nb-slide.is-before { transform: translateY(-100%); }

/* Fade */
.nb-fx--fade .nb-slide { transform: none; }

/* Stack: the incoming flyer sits down on top of the one leaving */
.nb-fx--stack .nb-slide { transform: scale(1.04); }
.nb-fx--stack .nb-slide.is-before { transform: scale(.96); opacity: 0; }

/* Cut */
.nb-fx--none .nb-slide { transition: none; transform: none; }

/* ==========================================================================
   A single flyer. With nothing to scroll between, the board asks for
   attention once rather than repeating a transition forever.
   ========================================================================== */

.nb--solo .nb-stage { position: relative; }

/* Pulse: a ring breathes outward from the edge. The flyer itself never
   moves, which is far less distracting than artwork that grows and shrinks
   behind text somebody is trying to read. */
.nb-solo--pulse .nb-stage::after {
	content: "";
	position: absolute;
	inset: -3px;
	border: 3px solid var(--nb-primary);
	border-radius: 16px;
	opacity: 0;
	pointer-events: none;
	animation: nbPulse 3s var(--nb-ease) infinite;
}

@keyframes nbPulse {
	0% { opacity: .85; transform: scale(1); }
	60% { opacity: 0; transform: scale(1.035); }
	100% { opacity: 0; transform: scale(1.035); }
}

/* Glow: the border brightens and settles */
.nb-solo--glow .nb-stage {
	box-shadow: 0 0 0 0 rgba(8, 98, 219, 0);
	animation: nbGlow 3.6s var(--nb-ease) infinite;
}

@keyframes nbGlow {
	0%, 100% { box-shadow: 0 0 0 0 rgba(8, 98, 219, 0); }
	50% { box-shadow: 0 0 0 6px rgba(8, 98, 219, .22); }
}

/* Float: the flyer lifts and lowers slowly */
.nb-solo--float .nb-stage {
	animation: nbFloat 5s ease-in-out infinite;
}

@keyframes nbFloat {
	0%, 100% { transform: translateY(0); }
	50% { transform: translateY(-8px); }
}

/* ---- Arrows ----
   On the artwork and almost invisible until wanted. A carousel that shouts
   about being a carousel takes attention away from the thing it is showing.
   They fade up on hover, and stay faintly visible on touch, where there is
   no hover to reveal them. */

.nb-arrow {
	position: absolute;

	/* Halfway down the flyer, not halfway down the stage. The stage also
	   holds the buttons, and on a narrow screen those stack full width and
	   grow tall — which dragged the arrows down onto them. The flyer's
	   height is its width divided by its ratio, so this puts them on the
	   artwork at every screen size.
	   The plain 50% first, for anything that cannot do container queries. */
	top: 50%;
	top: calc(100cqw / var(--nb-aspect-n, 1.6) / 2);
	z-index: 4;
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(17, 17, 17, .32);
	color: #fff;
	cursor: pointer;
	opacity: 0;
	transform: translateY(-50%);
	transition: opacity .22s, background-color .22s;
}

.nb:hover .nb-arrow,
.nb:focus-within .nb-arrow { opacity: .55; }

.nb .nb-arrow:hover { opacity: 1; background: rgba(17, 17, 17, .72); }

.nb-arrow:focus-visible {
	opacity: 1;
	background: var(--nb-ink);
	outline: 2px solid #fff;
	outline-offset: -4px;
}

.nb-arrow svg { width: 1.05rem; height: 1.05rem; }
.nb-arrow--prev { left: .6rem; }
.nb-arrow--next { right: .6rem; }

/* No hover on a touch screen, so they sit at a low opacity permanently. */
@media (hover: none) {
	.nb-arrow { opacity: .45; }
	.nb-arrow--prev { left: .4rem; }
	.nb-arrow--next { right: .4rem; }
}

/* ---- Dots ----
   Thin rules, not balls. When they are on at all they are a quiet progress
   indicator, not the loudest thing under the artwork. */

.nb-dots {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: .3rem;
	margin-top: .6rem;
}

.nb-dot {
	position: relative;
	width: 1.5rem;
	height: 2px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: var(--nb-rule);
	cursor: pointer;
	overflow: hidden;
	transition: background-color .2s;
}

.nb-dot:hover { background: #c3ccdb; }
.nb-dot:focus-visible { outline: 2px solid var(--nb-primary); outline-offset: 4px; }

.nb-dot-fill {
	position: absolute;
	inset: 0;
	width: 0;
	background: var(--nb-ink);
	border-radius: 999px;
}

.nb-dot.is-on .nb-dot-fill { width: 100%; }
.nb-dot.is-counting .nb-dot-fill { width: 100%; transition: width linear var(--nb-count, 6s); }
.nb-dot.is-counting.is-reset .nb-dot-fill { width: 0; transition: none; }

/* ---- Buttons ---- */

.nb-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .5rem;
	padding: .75rem 0 0;
}

/* The only arrangement there is. The flyer is in normal flow and the buttons
   follow it, so no screen size and no setting can put one on top of the
   other, or let the section below ride over either. The option to float the
   bar over the artwork has been removed: it caused every overlap this plugin
   has had, and it was never worth what it cost. */
.nb-actions,
.nb-place--below .nb-actions {
	position: static;
	padding: .7rem 0 0;
	border-top: 0;
	background: transparent;
}

.nb-actions--left { justify-content: flex-start; }
.nb-actions--center { justify-content: center; }
.nb-actions--right { justify-content: flex-end; }
.nb-actions--between { justify-content: space-between; }

.nb-actions--w-equal .nb-btn { flex: 1 1 0; }
.nb-actions--w-full { flex-direction: column; align-items: stretch; }
.nb-actions--w-full .nb-btn { width: 100%; }

.nb-btn {
	--nb-btn: var(--nb-primary);
	--nb-btn-text: #ffffff;
	--nb-btn-hover: var(--nb-primary-deep);

	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: .6rem 1.1rem;
	border: 2px solid var(--nb-btn);
	border-radius: var(--nb-btn-radius);
	background: var(--nb-btn);
	font-size: .875rem;
	font-weight: 700;
	line-height: 1.3;
	color: var(--nb-btn-text);
	text-decoration: none;
	cursor: pointer;
	transition: background-color .18s, border-color .18s, color .18s, transform .16s var(--nb-ease);
}

.nb-btn:hover {
	background: var(--nb-btn-hover);
	border-color: var(--nb-btn-hover);
	color: var(--nb-btn-text);
	transform: translateY(-1px);
}

.nb-btn:active { transform: translateY(0); }
.nb-btn:focus-visible { outline: 3px solid var(--nb-accent); outline-offset: 3px; }

.nb-btn--s { padding: .45rem .85rem; font-size: .8125rem; }
.nb-btn--m { padding: .6rem 1.1rem; font-size: .875rem; }
.nb-btn--l { padding: .8rem 1.45rem; font-size: 1rem; }

.nb-btn--outline { background: transparent; color: var(--nb-btn); }
.nb-btn--outline:hover { background: var(--nb-btn); color: var(--nb-btn-text); border-color: var(--nb-btn); }

.nb-btn.is-off {
	background: var(--nb-rule);
	border-color: var(--nb-rule);
	color: var(--nb-muted);
	cursor: not-allowed;
}

.nb-btn.is-off:hover { transform: none; background: var(--nb-rule); border-color: var(--nb-rule); color: var(--nb-muted); }

.nb-left { font-size: .75rem; font-weight: 700; color: var(--nb-accent-deep); }

/* ---- Modal ---- */

.nb-modal {
	position: fixed;
	inset: 0;
	z-index: 99999;
	display: grid;
	place-items: center;
	padding: 1.25rem;
}

.nb-modal[hidden] { display: none; }

.nb-modal-veil {
	position: absolute;
	inset: 0;
	background: rgba(17, 17, 17, .62);
	animation: nbVeil .25s ease both;
}

@keyframes nbVeil { from { opacity: 0; } to { opacity: 1; } }

.nb-modal-card {
	position: relative;
	width: 100%;
	max-width: 27rem;
	max-height: 90vh;
	overflow-y: auto;
	padding: 1.75rem;
	background: var(--nb-paper);
	border-radius: 16px;
	animation: nbCard .32s var(--nb-ease) both;
}

@keyframes nbCard {
	from { opacity: 0; transform: translateY(14px) scale(.98); }
	to { opacity: 1; transform: none; }
}

.nb-modal-x {
	position: absolute;
	top: .75rem;
	right: .75rem;
	width: 2rem;
	height: 2rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--nb-wash);
	font-size: 1.4rem;
	line-height: 1;
	color: var(--nb-muted);
	cursor: pointer;
	transition: background-color .18s, color .18s;
}

.nb-modal-x:hover { background: var(--nb-ink); color: #fff; }
.nb-modal-x:focus-visible { outline: 2px solid var(--nb-primary); outline-offset: 2px; }

.nb-modal-title {
	margin: 0 2rem .4rem 0;
	padding: 0;
	font-size: 1.35rem;
	font-weight: 700;
	letter-spacing: -.02em;
	line-height: 1.25;
	color: var(--nb-ink);
}

.nb-modal-blurb {
	margin: 0 0 1.2rem;
	font-size: .9375rem;
	color: var(--nb-muted);
}

.nb-field { margin-top: 1.1rem; }

.nb-label {
	display: block;
	margin: 0 0 .45rem;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--nb-muted);
}

.nb-input {
	display: block;
	width: 100%;
	height: auto;
	padding: .7rem .85rem;
	border: 1.5px solid var(--nb-rule);
	border-radius: 9px;
	background: var(--nb-paper);
	box-shadow: none;
	font-family: inherit;
	font-size: 1rem;
	line-height: 1.4;
	color: var(--nb-ink);
	transition: border-color .2s, box-shadow .22s;
}

.nb-input:focus {
	outline: 0;
	border-color: var(--nb-primary);
	box-shadow: 0 0 0 4px rgba(8, 98, 219, .13);
}

.nb-input--short { max-width: 6rem; }
.nb textarea.nb-input { resize: vertical; }

/* Off-screen rather than display:none, because some bots skip hidden fields
   and this one only works if they fill it. */
.nb-trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.nb-error {
	margin: 1.1rem 0 0;
	padding: .7rem .85rem;
	border-left: 3px solid var(--nb-bad);
	border-radius: 0 8px 8px 0;
	background: #f7dedb;
	font-size: .9375rem;
	color: var(--nb-bad);
}

.nb-submit {
	width: 100%;
	margin-top: 1.4rem;
	padding: .9rem 1.25rem;
	font-size: 1rem;
}

.nb-done { text-align: center; padding: 1rem 0 .5rem; }

.nb-seal {
	display: grid;
	place-items: center;
	width: 3.25rem;
	height: 3.25rem;
	margin: 0 auto 1.1rem;
	border-radius: 50%;
	background: var(--nb-accent-deep);
	animation: nbSeal .55s var(--nb-ease) both;
}

.nb-seal svg { width: 1.5rem; height: 1.5rem; }

@keyframes nbSeal {
	0% { opacity: 0; transform: scale(.4) rotate(-20deg); }
	60% { transform: scale(1.08) rotate(3deg); }
	100% { opacity: 1; transform: none; }
}

.nb-done h2 {
	margin: 0 0 .5rem;
	padding: 0;
	font-size: 1.35rem;
	font-weight: 700;
	letter-spacing: -.02em;
	color: var(--nb-ink);
}

.nb-done p { margin: 0; font-size: .9375rem; color: var(--nb-muted); }

.nb-setup {
	max-width: 40rem;
	margin-inline: auto;
	padding: .9rem 1.1rem;
	border-left: 3px solid #0862db;
	background: #eef4fe;
	font-size: .9375rem;
	color: #111111;
}

/* ---- Responsive ---- */

/* The track takes its height from its tallest slide. It used to be given an
   aspect ratio of its own, left over from when slides were absolutely
   positioned, and that fought the grid on narrow screens. */

/* ---- Narrow screens ----
   Below this width the buttons always sit under the artwork, whatever the
   setting says. A bar across the bottom of a flyer leaves too little of it
   visible on a phone, and it is the arrangement every overlap so far has
   come from. There is no setting that can put them back on top here. */

@media (max-width: 48rem) {
	.nb .nb-actions {
		position: static;
		max-height: none;
		overflow: visible;
		padding: .65rem 0 0;
		border-top: 0;
		background: transparent;
	}
}

@media (max-width: 34rem) {
	.nb-arrow { width: 2rem; height: 2rem; }
	.nb-arrow--prev { left: .45rem; }
	.nb-arrow--next { right: .45rem; }
	.nb-arrow svg { width: .95rem; height: .95rem; }

	.nb .nb-actions { flex-direction: column; align-items: stretch; }
	.nb .nb-btn { width: 100%; }
	.nb-modal-card { padding: 1.35rem 1.15rem; }
}

/* Motion is a courtesy, not a requirement. Autoplay is stopped in the
   script as well, so a board never moves under someone who asked it not to. */
@media (prefers-reduced-motion: reduce) {
	.nb *,
	.nb *::before,
	.nb *::after {
		animation: none !important;
		transition-duration: .01ms !important;
	}
}
