/* =========================================================================
   STEM In The Rockaways — Horizon edition — main stylesheet

   This is a visual restyle of the theme's original (Claude Build) edition:
   every Customizer setting, template part, and PHP helper is unchanged, so
   this file targets the exact same class names, just with a new "editorial
   magazine" look built from a reference site Ralph supplied — large serif
   display headlines, soft pastel-tinted cards, rotated framed photos over
   a soft mint backdrop shape, pill-shaped nav links, and a dark footer with
   warm-yellow section labels. Mobile-first; breakpoints at 640 / 900 / 1200px.
   ========================================================================= */

:root {
	/* ---- Brand palette ----
	   Every swatch below is wrapped as var(--stem-toolkit-<name>, <hex>):
	   the hex is this theme's own shipped default (nothing changes if
	   nothing else is active), and --stem-toolkit-<name> is a hook a color
	   customization tool can set at :root to override it site-wide -- see
	   the companion "STEM Site Colors Toolkit" plugin, which registers a
	   Customizer color picker for each one. This indirection is what makes
	   every color on the page changeable without editing this file: CSS
	   custom-property lookups resolve independent of stylesheet load
	   order, so it doesn't matter whether the toolkit's <style> block is
	   printed before or after this one. */
	--coral: var(--stem-toolkit-coral, #F68D5F);
	--coral-dark: var(--stem-toolkit-coral-dark, #e2723f);
	--coral-soft: var(--stem-toolkit-coral-soft, #fde3d5);
	--teal: var(--stem-toolkit-teal, #00A88F);
	--teal-dark: var(--stem-toolkit-teal-dark, #00806e);
	--teal-secondary: var(--stem-toolkit-teal-secondary, #00A78F);
	--soft-teal: var(--stem-toolkit-soft-teal, #E0F2F1);
	--teal-soft: var(--stem-toolkit-teal-soft, #d5efe9);
	--mint: var(--stem-toolkit-mint, #e0f2f1);
	--mint-soft: var(--stem-toolkit-mint-soft, #eef7f6);
	--navy: var(--stem-toolkit-navy, #234876);
	--navy-dark: var(--stem-toolkit-navy-dark, #16304f);
	--ink: var(--stem-toolkit-ink, #2C3650);
	--ink-2: var(--stem-toolkit-ink-2, #3d4a68);
	--muted: var(--stem-toolkit-muted, #6a7791);
	--line: var(--stem-toolkit-line, #e2e7f0);
	--sun: var(--stem-toolkit-sun, #ffd166);
	--sun-soft: var(--stem-toolkit-sun-soft, #fff1c9);
	--white: var(--stem-toolkit-white, #FFFFFF);
	--cream: var(--stem-toolkit-cream, #FFF8F3);
	--warm: var(--stem-toolkit-warm, #fff9f5);
	--radius-lg: 32px;
	--radius-md: 20px;
	--radius-sm: 12px;
	--shadow-soft: 0 24px 60px rgba(35, 72, 118, 0.10);
	--shadow-card: 0 8px 24px rgba(35, 72, 118, 0.08);
	--font-serif: 'DM Serif Display', Georgia, 'Times New Roman', serif;
	--font-body: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
	--container-width: 1160px;

	/* ---- Brand gradients (kept from the original build -- still used for
	   buttons, the donation panel, and a couple of accent details -- just
	   restrained to fewer places here, since this aesthetic leans on flat
	   pastel-tinted panels for most cards instead). ---- */
	--gradient-coral: linear-gradient(135deg, var(--coral) 0%, var(--coral-dark) 100%);
	--gradient-coral-hover: linear-gradient(315deg, var(--coral) 0%, var(--coral-dark) 100%);
	--gradient-teal: linear-gradient(135deg, var(--teal) 0%, var(--teal-dark) 100%);
	--gradient-navy: linear-gradient(135deg, var(--navy) 0%, var(--navy-dark) 100%);
	--gradient-navy-hover: linear-gradient(315deg, var(--navy) 0%, var(--navy-dark) 100%);
	--gradient-coral-teal: linear-gradient(135deg, var(--coral) 0%, var(--teal) 100%);
	--gradient-brand: linear-gradient(90deg, var(--coral) 0%, var(--teal) 55%, var(--navy) 100%);
	--wash-teal: linear-gradient(160deg, var(--soft-teal) 0%, #d2f0ea 100%);
	--wash-cream: linear-gradient(160deg, var(--cream) 0%, #ffece0 100%);
}

/* ---------- Reset-ish basics ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
}
body {
	margin: 0;
	font-family: var(--font-body);
	color: var(--ink);
	background-color: var(--white);
	font-size: 16.5px;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	/* overflow-x lives on <html> only (see the bottom of this file) —
	   setting it here too would break position:sticky on .site-header. */
	transition: background-color 0.35s ease;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--teal-dark); text-decoration: none; }
a:hover { color: var(--navy); }
h1, h2, h3, h4 { font-family: var(--font-serif); color: var(--ink); line-height: 1.08; letter-spacing: -0.01em; margin: 0 0 0.6em; font-weight: 400; }
p { margin: 0 0 1.2em; }
ul { margin: 0; padding: 0; list-style: none; }
button { font-family: inherit; }

/* ---------- Focus visibility (accessibility) ---------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--coral);
	outline-offset: 3px;
	border-radius: 4px;
}

/* ---------- Skip link ---------- */
.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	background: var(--navy);
	color: var(--white);
	padding: 14px 22px;
	z-index: 10000;
	border-radius: 0 0 8px 0;
}
.skip-link:focus {
	left: 0;
}
.screen-reader-text {
	border: 0; clip: rect(1px,1px,1px,1px); clip-path: inset(50%);
	height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; word-wrap: normal;
}

/* ---------- Layout helpers ---------- */
.stem-container {
	max-width: var(--container-width);
	margin: 0 auto;
	padding: 0 24px;
}
.stem-section-heading {
	font-size: clamp(1.75rem, 3vw, 2.5rem);
	max-width: 720px;
}
.stem-section-heading-center { margin-left: auto; margin-right: auto; text-align: center; }
.stem-kicker {
	position: relative;
	display: inline-block;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	font-weight: 800;
	font-size: 0.78rem;
	color: var(--teal-dark);
	margin: 0 0 0.8em;
	padding-left: 22px;
}
.stem-kicker::before {
	content: "";
	position: absolute;
	left: 0;
	top: 50%;
	transform: translateY(-50%);
	width: 14px;
	height: 2px;
	background: currentColor;
}
.stem-highlight-coral { color: var(--coral); font-style: italic; }

/* Site-name line above the hero headline (Customize > Homepage Hero) —
   larger than the kicker so a first-time visitor immediately sees what
   organization the site belongs to. Color is set inline (a per-site
   Customizer color, not a fixed palette value); position and font come
   from the classes below. */
.stem-hero-site-name {
	font-weight: 800;
	letter-spacing: 0.02em;
	/* Customize > Homepage Hero > "Site-name text size" sets
	   --stem-site-name-scale (inline, per-instance) as a percentage of this
	   original responsive size — 1 (100%) reproduces it exactly, any other
	   value scales it up/down without losing the fluid clamp() behavior. */
	font-size: calc(clamp(1.1rem, 2.2vw, 1.5rem) * var(--stem-site-name-scale, 1));
	margin: 0 0 0.5em;
	line-height: 1.15;
	/* Ralph: "as the site name text is modified make sure it doesn't go
	   to two lines keep it to one line." A larger scale on a narrow
	   screen could otherwise wrap onto a second line (the hero text
	   column has a finite width) — forcing nowrap keeps it one line at
	   any scale; text-overflow:ellipsis is a safety net for the extreme
	   end of the range (220% on a very narrow phone) so it degrades to a
	   clean truncation instead of visually breaking out of its column. */
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 100%;
}
.stem-hero-site-name-center { text-align: center; }
.stem-hero-site-name-font-heading { font-family: var(--font-serif); }
.stem-hero-site-name-font-body { font-family: var(--font-body); }

section { padding: clamp(48px, 7vw, 96px) 0; }

/* ---------- Buttons ---------- */
.stem-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 14px 28px;
	border-radius: 999px;
	font-weight: 600;
	font-size: 1rem;
	border: 2px solid transparent;
	transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease, color 0.15s ease;
	cursor: pointer;
}
.stem-btn:hover { transform: translateY(-2px); text-decoration: none; }
/* Each button variant gets its own dedicated color hooks (background,
   text, and hover state) rather than only inheriting the brand palette —
   so a specific button can be recolored on its own, while still
   defaulting to the palette-driven gradient/flat look below when no
   override is set (see the STEM Site Colors Toolkit plugin). */
.stem-btn-primary { background: var(--stem-btn-primary-bg, var(--gradient-coral)); color: var(--stem-btn-primary-text, var(--white)); box-shadow: 0 10px 26px rgba(246,141,95,0.32); }
.stem-btn-primary:hover { background: var(--stem-btn-primary-bg-hover, var(--gradient-coral-hover)); color: var(--stem-btn-primary-text, var(--white)); box-shadow: 0 14px 32px rgba(246,141,95,0.4); }
.stem-btn-outline { background: var(--stem-btn-outline-bg, var(--white)); border-color: var(--stem-btn-outline-border, var(--line)); color: var(--stem-btn-outline-text, var(--ink)); }
.stem-btn-outline:hover { background: var(--stem-btn-outline-bg-hover, var(--white)); border-color: var(--stem-btn-outline-border-hover, var(--navy)); color: var(--stem-btn-outline-text-hover, var(--navy)); }
.stem-btn-ghost { background: var(--stem-btn-ghost-bg, transparent); border-color: var(--stem-btn-ghost-border, rgba(35,72,118,0.25)); color: var(--stem-btn-ghost-text, var(--navy)); }
.stem-btn-ghost:hover { background: var(--stem-btn-ghost-bg-hover, var(--mint-soft)); border-color: var(--stem-btn-ghost-border-hover, var(--teal)); color: var(--stem-btn-ghost-text-hover, var(--navy)); }
.stem-btn-navy { background: var(--stem-btn-navy-bg, var(--gradient-teal)); color: var(--stem-btn-navy-text, var(--white)); box-shadow: 0 10px 26px rgba(0,168,143,0.28); }
.stem-btn-navy:hover { background: var(--stem-btn-navy-bg-hover, var(--gradient-navy-hover)); color: var(--stem-btn-navy-text, var(--white)); }
.stem-btn-large { padding: 16px 34px; font-size: 1.05rem; }

/* ---------- Announcement bar ---------- */
.stem-announcement-bar {
	background: var(--stem-announcement-bg, var(--mint-soft));
	color: var(--stem-announcement-text, var(--ink-2));
	border-bottom: 1px solid var(--line);
}
.stem-announcement-inner {
	max-width: var(--container-width);
	margin: 0 auto;
	padding: 12px 24px;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 16px;
	flex-wrap: wrap;
	text-align: center;
	position: relative;
}
.stem-announcement-message { margin: 0; font-size: 0.9rem; }
.stem-announcement-btn {
	background: var(--stem-announcement-btn-bg, var(--teal));
	color: var(--white);
	padding: 6px 18px;
	border-radius: 999px;
	font-weight: 700;
	font-size: 0.82rem;
	white-space: nowrap;
}
.stem-announcement-btn:hover { background: var(--stem-announcement-btn-bg-hover, var(--teal-dark)); color: var(--white); }
.stem-announcement-close {
	background: transparent;
	border: none;
	color: var(--ink-2);
	font-size: 1.4rem;
	line-height: 1;
	cursor: pointer;
	padding: 4px 8px;
	position: absolute;
	right: 8px;
	top: 50%;
	transform: translateY(-50%);
}
.stem-announcement-bar.is-dismissed { display: none; }

/* ---------- Header ---------- */
.site-header {
	position: sticky;
	top: 0;
	z-index: 999;
	background: var(--stem-header-bg, rgba(255,255,255,0.98));
	/* NOTE: intentionally no backdrop-filter here. It would create a new
	   containing block for this header's position:fixed descendant (the
	   mobile off-canvas menu), which then anchors to the header's own
	   ~70px-tall box instead of the viewport -- collapsing the slide-out
	   panel to a sliver instead of a full-height menu. */
	border-bottom: 1px solid rgba(35,72,118,0.08);
	box-shadow: 0 1px 0 rgba(22,48,79,0);
	transition: box-shadow 0.25s ease;
}
/* Condensed-on-scroll state (Ralph: "give me a better menu option it
   doesn't look modern") -- a sticky header that visibly settles/shrinks
   once the page scrolls is a common modern-nav cue. JS (main.js) toggles
   this class past a small scroll threshold; every actual size/spacing
   change below is a CSS transition, so the JS only ever flips one class. */
.site-header.is-scrolled {
	box-shadow: 0 8px 28px rgba(22,48,79,0.12);
}
.site-header.is-scrolled .stem-header-inner {
	padding-block: 8px;
}
.site-header.is-scrolled .site-branding img,
.site-header.is-scrolled .custom-logo {
	max-height: calc(var(--stem-header-logo-h, 64px) * 0.76);
}
.site-header::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	background: var(--gradient-brand);
}

/* ---------- Header background effects (Customize > Header) ---------- */
/* "Solid (original)" needs no extra rule — .site-header's own base
   background above already is that. Every other option layers on top of
   it via ::after (kept separate from ::before, which is always the thin
   brand-gradient top line regardless of which effect is chosen below). */
.stem-header-style-soft_gradient::after,
.stem-header-style-brand_glow::after,
.stem-header-style-dot_pattern::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
}
.stem-header-style-soft_gradient::after {
	background: linear-gradient(100deg, var(--coral-soft) 0%, transparent 45%, var(--teal-soft) 100%);
	opacity: 0.6;
}
.stem-header-style-brand_glow::after {
	background:
		radial-gradient(140px 70px at 12% 0%, rgba(246, 141, 95, 0.28), transparent 70%),
		radial-gradient(160px 80px at 88% 100%, rgba(0, 168, 143, 0.22), transparent 70%);
}
.stem-header-style-dot_pattern::after {
	background-image: radial-gradient(rgba(35, 72, 118, 0.14) 1.5px, transparent 1.5px);
	background-size: 16px 16px;
	opacity: 0.5;
}
.stem-header-style-bottom_line::before { height: 5px; }
.stem-header-style-soft_gradient .stem-header-inner,
.stem-header-style-brand_glow .stem-header-inner,
.stem-header-style-dot_pattern .stem-header-inner {
	position: relative;
	z-index: 1;
}

/* "Picture or Video" — a real image/video fills the header behind the
   logo/menu, with a light frosted overlay so both stay legible over any
   photo without needing to know its colors ahead of time. */
.stem-header-style-media { overflow: hidden; }
.stem-header-media {
	position: absolute;
	inset: 0;
	z-index: 0;
}
.stem-header-media-bg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.stem-header-media-overlay {
	position: absolute;
	inset: 0;
	background: rgba(255, 255, 255, 0.82);
}
.stem-header-style-media .stem-header-inner { position: relative; z-index: 1; }

.stem-header-inner {
	/* The containing block the centered desktop nav below is positioned
	   against — position:relative here does NOT interfere with the mobile
	   off-canvas menu's own position:fixed (only transform/filter/etc.
	   would do that; relative/sticky/absolute only affect position:absolute
	   descendants), so this is safe alongside that existing behavior. */
	position: relative;
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 14px 24px;
	gap: 20px;
	transition: padding 0.25s ease;
}
.site-branding img, .custom-logo { max-height: var(--stem-header-logo-h, 64px); width: auto; transition: max-height 0.25s ease; }
.site-branding-fallback { display: flex; align-items: center; gap: 10px; }
.site-branding-fallback .site-title { font-family: var(--font-serif); color: var(--ink); font-weight: 400; font-size: 1.25rem; }
.site-branding a { display: inline-flex; transition: opacity 0.2s ease; }
.site-branding a:hover { opacity: 0.8; }

.menu-toggle {
	display: none;
	flex-direction: column;
	gap: 5px;
	background: none;
	border: none;
	cursor: pointer;
	padding: 8px;
	/* A real, pre-existing quirk found while adding the mobile-menu
	   backdrop above: the toggle button has no position of its own, so it
	   was always painted BELOW .main-navigation once that panel opens
	   (any positioned element, even at z-index:auto, paints above
	   non-positioned in-flow content within the same stacking context --
	   here, both sit inside .site-header's own stacking context) -- on a
	   narrow phone width where the panel's right-anchored width happens to
	   reach the toggle's own position, this silently made the button
	   unclickable to close the menu again by tapping it a second time
	   (Escape and tapping outside the panel still worked). Giving the
	   button its own position + z-index above the panel's (960) fixes
	   this without touching anything about how/where the panel itself
	   renders. */
	position: relative;
	z-index: 1000;
}
.menu-toggle-bar { width: 26px; height: 3px; background: var(--ink); border-radius: 2px; transition: transform 0.2s ease, opacity 0.2s ease; }
.menu-toggle[aria-expanded="true"] .menu-toggle-bar:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] .menu-toggle-bar:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] .menu-toggle-bar:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* Wraps the hamburger together with the always-visible mobile Donate
   button (header.php) so both sit as ONE flex child of .stem-header-inner,
   keeping that container's existing space-between (site-branding on the
   far left, this wrapper on the far right) exactly as it was before this
   wrapper existed -- see the long comment on .stem-header-inner above.
   Collapses to zero visible width on desktop, where both children inside
   it are hidden (the real Donate CTA lives in .main-navigation instead). */
.stem-header-mobile-actions { display: flex; align-items: center; gap: 10px; }
.stem-mobile-donate-cta { display: none; }

.main-navigation {
	display: flex;
	align-items: center;
	gap: 28px;
}
.primary-menu, .footer-menu {
	display: flex;
	gap: 4px;
	flex-wrap: wrap;
}
.footer-menu { gap: 22px; }
.primary-menu a, .footer-menu a {
	color: var(--stem-header-nav-text, var(--ink-2));
	font-weight: 600;
}
.footer-menu a:hover { color: var(--teal); }
.primary-menu a {
	position: relative;
	padding: 10px 14px;
	border-radius: 999px;
	transition: background-color 0.2s ease, color 0.2s ease;
}
.primary-menu a:hover {
	background: var(--stem-header-nav-hover-bg, var(--mint-soft));
	color: var(--stem-header-nav-hover-text, var(--teal-dark));
}
/* Current-page indicator: WordPress adds `current-menu-item`/`current_page_item`
   (and, since WP 5.5, `aria-current="page"` on the link itself) to whichever
   item matches the page you're on when a real menu is assigned to Appearance >
   Menus > Primary Menu; stem_rockaways_fallback_menu() (functions.php) adds the
   same class + attribute by hand for the no-menu-assigned fallback. Both are
   targeted here so the highlight works either way. Styled as a filled pill,
   matching the hover state, rather than the underline treatment the original
   (Claude Build) edition uses. */
.primary-menu .current-menu-item > a,
.primary-menu .current_page_item > a,
.primary-menu .current-menu-ancestor > a,
.primary-menu .current_page_parent > a,
.primary-menu a[aria-current="page"] {
	color: var(--stem-header-nav-hover-text, var(--teal-dark));
	font-weight: 800;
	background: var(--stem-header-nav-hover-bg, var(--mint-soft));
}
.nav-cta { display: flex; gap: 10px; }
.nav-cta .stem-btn { padding: 10px 20px; font-size: 0.92rem; }

/* Dropdown submenus for any top-level menu item with children
   (Appearance > Menus lets an admin nest a "child" item under a "parent"
   one — WordPress adds the .menu-item-has-children class and the
   aria-haspopup/aria-expanded attributes automatically; see
   inc/accessibility.php). Opens on hover for mouse users and on
   focus-within for keyboard users, so Tabbing onto a child link also
   reveals its parent's submenu. */
.menu-item-has-children { position: relative; }
/* A small chevron on any top-level item that has a submenu, so its
   presence is visible before ever hovering/opening it (Ralph: "add an
   arrow to the top menu to show additional hidden items"). Rotates to
   point up once that item's submenu is actually open, reusing the exact
   same open-state selectors as .sub-menu itself just below so the two
   always agree. */
.menu-item-has-children > a {
	position: relative;
	padding-right: 26px;
}
.menu-item-has-children > a::after {
	content: "";
	position: absolute;
	right: 10px;
	top: 50%;
	width: 7px;
	height: 7px;
	margin-top: -5px;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform 0.2s ease;
	pointer-events: none;
}
.menu-item-has-children:hover > a::after,
.menu-item-has-children:focus-within > a::after,
.menu-item-has-children.submenu-open > a::after,
.menu-item-has-children > a[aria-expanded="true"]::after {
	transform: rotate(225deg);
	margin-top: -8px;
}
.sub-menu {
	position: absolute;
	top: 100%;
	left: 0;
	min-width: 220px;
	margin: 0;
	padding: 10px;
	list-style: none;
	/* Ralph (v1.9.0): "the sub menu item should not be white give it some
	   personality" — swapped the flat white dropdown for the theme's own
	   navy, with a thin brand-gradient accent bar across the top (the
	   same coral→teal→navy sweep used elsewhere in Horizon).
	   Ralph (this round): "i like the menus and appearance except for the
	   submenu make the submenu a transparent background" — the solid
	   navy panel is gone; the accent bar, cream text, hover states, and
	   shape below are all unchanged from v1.9.0. A backdrop blur is kept
	   so the cream text stays readable over whatever page content sits
	   behind the menu (a fully see-through panel with no color AND no
	   blur risks illegible light-on-light text over a light section of
	   the page) — it adds no color/tint of its own, only blur, so the
	   background itself is still genuinely transparent. Degrades
	   gracefully on any browser without backdrop-filter support: the
	   panel is simply transparent with no blur there, not broken. */
	background: transparent;
	background-clip: padding-box;
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	color: var(--cream);
	/* A transparent top border reads as a small gap between the nav pill
	   and its dropdown (Ralph: "the menu and sub menu overlap too much")
	   without actually moving the box away from top:100% — moving it with
	   a real gap (e.g. top: calc(100% + Npx)) would create a dead zone the
	   mouse has to cross with nothing hoverable in it, closing the menu
	   before the cursor ever reaches it. Layered as a border-image so the
	   gradient panel itself (via background-clip: padding-box) doesn't
	   bleed into that transparent strip. */
	border-top: 10px solid transparent;
	border-radius: var(--radius-md);
	box-shadow: 0 16px 40px rgba(22, 48, 79, 0.35);
	opacity: 0;
	visibility: hidden;
	transform: translateY(6px);
	transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
	z-index: 20;
}
.sub-menu::before {
	/* The thin brand-gradient accent line across the very top of the
	   panel — sits inside the transparent border strip above, on top of
	   the navy panel's own rounded corner. */
	content: "";
	position: absolute;
	top: 0;
	left: 8px;
	right: 8px;
	height: 3px;
	border-radius: 2px;
	background: var(--gradient-brand);
}
.menu-item-has-children:hover > .sub-menu,
.menu-item-has-children:focus-within > .sub-menu,
.menu-item-has-children.submenu-open > .sub-menu,
.menu-item-has-children > a[aria-expanded="true"] ~ .sub-menu {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}
.sub-menu .sub-menu { top: 0; left: 100%; border-top: 8px solid transparent; }
.sub-menu a {
	display: block;
	padding: 9px 14px;
	border-radius: var(--radius-sm);
	white-space: nowrap;
	color: var(--cream);
	transition: background 0.15s ease, color 0.15s ease, padding-left 0.15s ease;
}
.sub-menu a:hover,
.sub-menu a:focus-visible,
.sub-menu .menu-item-has-children:hover > a,
.sub-menu .menu-item-has-children:focus-within > a {
	background: var(--coral);
	color: var(--white);
	padding-left: 20px;
}
.sub-menu .menu-item-has-children > a { padding-right: 26px; }

@media (min-width: 900px) {
	/* Keeps the primary menu mathematically centered against the FULL
	   header width (not just the space left of the logo), so it stays
	   centered no matter how many menu items are added later or how wide
	   the logo/Donate button on either side happen to be — a 3-column
	   grid approach without an equal-width spacer column on the right
	   could only center the menu within the leftover space, not the true
	   page center. Only the menu list itself is centered (scoped to
	   .stem-header-inner so this never touches the same-named fallback
	   menu markup the footer can also render) — .nav-cta (the Donate
	   button) is left in .main-navigation's normal flex flow, which is
	   what keeps it pinned to the header's right edge via
	   .stem-header-inner's justify-content: space-between, same as
	   before. */
	.stem-header-inner .primary-menu {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
		/* A soft rounded "pill bar" container around the menu items
		   themselves (Ralph: "give me a better menu option it doesn't look
		   modern") -- previously the links floated directly on the header
		   background with nothing visually grouping them as one nav
		   control. No backdrop-filter here on purpose: it would create a
		   containing block for any fixed-position descendant, and while
		   .primary-menu itself has none today, keeping this consistent with
		   the no-backdrop-filter reasoning documented on .site-header above
		   avoids a future maintainer adding one and hitting that trap. */
		background: rgba(35, 72, 118, 0.05);
		border: 1px solid rgba(35, 72, 118, 0.08);
		border-radius: 999px;
		padding: 6px;
		gap: 2px;
	}
}

/* Mobile off-canvas menu: dim the rest of the page behind the slide-out
   panel while it's open, so it reads as a real overlay rather than a
   panel floating with nothing behind it. Pure CSS via :has() (already
   used elsewhere in this theme for the impact-card hover background,
   Baseline widely available since Dec 2023) -- no JS or extra markup
   needed. Stacked as content(auto) < backdrop(950) < .main-navigation
   panel(960) < .site-header(999) -- .main-navigation deliberately stays
   BELOW the header rather than above it: .site-header (logo,
   menu-toggle) has always painted above the panel's own z-index:auto
   default, which is what keeps the hamburger button clickable/visible
   on top of the open panel to close it again; giving the panel a
   z-index only has to clear the new backdrop, never the header. Never
   blocks clicks anywhere except closing the menu, which the existing
   "outside click" handler in main.js already does. */
body:has(.main-navigation.is-open)::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: 950;
	background: rgba(22, 48, 79, 0.45);
	animation: stem-nav-backdrop-in 0.25s ease;
}
@keyframes stem-nav-backdrop-in {
	from { opacity: 0; }
	to { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
	.site-header,
	.stem-header-inner,
	.site-branding img,
	.custom-logo {
		transition: none;
	}
	body:has(.main-navigation.is-open)::after {
		animation: none;
	}
}

@media (max-width: 900px) {
	.menu-toggle { display: flex; }
	.stem-mobile-donate-cta { display: inline-flex; }
	.stem-mobile-donate-cta .stem-btn { padding: 9px 18px; font-size: 0.85rem; }
	.main-navigation {
		position: fixed;
		inset: 0 0 0 auto;
		width: min(320px, 85vw);
		background: var(--white);
		flex-direction: column;
		align-items: flex-start;
		padding: 90px 28px 28px;
		box-shadow: -10px 0 40px rgba(0,0,0,0.15);
		transform: translateX(100%);
		transition: transform 0.25s ease;
		overflow-y: auto;
		/* Explicit z-index (rather than the default auto) so this panel
		   reliably paints above the dim backdrop above (950) regardless of
		   DOM order -- an auto z-index positioned element paints in the
		   SAME layer as z-index:0 elements, below anything with an
		   explicit positive z-index like the backdrop, which would
		   otherwise cover the open menu. Deliberately kept BELOW
		   .site-header's own z-index (999): see the backdrop rule's
		   comment above for why the header needs to stay on top. */
		z-index: 960;
	}
	.main-navigation.is-open { transform: translateX(0); }
	.primary-menu, .footer-menu { flex-direction: column; gap: 18px; width: 100%; }
	.nav-cta { flex-direction: column; width: 100%; margin-top: 24px; }
	.nav-cta .stem-btn { width: 100%; }
}

/* ---------- Hero ---------- */
.stem-hero {
	position: relative;
	/* Establishes a real stacking context for this section (contains the
	   mouse-reveal background layer, and the collage's positioned/z-index'd
	   photos and badges below, so none of it can ever compete with content
	   in a later section). isolation alone only controls stacking ORDER
	   though -- it doesn't stop content from visually overflowing past this
	   section's own box, which is the actual mechanism behind "shrinking
	   the browser window makes the impact-numbers section go behind the
	   hero image": at some in-between widths, the large collage photo
	   (sized by aspect-ratio against a container whose own height is a
	   fixed min-height, not calculated to match) renders taller than its
	   box and bleeds down into whatever comes after the hero. overflow:
	   hidden is the fix for THAT: it clips the hero's own contents to the
	   hero section's box, so nothing can bleed into .stem-impact-cards (or
	   any later section) regardless of viewport width. */
	isolation: isolate;
	overflow: hidden;
	padding-top: clamp(40px, 6vw, 80px);
	background: var(--stem-hero-bg, var(--warm));
}
.stem-hero-grid {
	position: relative;
	z-index: 1;
	display: grid;
	grid-template-columns: 1fr;
	gap: 48px;
	align-items: center;
}
@media (min-width: 900px) {
	.stem-hero-grid { grid-template-columns: 1.05fr 0.95fr; }
}
.stem-hero-headline { font-size: clamp(2.6rem, 6vw, 4.6rem); line-height: 1.02; margin-bottom: 0.4em; color: var(--stem-hero-heading, var(--ink)); }
.stem-hero-description { font-size: 1.15rem; max-width: 520px; color: var(--stem-hero-desc, var(--ink-2)); }
.stem-hero-description + .stem-hero-description { margin-top: 1em; }
.stem-hero-buttons { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 1.6em; }
/* A single visible button (the other toggled off under Customize > Homepage
   Hero / Featured Program) centers itself under the text instead of sitting
   flush left — shared by the hero's own buttons and the Featured Program
   button row, which reuses this same class. */
.stem-hero-buttons:has(> a:only-child) { justify-content: center; }

.stem-hero-collage {
	position: relative;
	min-height: 420px;
	/* Without an explicit z-index, `position: relative` alone does NOT
	   create a new stacking context, so this collage's positioned children
	   (photos/badges, all given a positive z-index below) could otherwise
	   escape into the page's root stacking context and paint above later,
	   non-positioned sections such as the impact-numbers row once the
	   layout narrows enough to change how those elements overlap.
	   `isolation: isolate` gives this element its own stacking context so
	   its children's z-index values only ever compete with each other,
	   never with content outside it — this is the fix for the
	   impact-numbers section appearing behind the hero photo when the
	   browser window is narrowed. */
	isolation: isolate;
}
.stem-collage-blob {
	position: absolute;
	width: 78%;
	height: 88%;
	background: var(--mint);
	border-radius: 50%;
	top: 4%;
	right: 0;
	z-index: 0;
}
.stem-collage-photo {
	position: absolute;
	border-radius: var(--radius-lg);
	overflow: hidden;
	box-shadow: var(--shadow-soft);
	border: 6px solid var(--white);
}
.stem-collage-photo img,
.stem-collage-photo video { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.4s ease; }
.stem-collage-photo:hover img,
.stem-collage-photo:hover video { transform: scale(1.04); }
.stem-hero-video { background: var(--navy); }
/* --stem-dodge-x/--stem-dodge-y are updated every animation frame by
   assets/js/main.js (only while the hero mouse-reveal effect is enabled
   and configured — see .stem-hero-reveal below) to push each photo away
   from a nearby cursor and spring it back once the cursor moves off; the
   var(...,0px) fallback keeps both photos perfectly still whenever that
   effect is off, disabled, or not yet in reach of JS. */
.stem-collage-photo-large { width: 74%; aspect-ratio: 4 / 5; top: 0; left: 0; z-index: 1; transform: rotate(-1.25deg) translate3d(var(--stem-dodge-x, 0px), var(--stem-dodge-y, 0px), 0); }
.stem-collage-photo-small { width: 46%; aspect-ratio: 4 / 5; bottom: -8%; right: 0; z-index: 2; transform: rotate(2deg) translate3d(var(--stem-dodge-x, 0px), var(--stem-dodge-y, 0px), 0); }
.stem-collage-badge {
	position: absolute;
	background: var(--white);
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-card);
	padding: 12px 18px;
	font-weight: 800;
	font-size: 0.85rem;
	color: var(--ink);
	z-index: 3;
	transform: rotate(-3deg);
}
.stem-collage-badge-label { top: 8%; left: -4%; color: var(--ink); }
.stem-collage-badge-label::before {
	content: "";
	display: inline-block;
	width: 8px;
	height: 8px;
	margin-right: 0.5em;
	border-radius: 50%;
	background: var(--coral);
}
.stem-collage-badge-impact { bottom: 6%; left: 8%; background: var(--white); color: var(--teal-dark); font-family: var(--font-serif); font-size: 1.1rem; font-weight: 400; transform: rotate(3deg); }

@media (max-width: 599px) {
	.stem-hero-collage { min-height: 340px; }
	.stem-collage-badge { font-size: 0.76rem; padding: 9px 12px; }
	.stem-collage-badge-label { left: 0; }
}

/* ---------- Hero mouse-reveal effect: soft-circle mask + dodge/bungee ---------- */
/* Direct child of .stem-hero itself (moved out of .stem-hero-collage at
   Ralph's request: "the entire top area should reveal the picture behind,
   not just the [collage] area") -- .stem-hero is already `position:
   relative; overflow: hidden;` and its own stacking context (isolation:
   isolate), so `position: absolute; inset: 0;` here sizes against the
   WHOLE hero section (copy column + collage column), and z-index: 0 keeps
   it safely behind .stem-hero-grid's z-index: 1 content. Three effects
   layer together here, all driven by assets/js/main.js:
   1. Restored 1.5.0-era behavior: the layer is masked to a soft circle
      that follows the cursor (--stem-reveal-x/--stem-reveal-y/
      --stem-reveal-r, a radial-gradient mask) — invisible except through
      that circle, closing back up to radius 0 once the mouse leaves the
      hero. The mousemove listener already measures the cursor against the
      whole hero section's own bounding rect (see main.js), so moving this
      layer to hero-section scope needed no JS coordinate changes.
   2. The two collage photos still dodge away from a nearby cursor, then
      "bungee" back with a light elastic overshoot — kept from the 1.6.0
      rework (--stem-dodge-x/--stem-dodge-y on
      .stem-collage-photo-large/-small above).
   3. NEW: the background image/video itself now also gets a subtle
      parallax "dodge" — it shifts gently opposite the cursor's position
      across the whole hero, then "bungees" back to center once the mouse
      leaves, reusing the same spring-physics pattern as #2 but scaled way
      down (it's a full-bleed background, not a small photo, so a large
      shift would just look like edges are showing). --stem-hero-bg-dodge-x/
      -y, set on .stem-hero-reveal-bg. The image is deliberately sized
      110% (see below) so this small shift never reveals a gap at the
      section's edge. */
.stem-hero-reveal {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	mask-image: radial-gradient(circle at var(--stem-reveal-x, 50%) var(--stem-reveal-y, 50%), #000 0, #000 var(--stem-reveal-r, 0px), transparent var(--stem-reveal-r, 0px));
	-webkit-mask-image: radial-gradient(circle at var(--stem-reveal-x, 50%) var(--stem-reveal-y, 50%), #000 0, #000 var(--stem-reveal-r, 0px), transparent var(--stem-reveal-r, 0px));
}
.stem-hero-reveal-bg {
	position: absolute;
	inset: -5%;
	width: 110%;
	height: 110%;
	object-fit: cover;
	display: block;
	transform: translate3d(var(--stem-hero-bg-dodge-x, 0px), var(--stem-hero-bg-dodge-y, 0px), 0);
}
/* Touch devices have no hovering mouse to drive this, and reduced-motion
   visitors shouldn't get a constantly-animating mask — same accessibility
   posture as the existing cursor trail elsewhere in this theme. */
@media (prefers-reduced-motion: reduce), (pointer: coarse) {
	.stem-hero-reveal { display: none; }
}

/* ---------- Impact cards ---------- */
.stem-impact-cards { padding-top: 0; background: var(--stem-impact-bg, transparent); }
.stem-impact-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 20px;
	margin-top: -20px;
}
@media (min-width: 768px) {
	.stem-impact-grid { grid-template-columns: repeat(4, 1fr); }
}
/* The grid item itself — .stem-impact-card-shuffle (see
   template-parts/impact-cards.php) — is what the mouse-driven "shuffle"
   dodge/bungee effect in assets/js/main.js actually moves (via
   --stem-impact-dodge-x/-y, mirroring the homepage hero's dodge physics),
   kept separate from .stem-impact-card so that motion never fights with
   the card's own hover-lift transition below. */
.stem-impact-card-shuffle {
	transform: translate3d(var(--stem-impact-dodge-x, 0px), var(--stem-impact-dodge-y, 0px), 0);
	/* `perspective` has to live on the PARENT of whatever gets the 3D
	   rotateY spin below, not on the rotating element itself, for the
	   rotation to actually look three-dimensional rather than flat. */
	perspective: 1400px;
}
/* Fast-mouse spin (Customize > Impact Numbers): a SEPARATE nested element
   from .stem-impact-card-shuffle above, specifically so the spin's
   transform+transition (set directly by assets/js/main.js when triggered)
   never fights the shuffle's own per-frame, transition-less dodge updates
   on the same element -- two different elements, two independent
   `transform` properties, no conflict either way. */
.stem-impact-card-spin {
	height: 100%;
}
.stem-impact-card {
	position: relative;
	min-width: 0; /* grid items default to min-width:auto (content-based), which let long
	                 label text force uneven 1fr columns and overflow the viewport on
	                 narrow phones even though body{overflow-x:hidden} was masking it. */
	/* All four cards stay the same size regardless of how much text is in
	   any one of them (Ralph: "ensure all the boxes are the same size") --
	   min-height (not a hard height) so a card is never visually shorter
	   than the others, while still never clipping unusually long edited
	   text. display:flex centers the text card's content vertically
	   inside that fixed-feeling box instead of just top-aligning it. */
	display: flex;
	flex-direction: column;
	justify-content: center;
	height: 100%;
	min-height: 190px;
	box-sizing: border-box;
	border-radius: var(--radius-md);
	padding: 28px 22px;
	text-align: center;
	box-shadow: var(--shadow-card);
	background: var(--white);
	transition: transform 0.25s ease, box-shadow 0.25s ease;
}
@media (min-width: 768px) {
	.stem-impact-card { min-height: 220px; }
}
.stem-impact-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-soft); }
.stem-impact-number { font-family: var(--font-serif); font-size: 2.3rem; font-weight: 400; margin: 0 0 4px; color: var(--ink); overflow-wrap: anywhere; }
@media (max-width: 599px) {
	/* At the 2-column mobile grid width, single unbreakable words (e.g. "Community")
	   can't wrap and forced the whole page wider than the viewport at the larger
	   editorial serif size above. Scaling the number down at this breakpoint keeps
	   every stat on one line without the overflow-wrap fallback having to kick in. */
	.stem-impact-number { font-size: 1.5rem; }
}
.stem-impact-label { margin: 0; font-size: 0.88rem; color: var(--ink-2); }
.stem-accent-coral { background: var(--coral-soft); }
.stem-accent-teal { background: var(--teal-soft); }
.stem-accent-navy { background: var(--mint); }
.stem-accent-sun { background: var(--sun-soft); }

/* A card only becomes an <a> when Customize > Impact Numbers has a
   destination link set for it (see template-parts/impact-cards.php) —
   reset link defaults so a clickable card looks identical to a plain one. */
a.stem-impact-card { display: block; text-decoration: none; color: inherit; cursor: pointer; }

/* Optional per-card photo (Customize > Impact Numbers) — object-fit:
   cover + a fixed aspect-ratio keeps the card's own footprint intact
   regardless of the photo's real dimensions ("do not let the images mess
   up the shape of the impact cards"). Shared by both the plain-link card
   markup and the flip-card front face below. A card showing a photo
   drops its text padding so the photo can sit edge-to-edge, clipped to
   the card's own rounded corners. */
/* flex: 1 (not a fixed aspect-ratio) so a photo card's image grows to fill
   its column-flex parent's full height -- the same min-height every other
   card gets above -- whatever the photo's own real dimensions are. */
.stem-impact-card-image { display: block; width: 100%; flex: 1 1 auto; min-height: 0; object-fit: cover; border-radius: inherit; }
a.stem-impact-card:has(.stem-impact-card-image) { padding: 0; overflow: hidden; }

/* Optional per-card video (Ralph: "the video are not playing in the
   impact, pathways, and tracks... make this for all cards on the home
   page"). Same flex-fill approach as the photo above, so a video takes
   over a card's footprint the same safe way a photo does. */
.stem-impact-card-video { display: block; width: 100%; height: 100%; flex: 1 1 auto; min-height: 0; border: 0; border-radius: inherit; }
iframe.stem-impact-card-video, video.stem-impact-card-video { object-fit: cover; }
a.stem-impact-card:has(.stem-impact-card-video),
.stem-impact-card-face-front:has(.stem-impact-card-video) { padding: 0; overflow: hidden; }
/* Instagram's own embed widget can't be forced into a fixed box the way a
   YouTube iframe or an uploaded file can — it always renders at its own
   fixed responsive width/aspect ratio. Rather than clipping or squashing
   it, this one card is let grow to whatever height Instagram's widget
   actually needs; every other card in a video-enabled grid still resizes
   uniformly (see .stem-impact-grid--has-video below). */
.stem-impact-card-face-front:has(.instagram-media),
a.stem-impact-card:has(.instagram-media) { overflow: visible; height: auto; }
.instagram-media { margin: 0 auto !important; }

/* Ralph: "resize the tile if necessary to fit the video, resize all cards
   uniformly" -- once ANY of the four cards has a video, every card in the
   grid (video or not) gets a taller, video-friendly minimum height so the
   whole row still reads as one consistent set of tiles. */
.stem-impact-grid--has-video .stem-impact-card { min-height: 260px; }
@media (min-width: 768px) {
	.stem-impact-grid--has-video .stem-impact-card { min-height: 300px; }
}

/* Click-to-flip (non-linked cards only — see template-parts/impact-cards.php
   for why a linked card never flips): a light 3D flip reveals the
   organization's logo on the back, then assets/js/main.js flips it back
   on its own after Customize > Impact Numbers > "Flip-back duration". The
   front face sizes the card in normal flow (its image, if any, or the
   number/label text); the back face is absolutely positioned to match
   that same box exactly, so nothing needs a guessed fixed height. */
.stem-impact-card-flippable {
	padding: 0;
	overflow: hidden;
	cursor: pointer;
	perspective: 1200px;
}
.stem-impact-card-flippable:focus-visible { outline: 3px solid var(--navy); outline-offset: 2px; }
.stem-impact-card-flip-inner {
	position: relative;
	/* Fills the flippable card's full height (the same min-height every
	   other card gets above), so both faces -- and the back face's
	   inset:0 in particular -- actually cover the whole card rather than
	   just however tall the front face's own content happens to be. */
	flex: 1 1 auto;
	width: 100%;
	min-height: 0;
	transition: transform 0.6s ease;
	transform-style: preserve-3d;
}
.stem-impact-card-flippable.is-flipped .stem-impact-card-flip-inner { transform: rotateY(180deg); }
.stem-impact-card-face { backface-visibility: hidden; }
.stem-impact-card-face-front {
	position: relative;
	height: 100%;
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: 28px 22px;
	box-sizing: border-box;
}
.stem-impact-card-face-front:has(.stem-impact-card-image) { padding: 0; }
.stem-impact-card-face-back {
	position: absolute;
	inset: 0;
	transform: rotateY(180deg);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
	box-sizing: border-box;
	background: var(--white);
}
.stem-impact-card-logo { display: block; max-width: 55%; max-height: 55%; object-fit: contain; }

@media (prefers-reduced-motion: reduce) {
	/* Keep the flip as a state change (it's a deliberate click, not
	   ambient motion) but swap the 3D rotation for a plain crossfade. */
	.stem-impact-card-flip-inner { transition: none; }
	.stem-impact-card-face-back { transform: none; opacity: 0; transition: opacity 0.2s ease; }
	.stem-impact-card-face-front { transition: opacity 0.2s ease; }
	.stem-impact-card-flippable.is-flipped .stem-impact-card-face-front { opacity: 0; }
	.stem-impact-card-flippable.is-flipped .stem-impact-card-face-back { opacity: 1; }
}

/* Hovering any impact card tints the whole page background to match that
   card's accent — purely decorative, so no reduced-motion override is
   needed beyond the transition itself being a color fade, not motion.
   :has() is Baseline widely available (since Dec 2023), so no fallback is
   needed; this is progressive enhancement only (nothing breaks without it). */
body:has(.stem-impact-card.stem-accent-coral:hover) { background-color: var(--coral-soft); }
body:has(.stem-impact-card.stem-accent-teal:hover) { background-color: var(--teal-soft); }
body:has(.stem-impact-card.stem-accent-navy:hover) { background-color: var(--mint); }
body:has(.stem-impact-card.stem-accent-sun:hover) { background-color: var(--sun-soft); }

/* ---------- Program pathways ---------- */
.stem-pathways-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 28px;
	margin-top: 40px;
}
@media (min-width: 768px) {
	.stem-pathways-grid { grid-template-columns: repeat(3, 1fr); }
}
.stem-pathway-card {
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 22px;
	box-shadow: none;
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.stem-pathway-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.stem-pathway-photo { position: relative; border-radius: var(--radius-md); overflow: hidden; margin-bottom: 18px; aspect-ratio: 4/3; }
.stem-pathway-photo img { width: 100%; height: 100%; object-fit: cover; }
.stem-pathway-photo iframe.stem-pathway-video,
.stem-pathway-photo video.stem-pathway-video { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }
/* Ralph: "resize the tile if necessary to fit the video, resize all cards
   uniformly" -- once any one pathway card has a video, every card's photo
   slot in this grid switches to a video-friendlier 16:9 ratio instead of
   the photo-only 4:3 above, video or not, so the row stays one consistent
   set of tiles. */
.stem-pathways-grid--has-video .stem-pathway-photo { aspect-ratio: 16/9; }
/* Instagram's own embed widget can't be forced into a fixed box the way a
   YouTube iframe or an uploaded file can — it always renders at its own
   fixed responsive width/aspect ratio. Rather than clipping or squashing
   it, this one card's photo slot is let grow to whatever height
   Instagram's widget actually needs; the other cards in the same grid
   still resize uniformly per the rule above. */
.stem-pathway-photo--video:has(.instagram-media) { aspect-ratio: auto; overflow: visible; }
.stem-pathway-photo--video .instagram-media { margin: 0 auto !important; }
.stem-pathway-grade {
	display: inline-block;
	color: var(--ink);
	background: var(--white);
	box-shadow: var(--shadow-card);
	font-weight: 800;
	text-transform: uppercase;
	font-size: 0.72rem;
	letter-spacing: 0.04em;
	padding: 0.35rem 0.7rem;
	border-radius: 999px;
	margin-bottom: 14px;
}
.stem-pathway-title { font-size: 1.5rem; margin-bottom: 8px; }
.stem-pathway-focus { color: var(--muted); margin: 0; }

/* ---------- Featured program ---------- */
.stem-featured-program { background: var(--stem-featured-bg, var(--warm)); border-radius: var(--radius-lg); margin: 0 auto; max-width: calc(var(--container-width) + 48px); }
.stem-pathways { background: var(--stem-pathways-bg, transparent); }
.stem-tracks { background: var(--stem-tracks-bg, transparent); }
.stem-mosaic { background: var(--stem-mosaic-bg, transparent); }
.stem-home-news { background: var(--stem-news-bg, transparent); }
.stem-featured-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 40px;
	align-items: center;
}
@media (min-width: 900px) {
	.stem-featured-grid { grid-template-columns: 1fr 1fr; }
}
.stem-featured-photo { position: relative; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-soft); aspect-ratio: 5/4; }
.stem-featured-photo img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.4s ease; }
.stem-featured-photo:hover img { transform: scale(1.05); }
.stem-featured-facts { display: flex; gap: 10px; flex-wrap: wrap; margin: 1.4em 0; padding: 0; }
.stem-featured-fact { background: var(--white); border-radius: var(--radius-sm); padding: 0.85rem 1rem; }
.stem-featured-fact dt { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; margin: 0; }
.stem-featured-fact dd { margin: 3px 0 0; font-weight: 700; color: var(--ink); }

/* ---------- Program tracks ---------- */
.stem-tracks-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 18px;
	margin-top: 40px;
}
@media (min-width: 768px) {
	.stem-tracks-grid { grid-template-columns: repeat(4, 1fr); }
}
.stem-track-card { text-align: center; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 18px 18px 22px; }
.stem-track-photo { border-radius: var(--radius-sm); overflow: hidden; aspect-ratio: 4/3; margin-bottom: 16px; box-shadow: none; }
.stem-track-photo img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; }
.stem-track-card:hover .stem-track-photo img { transform: scale(1.05); }
.stem-track-photo iframe.stem-track-video,
.stem-track-photo video.stem-track-video { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }
/* See the matching rule + comment on .stem-pathways-grid--has-video above. */
.stem-tracks-grid--has-video .stem-track-photo { aspect-ratio: 16/9; }
.stem-track-photo--video:has(.instagram-media) { aspect-ratio: auto; overflow: visible; }
.stem-track-photo--video .instagram-media { margin: 0 auto !important; }
.stem-track-title { font-size: 1.2rem; margin-bottom: 4px; }
.stem-track-tag { color: var(--teal-dark); font-weight: 700; text-transform: uppercase; font-size: 0.72rem; letter-spacing: 0.04em; margin: 0; }

/* ---------- Community mosaic ---------- */
.stem-mosaic-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 16px;
	margin-top: 40px;
}
@media (min-width: 768px) {
	.stem-mosaic-grid { grid-template-columns: repeat(3, 1fr); }
}
.stem-mosaic-item { border-radius: var(--radius-md); overflow: hidden; aspect-ratio: 1/1; box-shadow: var(--shadow-card); }
.stem-mosaic-item img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.4s ease; }
.stem-mosaic-item:hover img { transform: scale(1.08); }
.stem-mosaic-item-2, .stem-mosaic-item-5 { margin-top: 24px; }

/* ---------- Founder story ---------- */
.stem-founder { background: var(--stem-founder-bg, var(--warm)); }
.stem-founder-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 40px;
	align-items: center;
}
@media (min-width: 900px) {
	.stem-founder-grid { grid-template-columns: 0.8fr 1.2fr; }
}
.stem-founder-photo { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-soft); aspect-ratio: 4/5; max-width: 380px; }
.stem-founder-photo img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.4s ease; }
.stem-founder-photo:hover img { transform: scale(1.05); }
/* A big serif pull-quote treatment on the bio's opening line, with a
   coral drop-cap first letter -- matches the reference site's founder
   section without requiring the bio to actually be written as a <blockquote>
   (Ralph's bio text is arbitrary rich text from Customize > Founder Story). */
.stem-founder-bio p:first-of-type {
	font-family: var(--font-serif);
	font-size: clamp(1.5rem, 2.6vw, 2rem);
	line-height: 1.25;
	color: var(--ink);
}
.stem-founder-bio p:first-of-type::first-letter {
	float: left;
	color: var(--coral);
	font-size: 3.4em;
	line-height: 0.85;
	padding-right: 0.08em;
}
.stem-founder-bio p:last-child { margin-bottom: 0; }
.stem-founder-name { color: var(--ink); margin-top: 1.2em; }

/* ---------- Donation panel ---------- */
/* Background, border color, and photo scale all come from
   assets/css/main.css custom properties set inline on .stem-donate-panel
   itself (--stem-donate-bg / --stem-donate-border / --stem-donate-photo-scale
   — see template-parts/donation-panel.php), with the original coral used
   as the fallback for each so an install that hasn't touched these
   Customizer fields yet looks exactly like it always has. */
.stem-donate-photo {
	overflow: hidden;
	box-shadow: var(--shadow-card);
}
.stem-donate-photo img { display: block; width: 100%; height: auto; }

/* Layouts 1–2: photo spans the top of the whole panel, directly above the
   form+text card — the photo's bottom border and the card's top border
   are both removed so the two read as one continuously-bordered shape
   sharing a single boundary color. */
.stem-donate-photo-top {
	max-width: var(--stem-donate-photo-scale, 100%);
	margin: 0 auto;
	border: 3px solid var(--stem-donate-border, var(--coral));
	border-bottom: none;
	border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.stem-donate-photo-top + .stem-donate-card {
	border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Layouts 3–4: photo sits only above the text column, inside it — its own
   small self-contained bordered boundary in the same border color, rather
   than spanning the whole panel. */
.stem-donate-photo-text-col {
	max-width: var(--stem-donate-photo-scale, 100%);
	margin: 0 auto 24px;
	border: 3px solid var(--stem-donate-border, var(--coral));
	border-radius: var(--radius-md);
}

.stem-donate-card {
	background: var(--stem-donate-bg, var(--coral));
	border: 3px solid var(--stem-donate-border, var(--coral));
	border-radius: var(--radius-lg);
	padding: clamp(36px, 6vw, 64px);
	text-align: center;
	color: var(--white);
	max-width: 820px;
	width: 100%;
	margin: 0 auto;
	box-shadow: var(--shadow-soft);
	transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stem-donate-card:hover { transform: translateY(-3px); box-shadow: 0 26px 55px rgba(35, 72, 118, 0.28); }
.stem-donate-heading { color: var(--white); font-size: clamp(1.6rem, 3vw, 2.2rem); }
.stem-donate-copy { color: rgba(255,255,255,0.92); max-width: 560px; margin-left: auto; margin-right: auto; }
.stem-donate-card .stem-btn-navy { margin-top: 8px; }
.stem-donate-legal { font-size: 0.82rem; color: rgba(255,255,255,0.85); margin-top: 24px; margin-bottom: 0; }

/* Once a real Givebutter Form widget is embedded (Customize > Integrations
   > Givebutter Form widget ID), the panel switches from the centered
   text-only layout above to a two-column one — form on one side,
   heading/copy/legal text on the other (which side depends on the Layout
   option; form-left is the original default) — the form needs real width
   to render properly, so the centered/narrow constraints above are
   dropped only in this state. */
.stem-donate-card.has-form {
	max-width: none;
	text-align: left;
	display: grid;
	grid-template-columns: 1fr;
	gap: 32px;
	align-items: start;
}
@media (min-width: 900px) {
	.stem-donate-card.has-form { grid-template-columns: 1.05fr 1fr; }
	/* Layouts 2/4: form on the right instead of the left. Swapping the
	   grid item order (rather than duplicating markup) puts the text
	   column first visually while the form stays first in the DOM/source
	   order for the same reason it always has been. */
	.stem-donate-form-right .stem-donate-card.has-form { grid-template-columns: 1fr 1.05fr; }
	.stem-donate-form-right .stem-donate-form-col { order: 2; }
	.stem-donate-form-right .stem-donate-text-col { order: 1; }
}
/* Mobile: always show photo (already first, outside/inside these two
   columns depending on layout), then the heading/copy text, then the
   donation options (the Givebutter form, or the Donate button when no
   form is embedded) — regardless of which of the 4 desktop Layout options
   is selected. Below 900px the two columns above stack into one column
   already; .stem-donate-form-col is first in the source order (see
   template-parts/donation-panel.php), which put the form ahead of the
   text on every phone screen even for the "form-left" layouts. This is
   deliberately its own max-width rule rather than an edit to the
   min-width: 900px block above, so the desktop form-left/form-right
   behavior is untouched. */
@media (max-width: 899px) {
	.stem-donate-form-col { order: 2; }
	.stem-donate-text-col { order: 1; }
}
.stem-donate-form-col {
	background: var(--white);
	border-radius: var(--radius-md);
	padding: 16px;
}
.stem-donate-card.has-form .stem-donate-copy,
.stem-donate-card.has-form .stem-donate-legal { margin-left: 0; margin-right: 0; max-width: none; }
.stem-donate-card.has-form .stem-donate-legal { margin-top: 20px; }

/* ---------- Generic page header / content ---------- */
/* Minimal by design (see stem_rockaways_page_header() in
   inc/template-tags.php and Customize > Page Header): the H1 title is
   off by default, and this band's own padding is kept small regardless
   of whether the title is turned back on, so it never reclaims the
   original large title-band spacing. */
.stem-page-header { background: var(--stem-page-header-bg, var(--mint-soft)); padding: 20px 0; }
.stem-page-header .stem-kicker:first-child { margin-top: 0; }
/* Text size/font/color (Customize > Page Header) — --stem-page-header-scale
   multiplies the existing fluid clamp() sizes (1 = no change, matching the
   hero site-name text-size control's pattern); --stem-page-header-color is
   only ever set inline when an admin picks a color override, so both rules
   fall back to the theme's normal colors otherwise. Scoped to the title and
   subtitle only — the small uppercase kicker label keeps its own accent
   color/letter-spacing treatment regardless of this control, since it's a
   distinct decorative element rather than the page's "header text" itself. */
.stem-page-title { font-size: calc(clamp(2rem, 4vw, 2.8rem) * var(--stem-page-header-scale, 1)); margin: 0 0 0.3em; color: var(--stem-page-header-color, var(--ink)); }
.stem-page-title:first-child { margin-top: 0; }
.stem-page-subtitle { font-size: calc(1.1rem * var(--stem-page-header-scale, 1)); max-width: 720px; color: var(--stem-page-header-color, var(--ink-2)); margin: 0; }
.stem-page-header-font-heading .stem-page-title,
.stem-page-header-font-heading .stem-page-subtitle { font-family: var(--font-serif); }
.stem-page-header-font-body .stem-page-title,
.stem-page-header-font-body .stem-page-subtitle { font-family: var(--font-body); }
.stem-page-content { max-width: 820px; padding-top: 48px; padding-bottom: 48px; }
.stem-page-content h2 { margin-top: 1.4em; }
.stem-note { font-size: 0.92rem; color: var(--muted); }
.stem-legal-line { font-size: 0.88rem; color: var(--muted); border-top: 1px solid var(--line); padding-top: 16px; margin-top: 24px; }
.stem-callout { font-weight: 700; color: var(--ink); font-size: 1.15rem; }
.stem-chip {
	display: inline-block;
	background: var(--mint);
	border: none;
	border-radius: 999px;
	padding: 8px 18px;
	margin: 0 8px 8px 0;
	font-weight: 700;
	color: var(--navy);
	font-size: 0.85rem;
}
.stem-gallery-categories { margin: 24px 0 0; }

/* Redesigned (Ralph: "I need a better way to display the text") to match
   the same side-by-side photo+copy card treatment as Featured Program
   above, instead of a single centered column of plain text -- a card with
   its own background/shadow, photo and copy sitting side by side on
   wider screens, and left-aligned body text (a long centered paragraph is
   harder to read than a left-aligned one at this width). No wording
   changed, only the layout around it. */
.stem-scholarship { background: var(--stem-featured-bg, var(--warm)); }
.stem-scholarship-card {
	max-width: calc(var(--container-width) + 48px);
	margin: 0 auto;
	background: var(--white);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
	padding: clamp(28px, 5vw, 48px);
	display: grid;
	grid-template-columns: 1fr;
	gap: clamp(24px, 4vw, 40px);
	align-items: center;
}
@media (min-width: 768px) {
	.stem-scholarship-card { grid-template-columns: 0.9fr 1.1fr; }
}
.stem-scholarship-photo { margin-bottom: 0; }
.stem-scholarship-photo img {
	display: block;
	width: 100%;
	max-width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	margin: 0;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-soft);
}
.stem-scholarship-copy { text-align: left; }
.stem-scholarship-copy p { color: var(--ink-2); font-size: 1.05rem; line-height: 1.6; }

.stem-involved-card {
	background: var(--mint-soft);
	border-radius: var(--radius-lg);
	padding: clamp(28px, 5vw, 48px);
	text-align: center;
	margin-top: 32px;
	transition: box-shadow 0.25s ease, transform 0.25s ease;
}
.stem-involved-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-card); }

/* ---------- Contact ---------- */
/* Layout (Customize > Contact Page — Ralph: "give me options to display
   the get in touch portion... on the left, of the constant contact, on
   the right, or above or below"). A single flex row/column with the two
   possible blocks (.stem-contact-details, .stem-contact-cc-wrap) always
   in the same DOM order; "right"/"below" only ever flip the visual
   `order`, same technique already used for the Donation Panel's own
   Layout option (.stem-donate-form-right) -- so there's one markup
   structure to maintain, not five. */
.stem-contact-layout {
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: 48px;
	padding: 56px 0;
}
.stem-contact-details, .stem-contact-cc-wrap { flex: 1 1 320px; width: 100%; }
@media (min-width: 900px) {
	.stem-contact-layout-get_in_touch_left,
	.stem-contact-layout-get_in_touch_right {
		flex-direction: row;
	}
	.stem-contact-layout-get_in_touch_right .stem-contact-details { order: 2; }
	.stem-contact-layout-get_in_touch_right .stem-contact-cc-wrap { order: 1; }
}
.stem-contact-layout-get_in_touch_below .stem-contact-details { order: 2; }
.stem-contact-layout-get_in_touch_below .stem-contact-cc-wrap { order: 1; }
/* Only one of the two blocks actually rendered -- either "Constant
   Contact chooser alone" was picked, or a form/photo/detail on the other
   side just isn't configured yet. Center that single block instead of
   leaving it hugging the left edge or stretched full-width (Ralph: "make
   you best judgment for centering it on the page"). */
.stem-contact-layout-solo { align-items: center; }
.stem-contact-layout-solo > * { flex: 0 1 640px; max-width: 640px; }
.stem-contact-list { margin-bottom: 28px; }
.stem-contact-list li { margin-bottom: 10px; }

/* Constant Contact form selector (STEM Site Toolkit > Integrations —
   Ralph: "attempt override the look and match to the website theme if
   possible"). Constant Contact renders each form inside its own embedded
   iframe, which — being a different origin — this theme's CSS cannot
   reach inside of (its fonts/colors/spacing are set in Constant
   Contact's own account settings, not here). What CAN be themed, and is
   below: the dropdown itself, and the card the active form sits inside,
   so the surrounding page still reads as this site rather than a raw
   third-party embed dropped in unstyled. No top border/margin here any
   more -- previously this sat trailing below the two-column grid as an
   addendum; now it's one of the layout's own primary columns. */
.stem-contact-form-selector { width: 100%; }
.stem-contact-form-selector-label { display: block; font-weight: 700; margin-bottom: 10px; color: var(--ink); }
.stem-contact-form-select {
	font: inherit;
	font-weight: 600;
	color: var(--ink);
	background: var(--white);
	border: 2px solid var(--line);
	border-radius: var(--radius-sm);
	padding: 10px 16px;
	margin-bottom: 24px;
	min-width: 240px;
	cursor: pointer;
}
.stem-contact-form-select:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }
.stem-contact-form-panel {
	background: var(--mint-soft);
	border-radius: var(--radius-lg);
	padding: clamp(20px, 4vw, 32px);
}
/* Wraps into additional rows of up to 4 icons instead of spreading a long
   row of platforms (up to 13 are available under Customize > Social
   Media) all the way across the header/footer — max-width caps each row
   at exactly 4 icons' worth of width (4 × 40px icons + 3 × 12px gaps),
   and flex-shrink:0 on the icons themselves stops them from squeezing
   smaller to fit instead of wrapping. */
.stem-social-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; max-width: 196px; }
.stem-social-links a {
	display: flex; align-items: center; justify-content: center;
	width: 40px; height: 40px; border-radius: 50%;
	flex-shrink: 0;
	background: var(--mint); color: var(--navy);
}
.stem-social-links a:hover { background: var(--teal); color: var(--white); }
/* .stem-field / .stem-form-notice / .stem-form-success / .stem-form-error
   / .stem-form-honeypot were the on-site "Send a message" form's own
   styling (inc/contact-form.php) -- removed along with that file; nothing
   in the theme renders those classes any more (Ralph: "remove the send a
   message box an fields"). */

/* ---------- News / events ---------- */
.stem-news-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 28px;
	padding: 48px 0;
}
@media (min-width: 768px) {
	.stem-news-grid { grid-template-columns: repeat(3, 1fr); }
}
.stem-news-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-md); overflow: hidden; box-shadow: none; transition: transform 0.25s ease, box-shadow 0.25s ease; }
.stem-news-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.stem-news-card::before { content: none; }
.stem-news-thumb { display: block; overflow: hidden; background: linear-gradient(135deg, var(--teal-soft), var(--coral-soft)); }
.stem-news-thumb img { width: 100%; aspect-ratio: 4/3; object-fit: cover; transition: transform 0.4s ease; }
.stem-news-card:hover .stem-news-thumb img { transform: scale(1.06); }
.stem-news-title a:hover { color: var(--coral); }
.stem-news-body { padding: 20px; }
.stem-news-date { color: var(--muted); font-weight: 700; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; }
.stem-news-title { font-size: 1.25rem; margin: 8px 0 10px; }
.stem-news-title a { color: var(--ink); }
.stem-news-readmore { font-weight: 800; }

.stem-content-with-sidebar { display: grid; grid-template-columns: 1fr; gap: 40px; padding: 48px 0; }
@media (min-width: 900px) {
	.stem-content-with-sidebar { grid-template-columns: 2fr 1fr; }
}

/* ---------- Footer ---------- */
.site-footer { background: var(--stem-footer-bg, var(--ink)); color: var(--stem-footer-text, rgba(255,255,255,0.74)); padding-top: 64px; }

/* Footer newsletter band — sits above .stem-footer-grid so it reads as
   its own "take action" moment before the four link columns, per Ralph's
   "on top of the rest of the footer elements." Only the surrounding
   panel/spacing is styled here; the embedded Constant Contact form's own
   fields, button and colors are deliberately left alone (Ralph: "I'll
   change other colors from constant contact UI"), so this rule set never
   reaches into .ctct-inline-form's own children. */
.stem-footer-newsletter { padding-bottom: 40px; }
.stem-footer-newsletter-inner {
	display: flex;
	flex-direction: column;
	gap: 20px;
	background: rgba(255,255,255,0.06);
	border: 1px solid rgba(255,255,255,0.14);
	border-radius: var(--radius-md, 16px);
	padding: 28px 28px 32px;
}
.stem-footer-newsletter-heading {
	font-family: var(--font-serif);
	font-weight: 400;
	font-size: 1.4rem;
	color: var(--white);
	margin: 0 0 6px;
}
.stem-footer-newsletter-copy p { margin: 0; color: rgba(255,255,255,0.74); font-size: 0.95rem; max-width: 46ch; }
.stem-footer-newsletter-form { width: 100%; }
@media (min-width: 900px) {
	.stem-footer-newsletter-inner { flex-direction: row; align-items: center; justify-content: space-between; gap: 40px; padding: 32px 40px; }
	.stem-footer-newsletter-copy { flex: 1 1 auto; }
	.stem-footer-newsletter-form { flex: 0 1 420px; }
}

.stem-footer-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 36px;
	padding-bottom: 40px;
	border-bottom: 1px solid rgba(255,255,255,0.12);
}
@media (min-width: 768px) {
	.stem-footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
}
/* No white backdrop here: the logo is already a self-contained circular
   badge with its own ring/border built into the artwork, so adding a
   separate white circle behind it produced a visible double-ring/white
   halo against the dark footer. Just size and space it. */
.footer-brand .custom-logo, .footer-logo-fallback {
	max-height: 72px;
	margin-bottom: 14px;
}
.footer-slogan { font-family: var(--font-serif); font-weight: 400; font-size: 1.25rem; color: var(--white); margin-bottom: 6px; }
.footer-service-area { font-size: 0.9rem; color: rgba(255,255,255,0.6); }
.footer-contact-list { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; padding: 0; list-style: none; font-size: 0.9rem; }
.footer-contact-list a { color: rgba(255,255,255,0.78); }
.footer-contact-list a:hover { color: var(--coral-soft); }
.footer-contact-list li:last-child { color: rgba(255,255,255,0.6); }
.footer-heading { color: var(--stem-footer-heading, var(--sun)); font-family: var(--font-body); font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 16px; }
.footer-nav ul, .footer-actions-list { display: flex; flex-direction: column; gap: 10px; }
.footer-nav a, .footer-actions-list a { color: rgba(255,255,255,0.78); }
.footer-nav a:hover, .footer-actions-list a:hover { color: var(--coral-soft); }
.footer-connect .stem-social-links a { background: rgba(255,255,255,0.1); color: var(--white); }
.footer-connect .stem-social-links a:hover { background: var(--coral); }

.stem-seal-grid {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-start;
	gap: 24px;
	padding-top: 40px;
	padding-bottom: 40px;
	/* When every seal slot is blank, stem_rockaways_footer_seals() prints
	   nothing at all -- not even this wrapper -- so there is no leftover
	   40px top/bottom padding sitting in an empty box; see inc/template-tags.php. */
}
.stem-seal-item {
	width: 120px;
	height: 120px;
	background: var(--white);
	border-radius: var(--radius-sm);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 10px;
}
.stem-seal-item img { width: 100%; height: 100%; object-fit: contain; }

.footer-legal { text-align: center; padding: 24px 0 32px; font-size: 0.85rem; color: rgba(255,255,255,0.55); }
.footer-legal p { margin: 0 0 6px; }

/* ---------- Back to top ----------
   Deliberately anchored bottom-LEFT rather than bottom-right: this theme's
   own CSS/JS has no floating-position code for the Givebutter Donate
   button at all (confirmed by inspecting inc/template-tags.php and this
   file — the button widget renders inline wherever its tag is placed), so
   a "floating" donate button reported on the live site is coming from
   Givebutter's own widget script/dashboard settings, not from this theme,
   and floating widgets like that conventionally default to the
   bottom-right corner. Keeping our own back-to-top button on the opposite
   corner avoids the two ever overlapping regardless of exactly where
   Givebutter's script puts its own element. */
.stem-back-to-top {
	position: fixed;
	left: 24px;
	bottom: 24px;
	width: 48px;
	height: 48px;
	border-radius: 50%;
	background: var(--gradient-teal);
	color: var(--white);
	border: none;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	box-shadow: var(--shadow-soft);
	opacity: 0;
	visibility: hidden;
	transform: translateY(12px);
	transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease;
	z-index: 998;
}
.stem-back-to-top.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.stem-back-to-top:hover { background: var(--gradient-coral); }

/* ---------- Jotform embeds (Enroll / Enrollment Form pages) ---------- */
.stem-jotform-embed {
	border-radius: var(--radius-md);
	overflow: hidden;
	box-shadow: var(--shadow-card);
	margin: 24px 0;
}
.stem-jotform-embed iframe { display: block; }

/* ---------- Enrollment Form page ---------- */
.stem-enrollment-announcement { background: var(--mint-soft); border-radius: var(--radius-md); padding: clamp(20px, 4vw, 36px); margin-bottom: 24px; }
.stem-enrollment-announcement p:last-child { margin-bottom: 0; }
.stem-enrollment-downloads { display: flex; gap: 12px; flex-wrap: wrap; margin: 20px 0; }

/* ---------- Homepage News & Events section ---------- */
.stem-home-news { background: var(--warm); }
.stem-home-news-intro { max-width: 640px; margin: -12px auto 0; color: var(--ink-2); }
.stem-home-news-empty { text-align: center; color: var(--muted); padding: 24px 0 0; }

/* ---------- Givebutter widgets ---------- */
.stem-givebutter-form-embed { margin: 24px 0; }
.stem-givebutter-btn-wrap { display: inline-flex; }

/* ---------- Utility ---------- */
.stem-page-extra-content { padding: 40px 0; }
.alignwide { max-width: var(--container-width); margin-left: auto; margin-right: auto; }
.alignfull { max-width: none; }

/* Grid items default to min-width:auto (their content's natural width),
   which can quietly force a grid's "equal" 1fr columns to become uneven
   and overflow the viewport on narrow phones -- exactly what the
   impact-cards grid did once body's own overflow-x:hidden (removed above,
   since it broke the sticky header) stopped silently clipping it. Letting
   every grid item shrink below its content width is the standard fix. */
.stem-hero-grid > *, .stem-impact-grid > *, .stem-pathways-grid > *,
.stem-featured-grid > *, .stem-tracks-grid > *, .stem-mosaic-grid > *,
.stem-founder-grid > *, .stem-contact-layout > *, .stem-news-grid > *,
.stem-content-with-sidebar > *, .stem-footer-grid > * {
	min-width: 0;
}

/* Never allow horizontal scroll regardless of content.
   IMPORTANT: overflow-x must live on <html> only, not <body>. Setting a
   non-visible overflow on <body> makes it a scroll container of its own,
   which breaks position:sticky on .site-header (its sticky positioning
   would then be measured against body's box instead of the viewport,
   which is exactly why the header wasn't staying visible on scroll). */
html { max-width: 100%; overflow-x: hidden; }
body { max-width: 100%; }

/* ---------- Cursor logo trail (site-wide) ----------
   A small copy of the logo that follows the pointer with a soft, lagging
   "chase" motion (each frame it eases a fraction of the way toward the
   cursor, so the faster the cursor moves the more ground it has to make
   up and the more visible the lag becomes), plus a short comet-tail of
   gradient dots trailing behind it for a richer, more dynamic feel.
   Everything here is pointer-events:none so it never blocks clicks,
   hover, or focus, and JS only turns it on for mouse/trackpad users
   (matchMedia '(pointer: fine)') who haven't asked for reduced motion —
   see the "Cursor trail" block in main.js. The CSS-only reduced-motion
   rule below is a second, independent guard. */
.stem-cursor-trail {
	position: fixed;
	top: 0;
	left: 0;
	width: 0;
	height: 0;
	z-index: 9990;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.35s ease;
}
.stem-cursor-trail.is-active { opacity: 1; }
.stem-cursor-trail-logo,
.stem-cursor-trail-dot {
	position: absolute;
	top: 0;
	left: 0;
	border-radius: 50%;
	will-change: transform;
	transform: translate3d(-50%, -50%, 0);
}
.stem-cursor-trail-logo {
	/* The theme's global `img { max-width:100%; height:auto; }` reset (near
	   the top of this file) resolves that 100% against this element's
	   containing block -- .stem-cursor-trail, which is deliberately
	   width:0/height:0 -- so it must be explicitly cancelled here or the
	   logo collapses to almost nothing. */
	max-width: none;
	width: 38px;
	height: 38px;
	object-fit: contain;
	/* No white backdrop: the logo is already a self-contained circular
	   badge, so a separate white coin behind it just produced a visible
	   double-ring/white halo. The soft shadow below still gives it a bit
	   of lift as it trails across busy backgrounds. */
	box-shadow: 0 4px 18px rgba(35, 72, 118, 0.28);
}
.stem-cursor-trail-dot {
	/* Same override as .stem-cursor-trail-logo above, and for the same
	   reason -- these are now small copies of the logo image (Customize >
	   Cursor Logo Trail), not plain gradient-filled circles. */
	max-width: none;
	object-fit: contain;
	box-shadow: 0 3px 12px rgba(35, 72, 118, 0.22);
}
/* Each dot in the tail is a little smaller and fainter than the one
   before it, so the trail visibly tapers off rather than looking like a
   row of identical dots. Sized for up to 5 trailing dots (the maximum
   trail-length option); a shorter trail simply doesn't print the later img
   elements, so their rules never match anything. */
.stem-cursor-trail-dot:nth-of-type(1) { width: 20px; height: 20px; opacity: 0.9; }
.stem-cursor-trail-dot:nth-of-type(2) { width: 15px; height: 15px; opacity: 0.7; }
.stem-cursor-trail-dot:nth-of-type(3) { width: 11px; height: 11px; opacity: 0.5; }
.stem-cursor-trail-dot:nth-of-type(4) { width: 8px;  height: 8px;  opacity: 0.35; }
.stem-cursor-trail-dot:nth-of-type(5) { width: 6px;  height: 6px;  opacity: 0.22; }
@media (prefers-reduced-motion: reduce), (pointer: coarse) {
	.stem-cursor-trail { display: none; }
}

/* ---------- Board Members (About page, below Founder Story) ---------- */
/* Up to 10 slots (Customize > Board Members); a slot only ever renders
   with a real photo (see template-parts/board-members.php), and the whole
   section prints nothing at all if none are filled in. Three layout
   choices share the same card markup and just restyle it differently —
   "Pop Cards" mirrors the homepage impact-card lift+shadow treatment
   Ralph asked to match, "Tilt Gallery" is a playful scrapbook-style
   alternating rotation, and "Circle Avatars" is a simple friendly grid of
   circular portraits. */
/* auto-fit (not a fixed repeat(N, 1fr)) + justify-content: center is what
   actually centers the board on the page: with a fixed column count, fewer
   members than columns left empty tracks sitting on the right, visibly
   pushing the real photos to the left instead of centering them (Ralph:
   "the images of board should be centered on the page"). With auto-fit and
   a capped card width, the grid only ever creates as many tracks as there
   are members to show (up to what fits the row), and justify-content:
   center centers that actual group of cards within the section — true
   regardless of whether there are 1 or all 10 slots filled in. */
.stem-board-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(150px, 200px));
	justify-content: center;
	gap: 28px;
	margin-top: 40px;
}
.stem-board-card { min-width: 0; text-align: center; }
.stem-board-photo {
	position: relative;
	overflow: hidden;
	aspect-ratio: 1 / 1;
	margin-bottom: 14px;
	background: var(--mint-soft);
}
.stem-board-photo img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.4s ease; }
.stem-board-name { font-weight: 800; color: var(--ink); margin: 0 0 2px; }
.stem-board-affiliation { color: var(--ink-2); margin: 0; }
.stem-board-name.stem-board-text-small { font-size: 0.9rem; }
.stem-board-name.stem-board-text-medium { font-size: 1.05rem; }
.stem-board-name.stem-board-text-large { font-size: 1.3rem; }
.stem-board-affiliation.stem-board-text-small { font-size: 0.78rem; }
.stem-board-affiliation.stem-board-text-medium { font-size: 0.9rem; }
.stem-board-affiliation.stem-board-text-large { font-size: 1.05rem; }

/* Click-to-flip (Customize > Board Members > "Flip-back duration") — the
   same interaction as the homepage impact cards (see
   .stem-impact-card-flippable above), reusing the identical mechanics
   (perspective on the flippable card itself, the actual rotateY on its
   -flip-inner child, backface-visibility:hidden on both faces, the back
   face absolutely positioned to match) but under board-prefixed class
   names so this stays clearly its own thing from the impact cards.
   Deliberately does NOT touch .stem-board-photo or any of the three
   gallery layout styles below — the flip only adds a second face behind
   the existing photo, never changes how the photo itself displays. */
.stem-board-card-flippable {
	cursor: pointer;
	perspective: 1200px;
}
.stem-board-card-flippable:focus-visible { outline: 3px solid var(--navy); outline-offset: 2px; }
.stem-board-flip-inner {
	position: relative;
	transition: transform 0.6s ease;
	transform-style: preserve-3d;
}
.stem-board-card-flippable.is-flipped .stem-board-flip-inner { transform: rotateY(180deg); }
.stem-board-flip-face { backface-visibility: hidden; }
.stem-board-flip-face-back {
	position: absolute;
	inset: 0;
	transform: rotateY(180deg);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
	box-sizing: border-box;
	background: var(--white);
	border-radius: inherit;
}
.stem-board-flip-logo { display: block; max-width: 55%; max-height: 55%; object-fit: contain; }

@media (prefers-reduced-motion: reduce) {
	/* Same posture as the impact cards: keep the flip as a state change
	   (a deliberate click, not ambient motion) but swap the 3D rotation
	   for a plain crossfade. */
	.stem-board-flip-inner { transition: none; }
	.stem-board-flip-face-back { transform: none; opacity: 0; transition: opacity 0.2s ease; }
	.stem-board-flip-face-front { transition: opacity 0.2s ease; }
	.stem-board-card-flippable.is-flipped .stem-board-flip-face-front { opacity: 0; }
	.stem-board-card-flippable.is-flipped .stem-board-flip-face-back { opacity: 1; }
}

/* Layout 1 (default): "pop" cards, matching the homepage impact-card
   lift-on-hover treatment Ralph specifically asked to mirror. */
.stem-board-layout-pop_cards .stem-board-card {
	background: var(--white);
	border-radius: var(--radius-lg);
	padding: 16px 14px 20px;
	box-shadow: var(--shadow-card);
	transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.stem-board-layout-pop_cards .stem-board-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-soft); }
.stem-board-layout-pop_cards .stem-board-photo { border-radius: var(--radius-md); }
.stem-board-layout-pop_cards .stem-board-card:hover .stem-board-photo img { transform: scale(1.06); }

/* Layout 2: a playful, slightly-tilted scrapbook gallery — cards alternate
   rotation direction and straighten out on hover. */
.stem-board-layout-tilt_gallery .stem-board-card {
	background: var(--white);
	border: 6px solid var(--white);
	box-shadow: var(--shadow-soft);
	padding-bottom: 8px;
	transform: rotate(-2deg);
	transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stem-board-layout-tilt_gallery .stem-board-card:nth-child(even) { transform: rotate(2deg); }
.stem-board-layout-tilt_gallery .stem-board-card:nth-child(3n) { transform: rotate(-1deg); }
.stem-board-layout-tilt_gallery .stem-board-card:hover {
	position: relative;
	z-index: 2;
	transform: rotate(0deg) translateY(-6px);
	box-shadow: var(--shadow-card);
}

/* Layout 3: simple, friendly circular portraits. */
.stem-board-layout-circle_avatars .stem-board-photo {
	max-width: 160px;
	margin-left: auto;
	margin-right: auto;
	border-radius: 50%;
	border: 4px solid var(--mint);
	transition: transform 0.25s ease, border-color 0.25s ease;
}
.stem-board-layout-circle_avatars .stem-board-card:hover .stem-board-photo { transform: translateY(-4px) scale(1.05); border-color: var(--coral); }

/* ---------- Hover effects: reduced-motion override ----------
   The card-lift and photo-zoom hovers added throughout this file (impact
   cards, pathway/track/news cards, the donate and get-involved panels, the
   featured/founder/mosaic/hero-collage photos, and the site logo) all move
   or scale something. Anyone who has asked their OS for reduced motion
   still gets the hover's color/shadow feedback, just without the motion,
   consistent with how the cursor trail above is already handled. */
@media (prefers-reduced-motion: reduce) {
	.stem-btn:hover,
	.site-branding a:hover,
	.stem-collage-photo:hover img,
	.stem-collage-photo:hover video,
	.stem-impact-card:hover,
	.stem-pathway-card:hover,
	.stem-featured-photo:hover img,
	.stem-track-card:hover .stem-track-photo img,
	.stem-mosaic-item:hover img,
	.stem-founder-photo:hover img,
	.stem-donate-card:hover,
	.stem-involved-card:hover,
	.stem-news-card:hover,
	.stem-news-card:hover .stem-news-thumb img,
	.stem-board-layout-pop_cards .stem-board-card:hover,
	.stem-board-layout-pop_cards .stem-board-card:hover .stem-board-photo img,
	.stem-board-layout-tilt_gallery .stem-board-card:hover,
	.stem-board-layout-circle_avatars .stem-board-card:hover .stem-board-photo {
		transform: none;
	}
}

/* Fallback top offset for any jump to a ".stem-scrollspy-section" that
   doesn't go through the dots' own JS click handler (e.g. a keyboard user
   tabbing to a same-page link, or a browser restoring a #hash on load) —
   keeps the section's own top clear of the sticky header instead of
   letting it land underneath it. --stem-header-h is kept up to date by
   assets/js/main.js (measured from the real header, not guessed), with a
   safe static fallback here in case JS hasn't run yet. */
:root { --stem-header-h: 92px; }
.stem-scrollspy-section { scroll-margin-top: calc(var(--stem-header-h) + 16px); }

/* ---------- Side navigation dots (homepage only) ----------
   One small dot per homepage section actually on the page (built by
   assets/js/main.js from whatever ".stem-scrollspy-section" elements it
   finds, so this automatically matches whichever sections are enabled and
   however they're ordered under Customize > Homepage Sections — nothing
   here needs to be kept in sync by hand). Sits a little in from the edge
   rather than flush against it, and stays deliberately quiet until the
   mouse is nearby: a plain [hidden] element (no JS) or an empty one (no
   sections found) renders nothing, so there's no broken-looking column on
   a page where this never activates. */
.stem-section-dots {
	position: fixed;
	right: 20px;
	top: 50%;
	transform: translateY(-50%);
	z-index: 950;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
	padding: 10px 6px;
}
.stem-section-dots[hidden] { display: none; }

.stem-dot {
	position: relative;
	width: var(--stem-dot-size, 10px);
	height: var(--stem-dot-size, 10px);
	padding: 0;
	border-radius: 50%;
	border: none;
	background: rgba(35, 72, 118, 0.28); /* --navy at low opacity: quiet by default */
	cursor: pointer;
	transition: transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

/* Alternate "bars" style (Customize > Side Navigation Dots > Dot style):
   short rounded rectangles instead of round dots. Height still scales with
   the same Dot size setting; width stays fixed and slim so it reads as a
   bar rather than a stretched circle. */
.stem-dots-style-bars .stem-dot {
	width: 6px;
	height: calc(var(--stem-dot-size, 10px) * 2);
	border-radius: 3px;
}

/* "Before" — the whole column wakes up a little as the mouse approaches,
   ahead of actually touching any one dot. */
.stem-section-dots.is-near .stem-dot {
	background: rgba(35, 72, 118, 0.5);
	transform: scale(1.15);
}

/* "On hover" — the dot the mouse is actually over reacts further and its
   label appears. */
.stem-dot:hover,
.stem-dot:focus-visible {
	background: var(--teal);
	transform: scale(1.5);
}
.stem-dot:hover .stem-dot-label,
.stem-dot:focus-visible .stem-dot-label {
	opacity: 1;
	transform: translateX(0);
}

/* "When clicked" — a brief press-down before the page scrolls. */
.stem-dot:active {
	transform: scale(0.85);
	background: var(--coral);
}

/* The section currently in view: filled and a touch larger, persistently
   (not just on hover), so "which section am I in" is answerable at a
   glance. Fill color depends on the color-mode option (Customize > Side
   Navigation Dots) — solid by default, with the original gradient still
   available as a choice. Solid colors are reused from elsewhere in the
   theme's palette on purpose (teal/coral/navy each already appear in
   several other places), not new ones. */
.stem-dot.is-current {
	box-shadow: 0 0 0 3px var(--coral-soft);
	transform: scale(1.3);
}
.stem-dots-color-gradient .stem-dot.is-current { background: var(--gradient-coral-teal); }
.stem-dots-color-solid_teal .stem-dot.is-current { background: var(--teal); }
.stem-dots-color-solid_coral .stem-dot.is-current { background: var(--coral); box-shadow: 0 0 0 3px var(--soft-teal); }
.stem-dots-color-solid_navy .stem-dot.is-current { background: var(--navy); box-shadow: 0 0 0 3px var(--soft-teal); }
.stem-section-dots.is-near .stem-dot.is-current,
.stem-dot.is-current:hover {
	transform: scale(1.5);
}

/* The hover/focus "flyout" label naming the section. Base (compact) style
   below; the "large" and "card" size options (Customize > Side Navigation
   Dots) make it pop out more, per size. */
.stem-dot-label {
	position: absolute;
	right: 100%;
	top: 50%;
	transform: translate(6px, -50%);
	margin-right: 12px;
	white-space: nowrap;
	background: var(--navy);
	color: var(--white);
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.01em;
	padding: 4px 10px;
	border-radius: var(--radius-sm, 6px);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease, transform 0.15s ease;
}
.stem-dots-label-large .stem-dot-label {
	font-size: 0.85rem;
	font-weight: 700;
	padding: 8px 16px;
	border-radius: var(--radius-sm);
	margin-right: 14px;
}
.stem-dots-label-card .stem-dot-label {
	font-size: 0.95rem;
	font-weight: 700;
	padding: 12px 20px;
	border-radius: var(--radius-md);
	margin-right: 16px;
	box-shadow: var(--shadow-card);
	background: var(--white);
	color: var(--navy);
}

/* Footer contrast: once the dots column has scrolled down far enough to
   sit over the dark footer background (assets/js/main.js toggles
   .is-over-footer via an IntersectionObserver on the footer), lighten the
   resting/near dots and flip the flyout label to a light pill so both stay
   readable against the dark background. Only applied when the
   "automatically lighten..." option is on. */
.stem-dots-footer-contrast.is-over-footer .stem-dot {
	background: rgba(255, 255, 255, 0.4);
}
.stem-dots-footer-contrast.is-over-footer.is-near .stem-dot {
	background: rgba(255, 255, 255, 0.7);
}
.stem-dots-footer-contrast.is-over-footer .stem-dot.is-current {
	box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.4);
}
.stem-dots-footer-contrast.is-over-footer .stem-dot-label {
	background: var(--white);
	color: var(--navy);
}

/* Left-edge placement (Customize > Side Navigation Dots > Screen side) —
   mirrors the default right-edge position, flipping which side the
   flyout label pops out on (right of the dots, opening left-to-right)
   so it still opens toward empty space rather than back over the dots
   themselves. */
.stem-dots-position-left {
	left: 20px;
	right: auto;
}
.stem-dots-position-left .stem-dot-label {
	right: auto;
	left: 100%;
	margin-right: 0;
	margin-left: 12px;
	transform: translate(-6px, -50%);
}
.stem-dots-position-left.stem-dots-label-large .stem-dot-label { margin-right: 0; margin-left: 14px; }
.stem-dots-position-left.stem-dots-label-card .stem-dot-label { margin-right: 0; margin-left: 16px; }

/* Supplementary, mouse-driven navigation — hide on touch/narrow layouts
   where there's no "hovering nearby" to react to and the vertical space
   is needed for content, same posture as the cursor trail above. */
@media (max-width: 900px), (pointer: coarse) {
	.stem-section-dots { display: none; }
}

@media (prefers-reduced-motion: reduce) {
	.stem-section-dots.is-near .stem-dot,
	.stem-dot:hover,
	.stem-dot:focus-visible,
	.stem-dot:active,
	.stem-dot.is-current,
	.stem-section-dots.is-near .stem-dot.is-current,
	.stem-dot.is-current:hover {
		transform: none;
	}
}
