/*
 * Global stylesheet. Loads on every page.
 *
 * Anything used by more than one page lives here: tokens, layout, header,
 * footer, hero, buttons, forms, cards. Page-only styling lives in
 * assets/css/pages/<slug>.css and is enqueued conditionally in functions.php.
 *
 * Palette is taken from the logo: SJC brand blue, deep ocean navy for text,
 * pale sand neutrals for surfaces. Brand blue is the only accent on the page.
 *
 * Shape rule: buttons are full pill, surfaces are 24px, small media is 12px.
 */
:root {
	--ink: #0b3a5c;
	--muted: #4a6a80;
	--line: #dfe6ec;
	--bg: #fff;
	--sand: #f6f3ee;
	--tint: #d1e4ee;
	--accent: #0071b0;
	--accent-dark: #005a8d;
	--radius: 24px;
	--radius-sm: 12px;
	--container: 1180px;
	--step: 1.5rem;

	/*
	 * Header sizing. The bar condenses once the page scrolls past the sentinel;
	 * .site-header.is-condensed reassigns --nav-h / --logo-h and the properties
	 * that read them transition. Kept on :root so the hero can reserve the
	 * resting height without re-laying out as the bar shrinks.
	 */
	--nav-h: 80px;
	--nav-h-condensed: 58px;
	--logo-h: 56px;
	--logo-h-condensed: 38px;
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--display: "Outfit", system-ui, sans-serif;
	--nav: "Orienta", system-ui, sans-serif;
	--fun: "Bungee", var(--display);
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

/*
 * In-page anchors glide rather than teleport, so the reader keeps their place
 * when a link sends them elsewhere on the same page. Honoured natively by the
 * browser, which is why no click handler is needed — and skipped for anyone
 * who has asked the OS for less motion, since a long scroll is exactly the
 * kind of movement that setting exists to suppress.
 */
@media (prefers-reduced-motion: no-preference) {
	html {
		scroll-behavior: smooth;
	}
}

/*
 * A few decorative elements (the wave dividers, the chat button's pulse ring,
 * carousel arrows sitting at -12px) deliberately paint past their own box.
 * That ink overflow counts toward the page's scrollable width even while
 * invisible, so it can add a sliver of horizontal scroll on narrow viewports.
 * Clipping it here is cheaper and more robust than chasing each offender.
 */
body {
	margin: 0;
	overflow-x: clip;
	background: var(--bg);
	color: var(--ink);
	font-family: var(--display);
	line-height: 1.6;
}

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

a {
	color: var(--accent);
}

.container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--step);
}

.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.skip-link:focus {
	position: fixed;
	top: 1rem;
	left: 1rem;
	width: auto;
	height: auto;
	clip-path: none;
	padding: 0.5rem 1rem;
	background: var(--bg);
	z-index: 100;
}

/* Header */

/*
 * Two states, one element.
 *
 * At rest the bar is tall and carries no panel of its own: only a top-down
 * white scrim (::before) so the nav stays legible where it floats over the
 * hero photograph. Once scrolled it condenses into a shorter frosted panel
 * with a real edge, and the scrim fades out.
 *
 * The state flip is driven by .is-condensed, set from an IntersectionObserver
 * on .header-sentinel in main.js. No scroll listener is involved.
 */

.header-sentinel {
	position: absolute;
	top: 0;
	left: 0;
	width: 1px;
	height: 48px;
	pointer-events: none;
}

.site-header {
	position: sticky;
	top: 0;
	z-index: 50;
	background-color: rgb(255 255 255 / 0%);
	-webkit-backdrop-filter: blur(6px) saturate(120%);
	backdrop-filter: blur(6px) saturate(120%);
	border-bottom: 1px solid rgb(11 58 92 / 0%);
	border-radius: 0;
	transition:
		background-color 0.4s var(--ease-out),
		backdrop-filter 0.4s var(--ease-out),
		-webkit-backdrop-filter 0.4s var(--ease-out),
		border-color 0.4s var(--ease-out),
		border-radius 0.4s var(--ease-out),
		box-shadow 0.4s var(--ease-out);
}

/*
 * The scrim is a child, so it paints over the blurred backdrop but under the
 * logo and nav. Fading its opacity is the only way to cross-dissolve into the
 * flat condensed fill: background-image itself is not animatable.
 */
.site-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;

	/*
	 * Held near-opaque through the band the logo and links occupy, then
	 * dissolved over the last stretch so the bar has no edge at rest. The nav
	 * is right-aligned, where the hero's own left-to-right overlay has already
	 * faded out, so this scrim is the only thing keeping --muted legible over
	 * the photograph.
	 */
	background: linear-gradient(
		180deg,
		rgb(255 255 255 / 92%) 0%,
		rgb(255 255 255 / 82%) 62%,
		rgb(255 255 255 / 30%) 100%
	);
	pointer-events: none;
	transition: opacity 0.4s var(--ease-out);
}

.site-header.is-condensed {
	--nav-h: var(--nav-h-condensed);
	--logo-h: var(--logo-h-condensed);

	background-color: rgb(255 255 255 / 72%);
	-webkit-backdrop-filter: blur(20px) saturate(180%);
	backdrop-filter: blur(20px) saturate(180%);
	border-bottom-color: rgb(11 58 92 / 8%);
	border-bottom-left-radius: var(--radius);
	border-bottom-right-radius: var(--radius);

	/* Inner highlight above the hairline reads as the lit edge of the glass. */
	box-shadow:
		inset 0 -1px 0 rgb(255 255 255 / 70%),
		0 8px 32px rgb(11 58 92 / 10%);
}

.site-header.is-condensed::before {
	opacity: 0;
}

/* Front page: header floats over the hero instead of pushing it down. */
.home .site-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--step);
	min-height: var(--nav-h);
	transition: min-height 0.4s var(--ease-out);
}

.site-brand__logo {
	display: block;
	line-height: 0;
}

.site-brand__logo img,
.site-brand .custom-logo {
	height: var(--logo-h);
	width: auto;
	transition: height 0.4s var(--ease-out);
}

.site-brand__title {
	font-weight: 650;
	font-size: 1.15rem;
	text-decoration: none;
	color: var(--ink);
}

.site-nav__list {
	display: flex;
	align-items: center;
	gap: 1.75rem;
	margin: 0;
	padding: 0;
	list-style: none;
	font-family: var(--nav);
}

.site-nav__list a {
	position: relative;
	text-decoration: none;
	color: var(--muted);
	font-size: 1rem;
	letter-spacing: 0.01em;
	transition: color 0.2s ease;
}

.site-nav__list a:hover,
.site-nav__list a:focus-visible,
.site-nav__list .current-menu-item > a {
	color: var(--ink);
}

/* Donate is the one link in the nav meant to get chosen, not just followed. */
.site-nav__list a[href*="/donate"] {
	font-weight: 700;
}

/*
 * Hover and current page share one indicator, so the nav always shows where
 * you are and previews where you would land. scaleX keeps it off the layout.
 */
.site-nav__list a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.4rem;
	height: 2px;
	border-radius: 2px;
	background: var(--accent);
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.3s var(--ease-out);
}

.site-nav__list a:hover::after,
.site-nav__list a:focus-visible::after,
.site-nav__list .current-menu-item > a::after {
	transform: scaleX(1);
}

.site-header a:focus-visible,
.nav-toggle:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 4px;
	border-radius: 4px;
}

/*
 * Dropdown: desktop shows it on hover/focus-within, positioned under the
 * parent item. Sponsorships > Kiddush / Dedication / Sustainers Circle today.
 */
.site-nav__list .menu-item-has-children {
	position: relative;
}

.site-nav__list .sub-menu {
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translate(-50%, 6px);
	z-index: 10;
	min-width: 12rem;
	margin: 0;
	padding: 0.5rem;
	list-style: none;
	border-radius: var(--radius-sm);
	background: var(--bg);
	box-shadow: 0 16px 40px rgb(11 20 32 / 18%);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.18s ease, transform 0.18s var(--ease-out), visibility 0.18s;
}

.site-nav__list .menu-item-has-children:hover > .sub-menu,
.site-nav__list .menu-item-has-children:focus-within > .sub-menu {
	opacity: 1;
	visibility: visible;
	transform: translate(-50%, 0);
}

.site-nav__list .sub-menu li {
	list-style: none;
}

.site-nav__list .sub-menu li + li {
	margin-top: 0.15rem;
}

.site-nav__list .sub-menu a {
	display: block;
	padding: 0.5rem 0.85rem;
	border-radius: 8px;
	color: var(--ink);
	font-size: 0.95rem;
	white-space: nowrap;
}

.site-nav__list .sub-menu a:hover,
.site-nav__list .sub-menu a:focus-visible {
	background: var(--tint);
}

.site-nav__list .sub-menu a::after {
	display: none;
}

/* Hamburger. Hidden on desktop, where the nav sits inline. */

.nav-toggle {
	display: none;
	position: relative;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	border-radius: var(--radius-sm);
	background: none;
	color: var(--ink);
	cursor: pointer;
}

.nav-toggle:hover {
	background: rgb(11 58 92 / 6%);
}

.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
	position: absolute;
	left: 50%;
	width: 22px;
	height: 2px;
	border-radius: 2px;
	background: currentcolor;
	transition: transform 0.25s ease, opacity 0.15s ease;
}

.nav-toggle__bars {
	top: 50%;
	transform: translate(-50%, -50%);
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
	content: "";
	left: 0;
}

.nav-toggle__bars::before {
	transform: translateY(-7px);
}

.nav-toggle__bars::after {
	transform: translateY(7px);
}

/* Open: bars collapse into an X. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bars {
	background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before {
	transform: rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after {
	transform: rotate(-45deg);
}

/*
 * The condensed state still applies under reduced motion; it just snaps
 * instead of easing. Losing the shrink entirely would lose the wayfinding.
 */
@media (prefers-reduced-motion: reduce) {
	.site-header,
	.site-header::before,
	.site-header__inner,
	.site-brand__logo img,
	.site-brand .custom-logo,
	.site-nav__list a,
	.site-nav__list a::after,
	.site-nav__list .sub-menu,
	.nav-toggle__bars,
	.nav-toggle__bars::before,
	.nav-toggle__bars::after {
		transition: none;
	}
}

/* Without blur the bar must carry its own opaque fill to stay readable. */
@media (prefers-reduced-transparency: reduce) {
	.site-header,
	.site-header.is-condensed,
	.site-nav {
		background-color: var(--bg);
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
	}

	.site-header::before {
		display: none;
	}
}

/*
 * Narrow: the nine top-level items plus the logo need ~1140px on one line, so
 * below that the nav drops into a panel under the header bar and the
 * hamburger opens it. Add a top-level item and this number has to grow.
 */
@media (max-width: 1140px) {
	/* 80px of chrome is too much of a phone viewport to spend on the bar. */
	:root {
		--nav-h: 68px;
		--nav-h-condensed: 54px;
		--logo-h: 44px;
		--logo-h-condensed: 34px;
	}

	.nav-toggle {
		display: block;
	}

	.site-nav {
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		display: none;
		padding: 0.5rem var(--step) 1.5rem;
		background: rgb(255 255 255 / 92%);
		-webkit-backdrop-filter: blur(20px) saturate(180%);
		backdrop-filter: blur(20px) saturate(180%);
		border-bottom-left-radius: var(--radius);
		border-bottom-right-radius: var(--radius);
		box-shadow: 0 12px 24px rgb(11 58 92 / 10%);
	}

	.site-nav.is-open {
		display: block;
	}

	.site-nav__list {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
	}

	.site-nav__list li + li {
		border-top: 1px solid var(--line);
	}

	.site-nav__list a {
		display: block;
		padding-block: 0.9rem;
		font-size: 1.1rem;
	}

	/* The sliding underline belongs to the inline nav, not the stacked panel. */
	.site-nav__list a::after {
		display: none;
	}

	/* Submenu becomes a static, always-open indent instead of a hover flyout. */
	.site-nav__list .sub-menu {
		position: static;
		opacity: 1;
		visibility: visible;
		transform: none;
		box-shadow: none;
		padding: 0 0 0 1rem;
		transition: none;
	}

	.site-nav__list .sub-menu a {
		padding-block: 0.7rem;
		color: var(--muted);
	}
}

/* Hero */

.hero {
	position: relative;
	isolation: isolate;
	display: flex;
	align-items: center;
	min-height: 58svh;
	padding-block: 4rem;
	overflow: hidden;
}

/*
 * Only the front page hero sits under the fixed header, so it reserves the
 * bar's resting height. This reads --nav-h from :root, not from the header's
 * condensed override, so the hero never reflows as the bar shrinks.
 */
.home .hero--tall {
	padding-top: calc(9rem + var(--nav-h));
}

.hero__bg {
	position: absolute;
	inset: 0;
	z-index: -2;
	background-position: center;
	background-size: cover;
}

/*
 * The frond artwork carries its detail on the left and its clean glow on the
 * right, so it is mirrored on the pages that use it: fronds become a
 * right-hand flourish and the light falls behind the headline. The homepage
 * beach photo is a real photograph and stays unmirrored.
 */
.hero:not(.hero--tall) .hero__bg {
	transform: scaleX(-1);
}

/*
 * Artwork is already pale, so this is a light lift for the text column, not a
 * full overlay. Navy on the palest fronds still clears WCAG AA.
 */
.hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(
		100deg,
		rgb(255 255 255 / 72%) 0%,
		rgb(255 255 255 / 45%) 38%,
		rgb(255 255 255 / 0%) 70%
	);
}

.hero__text {
	max-width: 52ch;
}

.hero__heading {
	margin: 0;
	font-size: clamp(2.75rem, 5.6vw, 4.75rem);
	font-weight: 600;
	line-height: 1.08;
	letter-spacing: -0.025em;
	text-wrap: balance;
}

.hero__subheading {
	margin: 1.25rem 0 0;
	max-width: 56ch;
	color: var(--muted);
	font-size: clamp(1.2rem, 1.8vw, 1.5rem);
	line-height: 1.5;
}

.hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin-top: 2rem;
}

/* Entrance: settles the message in once, so the eye lands on the headline
   before the CTAs. Disabled entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
	.hero__heading,
	.hero__subheading,
	.hero__actions {
		animation: sjc-rise 0.8s cubic-bezier(0.16, 1, 0.3, 1) backwards;
	}

	.hero__subheading {
		animation-delay: 0.1s;
	}

	.hero__actions {
		animation-delay: 0.2s;
	}
}

@keyframes sjc-rise {
	from {
		opacity: 0;
		transform: translateY(14px);
	}
}

@media (max-width: 720px) {
	.hero__text {
		max-width: none;
	}

	.hero::before {
		background: linear-gradient(
			180deg,
			rgb(255 255 255 / 78%) 0%,
			rgb(255 255 255 / 60%) 60%,
			rgb(255 255 255 / 25%) 100%
		);
	}
}

/* Buttons */

.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0.85rem 1.75rem;
	border: 1px solid var(--accent);
	border-radius: 999px;
	background: var(--accent);
	color: #fff;
	font-weight: 500;
	font-size: 1rem;
	white-space: nowrap;
	text-decoration: none;
	transition: background 0.25s cubic-bezier(0.16, 1, 0.3, 1),
		transform 0.15s ease;
	cursor: pointer;
}

.button:hover {
	background: var(--accent-dark);
	border-color: var(--accent-dark);
}

.button:active {
	transform: translateY(1px);
}

.button--ghost {
	background: rgb(255 255 255 / 80%);
	border-color: var(--ink);
	color: var(--ink);
}

.button--ghost:hover {
	background: var(--ink);
	border-color: var(--ink);
	color: #fff;
}

/*
 * Tinted page wash: brand blue with the frond artwork fixed behind the content
 * at 20%. Add .page--wash to any page that wants it.
 */
.page--wash {
	position: relative;
	isolation: isolate;
	background: var(--tint);
}

.page--wash::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: url("../images/hero.jpg");
	background-position: center;
	background-size: cover;
	background-attachment: fixed;
	opacity: 0.2;
}

/* Page intro. Centred title + lead, used by any page that skips the hero. */

.intro {
	padding-block: clamp(4rem, 8vw, 7rem);
	text-align: center;
}

.intro__title {
	margin: 0;
	font-size: clamp(2.25rem, 5vw, 3.5rem);
	font-weight: 600;
	line-height: 1.05;
	letter-spacing: -0.025em;
}

.intro__lead {
	margin: 1.5rem auto 0;
	max-width: 60ch;
	font-size: clamp(1.1rem, 1.6vw, 1.3rem);
	line-height: 1.55;
	text-wrap: pretty;
}

.intro__note {
	margin: 1.25rem auto 0;
	max-width: 50ch;
	color: var(--muted);
	font-size: 1.05rem;
}

/* Mission statement. The homepage and the About page both print it
   (template-parts/home/mission.php), so it lives here. */

.mission {
	padding-block: clamp(4rem, 9vw, 7rem);
	background: var(--bg);
}

.mission__inner {
	max-width: 90ch;
	text-align: center;
}

.mission__eyebrow {
	margin: 0;
	color: var(--accent);
	font-size: 0.95rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.mission__lead {
	margin: 1.25rem 0 0;
	font-size: clamp(1.5rem, 3vw, 2.15rem);
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.mission__body {
	margin: 1.5rem 0 0;
	color: var(--muted);
	font-size: clamp(1.05rem, 1.5vw, 1.2rem);
	line-height: 1.7;
}

/* Responsive 16:9 shell for an embed. Used by the homepage ChillZone section
   and the ChillZone page, so it lives here rather than in either's stylesheet. */

.video {
	position: relative;
	aspect-ratio: 16 / 9;
	border-radius: var(--radius);
	overflow: hidden;
	box-shadow: 0 18px 40px rgb(0 0 0 / 30%);
}

.video__frame {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

/* Content */

.page__content,
.post__content {
	padding-block: 3rem;
	max-width: 72ch;
}

.page__content--centered {
	margin-inline: auto;
	text-align: center;
}

.page__content--full {
	max-width: none;
}

.post__header {
	padding-top: 3rem;
}

.post__title {
	margin: 0;
	font-size: clamp(1.75rem, 4vw, 2.5rem);
	line-height: 1.15;
}

.post__meta {
	color: var(--muted);
	font-size: 0.9rem;
}

/* Event post page details header (sjc_event_show_details_header()). */

.event-header__type {
	display: inline-block;
	margin-bottom: 0.6rem;
	padding: 0.2rem 0.6rem;
	border-radius: 999px;
	background: var(--sand);
	color: var(--accent);
	font-size: 0.72rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
}

.event-header__title {
	margin-bottom: 0.4rem;
}

.event-header__subtitle {
	margin: 0 0 0.75rem;
	max-width: 60ch;
	color: var(--muted);
	font-size: 1.05rem;
	line-height: 1.5;
}

/* Status reads as a banner, not a chip — on a page someone landed on to find
   out whether the thing is happening, it is the first thing to answer. */
.event-header__flag {
	display: block;
	margin: 0 0 1rem;
	padding: 0.6rem 0.9rem;
	border-radius: var(--radius-sm);
	font-size: 0.9rem;
	font-weight: 600;
}

.event-header__flag--cancelled {
	background: #fdecea;
	color: #b3261e;
}

.event-header__flag--tentative {
	background: var(--sand);
	color: var(--muted);
}

.event-single .event-header__title {
	text-decoration: none;
}

.event-single.status-cancelled .event-header__title {
	text-decoration: line-through;
	text-decoration-thickness: 1px;
}

/* Detail rows. Label column is fixed so the values line up down the list. */
.event-header__details {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin: 1rem 0 0;
	padding: 1.1rem 1.25rem;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: var(--bg);
	max-width: 46rem;
	/* White on tint reads as a flat patch without a resting shadow — same
	   treatment the event cards get on the events page. */
	box-shadow: 0 1px 2px rgb(11 20 32 / 6%), 0 6px 16px rgb(11 20 32 / 6%);
}

.event-header__row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 1rem;
}

.event-header__row dt {
	flex: 0 0 7.5rem;
	color: var(--muted);
	font-size: 0.85rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.event-header__row dd {
	flex: 1;
	min-width: 0;
	margin: 0;
}

.event-header__row--when dd {
	color: var(--accent);
	font-weight: 600;
}

/* The editor's own content, on the wash: a panel, so the prose has a surface
   to sit on instead of running straight over the tint and the frond behind it. */
.event-single__body {
	/* Full container width, not .post__content's 72ch reading column — this is
	   a panel on the wash, and a half-width panel in a full-width container
	   reads as a mistake rather than as a measure. */
	max-width: none;
	margin-top: 2rem;
	padding: clamp(1.5rem, 3vw, 2.25rem);
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: var(--bg);
	box-shadow: 0 1px 2px rgb(11 20 32 / 6%), 0 6px 16px rgb(11 20 32 / 6%);
}

.event-single__body > :first-child {
	margin-top: 0;
}

.event-single__body > :last-child {
	margin-bottom: 0;
}

/* Lightbox and external events: the title alone. Nobody is meant to land here,
   so it gets breathing room rather than a layout implying more to come. */
.event-single--bare .post__header {
	padding-block: clamp(4rem, 12vw, 8rem);
}

/* The page sits on the same tinted wash as the events page it came from, so
   the panels below read as objects on it rather than as a bare document. */
.event-single {
	padding-bottom: clamp(3rem, 6vw, 5rem);
}

/* Details on the left, flyer thumbnail on the right. No rule underneath — on
   the wash the gap between panels already separates the header from the
   editor's own content below. */
.event-header {
	padding-bottom: 2rem;
}

.event-header__inner {
	display: flex;
	align-items: flex-start;
	gap: clamp(1.5rem, 4vw, 3rem);
}

.event-header__main {
	flex: 1;
	min-width: 0;
}

/* Flyer: a button, since it opens the lightbox. Stripped of button chrome. */
.event-header__flyer {
	flex: 0 0 clamp(9rem, 22vw, 15rem);
	margin: 0;
}

.event-header__flyer-button {
	position: relative;
	display: block;
	width: 100%;
	padding: 0;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: none;
	font: inherit;
	line-height: 0;
	cursor: pointer;
	overflow: hidden;
	transition: transform 0.18s var(--ease-out), box-shadow 0.18s var(--ease-out);
}

.event-header__flyer-button:hover,
.event-header__flyer-button:focus-visible {
	transform: translateY(-2px);
	box-shadow: 0 12px 26px rgb(11 20 32 / 16%);
}

.event-header__flyer-button img {
	width: 100%;
	height: auto;
	display: block;
}

.event-header__flyer-hint {
	position: absolute;
	right: 0.5rem;
	bottom: 0.5rem;
	padding: 0.25rem 0.6rem;
	border-radius: 999px;
	background: rgb(11 20 32 / 72%);
	color: #fff;
	font-size: 0.72rem;
	font-weight: 600;
	line-height: 1.4;
}

/* No body content: the flyer runs alone below, so the details above it
   center on the page instead of sitting flush left against empty space where
   the side thumbnail used to be. */
.event-header--no-body .event-header__main {
	text-align: center;
}

.event-header--no-body .event-header__details {
	margin-inline: auto;
	text-align: left;
}

.event-header--no-body .event-header__subtitle {
	margin-inline: auto;
}

/* No body content: the flyer IS the page, so it runs below the details at as
   close to full size as the artwork allows rather than as a side thumbnail.
   Capped at the reading column so a tall portrait flyer still fits on screen. */
.event-header__flyer--full {
	flex: none;
	width: 100%;
	max-width: 46rem;
	margin: clamp(1.5rem, 3vw, 2.5rem) auto 0;
}

.event-header__flyer--full .event-header__flyer-button {
	box-shadow: 0 2px 6px rgb(11 20 32 / 8%), 0 18px 40px rgb(11 20 32 / 14%);
}

.event-header__flyer--full .event-header__flyer-hint {
	right: 0.9rem;
	bottom: 0.9rem;
	padding: 0.4rem 0.9rem;
	font-size: 0.8rem;
}

/* Stacked on narrow screens, flyer first — it is what people recognise. */
@media (max-width: 700px) {
	.event-header__inner {
		flex-direction: column-reverse;
		align-items: stretch;
	}

	/* Scoped to the side thumbnail — the no-body flyer below is meant to stay
	   full width on a phone, where it is the whole point of the page. */
	.event-header__inner .event-header__flyer {
		flex: 0 0 auto;
		align-self: flex-start;
		max-width: 13rem;
	}
}

/* ---------------------------------------------------------------------------
   Flyer lightbox. Shared by the homepage carousel, the events page and a
   single event's post page — see template-parts/global/lightbox.php and
   assets/js/lightbox.js. Fades in; JS toggles .is-open one frame after
   unhiding so the transition has a start state to animate from.
   --------------------------------------------------------------------------- */

.lightbox[hidden] {
	display: none;
}

.lightbox {
	position: fixed;
	inset: 0;
	z-index: 999;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.85rem;
	padding: clamp(1rem, 4vw, 2.5rem);
	background: rgb(4 18 28 / 94%);
	opacity: 0;
	transition: opacity 0.25s ease-in-out; /* FADE_MS in lightbox.js */
}

.lightbox.is-open {
	opacity: 1;
}

.lightbox__bar {
	position: absolute;
	top: 1rem;
	right: 1.25rem;
	left: 1.25rem;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}

.lightbox__zoom {
	display: flex;
	align-items: center;
	gap: 0.25rem;
	padding: 0.25rem;
	border-radius: 999px;
	background: rgb(255 255 255 / 12%);
}

.lightbox__zoom-btn {
	width: 2.25rem;
	height: 2.25rem;
	border: 0;
	border-radius: 50%;
	background: none;
	color: #fff;
	font-size: 1.25rem;
	line-height: 1;
	cursor: pointer;
	transition: background 0.15s ease;
}

.lightbox__zoom-btn:hover {
	background: rgb(255 255 255 / 20%);
}

.lightbox__zoom-level {
	min-width: 3.5rem;
	color: #fff;
	font-size: 0.82rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	text-align: center;
}

.lightbox__close {
	width: 2.75rem;
	height: 2.75rem;
	border: 0;
	border-radius: 50%;
	background: rgb(255 255 255 / 12%);
	color: #fff;
	font-size: 1.75rem;
	line-height: 1;
	cursor: pointer;
	transition: background 0.15s ease;
}

.lightbox__close:hover {
	background: rgb(255 255 255 / 24%);
}

.lightbox__figure {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	margin: 0;
	max-width: min(92vw, 1000px);
	max-height: 88vh;
	min-height: 0;
	transform: scale(0.94);
	transition: transform 0.25s ease-in-out;
}

.lightbox.is-open .lightbox__figure {
	transform: scale(1);
}

/* Zooming grows the flyer itself rather than cropping it inside a fixed frame,
   so the artwork gets genuinely bigger on screen. The transform is visual only,
   so the scaled image overflows this box without disturbing the caption's
   layout — nothing here may clip it. */
.lightbox__stage {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 0;
	touch-action: none;
	cursor: zoom-in;
}

.lightbox.is-zoomed .lightbox__stage {
	cursor: grab;
}

.lightbox.is-dragging .lightbox__stage {
	cursor: grabbing;
}

.lightbox__img {
	max-width: 100%;
	max-height: 80vh;
	object-fit: contain;
	border-radius: var(--radius-sm);
	transform-origin: center center;
	user-select: none;
	-webkit-user-drag: none;
}

.lightbox__caption {
	flex: 0 0 auto;
	color: #fff;
	font-size: 1.05rem;
	text-align: center;
}

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

	.lightbox__figure {
		transform: none;
	}
}

/* Map. Reusable: the Contact page will want this too. */

.map {
	margin-top: 2rem;
	border-radius: var(--radius);
	overflow: hidden;
	border: 1px solid var(--line);
}

.map__frame {
	display: block;
	width: 100%;
	height: 280px;
	border: 0;
	filter: grayscale(20%);
}

/* Forms. Reusable: the Contact page will want this too. */

.form {
	padding: clamp(1.75rem, 4vw, 2.5rem);
	border-radius: var(--radius);
	background: var(--sand);
}

.form__title {
	margin: 0 0 1.75rem;
	font-size: 1.35rem;
	font-weight: 600;
}

.field {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin-bottom: 1.25rem;
}

.field__label {
	color: var(--ink);
	font-size: 0.95rem;
	font-weight: 500;
}

.field__hint {
	margin-left: 0.35rem;
	color: var(--muted);
	font-weight: 400;
	font-size: 0.85rem;
}

.field__input {
	padding: 0.8rem 1rem;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: #fff;
	color: var(--ink);
	font: inherit;
	font-size: 1rem;
}

.field__input:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
	border-color: var(--accent);
}

textarea.field__input {
	resize: vertical;
	min-height: 8rem;
}

/* Honeypot. Never shown, never focusable. */
.field__alt {
	display: none;
}

.form .button {
	margin-top: 0.5rem;
	width: 100%;
}

/* Result of a fetch submit, printed under the button by form-submit.js. */
.form__status {
	margin: 0.85rem 0 0;
	font-size: 0.92rem;
	line-height: 1.5;
}

/* Empty status text must not reserve a line, or the form grows on load. */
.form__status:empty {
	display: none;
}

.form__status[data-state="ok"] {
	color: #1a7f4b;
}

.form__status[data-state="error"] {
	color: #a3262c;
}

/* Attribution Google requires when the badge is hidden. */
.form__recaptcha-note {
	display: block;
	margin-top: 0.85rem;
	color: var(--muted);
	font-size: 0.72rem;
	line-height: 1.5;
}

.form__recaptcha-note a {
	color: inherit;
}

@media (min-width: 480px) {
	.form .button {
		width: auto;
	}
}

/*
 * Floating message button + its popover. Site-wide (printed by the footer on
 * every page except Contact Us, which already carries the form inline).
 *
 * Deliberately not a modal: no backdrop, no scroll lock. The panel grows out
 * of the button it is anchored to, so the page behind stays visible and usable
 * — a message is an aside, not something that should take the page hostage.
 */

.chat-widget {
	position: fixed;
	right: 1.5rem;
	bottom: 1.5rem;
	z-index: 95;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.85rem;
}

/* The button */

.chat-fab {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 58px;
	height: 58px;
	border: none;
	border-radius: 50%;
	background: var(--accent);
	color: #fff;
	box-shadow: 0 10px 30px rgb(11 58 92 / 32%);
	cursor: pointer;
	transition: background 0.25s cubic-bezier(0.16, 1, 0.3, 1),
		transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
		box-shadow 0.25s ease;
}

.chat-fab:hover {
	background: var(--accent-dark);
	transform: scale(1.08);
	box-shadow: 0 14px 36px rgb(11 58 92 / 40%);
}

.chat-fab:active {
	transform: scale(0.94);
}

/*
 * A halo that pulses out of the button while it is closed, to catch the eye
 * once the page has settled. It stops the moment the panel opens — by then it
 * has done its job and would only compete with the form.
 */
.chat-fab::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: var(--accent);
	opacity: 0;
	animation: chat-fab-pulse 2.8s ease-out 2s infinite;
}

.chat-fab.is-open::before,
.chat-fab:hover::before {
	animation: none;
}

@keyframes chat-fab-pulse {
	0% {
		transform: scale(1);
		opacity: 0.45;
	}

	70%,
	100% {
		transform: scale(1.7);
		opacity: 0;
	}
}

/*
 * The two icons are stacked in the same cell and cross-faded, each spinning
 * the short way round, so the bubble turns into the close X rather than
 * blinking over to it.
 */
.chat-fab__icons {
	position: relative;
	display: block;
	width: 26px;
	height: 26px;
}

.chat-fab__icon {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	transition: opacity 0.25s ease, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.chat-fab__icon--close {
	opacity: 0;
	transform: rotate(-90deg) scale(0.5);
}

.chat-fab.is-open .chat-fab__icon--chat {
	opacity: 0;
	transform: rotate(90deg) scale(0.5);
}

.chat-fab.is-open .chat-fab__icon--close {
	opacity: 1;
	transform: none;
}

/* The panel */

.chat-panel[hidden] {
	display: none;
}

/*
 * Anchored to the button's corner: it scales up out of there rather than
 * arriving from nowhere. The overshoot easing gives it a little spring on the
 * way in; closing is a plain, quicker ease so dismissing never feels bouncy.
 */
.chat-panel {
	transform-origin: bottom right;
	display: flex;
	flex-direction: column;
	width: min(370px, calc(100vw - 3rem));
	max-height: min(70vh, 620px);
	overflow: hidden;
	padding: 1.6rem;
	border-radius: var(--radius);
	background: var(--sand);
	box-shadow: 0 24px 60px rgb(11 20 32 / 22%);
	opacity: 0;
	transform: translateY(14px) scale(0.86);
	transition: opacity 0.18s ease, transform 0.2s ease;
}

.chat-panel--visible {
	opacity: 1;
	transform: none;
	transition: opacity 0.28s ease, transform 0.42s cubic-bezier(0.34, 1.4, 0.64, 1);
}

.chat-panel__head {
	flex: none;
	margin-bottom: 1.75rem;
}

/*
 * The scroll lives on the body, not the panel, so the heading stays put and
 * the scrollbar runs inside the panel's padding instead of hard against its
 * rounded edge.
 *
 * Every side is padded and then pulled back by an equal negative margin: the
 * padding is what a focused field's outline sits in (a scroll container clips
 * anything past its padding box, and outlines are drawn outside the border),
 * while the negative margin cancels it so the fields stay aligned with the
 * heading above. The right side is padded wider because the scrollbar track
 * shares that gutter.
 */
.chat-panel__body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	margin: -0.35rem -0.9rem -0.35rem -0.35rem;
	padding: 0.35rem 0.9rem 0.35rem 0.35rem;
	scrollbar-width: thin;
	scrollbar-color: rgb(11 58 92 / 22%) transparent;
}

.chat-panel__body::-webkit-scrollbar {
	width: 6px;
}

.chat-panel__body::-webkit-scrollbar-track {
	background: transparent;
}

.chat-panel__body::-webkit-scrollbar-thumb {
	border-radius: 999px;
	background: rgb(11 58 92 / 22%);
}

.chat-panel__body::-webkit-scrollbar-thumb:hover {
	background: rgb(11 58 92 / 38%);
}

.chat-panel__title {
	margin: 0;
	font-size: 1.2rem;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.chat-panel__lead {
	margin: 0.35rem 0 0;
	color: var(--muted);
	font-size: 0.9rem;
}

/* The panel is the surface, so the form drops its own. */
.chat-panel .form {
	padding: 0;
	border-radius: 0;
	background: none;
}

/*
 * The contents rise in behind the panel itself, one row after the next, so the
 * form reads as filling in rather than appearing all at once. Delays are on
 * the row index; the honeypot is display:none and takes no visual slot, but it
 * still counts as a child, hence the button landing on its own step.
 */
.chat-panel__head,
.chat-panel .form > * {
	opacity: 0;
	transform: translateY(8px);
}

.chat-panel--visible .chat-panel__head,
.chat-panel--visible .form > * {
	opacity: 1;
	transform: none;
	transition: opacity 0.3s ease, transform 0.3s ease;
}

.chat-panel--visible .chat-panel__head {
	transition-delay: 0.06s;
}

.chat-panel--visible .form > :nth-child(1) {
	transition-delay: 0.1s;
}

.chat-panel--visible .form > :nth-child(2) {
	transition-delay: 0.14s;
}

.chat-panel--visible .form > :nth-child(3) {
	transition-delay: 0.18s;
}

.chat-panel--visible .form > :nth-child(4) {
	transition-delay: 0.22s;
}

.chat-panel--visible .form > :nth-child(n + 5) {
	transition-delay: 0.26s;
}

/* The button is full width here — the panel is too narrow for it to sit alone. */
.chat-panel .form .button {
	width: 100%;
}

@media (max-width: 480px) {
	.chat-widget {
		right: 1rem;
		bottom: 1rem;
	}

	.chat-panel {
		width: calc(100vw - 2rem);
	}
}

/*
 * Reduced motion: the panel still fades, but nothing springs, staggers, or
 * pulses.
 */
@media (prefers-reduced-motion: reduce) {
	.chat-fab,
	.chat-fab__icon,
	.chat-panel,
	.chat-panel__head,
	.chat-panel .form > * {
		transition-duration: 0.01ms;
		transition-delay: 0s;
		transform: none;
	}

	.chat-fab::before {
		animation: none;
	}
}

/* Cards. Used by the homepage and the blog index. */

.card-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: var(--step);
	margin: 0;
	padding: 0;
	list-style: none;
}

.card__link {
	display: block;
	height: 100%;
	padding: 1.25rem;
	border: 1px solid var(--line);
	border-radius: var(--radius);
	color: inherit;
	text-decoration: none;
}

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

.card__image {
	border-radius: calc(var(--radius) - 2px);
	margin-bottom: 1rem;
}

.card__title {
	margin: 0 0 0.5rem;
	font-size: 1.1rem;
}

.card__excerpt {
	margin: 0;
	color: var(--muted);
	font-size: 0.95rem;
}

/* Footer */

/*
 * One sand slab closing the page, flush against the last section.
 *
 * Square top, not rounded: the corner wedges of a rounded top expose the white
 * body behind the footer, which reads as two notches against any section that
 * does not end on white. The home page ends on --sand .shabbat, so it would.
 *
 * --sand, not --ink: the logo is brand blue on transparent, which lands at
 * 2.2:1 on navy, and inverting it would merge the SJC letters into their own
 * backing box. Sand keeps the mark usable as-is. The hairline carries the
 * separation instead, since .shabbat hands off sand to sand with no edge.
 */
.site-footer {
	border-top: 1px solid var(--line);
	background: var(--sand);
	color: var(--muted);
}

.site-footer__inner {
	padding-block: clamp(2.5rem, 4vw, 3rem);
}

/* Subscribe column */

/*
 * Jumped to by the homepage newsletter channel. The header is fixed, so
 * without this the heading lands underneath it — offset by the condensed bar,
 * since the header has always condensed by the time a jump this far down lands.
 */
.footer-subscribe {
	scroll-margin-block-start: calc(var(--nav-h-condensed) + 1.5rem);
}

/*
 * A peer of the link columns, not a banner: same heading, no card, no fill.
 * The white inputs carry their own --line border, so they read against --sand
 * without needing a tinted surface behind them.
 */
.footer-subscribe__intro {
	margin: 0 0 1rem;
	color: var(--muted);
	font-size: 0.95rem;
	line-height: 1.6;
}

/* Column-width, so the fields stack rather than competing for one line. */
.footer-subscribe__form {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
}

.footer-subscribe__field {
	margin-bottom: 0;
}

.footer-subscribe__submit {
	width: 100%;
}

/* Brand, links, contact, subscribe */

.site-footer__grid {
	display: grid;
	grid-template-columns: 1.4fr 0.9fr 1.1fr 1.3fr;
	gap: clamp(1.75rem, 3.5vw, 3rem);
	padding-block: clamp(2rem, 4vw, 3rem);
}

.site-footer__logo {
	display: inline-block;
	line-height: 0;
}

.site-footer__logo img {
	width: auto;
	height: 52px;
}

.site-footer__blurb {
	margin: 1.25rem 0 0;
	max-width: 32ch;
	font-size: 1rem;
	line-height: 1.6;
}

.site-footer__social {
	display: flex;
	gap: 0.75rem;
	margin: 1.5rem 0 0;
	padding: 0;
	list-style: none;
}

/* Same move as .button--ghost: white until hovered, then it fills with ink. */
.social-link {
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	border: 1px solid var(--line);
	border-radius: 999px;
	background: var(--bg);
	color: var(--ink);
	transition:
		background 0.25s var(--ease-out),
		border-color 0.25s var(--ease-out),
		color 0.25s var(--ease-out),
		transform 0.15s ease;
}

.social-link:hover {
	background: var(--ink);
	border-color: var(--ink);
	color: #fff;
	transform: translateY(-2px);
}

.social-link__icon {
	width: 20px;
	height: 20px;
}

.site-footer__heading {
	margin: 0 0 1rem;
	color: var(--ink);
	font-size: 1rem;
	font-weight: 600;
}

.site-footer__list {
	display: grid;
	gap: 0.7rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-footer__list a {
	color: var(--muted);
	font-size: 0.95rem;
	text-decoration: none;
	transition: color 0.2s ease;
}

.site-footer__list a:hover,
.site-footer__list a:focus-visible,
.site-footer__list .current-menu-item > a {
	color: var(--ink);
}

/* Contact details only — the Pages menu shares .site-footer__list and has no
   icons, so the icon layout is scoped to this modifier rather than the base. */
.site-footer__list--contact a {
	display: flex;
	align-items: flex-start;
	gap: 0.6rem;
}

/* Sits on the cap height of the first line, so the address staying on one line
   or wrapping to two doesn't move the marker off its text. */
.site-footer__icon {
	flex: none;
	width: 18px;
	height: 18px;
	margin-top: 0.15em;
	color: var(--accent);
	opacity: 0.75;
	transition: opacity 0.2s ease;
}

.site-footer__list--contact a:hover .site-footer__icon,
.site-footer__list--contact a:focus-visible .site-footer__icon {
	opacity: 1;
}

/* Copyright bar */

.site-footer__bar {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	padding-top: 1.75rem;
	border-top: 1px solid var(--line);
}

.site-footer__copy {
	margin: 0;
	font-size: 0.9rem;
}

/* 501(c)(3) disclosure. Its own full-width row so it never gets squeezed
   between the copyright and the links. */
.site-footer__nonprofit {
	order: 1;
	flex-basis: 100%;
	margin: 0;
	color: var(--muted);
	font-size: 0.85rem;
}

.site-footer__legal {
	margin: 0;
	font-size: 0.9rem;
}

/* The staff login/dashboard link: present for those looking for it, quiet
   enough that nobody else has to wonder what it is. */
.site-footer__admin {
	margin: 0;
	margin-left: auto;
	font-size: 0.85rem;
}

.site-footer__admin a {
	color: var(--muted);
	text-decoration: none;
	opacity: 0.75;
}

.site-footer__admin a:hover,
.site-footer__admin a:focus-visible {
	color: var(--muted);
	text-decoration: none;
	opacity: 1;
}

.site-footer a:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 4px;
	border-radius: 4px;
}

/*
 * Four columns stop fitting well before the breakpoint the nav uses. Brand and
 * subscribe are the wide ones, so they take a full row each and the two link
 * columns pair up between them.
 */
@media (max-width: 1000px) {
	.site-footer__grid {
		grid-template-columns: 1fr 1fr;
	}

	.site-footer__brand,
	.footer-subscribe {
		grid-column: 1 / -1;
	}

	.footer-subscribe__form {
		flex-direction: row;
		flex-wrap: wrap;
	}

	.footer-subscribe__field {
		flex: 1 1 200px;
	}

	.footer-subscribe__submit {
		width: auto;
		flex: none;
	}
}

@media (max-width: 560px) {
	.site-footer__grid {
		grid-template-columns: 1fr;
	}

	.footer-subscribe__form {
		flex-direction: column;
	}

	.footer-subscribe__submit {
		width: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	.social-link,
	.site-footer__list a,
	.site-footer__icon {
		transition: none;
	}
}
