/* ============================================
   NJS THEME — Design Token Layer + Base Styles
   NJ Swingsets & Playgrounds — njswingsets-2026

   Locked design tokens: 08-UI-SPEC.md (D-01/D-02/D-03)
   Structural convention: docs/county-pages-html/njs-components.css
   (banner comments + :root token block + scoped base rules —
   token VALUES here are UI-SPEC's, not that file's older palette)

   3 core colors + neutrals (D-03) / 2 fonts (D-02) / 4 font sizes,
   2 weights (UI-SPEC Typography) — no exceptions.
   ============================================ */

/* ============================================
   DESIGN TOKENS
   ============================================ */
:root {
	/* Color — 3 core colors + neutrals (D-03). The brand kit's old 5-accent
	   checkout/sale/search-heading colors are dropped per D-03 — do not
	   reintroduce them; see 08-UI-SPEC.md Color section for the full list. */
	--color-primary: #f48e2e;   /* orange — reserved for primary CTAs only */
	--color-accent: #76c355;    /* green — secondary/lower-emphasis actions */
	--color-sale: #d9412e;      /* red — sale badge + destructive/error states */
	--color-ink: #1a1a1a;       /* body/heading text */
	--color-bg: #ffffff;        /* page background, card surfaces */
	--color-neutral: #f5f5f2;   /* light neutral section background */
	--color-divider: #cfcfcf;   /* hairline dividers */

	/* Typography — Barlow Condensed (headings/buttons/nav; Oswald until
	   2026-09-26), Inter (body/UI chrome).
	   Never the heading font for body text (D-02 hard constraint).
	   'Oswald Fallback'/'Inter Fallback' (13-14 Task 3, PERF-02/D-08 CLS fix)
	   are metric-matched local-only @font-face declarations in fonts.css —
	   they render with Oswald/Inter's real box-model metrics before the
	   webfont itself arrives, so font-display:swap causes no layout shift. */
	--font-heading: 'Barlow Condensed', 'Barlow Condensed Fallback', sans-serif; /* was 'Oswald', 'Oswald Fallback' until 2026-09-26 */
	--font-body: 'Inter', 'Inter Fallback', sans-serif; /* single swap point per D-02 discretion */

	/* Fluid type scale — 4 sizes across the theme, plus --step-subheading for
	   H3 inside page content (added 2026-09-26) */
	--step-display: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);     /* H1 — hero, page titles */
	--step-heading: clamp(1.375rem, 1.1rem + 1.2vw, 2rem);    /* H2/H3 — section/card titles */
	--step-subheading: clamp(1.25rem, 1.1rem + 0.5vw, 1.4375rem); /* H3 inside page content (.njs-body) — 20px to 23px, 2026-09-26: at --step-heading H3s matched H2s and the page had no hierarchy */
	--step-body: clamp(1rem, 0.95rem + 0.2vw, 1.0625rem);     /* body copy */
	--step-label: 14px;                                        /* nav links, meta, badges, buttons, form labels */

	/* Spacing scale — multiples of 4 */
	--space-xs: 4px;
	--space-sm: 8px;
	--space-md: 16px;
	--space-lg: 24px;
	--space-xl: 32px;
	--space-2xl: 48px;
	--space-3xl: 64px;

	/* Layout */
	--container-max: 1680px; /* FLUID cap: content grows with the viewport (min(1680, 94%)) to match WillyGoat, which measures ~1360 @1440 and ~1680 @1920. Full-width header/hero/bands are separate. Long-form text uses --text-measure. */
	--text-measure: 45rem;   /* 720px, LOCKED 2026-09-27, see 260927-cqn-DECISIONS.md */

	/* Border radius scale — buttons/inputs 4px, cards/panels 8px, badges/pills 9999px */
	--radius-sm: 4px;
	--radius-md: 8px;
	--radius-pill: 9999px;
}

/* ============================================
   BASE / RESET
   ============================================ */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background-color: var(--color-bg);
	color: var(--color-ink);
	font-family: var(--font-body);
	font-weight: 400;
	font-size: var(--step-body);
	line-height: 1.6;
}

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

a {
	color: inherit;
}

h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: var(--font-heading);
	font-weight: 500;
	line-height: 1.2;
	margin: 0 0 var(--space-md);
}

h1 {
	font-size: var(--step-display);
	line-height: 1.15;
}

h2,
h3 {
	font-size: var(--step-heading);
}

p {
	margin: 0 0 var(--space-md);
}

/* ============================================
   LAYOUT UTILITIES
   ============================================ */
.njs-container {
	/* Fluid: grow with the viewport up to the cap, ~3% gutters each side —
	   matches WillyGoat (≈1360 @1440, ≈1680 @1920). Was a fixed 1200/1400 cap
	   that left too much edge whitespace on wide monitors. */
	width: min(var(--container-max), 94%);
	margin-inline: auto;
}

.njs-main {
	padding-block: var(--space-xl);
}

/* ============================================
   ICON BUTTON BASE (44px tap-target floor — UI-SPEC Spacing exceptions)
   ============================================ */
.njs-icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: var(--space-xs);
	background: none;
	border: none;
	color: var(--color-ink);
	text-decoration: none;
	cursor: pointer;
}

.njs-icon {
	width: 22px;
	height: 22px;
}

/* ============================================
   ANNOUNCEMENT BAR
   ============================================ */
.njs-announcement-bar {
	background-color: var(--color-neutral);
}

.njs-announcement-bar__text {
	margin: 0;
	padding-block: var(--space-sm);
	text-align: center;
	font-size: var(--step-label);
	color: var(--color-ink);
}

/* ============================================
   DESKTOP HEADER (≥1025px — collapses to mobile header at ≤1024px)
   Sticky + condense-on-scroll (brief item 3): stays pinned to the
   viewport top, shrinks after ~100px of scroll (nav.js toggles
   html.njs-is-scrolled — see MOBILE HEADER + CONDENSE rules below).
   ============================================ */
.njs-site-header {
	background-color: var(--color-bg);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
	position: sticky;
	top: 0;
	z-index: 20;
	transition: box-shadow 200ms ease;
}

.njs-site-header__inner {
	display: flex;
	align-items: center;
	gap: var(--space-lg);
	min-height: 88px;
	transition: min-height 200ms ease;
	/* Full-width header: span the viewport (override the fluid .njs-container
	   width) so the logo sits near the left edge and phone/cart near the right,
	   with the nav spread across — the full-width menu Jay asked for. */
	width: 100%;
	max-width: none;
	padding-inline: clamp(1rem, 3vw, 3rem);
}

.njs-site-header__logo {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	flex-shrink: 0;
}

.njs-site-header__logo-img {
	height: 48px;
	width: auto;
	transition: height 200ms ease;
}

html.njs-is-scrolled .njs-site-header__inner {
	min-height: 60px;
}

html.njs-is-scrolled .njs-site-header__logo-img {
	height: 34px;
}

html.njs-is-scrolled .njs-site-header {
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.njs-primary-nav {
	flex: 1 1 auto;
}

.njs-primary-nav__list {
	display: flex;
	align-items: center;
	gap: var(--space-lg);
	list-style: none;
	margin: 0;
	padding: 0;
}

/* No position:relative here — the mega-dropdown panel positions itself
   relative to .njs-site-header (a full-width positioned ancestor) so its
   `left: 50%; transform: translateX(-50%); width: 100vw;` centers against
   the viewport, not against this narrow <li>'s own box (which would clip
   most of the panel off-screen — found + fixed during this plan's Task 3
   staging screenshot review). */

.njs-primary-nav__list > li > a,
.njs-primary-nav__list > li > .njs-nav-trigger,
.njs-primary-nav__list > li > .njs-nav-label {
	display: inline-block;
	padding-block: var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	text-decoration: none;
	color: var(--color-ink);
	border-bottom: 2px solid transparent;
}

/* Phase 29 (D9): an open-only main-row item is a disclosure <button>
   (inc/nav-walker.php njs_nav_item_markup()). It must look exactly like the
   link labels beside it, so only the UA button chrome is reset here. The
   2px transparent bottom border stays (same box height as the links), and
   the focus ring is left to the UA default, the same ring the links get. */
.njs-primary-nav__list > li > .njs-nav-trigger {
	-webkit-appearance: none;
	appearance: none;
	margin: 0;
	padding-inline: 0;
	background: none;
	border-top: 0;
	border-right: 0;
	border-left: 0;
	border-radius: 0;
	line-height: inherit;
	text-align: inherit;
	cursor: pointer;
}

.njs-primary-nav__list > li > a:hover,
.njs-primary-nav__list > li > a:focus-visible,
.njs-primary-nav__list > li > .njs-nav-trigger:hover,
.njs-primary-nav__list > li > .njs-nav-trigger:focus-visible {
	border-bottom-color: var(--color-primary);
}

.njs-header-utility {
	display: flex;
	align-items: center;
	gap: var(--space-sm);
	flex-shrink: 0;
}

/* 29-08 D12 (Jay 2026-10-19 "Try smaller box and lets see."): the product search form
   (template-parts/header-search.php). Laptops: an open box in the menu's row, 260px wide at most and
   180px at least, 40px tall so the 88px header and the 60px scrolled header hold. Phones: the field
   at the top of the drawer, the drawer's full width. Light theme colors only. */
.njs-header-search {
	display: flex;
	align-items: center;
	background-color: #ffffff;
	border: 1px solid #c4c4c4;
	border-radius: 6px;
	color: var(--color-ink);
}

.njs-header-search:focus-within {
	border-color: var(--color-ink);
}

/* The extra class and attribute outrank `.woocommerce-page input[type="search"]` (a bordered 44px form
   field), which otherwise draws a second box inside the search box on shop, category and results pages. */
.njs-header-search .njs-header-search__input[type="search"] {
	flex: 1 1 auto;
	width: auto;
	min-width: 0;
	min-height: 0;
	height: 100%;
	margin: 0;
	border-radius: 0;
	padding: 0 0 0 12px;
	border: 0;
	background: transparent;
	font-family: var(--font-body);
	font-size: 14px;
	color: var(--color-ink);
	-webkit-appearance: none;
	appearance: none;
}

.njs-header-search__input::placeholder {
	color: #5f5f5f;
	opacity: 1;
}

.njs-header-search__input:focus {
	outline: none;
}

.njs-header-search__input::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
}

.njs-header-search__submit {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--color-ink);
	cursor: pointer;
}

.njs-header-search__submit:focus-visible {
	outline: 2px solid var(--color-ink);
	outline-offset: -2px;
}

.njs-header-search--desktop {
	flex: 0 1 260px;
	min-width: 180px;
	height: 40px;
}

.njs-header-search--drawer {
	height: 44px;
	margin: var(--space-sm) var(--space-sm) 0;
}

.njs-phone-link {
	display: inline-flex;
	align-items: center;
	gap: var(--space-xs);
	min-height: 44px;
	text-decoration: none;
	color: var(--color-ink);
	font-size: var(--step-label);
}

.njs-phone-link__number {
	white-space: nowrap;
}

.njs-cart-link {
	position: relative;
}

.njs-cart-badge {
	position: absolute;
	top: 2px;
	right: 2px;
	min-width: 16px;
	height: 16px;
	padding-inline: 3px;
	border-radius: var(--radius-pill);
	background-color: var(--color-primary);
	color: var(--color-ink);
	font-size: 10px;
	line-height: 16px;
	text-align: center;
}

/* ---- Quote-cart counter (D-14, plan 11-07) — sits beside the cart
   counter above, same badge treatment, never replaces it (D-01/D-02) ---- */
.njs-quote-link {
	position: relative;
}

.njs-quote-badge {
	position: absolute;
	top: 2px;
	right: 2px;
	min-width: 16px;
	height: 16px;
	padding-inline: 3px;
	border-radius: var(--radius-pill);
	background-color: var(--color-primary);
	color: var(--color-ink);
	font-size: 10px;
	line-height: 16px;
	text-align: center;
}

/* ---- Quote-form email-or-phone guard message (D-17, plan 11-07) ----
   Inserted by assets/js/quote-form-guards.js when a submission has both
   Email and Phone empty. Reuses --color-sale, the token this theme already
   documents for destructive/error states — no new color literal. ---- */
.njs-quote-form-guard-msg {
	color: var(--color-sale);
	font-size: var(--step-label);
	margin: 0 0 var(--space-sm);
}

/* ============================================
   MEGA-MENU (desktop, ≥1025px, CSS-hover panel)
   ============================================ */
.mega-dropdown {
	display: none;
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%);
	width: 100vw;
	max-width: 100vw;
	background-color: var(--color-bg);
	border-top: 2px solid var(--color-primary);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
	z-index: 30;
}

.njs-primary-nav__list > li:hover > .mega-dropdown,
.njs-primary-nav__list > li:focus-within > .mega-dropdown {
	display: block;
}

/* Phase 29 (D9): an open-only item's panel also opens on click, through
   .is-open set by assets/js/nav.js (Safari never focuses a clicked button,
   so :focus-within alone misses the click path). .is-dismissed is set by
   nav.js when the reader closes it (click again, Escape, pointer leaving)
   while focus or the pointer is still inside, and wins over hover and
   focus-within until focus leaves. Only ever set on a .njs-nav-trigger li. */
.njs-primary-nav__list > li.is-open > .mega-dropdown {
	display: block;
}

.njs-primary-nav__list > li.is-dismissed > .mega-dropdown {
	display: none;
}

/* Hover bridge — fixes the Safari-unusable dead-gap bug: `.mega-dropdown`
   is positioned `top: 100%` against `.njs-site-header` (not against its own
   `<li>`), so there's empty space between the bottom of the nav link's box
   and the top of this panel. `.njs-site-header__inner` centers its flex
   children (`align-items: center`) inside a taller row than the ~54px nav
   link box (14px label * 1.6 line-height + 2 * 16px `--space-md` padding),
   so that gap is real: ~17px at the default 88px header height, ~3px once
   `html.njs-is-scrolled` shrinks it to 60px (see .njs-site-header__inner
   rules above). Crossing that gap drops `li:hover` and the panel
   `display:none`s before the pointer arrives — Chrome's grace-period hover
   intent hides it too, just slower, which is why the bug reads as
   Safari-only. This `::before` is a DOM descendant of `.mega-dropdown`,
   which is itself rendered inside the trigger `<li>` (see
   inc/nav-walker.php render_desktop_panel()) — so hovering it keeps
   `li:hover` (and this panel) alive exactly like hovering the panel body
   does.

   Height 30px, not the original 20px: 20px cleared the vertical gap for a
   pointer travelling straight down, but the triggers (`Products`,
   `Commercial`) are ~67px wide while their submenu items span the full-width
   panel, so a pointer moving diagonally toward a far-left/right item exits the
   trigger link's *side* (x < link) while still ~2px above a 20px bridge
   (bridge top at panel−20 ≈ y106; the pointer exits the ~54px link at ≈y100),
   lands in dead space, drops `li:hover`, and the panel `display:none`s before
   it arrives. 30px lifts the bridge top to ≈y96 so it catches the pointer the
   instant it leaves the link's edge — verified live (Playwright) against the
   leftmost and rightmost items in both the default and `njs-is-scrolled`
   header states. It stays clear of the sibling nav links at their centre
   height, so hovering across to an adjacent top-level menu still works.
   Transparent and only ever in the DOM/paintable while the panel itself is
   `display: block`, so it can't intercept pointer events at any other time.
   No media query needed — `.njs-site-header` (this rule's only ancestor)
   is itself `display: none` at <=1024px (see `@media (max-width: 1024px)`
   below), so this never reaches the mobile drawer. */
.mega-dropdown::before {
	content: "";
	position: absolute;
	top: -30px;
	left: 0;
	right: 0;
	height: 30px;
}

.mega-dropdown__inner {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--space-lg);
	padding-block: var(--space-lg);
}

.mega-dropdown__col-title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	margin: 0 0 var(--space-sm);
	color: var(--color-ink);
}

.mega-dropdown__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--space-sm);
}

.mega-dropdown__list a,
.mega-dropdown__browse-all {
	font-size: var(--step-body);
	color: var(--color-ink);
	text-decoration: none;
}

.mega-dropdown__list a:hover,
.mega-dropdown__browse-all:hover {
	color: var(--color-primary);
	text-decoration: underline;
}

.mega-dropdown__browse-all {
	display: inline-block;
	font-family: var(--font-heading);
	font-weight: 500;
}

/* ============================================
   MOBILE HEADER (≤1024px — desktop header hides, this shows)
   ============================================ */
.njs-mobile-header {
	display: none;
	background-color: var(--color-bg);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
	position: sticky;
	top: 0;
	z-index: 20;
}

.njs-mobile-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 64px;
	transition: min-height 200ms ease;
}

.njs-mobile-header__logo {
	display: inline-flex;
	justify-content: center;
	text-decoration: none;
	flex: 1 1 auto;
}

.njs-mobile-header__logo-img {
	height: 34px;
	width: auto;
	transition: height 200ms ease;
}

html.njs-is-scrolled .njs-mobile-header__inner {
	min-height: 52px;
}

html.njs-is-scrolled .njs-mobile-header__logo-img {
	height: 26px;
}

.njs-mobile-header__actions {
	display: flex;
	align-items: center;
	gap: var(--space-xs);
}

/* ============================================
   MOBILE DRAWER + OVERLAY (D-16 — 375px hard floor)
   ============================================ */
.njs-drawer-overlay {
	display: none;
	position: fixed;
	inset: 0;
	background-color: rgba(0, 0, 0, 0.4);
	z-index: 40;
}

.njs-drawer-overlay.is-open {
	display: block;
}

/* Visibility is controlled by the `hidden` HTML attribute (fully removed
   from layout + accessibility tree when closed). While unhidden, position
   is controlled by the .is-open class so nav.js can remove .is-open first
   (triggering the slide-out transition) and only set `hidden` back to true
   once the 250ms transition finishes — see assets/js/nav.js closeDrawer(). */
.njs-drawer {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	width: 85vw;
	max-width: 320px;
	background-color: var(--color-bg);
	z-index: 50;
	overflow-y: auto;
	transform: translateX(-100%);
	transition: transform 250ms ease;
}

.njs-drawer.is-open {
	transform: translateX(0);
}

.njs-drawer__header {
	display: flex;
	justify-content: flex-end;
	padding: var(--space-sm);
	border-bottom: 1px solid var(--color-divider);
}

.njs-drawer__list {
	list-style: none;
	margin: 0;
	padding: var(--space-sm) 0;
}

.njs-drawer__list > li {
	position: relative;
	border-bottom: 1px solid var(--color-divider);
}

.njs-drawer__list > li > a,
.njs-drawer__list > li > .njs-nav-label {
	display: block;
	padding: var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	text-decoration: none;
	color: var(--color-ink);
}

/* Mega items in the drawer reserve room for the accordion toggle button
   beside the label link. */
.njs-drawer__list > li:has(.njs-accordion-toggle) > a {
	padding-right: 56px;
}

.njs-accordion-toggle {
	position: absolute;
	top: 0;
	right: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	background: none;
	border: none;
	color: var(--color-ink);
	cursor: pointer;
}

/* Phase 29 (D9): an open-only drawer item's label IS the accordion toggle
   (inc/nav-walker.php 'label-toggle'), so it is a full-width row in the
   drawer link typography, not the absolute 44x44 icon toggle. The right
   padding puts its chevron on the same vertical line as the icon toggles'
   (22px from the edge = 13px + half the 18px icon). nav.js binds it like
   every other .njs-accordion-toggle. */
.njs-drawer__list > li > .njs-accordion-toggle--label {
	position: static;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-sm);
	width: 100%;
	min-height: 44px;
	margin: 0;
	padding: var(--space-md) 13px var(--space-md) var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	line-height: inherit;
	text-align: left;
	text-transform: uppercase;
	letter-spacing: 1px;
	color: var(--color-ink);
}

.njs-accordion-toggle__chevron {
	width: 18px;
	height: 18px;
	transition: transform 200ms ease;
}

.njs-accordion-toggle[aria-expanded="true"] .njs-accordion-toggle__chevron {
	transform: rotate(180deg);
}

.njs-accordion-panel {
	padding: 0 var(--space-md) var(--space-md);
}

.njs-accordion-group {
	margin-bottom: var(--space-md);
}

.njs-accordion-group__title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	margin: 0 0 var(--space-xs);
	color: var(--color-ink);
}

/* ============================================
   FOOTER — rich rebuild (plan 08-04 revision, brief item 6)
   Logo + address/contact + email-signup top block, 4-column link nav,
   social icons + payment trust row, copyright line. Matches the live
   site's footer structure (homepage-capture/INVENTORY.md §11).
   ============================================ */
.njs-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.njs-site-footer {
	background-color: #1a1a1a; /* palette C dark footer (261002-ouc), light text below */
	color: #f2f2f2;
	padding-block: var(--space-2xl);
	margin-top: var(--space-2xl);
}

.njs-site-footer__top {
	display: grid;
	grid-template-columns: 1fr 1.4fr 1fr;
	gap: var(--space-xl);
	align-items: start;
	padding-bottom: var(--space-2xl);
	margin-bottom: var(--space-2xl);
	border-bottom: 1px solid rgba(255, 255, 255, 0.18);
}

/* The logo's brown wordmark is unreadable on #1a1a1a, so it sits on a white plate. */
.njs-site-footer__logo-link {
	display: inline-block;
	justify-self: start; /* grid item: hug the logo instead of stretching the plate */
	background-color: #ffffff;
	padding: 8px 12px;
	border-radius: var(--radius-sm);
}

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

.njs-site-footer__contact-row {
	display: flex;
	flex-direction: column;
	gap: var(--space-md);
}

.njs-site-footer__contact-item {
	display: flex;
	align-items: flex-start;
	gap: var(--space-sm);
}

.njs-site-footer__contact-item .njs-icon {
	flex-shrink: 0;
	margin-top: 2px;
	color: var(--color-primary);
}

.njs-site-footer__contact-label {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	margin: 0 0 var(--space-xs);
}

.njs-site-footer__contact-value {
	margin: 0;
	font-size: var(--step-label);
}

.njs-site-footer__contact-value a {
	color: #f2f2f2;
	text-decoration: none;
}

.njs-site-footer__contact-value a:hover {
	color: var(--color-primary);
}

.njs-site-footer__signup-heading {
	font-size: var(--step-body);
	text-transform: none;
	margin: 0 0 var(--space-sm);
}

.njs-site-footer__signup-row {
	display: flex;
	gap: var(--space-sm);
}

.njs-site-footer__signup-input {
	flex: 1 1 auto;
	min-height: 44px;
	padding: 0 var(--space-md);
	border: 1px solid var(--color-divider);
	border-radius: var(--radius-sm);
	font-family: var(--font-body);
	font-size: var(--step-label);
	background-color: var(--color-bg);
	color: var(--color-ink);
}

.njs-site-footer__signup-btn[disabled] {
	opacity: 0.5;
	cursor: not-allowed;
}

.njs-site-footer__grid {
	display: grid;
	grid-template-columns: repeat(5, 1fr); /* 29-08 D10: fifth column, Service Areas (1025px and up) */
	gap: var(--space-xl);
}

.njs-site-footer__heading {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	margin: 0 0 var(--space-md);
}

/* 29-08 D10: region subheadings in the Service Areas column (North Jersey, Central Jersey).
   #b3b3b3 on the #1a1a1a footer is about 8.3:1, over the 4.5 the contrast gate (c6) needs. */
.njs-site-footer__subheading {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: 0.8125rem;
	color: #b3b3b3;
	margin: 0 0 var(--space-xs);
}

.njs-site-footer__list + .njs-site-footer__subheading {
	margin-top: var(--space-md);
}

.njs-site-footer__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--space-sm);
}

.njs-site-footer__list a {
	color: #f2f2f2;
	text-decoration: none;
	font-size: var(--step-label);
}

.njs-site-footer__list a:hover {
	color: var(--color-primary);
	text-decoration: underline;
}

.njs-site-footer__learn-more-contact {
	font-size: var(--step-label);
	margin: var(--space-sm) 0 0;
}

.njs-site-footer__learn-more-contact a {
	color: #f2f2f2;
	text-decoration: none;
}

.njs-site-footer__bottom {
	margin-top: var(--space-2xl);
	padding-top: var(--space-lg);
	border-top: 1px solid rgba(255, 255, 255, 0.18);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-md);
}

.njs-site-footer__copy {
	font-size: var(--step-label);
	color: #f2f2f2;
	margin: 0;
}

.njs-site-footer__social {
	display: flex;
	align-items: center;
	gap: var(--space-xs);
	list-style: none;
	margin: 0;
	padding: 0;
}

.njs-site-footer__social .njs-icon-btn {
	color: #f2f2f2;
}

.njs-site-footer__social .njs-icon-btn:hover {
	color: var(--color-primary);
}

.njs-site-footer__payments {
	font-size: var(--step-label);
	color: #f2f2f2;
	opacity: 0.7;
	margin: 0;
	width: 100%;
	text-align: center;
}

@media (max-width: 1024px) {
	.njs-site-footer__top {
		grid-template-columns: 1fr;
	}

	.njs-site-footer__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

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

	.njs-site-footer__bottom {
		flex-direction: column;
		text-align: center;
	}
}

/* ============================================
   BUTTONS (component inventory — UI-SPEC)
   ============================================ */
.njs-btn {
	display: inline-block;
	min-height: 44px;
	padding: 12px 24px;
	border-radius: var(--radius-sm);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	text-decoration: none;
	text-align: center;
	cursor: pointer;
	border: none;
	transition: box-shadow 150ms ease, background-color 150ms ease, color 150ms ease;
}

.njs-btn-primary {
	background-color: var(--color-primary);
	color: var(--color-ink);
}

.njs-btn-primary:hover {
	background-color: color-mix(in srgb, var(--color-primary) 92%, black);
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.njs-btn-secondary {
	background-color: transparent;
	color: var(--color-accent);
	border: 2px solid var(--color-accent);
}

.njs-btn-secondary:hover {
	background-color: var(--color-accent);
	color: var(--color-bg);
}

.njs-btn[disabled],
.njs-btn-disabled {
	opacity: 0.4;
	cursor: not-allowed;
}

/* Default treatment for a bare `.njs-btn` (no -primary/-secondary modifier).
   The converter renames old `cta-button` → `njs-btn` with no modifier, so
   in-content CTAs would otherwise fall through to a plain text link. Give
   them the outlined-green (secondary-equivalent) look: a clear, tappable,
   on-brand button that reads as a lower-emphasis action — not the hard-sell
   orange. Orange filled `.njs-btn-primary` stays the deliberate, opt-in
   choice for the single main conversion CTA. Specificity (0,4,0) via the
   :not() chain intentionally beats the generic `.njs-body a` (0,1,1) so
   these render as buttons even inside article body content. */
.njs-btn:not(.njs-btn-primary):not(.njs-btn-secondary):not(.njs-btn-disabled) {
	background-color: transparent;
	color: var(--color-accent);
	border: 2px solid var(--color-accent);
}

.njs-btn:not(.njs-btn-primary):not(.njs-btn-secondary):not(.njs-btn-disabled):hover {
	background-color: var(--color-accent);
	color: var(--color-bg);
}

/* ============================================
   CARDS (component inventory — UI-SPEC)
   ============================================ */
.njs-card {
	background-color: var(--color-bg);
	border-radius: var(--radius-md);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
	padding: var(--space-md);
	transition: box-shadow 150ms ease, transform 150ms ease;
}

.njs-card:hover {
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
	transform: translateY(-2px);
}

/* ============================================
   RESPONSIVE STRUCTURAL BREAKPOINTS
   Fluid clamp() handles type/spacing scaling — these handle
   structural column-count changes only, per UI-SPEC Layout & Breakpoints.
   ============================================ */
@media (min-width: 1025px) {
	/* Drawer/overlay/mobile header never render on desktop, even if JS
	   adds an .is-open class for some other reason. */
	.njs-drawer,
	.njs-drawer-overlay {
		display: none !important;
	}
}

@media (max-width: 1024px) {
	/* Nav collapse breakpoint (D-16) — desktop header/mega-menu hides,
	   mobile header + hamburger/drawer show. One collapse point, not
	   three header states, per UI-SPEC Layout & Breakpoints. */
	.njs-site-header {
		display: none;
	}

	.njs-mobile-header {
		display: block;
	}
}

@media (max-width: 767px) {
	.njs-main {
		padding-block: var(--space-lg);
	}
}

/* ============================================
   HOMEPAGE (front-page.php) — D-05/D-06/D-07
   Section rhythm: alternating white / neutral backgrounds,
   64/48/32px (desktop/tablet/mobile) vertical padding per
   UI-SPEC "Homepage Layout".
   ============================================ */
.njs-homepage {
	padding-block: 0;
}

.njs-section {
	padding-block: var(--space-3xl);
}

.njs-section--neutral {
	background-color: var(--color-neutral);
}

/* Dark/high-contrast section variant (brief item 5) — used for the 6-tile
   category grid so the photo tiles pop against a near-black background,
   matching the live site's high-contrast treatment. */
.njs-section--dark {
	background-color: var(--color-ink);
	color: var(--color-bg);
}

.njs-section--dark .njs-section__heading {
	color: var(--color-bg);
}

/* Sentence case (brief item 2) — headings carry their natural title-case
   text (already stored that way in front-page.php's esc_html_e() calls),
   no CSS uppercase transform. Oswald 500 still carries the visual weight.
   Uppercase is now reserved for nav labels, buttons, and small eyebrow-
   style labels only (see Header/Footer/Button rules elsewhere). */
.njs-section__heading {
	text-align: left;
	margin-bottom: var(--space-lg);
	position: relative;
	padding-bottom: var(--space-sm);
}

.njs-section__heading::after {
	content: '';
	display: block;
	width: 64px;
	height: 3px;
	background-color: var(--color-primary);
	margin-top: var(--space-sm);
}

.njs-section__heading a {
	color: inherit;
	text-decoration: none;
}

@media (max-width: 1024px) {
	.njs-section {
		padding-block: var(--space-2xl);
	}
}

@media (max-width: 767px) {
	.njs-section {
		padding-block: var(--space-xl);
	}
}

/* ---- Hero ---- */
.njs-hero {
	background-size: cover;
	background-position: center;
	background-color: var(--color-ink);
	padding-block: var(--space-3xl);
}

.njs-hero__inner {
	text-align: center;
	color: var(--color-bg);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-md);
	text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

.njs-hero__title {
	color: var(--color-bg);
	max-width: 900px;
}

.njs-hero__tagline {
	max-width: 640px;
	margin: 0;
	font-size: var(--step-body);
}

/* Trust strip (brief item 9) — verbatim "10K+ Satisfied Customers" stat
   (also carried in the About/Trust Stats section) surfaced nearer the
   hero, not only mid-page. */
.njs-hero__trust {
	display: flex;
	align-items: center;
	gap: var(--space-sm);
	margin: var(--space-sm) 0 0;
	font-size: var(--step-label);
}

.njs-hero__trust-stars {
	color: var(--color-primary);
	letter-spacing: 2px;
}

@media (min-width: 1025px) {
	.njs-hero {
		padding-block: 96px;
	}
}

/* ---- Hero CTA tiles ----
   Overlap the hero's bottom edge (brief item 4 — layered depth, matches
   the live site instead of a flat row below the hero). Negative margin
   pulls the tiles up into the hero's bottom padding; z-index + solid
   white card background (.njs-card) keep them legible over the photo. */
.njs-hero-tiles {
	position: relative;
	z-index: 5;
	padding-block: 0 var(--space-2xl);
	margin-top: -72px;
}

.njs-hero-tiles__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-lg);
}

.njs-hero-tile {
	padding: 0;
	overflow: hidden;
}

.njs-hero-tile__image {
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform 300ms ease;
}

.njs-hero-tile:hover .njs-hero-tile__image {
	transform: scale(1.04);
}

.njs-hero-tile__title {
	font-size: var(--step-label);
	margin: var(--space-md) var(--space-md) var(--space-xs);
}

.njs-hero-tile__link {
	display: inline-block;
	margin: 0 var(--space-md) var(--space-md);
	color: var(--color-primary);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-decoration: none;
}

.njs-hero-tile__link:hover {
	text-decoration: underline;
}

@media (max-width: 1024px) {
	.njs-hero-tiles {
		margin-top: -48px;
	}
}

@media (max-width: 767px) {
	.njs-hero-tiles {
		margin-top: -32px;
	}

	.njs-hero-tiles__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- 6-tile category grid ---- */
.njs-category-grid__grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--space-lg);
}

.njs-category-tile {
	position: relative;
	padding: 0;
	min-height: 320px;
	background-size: cover;
	background-position: center;
	display: flex;
	align-items: flex-end;
	overflow: hidden;
}

.njs-category-tile__scrim {
	width: 100%;
	padding: var(--space-lg) var(--space-md) var(--space-md);
	background: linear-gradient(to top, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.05));
	color: var(--color-bg);
	transition: background 200ms ease;
}

.njs-category-tile:hover .njs-category-tile__scrim {
	background: linear-gradient(to top, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.15));
}

.njs-category-tile__title {
	color: var(--color-bg);
	font-size: var(--step-heading);
}

.njs-category-tile__body {
	color: var(--color-bg);
	font-size: var(--step-body);
	margin-bottom: var(--space-md);
}

@media (max-width: 767px) {
	.njs-category-grid__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- Featured products (live WooCommerce query, D-07) ---- */
.njs-featured-products__grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--space-lg);
}

.njs-product-card {
	text-decoration: none;
	color: var(--color-ink);
}

.njs-product-card__image-wrap {
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border-radius: var(--radius-md);
	margin-bottom: var(--space-sm);
}

.njs-product-card__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.njs-product-card__title {
	font-size: var(--step-body);
	margin: 0 0 var(--space-xs);
}

.njs-product-card__price {
	font-family: var(--font-body);
	font-weight: 400;
	color: var(--color-ink);
	margin: 0;
}

@media (max-width: 1024px) {
	.njs-featured-products__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 480px) {
	.njs-featured-products__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- About / trust stats ---- */
.njs-about-stats__grid {
	display: grid;
	grid-template-columns: 1fr 1.2fr 1fr;
	gap: var(--space-xl);
	align-items: center;
}

.njs-about-stats__heading {
	text-transform: none;
}

.njs-about-stats__image img {
	width: 100%;
}

.njs-about-stats__list {
	display: flex;
	flex-direction: column;
	gap: var(--space-lg);
	margin: 0;
}

.njs-about-stats__stat dt {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-display);
	color: var(--color-ink);
}

.njs-about-stats__stat dd {
	margin: 0;
	font-size: var(--step-label);
}

@media (max-width: 1024px) {
	.njs-about-stats__grid {
		grid-template-columns: 1fr;
		text-align: center;
	}

	.njs-about-stats__list {
		flex-direction: row;
		justify-content: center;
		flex-wrap: wrap;
	}
}

/* ---- Blog teaser ---- */
.njs-blog-teaser__grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--space-lg);
	margin-bottom: var(--space-lg);
}

.njs-blog-card {
	text-decoration: none;
	color: var(--color-ink);
}

.njs-blog-card__image-wrap {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--radius-md);
	margin-bottom: var(--space-sm);
}

.njs-blog-card__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.njs-blog-card__meta {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.7;
	margin: 0 0 var(--space-xs);
}

.njs-blog-card__title {
	font-size: var(--step-body);
	margin: 0;
}

@media (max-width: 1024px) {
	.njs-blog-teaser__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 480px) {
	.njs-blog-teaser__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- Yard/Site Consultation banner ---- */
.njs-consultation-banner {
	background-color: var(--color-ink);
	color: var(--color-bg);
}

.njs-consultation-banner__grid {
	display: grid;
	grid-template-columns: 1.2fr 1fr;
	gap: var(--space-xl);
	align-items: center;
}

.njs-consultation-banner__copy p {
	color: var(--color-bg);
}

.njs-consultation-banner__heading {
	color: var(--color-bg);
}

.njs-consultation-banner__body {
	font-size: var(--step-body);
}

.njs-consultation-banner__image img {
	width: 100%;
	max-width: 320px;
	margin-inline: auto;
}

@media (max-width: 1024px) {
	.njs-consultation-banner__grid {
		grid-template-columns: 1fr;
		text-align: center;
	}

	.njs-consultation-banner__image {
		order: -1;
	}
}

/* ---- Commercial Play Equipment 3-tile grid ---- */
.njs-commercial-tiles__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-lg);
}

.njs-commercial-tile {
	text-decoration: none;
	color: var(--color-ink);
	padding: 0;
	overflow: hidden;
}

.njs-commercial-tile img {
	width: 100%;
	aspect-ratio: 3 / 4;
	object-fit: cover;
}

.njs-commercial-tile__title {
	text-align: center;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	margin: var(--space-sm) 0;
}

@media (max-width: 767px) {
	.njs-commercial-tiles__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- Testimonials ---- */
.njs-testimonials__intro {
	max-width: 480px;
}

/* One card per business line: residential swingsets, parties, commercial.
   auto-fit rather than a fixed repeat(3,...) so the row still reads correctly
   while the commercial card is gated off in front-page.php — two cards fill
   the row instead of leaving a hole, and it becomes a true 3-up the moment
   Jay supplies the commercial testimonial. */
.njs-testimonials__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
	gap: var(--space-lg);
}

/* Image column was a fixed 200px, which was fine at 2-up but starves the quote
   at 3-up (a ~520px card leaves ~300px of text). Proportional with a floor
   keeps the image reasonable at both counts. */
.njs-testimonial {
	display: grid;
	grid-template-columns: minmax(140px, 32%) 1fr;
	gap: var(--space-md);
	align-items: center;
	padding: var(--space-md);
}

.njs-testimonial__image {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var(--radius-md);
}

.njs-testimonial__stars {
	color: var(--color-primary);
	letter-spacing: 2px;
	margin: 0 0 var(--space-xs);
}

.njs-testimonial__title {
	font-size: var(--step-body);
	margin: 0 0 var(--space-xs);
}

.njs-testimonial__quote {
	font-size: var(--step-label);
	margin: 0 0 var(--space-xs);
}

.njs-testimonial__author {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	margin: 0;
}

@media (max-width: 767px) {
	.njs-testimonials__grid {
		grid-template-columns: 1fr;
	}

	.njs-testimonial {
		grid-template-columns: 1fr;
	}
}

/* ---- Instagram grid ---- */
.njs-instagram-grid__intro {
	max-width: 480px;
}

.njs-instagram-grid__grid {
	display: grid;
	grid-template-columns: repeat(6, 1fr);
	gap: var(--space-sm);
}

.njs-instagram-grid__item img {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var(--radius-sm);
	transition: opacity 150ms ease;
}

.njs-instagram-grid__item:hover img {
	opacity: 0.85;
}

@media (max-width: 767px) {
	.njs-instagram-grid__grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* ============================================
   WOOCOMMERCE — Shop/Archive, Product, Cart/Checkout/My-Account
   (Plan 08-05, D-15 dual CTA). Every rule below styles WooCommerce
   core's own default markup directly (no template overrides) — see
   inc/woocommerce-hooks.php's `woocommerce_enqueue_styles` filter,
   which disables WC's bundled stylesheet so these are the only rules
   in play. Scoped under WooCommerce's own `.woocommerce-page` body class
   (added by wc_body_class() on every WC page type: shop/product/
   taxonomy AND cart/checkout/my-account) rather than the woocommerce.php
   wrapper div — cart/checkout/my-account are plain WP Pages containing a
   shortcode and render via page.php, not woocommerce.php, so a wrapper-
   div scope would silently never match them (Rule 1 fix, found during
   this plan's own Task 3 staging verification).
   ============================================ */

/* ---- Shop/category archive: reserved filter-sidebar layout ---- */
.njs-shop-layout {
	display: grid;
	grid-template-columns: 280px 1fr;
	gap: var(--space-xl);
	align-items: start;
}

.njs-shop-sidebar__widget {
	margin-bottom: var(--space-lg);
}

.njs-shop-sidebar__widget-title {
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
}

@media (max-width: 1024px) {
	.njs-shop-layout {
		grid-template-columns: 1fr;
	}
}

/* ---- Shop/category archive: product grid (Card treatment) ---- */
.woocommerce-page ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: var(--space-lg);
	list-style: none;
	margin: 0 0 var(--space-lg);
	padding: 0;
}

.woocommerce-page ul.products li.product {
	position: relative;
	background-color: var(--color-bg);
	border-radius: var(--radius-md);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
	padding: var(--space-md);
	list-style: none;
	transition: box-shadow 150ms ease, transform 150ms ease;
}

.woocommerce-page ul.products li.product:hover {
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
	transform: translateY(-2px);
}

.woocommerce-page ul.products li.product > a:not(.button) {
	display: block;
	text-decoration: none;
	color: var(--color-ink);
}

.woocommerce-page ul.products li.product img {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var(--radius-md);
	margin-bottom: var(--space-sm);
}

.woocommerce-page ul.products li.product .woocommerce-loop-product__title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-body);
	color: var(--color-ink);
	margin: 0 0 var(--space-xs);
}

.woocommerce-page ul.products li.product .price {
	font-family: var(--font-body);
	font-weight: 400;
	font-size: var(--step-body);
	color: var(--color-ink);
}

.woocommerce-page ul.products li.product .price del {
	opacity: 0.6;
	text-decoration: line-through;
}

.woocommerce-page ul.products li.product .onsale {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 2;
	min-width: 0;
	min-height: 0;
	line-height: 1.6;
	padding: 2px 10px;
	border-radius: var(--radius-pill);
	background-color: var(--color-sale);
	color: var(--color-bg);
	font-family: var(--font-body);
	font-weight: 400;
	font-size: 12px;
}

.woocommerce-page ul.products li.product .button {
	display: block;
	margin-top: var(--space-sm);
	width: 100%;
}

@media (max-width: 480px) {
	.woocommerce-page ul.products {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* ---- Buttons: map WooCommerce's default .button to the Primary style,
   and its "back"/secondary actions to the Secondary outline style ---- */
.woocommerce-page .button {
	display: inline-block;
	min-height: 44px;
	padding: 12px 24px;
	border-radius: var(--radius-sm);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 1px;
	text-decoration: none;
	text-align: center;
	cursor: pointer;
	border: none;
	background-color: var(--color-primary);
	color: var(--color-ink);
	transition: box-shadow 150ms ease, background-color 150ms ease, color 150ms ease;
}

.woocommerce-page .button:hover {
	background-color: color-mix(in srgb, var(--color-primary) 92%, black);
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.woocommerce-page .button.disabled,
.woocommerce-page .button:disabled {
	opacity: 0.4;
	cursor: not-allowed;
}

.woocommerce-page .button.wc-backward,
.woocommerce-page a.wc-backward {
	background-color: transparent;
	color: var(--color-accent);
	border: 2px solid var(--color-accent);
}

.woocommerce-page .button.wc-backward:hover,
.woocommerce-page a.wc-backward:hover {
	background-color: var(--color-accent);
	color: var(--color-bg);
}

/* ---- Empty states (cart-empty verbatim copy, UI-SPEC) ---- */
.njs-empty-state {
	text-align: center;
	padding-block: var(--space-2xl);
}

.njs-empty-state__heading {
	margin-bottom: var(--space-sm);
}

.njs-empty-state__body {
	max-width: 480px;
	margin: 0 auto var(--space-lg);
	color: var(--color-ink);
}

/* ---- D-15 empty quote-cart state (plan 11-08) ----
   Theme-owned block, built by assets/js/quote-empty-state.js and inserted
   as a SIBLING of ELEX's own #quote_list React root (never a child of it —
   see that file's own comment on why). Extends the shared .njs-empty-state
   base above (centered heading/body pattern) rather than duplicating it;
   the form and its fields are left-aligned within that centered container,
   since a form reads better ranged left than centered. No new color
   literals — every rule below reuses the existing token set. */
.njs-quote-empty {
	max-width: 640px;
	margin-inline: auto;
}

.njs-quote-empty__body {
	text-align: left;
}

.njs-quote-empty__continue {
	margin-bottom: var(--space-lg);
}

.njs-quote-empty__divider {
	border: none;
	border-top: 1px solid var(--color-divider);
	margin-block: var(--space-lg);
}

.njs-quote-empty__form-heading {
	text-align: left;
	margin-bottom: var(--space-md);
}

.njs-quote-empty-form {
	text-align: left;
}

.njs-quote-empty-form__field {
	margin-bottom: var(--space-md);
}

.njs-quote-empty-form__label {
	display: block;
	font-weight: 500;
	margin-bottom: var(--space-xs);
}

.njs-quote-empty-form__required {
	color: var(--color-sale);
}

.njs-quote-empty-form__optional {
	font-weight: 400;
	color: var(--color-ink);
	opacity: 0.6;
}

.njs-quote-empty-form__hint {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.7;
	margin: 0 0 var(--space-xs);
}

.njs-quote-empty-form__options {
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
}

.njs-quote-empty-form input[type="text"],
.njs-quote-empty-form input[type="email"],
.njs-quote-empty-form input[type="tel"],
.njs-quote-empty-form select,
.njs-quote-empty-form textarea {
	width: 100%;
	max-width: 100%;
	padding: var(--space-sm);
	border: 1px solid var(--color-divider);
	border-radius: var(--radius-sm);
	font-family: var(--font-body);
	font-size: var(--step-body);
	color: var(--color-ink);
	background-color: var(--color-bg);
}

.njs-quote-empty-form__hedge {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.8;
	margin: 0 0 var(--space-md);
}

.njs-quote-empty-form__submit {
	width: 100%;
}

@media (min-width: 480px) {
	.njs-quote-empty-form__submit {
		width: auto;
	}
}

/* ---- Tables: cart, order review ---- */
.woocommerce-page table.cart,
.woocommerce-page table.shop_table {
	width: 100%;
	border-collapse: collapse;
	margin-bottom: var(--space-lg);
}

.woocommerce-page table.cart th,
.woocommerce-page table.shop_table th {
	font-family: var(--font-heading);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: var(--step-label);
	text-align: left;
	padding: var(--space-sm) var(--space-md);
	border-bottom: 2px solid var(--color-divider);
}

.woocommerce-page table.cart td,
.woocommerce-page table.shop_table td {
	padding: var(--space-md);
	border-bottom: 1px solid var(--color-divider);
	font-size: var(--step-label);
	vertical-align: middle;
}

.woocommerce-page table.cart img {
	width: 64px;
	height: 64px;
	object-fit: cover;
	border-radius: var(--radius-sm);
}

/* ---- Cart "remove item" (x) link (WC core class .remove, no theme
   markup/template override) — same icon-only 44px tap-target floor as
   .njs-icon-btn (UI-SPEC Spacing exceptions); WC's own bundled CSS
   normally sizes this, disabled here per woocommerce_enqueue_styles. ---- */
.woocommerce-page a.remove {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	color: var(--color-sale);
	font-size: 20px;
	line-height: 1;
	text-decoration: none;
	border-radius: var(--radius-sm);
}

.woocommerce-page a.remove:hover,
.woocommerce-page a.remove:focus-visible {
	background-color: var(--color-neutral);
}

/* ---- Mobile card-stacked tables (375px hard floor, THEME-04) ----
   WooCommerce core's own `shop_table_responsive` marker class (cart
   items, cart-totals, my-account orders) is designed to be paired with
   WC's bundled frontend CSS for this exact stacking behavior — since
   this theme disables WC's default stylesheet
   (`woocommerce_enqueue_styles` => `__return_empty_array`, see
   inc/woocommerce-hooks.php) to avoid double-styling, that stacking
   rule never shipped, and the plain <table> auto-sized its columns
   (image + long product title + price + qty stepper + subtotal) wider
   than the 375px viewport. Reimplemented here using WC core's own
   `data-title` attributes (already present on every relevant <td>/<th>
   in the vendored WooCommerce templates — verified via direct template
   read, not assumed) so the fix works with zero PHP/template changes. */
@media (max-width: 767px) {
	.woocommerce-page table.shop_table_responsive,
	.woocommerce-page table.shop_table_responsive tbody,
	.woocommerce-page table.shop_table_responsive tr,
	.woocommerce-page table.shop_table_responsive td {
		display: block;
		width: 100%;
	}

	.woocommerce-page table.shop_table_responsive thead {
		display: none;
	}

	.woocommerce-page table.shop_table_responsive tr {
		padding-block: var(--space-md);
		border-bottom: 1px solid var(--color-divider);
	}

	/* Totals/order-summary rows (WC core's cart-totals.php and checkout's
	   review-order.php both use this exact <th>Subtotal</th><td
	   data-title="Subtotal">$x</td> row shape for cart-subtotal/
	   cart-discount/shipping/fee/tax-rate/tax-total/order-total rows —
	   cart-totals.php emits these as loose <tr> children of <table>
	   (the browser auto-wraps them in an implicit <tbody>, NOT <tfoot>,
	   confirmed via a live DOM dump — a `tfoot`-scoped selector silently
	   never matched this table), while review-order.php uses a real
	   <tfoot>. Target by the row classes WC core actually applies so both
	   markup shapes are covered identically, regardless of tbody/tfoot. */
	.woocommerce-page table.shop_table_responsive tr.cart-subtotal,
	.woocommerce-page table.shop_table_responsive tr.cart-discount,
	.woocommerce-page table.shop_table_responsive tr.shipping,
	.woocommerce-page table.shop_table_responsive tr.fee,
	.woocommerce-page table.shop_table_responsive tr.tax-rate,
	.woocommerce-page table.shop_table_responsive tr.tax-total,
	.woocommerce-page table.shop_table_responsive tr.order-total {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--space-sm);
	}

	.woocommerce-page table.shop_table_responsive tr.cart-subtotal th,
	.woocommerce-page table.shop_table_responsive tr.cart-subtotal td,
	.woocommerce-page table.shop_table_responsive tr.cart-discount th,
	.woocommerce-page table.shop_table_responsive tr.cart-discount td,
	.woocommerce-page table.shop_table_responsive tr.shipping th,
	.woocommerce-page table.shop_table_responsive tr.shipping td,
	.woocommerce-page table.shop_table_responsive tr.fee th,
	.woocommerce-page table.shop_table_responsive tr.fee td,
	.woocommerce-page table.shop_table_responsive tr.tax-rate th,
	.woocommerce-page table.shop_table_responsive tr.tax-rate td,
	.woocommerce-page table.shop_table_responsive tr.tax-total th,
	.woocommerce-page table.shop_table_responsive tr.tax-total td,
	.woocommerce-page table.shop_table_responsive tr.order-total th,
	.woocommerce-page table.shop_table_responsive tr.order-total td {
		width: auto;
		flex: 0 1 auto;
		padding: 0;
		border-bottom: none;
	}

	/* Suppress the redundant data-title::before on these rows' <td> — the
	   sibling <th> already renders the same label as visible text.
	   Matches the [data-title] attribute selector's specificity below so
	   this suppression actually wins the cascade (a plain class selector
	   loses to `td[data-title]::before` despite appearing later — found
	   via this deploy's own re-verification screenshot, not assumed). */
	.woocommerce-page table.shop_table_responsive tr.cart-subtotal td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.cart-discount td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.shipping td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.fee td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.tax-rate td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.tax-total td[data-title]::before,
	.woocommerce-page table.shop_table_responsive tr.order-total td[data-title]::before {
		content: none;
	}

	.woocommerce-page table.shop_table_responsive td {
		padding: var(--space-xs) 0;
		border-bottom: none;
		text-align: left;
	}

	.woocommerce-page table.shop_table_responsive td.product-remove,
	.woocommerce-page table.shop_table_responsive td.product-thumbnail {
		display: inline-block;
		width: auto;
		vertical-align: middle;
	}

	.woocommerce-page table.shop_table_responsive td[data-title]::before,
	.woocommerce-page table.shop_table_responsive th[data-title]::before {
		content: attr(data-title) ": ";
		font-family: var(--font-heading);
		font-weight: 500;
		text-transform: uppercase;
		letter-spacing: 1px;
		font-size: var(--step-label);
	}

	.woocommerce-page table.shop_table_responsive td.product-name::before {
		content: none;
	}
}

.woocommerce-page .coupon .input-text,
.woocommerce-page input.qty {
	min-height: 44px;
	padding: 0 var(--space-sm);
	border: 1px solid var(--color-divider);
	border-radius: var(--radius-sm);
	font-family: var(--font-body);
	font-size: var(--step-label);
}

/* ---- Form fields: checkout billing/shipping, my-account edit forms ---- */
.woocommerce-page .form-row {
	margin-bottom: var(--space-md);
}

.woocommerce-page .form-row label {
	display: block;
	font-size: var(--step-label);
	margin-bottom: var(--space-xs);
}

.woocommerce-page input[type="text"],
.woocommerce-page input[type="email"],
.woocommerce-page input[type="tel"],
.woocommerce-page input[type="password"],
.woocommerce-page input[type="number"],
.woocommerce-page input[type="search"],
.woocommerce-page select,
.woocommerce-page textarea {
	width: 100%;
	min-height: 44px;
	padding: 0 var(--space-md);
	border: 1px solid var(--color-divider);
	border-radius: var(--radius-sm);
	font-family: var(--font-body);
	font-size: var(--step-label);
	background-color: var(--color-bg);
	color: var(--color-ink);
}

.woocommerce-page textarea {
	min-height: 88px;
	padding-block: var(--space-sm);
}

/* ---- Checkout: two-column layout (customer details / order review) ---- */
.woocommerce-page .col2-set {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-lg);
}

.woocommerce-page .col2-set .col-1,
.woocommerce-page .col2-set .col-2 {
	flex: 1 1 280px;
	min-width: 0;
}

.woocommerce-page #order_review,
.woocommerce-page .woocommerce-checkout-review-order-table {
	background-color: var(--color-neutral);
	border-radius: var(--radius-md);
	padding: var(--space-lg);
}

@media (min-width: 1025px) {
	.woocommerce-page form.checkout {
		display: grid;
		grid-template-columns: 1.3fr 1fr;
		gap: var(--space-xl);
		align-items: start;
	}

	.woocommerce-page form.checkout #customer_details {
		grid-column: 1;
		grid-row: 1 / span 3;
	}

	.woocommerce-page form.checkout #order_review_heading {
		grid-column: 2;
		grid-row: 1;
	}

	.woocommerce-page form.checkout #order_review {
		grid-column: 2;
		grid-row: 2;
	}
}

/* ---- My Account: nav + content two-column layout ----
   My Account is a plain WP Page (page.php), not woocommerce.php — the
   shortcode's nav+content markup lands inside page.php's own
   .njs-entry-content wrapper, so that (not .njs-woo-page) is the real
   common ancestor to lay out as a flex row. */
.woocommerce-account .njs-entry-content {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: var(--space-xl);
}

.woocommerce-account .woocommerce-MyAccount-navigation {
	flex: 0 0 240px;
}

.woocommerce-account .woocommerce-MyAccount-navigation ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
}

.woocommerce-account .woocommerce-MyAccount-navigation a {
	display: block;
	padding: var(--space-sm) var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	text-decoration: none;
	color: var(--color-ink);
	border-radius: var(--radius-sm);
}

.woocommerce-account .woocommerce-MyAccount-navigation .is-active a {
	color: var(--color-primary);
	background-color: var(--color-neutral);
}

.woocommerce-account .woocommerce-MyAccount-content {
	flex: 1 1 320px;
	min-width: 0;
}

@media (max-width: 767px) {
	.woocommerce-account .njs-entry-content {
		flex-direction: column;
	}
}

/* ---- Single product: gallery + summary ---- */
.woocommerce-page .woocommerce-product-gallery img {
	border-radius: var(--radius-md);
}

.woocommerce-page .summary .price {
	/* Price emphasis reserved for the product page only (UI-SPEC Color) —
	   the archive/card price above stays ink, not orange. */
	color: var(--color-primary);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
}

.woocommerce-page .summary .price del {
	color: var(--color-ink);
	opacity: 0.6;
	font-family: var(--font-body);
	font-weight: 400;
	font-size: var(--step-body);
}

/* ---- Dual CTA (D-15): checkout path + quote path, independent blocks,
   stacked mobile / side-by-side desktop when both render ---- */
.njs-product-ctas {
	display: flex;
	flex-direction: column;
	gap: var(--space-md);
	margin: var(--space-md) 0 var(--space-lg);
}

.njs-product-ctas .cart {
	margin: 0;
}

.njs-quote-cta {
	display: inline-flex;
}

@media (min-width: 768px) {
	.njs-product-ctas {
		flex-direction: row;
		align-items: center;
		flex-wrap: wrap;
	}
}

/* ---- Spec block (D-19/D-20, plan 11.5-09) — renders below the CTAs
   (priority 35, after the wrapper closes at 32). Collapses to nothing when
   a product has no stored specs (D-27), so no empty-state rule is needed
   here — the PHP callback never echoes the wrapper in that case. ---- */
.njs-spec-block {
	margin: var(--space-lg) 0;
	padding-top: var(--space-md);
	border-top: 1px solid var(--color-divider);
}

.njs-spec-heading {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
	margin: 0 0 var(--space-sm);
}

.njs-spec-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-xs) var(--space-sm);
	padding: var(--space-sm) 0;
	border-bottom: 1px solid var(--color-divider);
	font-family: var(--font-body);
	font-size: var(--step-body);
}

.njs-spec-row:last-of-type {
	border-bottom: none;
}

.njs-spec-label {
	/* Fixed basis (not min-width) — the longest label ("Installed
	   Dimensions") must wrap within its own column rather than growing
	   past a floor and pushing the value column out of alignment with
	   every other row (found in Jay's checkpoint review, 2026-07-30). */
	flex: 0 0 13rem;
	font-weight: 600;
	color: var(--color-ink);
}

.njs-spec-value {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
	color: var(--color-ink);
	opacity: 0.85;
}

.njs-spec-zone-line {
	display: block;
}

/* ---- Tier-scoped CTA order + weight swap (D-03, D-04, plan 11-02)
   Both CTAs always render (D-01/D-02) — only their flex order and visual
   weight change. `order` alone reorders the stack correctly at both the
   mobile (column) and desktop (row, ≥768px) layouts above, so no separate
   mobile media query is needed. Weight reuses the existing .njs-btn-
   primary/.njs-btn-secondary color tokens rather than inventing new
   classes; WooCommerce's native cart submit button carries no inline
   styles so a plain rule suffices, but the ELEX quote button renders
   with inline background-color/color/border set by its own admin config
   (view/quote/add_to_quote.php) — !important is required there to win
   over an inline style, matching the specificity escalation pattern
   already used at `.njs-body a.njs-btn-primary` below for anchors. ---- */
.njs-tier-commercial .njs-quote-cta {
	order: 1;
}

.njs-tier-commercial .cart {
	order: 2;
}

.njs-tier-residential .cart {
	order: 1;
}

.njs-tier-residential .njs-quote-cta {
	order: 2;
}

.njs-tier-commercial .njs-quote-cta a,
.njs-tier-commercial .njs-quote-cta button {
	background-color: var(--color-primary) !important;
	color: var(--color-ink) !important;
	border: none !important;
}

.njs-tier-residential .cart button[type="submit"] {
	background-color: var(--color-primary);
	color: var(--color-ink);
	border: none;
}

.njs-tier-commercial .cart button[type="submit"] {
	background-color: transparent;
	color: var(--color-accent);
	border: 2px solid var(--color-accent);
}

.njs-tier-residential .njs-quote-cta a,
.njs-tier-residential .njs-quote-cta button {
	background-color: transparent !important;
	color: var(--color-accent) !important;
	border: 2px solid var(--color-accent) !important;
}

/* ============================================
   MICRO-INTERACTIONS — budgeted scroll-reveal (brief item 7)
   Section-level only (not per-card) to keep the IntersectionObserver
   workload light — see assets/js/nav.js. Respects prefers-reduced-motion.

   Progressive-enhancement default: .njs-reveal is fully visible with NO
   CSS-authored hidden state. nav.js adds the .njs-reveal-armed class at
   runtime (only when JS has actually run and can guarantee a reveal), and
   THAT class is what applies the hidden-until-visible transform. This
   guarantees content is never permanently invisible if JS fails to load,
   errors out, or a rendering/screenshot tool never fires scroll/
   intersection events (crawlers, automated capture, print) — the un-
   enhanced state is always "fully visible," never "hidden."
   ============================================ */
.njs-reveal.njs-reveal-armed {
	opacity: 0;
	transform: translateY(20px);
	transition: opacity 500ms ease, transform 500ms ease;
}

.njs-reveal.njs-reveal-armed.is-visible {
	opacity: 1;
	transform: none;
}

/* ============================================
   CONTENT PAGE (page-content.php) — portable post_content system
   (Plan 08-06, THEME-02/D-09). Structural convention PORTED from
   docs/county-pages-html/njs-components.css — the project's canonical,
   live-proven content-page component library (answer-capsule, quick-
   answer, fact-block, cta-section, faq-item/faq-answer, author-box,
   trust-bar, callouts, compare-cards, breadcrumb — the same classes
   CLAUDE.md's HTML-preservation rules protect). Same "structure from that
   file, VALUES from this theme's own tokens" rule the file header above
   already establishes for the rest of theme.css — headings still use
   Oswald 500 / this theme's 4-size step scale (UI-SPEC Typography: exactly
   4 sizes, 2 weights, no exceptions), NOT njs-components.css's own older
   --njs-black/--njs-font-body palette. Only in-content H2/H3 lose the
   uppercase transform (sentence case, SEO text preserved verbatim).

   Reused by: page-content.php today (4 WP-native keeper pages, plan
   08-06). Phase 10's blog/county/Shopify-sourced content lands through
   this identical markup + these identical classes — this section IS the
   generic-template proof.
   ============================================ */

:root {
	/* Content-page layout tokens (njs-components.css structure) — distinct
	   from --container-max (1680, homepage/product-grid fluid width).
	   Content pages use a fixed, narrower measure for long-form
	   readability plus a fixed sidebar, not the fluid site container. */
	--njs-max-width: 1200px;
	--njs-content-width: 900px;
	--njs-sidebar-width: 280px;

	/* Pastel callout-tint backgrounds — not part of the 3-core-color/
	   neutral UI-SPEC palette (those are reserved-meaning tokens: primary
	   is CTA-only, sale is destructive-only), so warning/tip callouts get
	   their own dedicated low-saturation tint tokens instead of overloading
	   --color-sale/--color-accent as a background fill. */
	--njs-callout-warning-bg: #fef3c7;
	--njs-callout-tip-bg: #ecfdf5;
}

/* ---- Base (scoped to .njs-body, matches njs-components.css's own scope
   convention so ported component classes render identically) ---- */
.njs-body {
	font-family: var(--font-body);
	font-size: var(--step-body);
	line-height: 1.7;
	color: var(--color-ink);
}

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

/* ---- Layout: 1200px shell / 900px text column + 280px sticky sidebar,
   40px gap (njs-components.css tokens, literal per plan spec) ---- */
.njs-content-wrapper {
	max-width: var(--njs-max-width);
	margin: 0 auto;
	padding: var(--space-lg) var(--space-md) var(--space-3xl);
}

.njs-content-layout {
	display: flex;
	gap: 40px; /* literal per plan spec — not on the 4/8/16/24/32/48/64 spacing
	              scale, same reasoning as --container-max: a dedicated
	              structural-layout dimension, not component-internal spacing */
	align-items: flex-start;
}

.njs-content-col {
	flex: 1;
	max-width: var(--njs-content-width);
	min-width: 0;
}

.njs-sidebar {
	width: var(--njs-sidebar-width);
	flex-shrink: 0;
	position: sticky;
	top: 20px;
	max-height: calc(100vh - 40px);
	overflow-y: auto;
}

.njs-body img,
.njs-sidebar img {
	image-rendering: -webkit-optimize-contrast;
	image-rendering: crisp-edges;
}

/* ---- Typography — in-content headings stay Oswald 500 / this theme's
   step scale (UI-SPEC), sentence case only (no uppercase transform),
   SEO H2 id/text preserved verbatim by the extraction/authoring step,
   never altered here. ---- */
.njs-body h1 {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-display);
	line-height: 1.15;
	color: var(--color-ink);
	margin: 0 0 var(--space-lg);
}

.njs-body h2 {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	line-height: 1.3;
	color: var(--color-ink);
	margin: var(--space-2xl) 0 var(--space-md);
	padding-top: var(--space-lg);
	border-top: 1px solid var(--color-divider);
	text-transform: none; /* sentence case — SEO heading text verbatim, D-10/CLAUDE.md */
}

.njs-body h2:first-of-type {
	border-top: none;
	padding-top: 0;
}

.njs-body h3 {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-subheading);
	line-height: 1.3;
	color: var(--color-ink);
	margin: var(--space-xl) 0 var(--space-sm);
	text-transform: none; /* sentence case — no uppercase, matches H2 rule */
}

.njs-body p {
	margin: 0 0 var(--space-md);
	max-width: 100%;
}

.njs-body ul,
.njs-body ol {
	margin: 0 0 var(--space-md) var(--space-lg);
}

.njs-body li {
	margin-bottom: var(--space-sm);
}

/* Content links use the green accent, not orange. Palette rule: orange
   (--color-primary) is reserved for PRIMARY CTAs only; inline links are
   lower-emphasis actions → --color-accent (green). Keeps the underline as
   a non-color affordance. Primary/secondary .njs-btn keep their own colors
   via the higher-specificity rules below. */
.njs-body a {
	color: var(--color-accent);
	text-decoration: underline;
}

.njs-body a:hover {
	color: color-mix(in srgb, var(--color-accent) 80%, black);
}

/* Restore the sitewide .njs-btn button component's own color/decoration
   inside .njs-body — `.njs-body a` above (class+element, specificity 0,1,1)
   otherwise beats `.njs-btn-primary` (single class, 0,1,0) and renders
   orange text on an orange background (invisible), found + fixed during
   this plan's own Task 3 staging verification. */
.njs-body a.njs-btn {
	text-decoration: none;
}

.njs-body a.njs-btn:hover {
	text-decoration: none;
}

.njs-body a.njs-btn-primary,
.njs-body a.njs-btn-primary:hover {
	color: var(--color-ink);
}

.njs-body a.njs-btn-secondary {
	color: var(--color-accent);
}

.njs-body a.njs-btn-secondary:hover {
	color: var(--color-bg);
}

/* Credential badges are subtle ink pills, not links to emphasize — the
   generic `.njs-body a` rule (0,1,1) otherwise clobbers the badge's own
   color/decoration (0,1,0). Restore the intended pill look at higher
   specificity so badges read as credentials, not green underlined links. */
.njs-body a.njs-credential-badge {
	color: var(--color-ink);
	text-decoration: none;
}

.njs-body a.njs-credential-badge:hover {
	color: var(--color-ink);
	text-decoration: none;
}

.njs-body hr {
	border: none;
	border-top: 1px solid var(--color-divider);
	margin: var(--space-xl) 0;
}

/* ---- Breadcrumb ---- */
.njs-breadcrumb {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.7;
	margin-bottom: var(--space-md);
}

.njs-breadcrumb a {
	color: var(--color-ink);
	opacity: 0.7;
	text-decoration: none;
}

.njs-breadcrumb a:hover {
	opacity: 1;
	text-decoration: underline;
}

/* ---- Blog archive (category.php, plan 10-03, D-04) — single full-width
   column, one card per article. No two-column njs-content-layout split
   here (an archive has no per-article TOC). ---- */
.njs-archive-col {
	max-width: var(--njs-content-width);
	margin: 0 auto;
}

.njs-archive-description {
	margin-bottom: var(--space-lg);
	color: var(--color-ink);
	opacity: 0.85;
}

.njs-archive-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-xl);
}

.njs-archive-item {
	padding-bottom: var(--space-xl);
	border-bottom: 1px solid var(--color-divider);
}

.njs-archive-item:last-child {
	border-bottom: none;
	padding-bottom: 0;
}

.njs-archive-item__title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	line-height: 1.3;
	margin: 0 0 var(--space-xs);
}

.njs-archive-item__title a {
	color: var(--color-ink);
	text-decoration: none;
}

.njs-archive-item__title a:hover {
	text-decoration: underline;
}

.njs-archive-item__meta {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.7;
	margin: 0 0 var(--space-sm);
}

.njs-archive-item__excerpt {
	margin: 0;
	color: var(--color-ink);
}

.njs-archive-empty {
	color: var(--color-ink);
	opacity: 0.85;
}

/* ---- Answer capsule — primary AI-citation / above-the-fold summary ---- */
.njs-answer-capsule {
	background: var(--color-neutral);
	border-left: 4px solid var(--color-ink);
	padding: var(--space-lg) var(--space-lg);
	margin: 0 0 var(--space-xl);
	font-weight: 500;
	font-size: var(--step-body);
	line-height: 1.6;
}

.njs-answer-capsule strong {
	color: var(--color-ink);
}

/* ---- Quick answer — border-accent + dark-pill variant ---- */
.njs-quick-answer {
	background: var(--color-neutral);
	border-left: 4px solid var(--color-primary);
	padding: var(--space-md) var(--space-lg);
	margin: 0 0 var(--space-lg);
	font-weight: 500;
}

.njs-quick-answer::before {
	content: "Quick Answer: ";
	font-weight: 700;
	color: var(--color-ink);
}

.njs-quick-answer-pill {
	background: var(--color-ink);
	color: var(--color-bg);
	padding: var(--space-md) var(--space-lg);
	margin: 0 0 var(--space-lg);
	font-size: var(--step-body);
	font-weight: 500;
	line-height: 1.6;
}

.njs-quick-answer-pill::before {
	content: "Quick Answer: ";
	font-weight: 700;
}

/* ---- Fact block ---- */
.njs-fact-block {
	background: var(--color-bg);
	border: 2px solid var(--color-ink);
	padding: var(--space-lg) var(--space-lg);
	margin: var(--space-lg) 0;
}

.njs-fact-block ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.njs-fact-block li {
	padding: var(--space-xs) 0;
	font-size: var(--step-label);
	border-bottom: 1px solid var(--color-divider);
}

.njs-fact-block li:last-child {
	border-bottom: none;
}

/* ---- Author box ---- */
.njs-author-box {
	display: flex;
	gap: var(--space-lg);
	align-items: flex-start;
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	border-left: 4px solid var(--color-ink);
	padding: var(--space-lg);
	margin: var(--space-lg) 0;
}

.njs-author-photo {
	width: 80px;
	height: 80px;
	border-radius: 50%;
	background: var(--color-divider);
	flex-shrink: 0;
	overflow: hidden;
}

.njs-author-photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.njs-author-box .njs-author-info p {
	margin: 0 0 var(--space-sm);
	font-size: var(--step-body);
	color: var(--color-ink);
	opacity: 0.75;
}

.njs-author-heading {
	margin: 0 0 var(--space-xs);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
}

.njs-author-credentials {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-sm);
	margin-top: var(--space-sm);
}

.njs-credential-badge {
	background: var(--color-bg);
	color: var(--color-ink);
	opacity: 0.75;
	font-size: 12px;
	font-weight: 600;
	padding: 4px 10px;
	text-transform: uppercase;
	letter-spacing: 0.3px;
	text-decoration: none;
	display: inline-block;
}

a.njs-credential-badge:hover {
	background: var(--color-divider);
	opacity: 1;
	text-decoration: none;
}

/* ---- Extended author bio (end-of-article) ----
   The longer "About Jay" bio that closes a blog post. Deliberately distinct
   from the compact .njs-author-box credibility card at the top: a divider-led,
   transparent block (no card border/background) with a larger photo, so the two
   author touchpoints on a post read as two different things, not a duplicate. */
.njs-author-bio-extended {
	display: flex;
	gap: var(--space-lg);
	align-items: flex-start;
	background: transparent;
	border: 0;
	border-top: 2px solid var(--color-ink);
	padding: var(--space-lg) 0 0;
	margin: var(--space-lg) 0;
}

.njs-author-bio-extended .njs-author-photo {
	width: 96px;
	height: 96px;
}

.njs-author-bio-extended .njs-author-info p {
	margin: 0 0 var(--space-sm);
	font-size: var(--step-body);
	color: var(--color-ink);
	opacity: 0.85;
}

.njs-author-bio-extended h3 {
	margin: 0 0 var(--space-xs);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
}

@media (max-width: 767px) {
	.njs-author-bio-extended {
		flex-direction: column;
		text-align: center;
		align-items: center;
	}
}

/* ---- Trust bar — pages only, centered strip ---- */
.njs-trust-bar {
	display: flex;
	justify-content: center;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-lg);
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	padding: var(--space-md) var(--space-lg);
	margin: 0 0 var(--space-lg);
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.8;
	text-align: center;
}

.njs-trust-bar .njs-trust-star {
	color: var(--color-primary);
	opacity: 1;
}

@media (max-width: 767px) {
	.njs-author-box {
		flex-direction: column;
		text-align: center;
		align-items: center;
	}

	.njs-author-credentials {
		justify-content: center;
	}

	.njs-trust-bar {
		flex-direction: column;
		gap: var(--space-sm);
	}
}

/* ---- Callout boxes ---- */
.njs-callout {
	padding: var(--space-md) var(--space-lg);
	margin: var(--space-lg) 0;
	font-size: var(--step-body);
	line-height: 1.6;
}

/* Safety net: some pages were migrated with the base `callout` class mapped to
   a modifier (e.g. njs-callout-tip) rather than the base njs-callout, leaving
   the box without padding. Give the modifiers their own box treatment so they
   render correctly standalone. Harmless when the base class is also present —
   identical token values, no double padding. */
.njs-callout-tip,
.njs-callout-warning,
.njs-callout-budget,
.njs-callout-stat {
	padding: var(--space-md) var(--space-lg);
	margin: var(--space-lg) 0;
	font-size: var(--step-body);
	line-height: 1.6;
}

.njs-callout-warning {
	background: var(--njs-callout-warning-bg);
	border-left: 4px solid var(--color-sale);
}

.njs-callout-tip {
	background: var(--njs-callout-tip-bg);
	border-left: 4px solid var(--color-accent);
}

.njs-callout-budget {
	background: color-mix(in srgb, var(--color-primary) 12%, white);
	border-left: 4px solid var(--color-primary);
}

.njs-callout-stat {
	background: var(--color-neutral);
	border-left: 4px solid var(--color-ink);
}

.njs-callout strong:first-child {
	display: block;
	margin-bottom: var(--space-xs);
}

/* Key-takeaways callout — emphasized box; carries its own padding since the
   guide-template markup applies the modifier without a base .njs-callout. */
.njs-callout-key-takeaways {
	padding: var(--space-md) var(--space-lg);
	margin: var(--space-lg) 0;
	border-left: 4px solid var(--color-ink);
}

.njs-callout-key-takeaways ul {
	margin-top: var(--space-sm);
	padding-left: 18px;
}

/* Guide-template sub-heading: <p> promoted to an h4-level heading. */
.njs-h4-replacement {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: 1.125rem;
	line-height: 1.2;
	color: var(--color-ink);
	margin: var(--space-lg) 0 var(--space-sm);
}

/* ---- Link-out: internal "keep reading" cross-reference box ----
   A navigation affordance, intentionally distinct from the advisory callout
   family: neutral panel, accent-green left rail, and a high-contrast underlined
   link with a → so it reads as "go here", not "heed this advice". */
.njs-link-out {
	background: var(--color-neutral);
	border-left: 4px solid var(--color-accent);
	padding: var(--space-md) var(--space-lg);
	margin: var(--space-lg) 0;
	font-size: var(--step-body);
	line-height: 1.6;
}

.njs-link-out a {
	font-weight: 600;
	color: var(--color-ink);
	text-decoration: underline;
}

.njs-link-out a::after {
	content: " \2192";
	text-decoration: none;
	display: inline-block;
}

/* ---- Compare cards ---- */
.njs-compare-cards {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-md);
	margin: var(--space-lg) 0;
}

@media (max-width: 500px) {
	.njs-compare-cards {
		grid-template-columns: 1fr;
	}
}

.njs-compare-card {
	border: 1px solid var(--color-divider);
	padding: var(--space-lg);
}

.njs-compare-card-title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	color: var(--color-ink);
	margin-bottom: var(--space-sm);
	padding-bottom: var(--space-sm);
	border-bottom: 2px solid var(--color-ink);
}

.njs-compare-card ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.njs-compare-card li {
	padding: var(--space-sm) 0;
	font-size: var(--step-label);
	border-bottom: 1px solid var(--color-divider);
}

.njs-compare-card li:last-child {
	border-bottom: none;
}

/* ---- Procurement strip (commercial pages) — Phase 16. Base layout on
   .njs-trust-bar's centered flex strip; individual qualification line
   items use the .njs-fact-block li divider-list treatment; the co-op /
   registration pills reuse .njs-credential-badge directly (theme.css
   ~line 2684) rather than forking a new badge style. ---- */
.njs-procurement-strip {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-md);
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	padding: var(--space-lg);
	margin: 0 0 var(--space-lg);
	text-align: center;
}

.njs-procurement-strip__heading {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	color: var(--color-ink);
	margin: 0;
}

.njs-procurement-strip__list {
	list-style: none;
	padding: 0;
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0 var(--space-lg);
}

.njs-procurement-strip__list li {
	padding: var(--space-xs) 0;
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.8;
	border-bottom: 1px solid var(--color-divider);
}

.njs-procurement-strip__badges {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-sm);
}

@media (max-width: 767px) {
	.njs-procurement-strip {
		flex-direction: column;
	}

	.njs-procurement-strip__list {
		flex-direction: column;
		gap: var(--space-xs);
		align-items: center;
	}
}

/* ---- Project proof cards (commercial pages) — Phase 16. Shell composed
   from .njs-card (theme.css ~line 891), image slot from the
   .njs-commercial-tile img aspect-ratio treatment (~line 1375), heading
   from .njs-compare-card-title's divider style (~line 2901), and the
   grid shape from .njs-testimonials__grid (~line 1405).
   .njs-proof-card--video is layout-identical to the photo card, swapping
   the image slot for an inert "video coming soon" placeholder — content
   lands in Phase 18 plan 18-05, not here. ---- */
.njs-proof-cards {
	margin: var(--space-lg) 0;
}

.njs-proof-cards__heading {
	max-width: 480px;
	margin: 0 0 var(--space-md);
}

.njs-proof-cards__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: var(--space-lg);
}

.njs-proof-card {
	background-color: var(--color-bg);
	border-radius: var(--radius-md);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
	padding: var(--space-md);
	transition: box-shadow 150ms ease, transform 150ms ease;
}

.njs-proof-card:hover {
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
	transform: translateY(-2px);
}

.njs-proof-card__image-slot {
	width: 100%;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	background: var(--color-neutral);
	border-radius: var(--radius-sm);
}

.njs-proof-card__title {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	color: var(--color-ink);
	margin: var(--space-sm) 0 var(--space-xs);
	padding-bottom: var(--space-xs);
	border-bottom: 2px solid var(--color-ink);
}

.njs-proof-card__location {
	font-weight: 400;
	opacity: 0.75;
}

.njs-proof-card__blurb {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.8;
	margin: 0;
}

.njs-proof-card--video .njs-proof-card__video-slot {
	width: 100%;
	aspect-ratio: 3 / 4;
	background: var(--color-neutral);
	border-radius: var(--radius-sm);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-xs);
	color: var(--color-ink);
	opacity: 0.6;
}

.njs-proof-card__video-icon {
	font-size: var(--step-heading);
}

.njs-proof-card__video-label {
	font-size: var(--step-label);
	text-transform: uppercase;
	letter-spacing: 0.5px;
}

@media (max-width: 767px) {
	.njs-proof-cards__grid {
		grid-template-columns: 1fr;
	}
}

/* ---- CTA blocks (dark / soft / phone-line) — buttons inside reuse this
   theme's existing .njs-btn/.njs-btn-primary/.njs-btn-secondary component
   (UI-SPEC Buttons), not a separate content-only button style. ---- */
.njs-cta-dark {
	background: var(--color-ink);
	color: var(--color-bg);
	padding: var(--space-xl) var(--space-lg);
	margin: var(--space-2xl) 0;
	text-align: center;
}

.njs-cta-dark h3 {
	color: var(--color-bg);
	margin: 0 0 var(--space-sm);
}

.njs-cta-dark p {
	color: color-mix(in srgb, var(--color-bg) 80%, transparent);
	margin-bottom: var(--space-lg);
}

.njs-cta-soft {
	background: var(--color-neutral);
	color: var(--color-ink);
	text-align: left;
	padding: var(--space-lg);
}

.njs-cta-soft p {
	color: var(--color-ink);
	opacity: 0.85;
	margin-bottom: var(--space-md);
}

.njs-cta-phone-line {
	margin-top: var(--space-md);
	margin-bottom: 0;
	font-size: var(--step-label);
}

.njs-cta-phone-link {
	color: inherit;
	font-weight: 700;
}

/* ---- Before / After comparison (mfn_before_after Elementor widget
   flattened to a static two-image comparison — D-10 "flatten interactive
   widgets into clean single-flow sections," same principle already
   applied to accordion/tabs). ---- */
.njs-before-after {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-md);
	margin: var(--space-lg) 0;
}

@media (max-width: 500px) {
	.njs-before-after {
		grid-template-columns: 1fr;
	}
}

.njs-before-after figure {
	margin: 0;
}

.njs-before-after img {
	width: 100%;
	height: auto;
	display: block;
}

.njs-before-after figcaption {
	font-size: var(--step-label);
	font-weight: 600;
	text-align: center;
	padding-top: var(--space-sm);
	text-transform: uppercase;
	letter-spacing: 0.5px;
	color: var(--color-ink);
	opacity: 0.7;
}

/* ---- Content image ---- */
.njs-content-image {
	margin: var(--space-lg) 0;
}

.njs-content-image img {
	width: 100%;
	height: auto;
	display: block;
}

.njs-content-image figcaption {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.65;
	text-align: center;
	padding-top: var(--space-sm);
}

/* ---- Blog layer (single.php, plan 10.2) ----
   The 6 "Ultimate Guide" blog posts carry their own long-form section
   components not present on any page-content.php page: an in-body
   expandable detail block (layer-2), a multi-part guide section divider
   (part-header/part-label), an end-of-article internal-links block
   (related-reading), a bigger boxed CTA variant (cta-block, distinct from
   the existing .njs-cta-soft/.njs-cta-dark), and an unresolved-image stub
   marker (image-placeholder). See scripts/convert-content-to-njs.php's
   njs_convert_blog_rename_additions() docblock for the full source-token
   list this styles. */

/* ---- Layer-2 (in-body expandable detail -- long-form sections that go
   deeper than the buyer-basics layer immediately above them; native
   details/summary, same accessible-disclosure pattern as .njs-mobile-toc
   above but styled distinctly since this holds real body content, not
   chrome) ---- */
.njs-layer-2 {
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	border-left: 4px solid var(--color-accent);
	margin: var(--space-lg) 0;
}

.njs-layer-2 summary {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-body);
	color: var(--color-ink);
	padding: var(--space-md) var(--space-lg);
	cursor: pointer;
	list-style: none;
}

.njs-layer-2 summary::-webkit-details-marker {
	display: none;
}

.njs-layer-2-content {
	padding: 0 var(--space-lg) var(--space-lg);
}

.njs-layer-2-content p:last-child {
	margin-bottom: 0;
}

/* ---- Part header (multi-part "Ultimate Guide" section divider -- an
   eyebrow label + the section's own H2, e.g. "Part 1 -- The Overview") ---- */
.njs-part-header {
	margin: var(--space-2xl) 0 var(--space-lg);
	padding-top: var(--space-xl);
	border-top: 2px solid var(--color-divider);
}

.njs-part-header:first-child {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}

.njs-part-header h2 {
	margin-top: 0;
}

.njs-part-label {
	display: inline-block;
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.5px;
	color: var(--color-bg);
	background: var(--color-ink);
	padding: 4px 10px;
	margin-bottom: var(--space-sm);
}

/* ---- Related reading (end-of-article internal links) ---- */
.njs-related-reading {
	margin-top: var(--space-2xl);
	padding-top: var(--space-xl);
	border-top: 2px solid var(--color-divider);
}

.njs-related-reading h3 {
	margin: 0 0 var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
}

.njs-related-reading ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.njs-related-reading li {
	padding: var(--space-sm) 0;
	border-bottom: 1px solid var(--color-divider);
}

.njs-related-reading li:last-child {
	border-bottom: none;
}

.njs-related-reading a {
	color: var(--color-ink);
	font-weight: 600;
	text-decoration: none;
}

.njs-related-reading a:hover {
	text-decoration: underline;
}

/* ---- CTA block (generic boxed CTA; combine with .njs-cta-soft for the
   existing neutral-background treatment, or use bare for a bordered box
   with its own heading -- reuses .njs-btn/.njs-btn-primary for any button
   inside, same as the other CTA variants above) ---- */
.njs-cta-block {
	padding: var(--space-lg);
	margin: var(--space-xl) 0;
	border: 1px solid var(--color-divider);
}

.njs-cta-block h3 {
	margin: 0 0 var(--space-sm);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
}

.njs-cta-block p:last-of-type {
	margin-bottom: 0;
}

/* ---- CTA soft, tight spacing modifier (combine with .njs-cta-block
   .njs-cta-soft for a denser, mid-paragraph callout rather than a
   section-break-level CTA) ---- */
.njs-cta-soft-tight {
	padding: var(--space-md);
	margin: var(--space-lg) 0;
}

/* ---- Image placeholder (unresolved image stub -- marks where a real
   photo still needs to be sourced/uploaded before publish; intentionally
   visually distinct so it can never be mistaken for finished content, per
   the project's no-fabrication rule) ---- */
.njs-image-placeholder {
	border: 2px dashed var(--color-divider);
	background: var(--color-neutral);
	color: var(--color-ink);
	opacity: 0.6;
	font-style: italic;
	font-size: var(--step-label);
	padding: var(--space-xl);
	margin: var(--space-lg) 0;
	text-align: center;
}

/* ---- Sidebar TOC ---- */
.njs-toc {
	background: var(--color-bg);
	border: 1px solid var(--color-divider);
	padding: var(--space-lg);
	margin-bottom: var(--space-lg);
}

.njs-toc-title {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.5px;
	color: var(--color-ink);
	opacity: 0.65;
	margin: 0 0 var(--space-md);
	padding-bottom: var(--space-sm);
	border-bottom: 2px solid var(--color-divider);
}

.njs-toc-list {
	list-style: none;
	padding: 0;
	margin: 0;
}

.njs-toc-list li {
	margin-bottom: var(--space-sm);
}

.njs-toc-list a {
	color: var(--color-ink);
	opacity: 0.7;
	text-decoration: none;
	font-size: var(--step-label);
	display: block;
	padding: 6px 10px;
	border-left: 3px solid transparent;
	transition: all 0.2s ease;
}

.njs-toc-list a:hover {
	background: var(--color-neutral);
	opacity: 1;
	border-left-color: var(--color-primary);
}

/* ---- Mobile TOC (details/summary, hidden on desktop where the sticky
   sidebar TOC already renders) ---- */
.njs-mobile-toc {
	display: none;
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	padding: 0;
	margin: 0 0 var(--space-lg);
}

.njs-mobile-toc summary {
	font-size: var(--step-label);
	font-weight: 700;
	padding: var(--space-md) var(--space-lg);
	cursor: pointer;
	list-style: none;
}

.njs-mobile-toc summary::-webkit-details-marker {
	display: none;
}

.njs-mobile-toc .njs-toc-list {
	padding: 0 var(--space-lg) var(--space-md);
}

/* ---- Sidebar CTA ---- */
.njs-sidebar-cta {
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	padding: var(--space-lg);
	text-align: center;
}

.njs-sidebar-cta-heading {
	margin: 0 0 var(--space-md);
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-label);
	color: var(--color-ink);
}

.njs-sidebar-cta a {
	color: var(--color-primary);
	text-decoration: none;
	display: block;
	margin: var(--space-sm) 0;
	font-weight: 600;
}

.njs-sidebar-cta a:hover {
	text-decoration: underline;
}

.njs-sidebar-cta-note {
	font-size: var(--step-label);
	margin: var(--space-sm) 0 0;
	color: var(--color-ink);
	opacity: 0.65;
}

/* ---- FAQ accordion (native details/summary, no JS — nested-accordion/
   nested-tabs Elementor widgets flatten to this, D-10) ---- */
details.njs-faq-item {
	border-bottom: 1px solid var(--color-divider);
}

details.njs-faq-item summary {
	padding: var(--space-md) 0;
	font-weight: 600;
	cursor: pointer;
	font-size: var(--step-body);
	list-style: none;
}

details.njs-faq-item summary::-webkit-details-marker {
	display: none;
}

details.njs-faq-item summary::before {
	content: "Q: ";
	font-weight: 700;
}

details.njs-faq-item .njs-faq-answer {
	padding: 0 0 var(--space-md);
	font-size: var(--step-body);
	line-height: 1.6;
}

.njs-faq-answer p:last-child {
	margin-bottom: 0;
}

/* ---- Responsive — sidebar/mobile breakpoint (UI-SPEC structural
   breakpoint, ≤767px, matches the plan's explicit spec) ---- */
@media (max-width: 767px) {
	.njs-content-layout {
		flex-direction: column;
	}

	.njs-sidebar {
		display: none;
	}

	.njs-mobile-toc {
		display: block;
	}

	.njs-content-col {
		max-width: 100%;
	}
}

/* ============================================
   PHASE 10.1 CONTENT COMPONENTS
   (10.1-01, T-10.1-01) — the GAP list from
   .planning/phases/10.1-content-component-system-and-conversion/10.1-RENAME-MAP.md.
   Content classes with NO njs- rule anywhere above. Added ONCE, site-wide,
   additive only — never per-page inline CSS. Visual intent ported from
   docs/county-pages-html/njs-components.css where that file has the
   component (njs-table*, njs-author-social-links), and from the service
   drafts' own inline <style> block where it doesn't (cta-buttons/-heading,
   steps-list, page-footer/last-updated, project-card family, section-alt,
   faq-section) — using this theme's own --color-, --space-, --step-
   tokens throughout, matching the surrounding file's convention rather
   than njs-components.css's older --njs-* palette.
   ============================================ */

/* ---- Table (table-wrapper is the OUTER scroll wrapper, table is the
   INNER element — a two-element pair, never one selector doing both jobs.
   proc-table / inspection-table / a bare <table> are the SAME
   scroll-wrapped table pattern and fold into this one target. ---- */
.njs-table-wrapper {
	overflow-x: auto;
	margin: var(--space-lg) 0;
	-webkit-overflow-scrolling: touch;
}

.njs-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--step-label);
}

.njs-table th {
	background: var(--color-neutral);
	color: var(--color-ink);
	padding: var(--space-sm) var(--space-md);
	text-align: left;
	font-weight: 600;
	white-space: nowrap;
}

.njs-table td {
	padding: var(--space-sm) var(--space-md);
	border-bottom: 1px solid var(--color-divider);
	vertical-align: top;
}

.njs-table tr:nth-child(even) {
	background: var(--color-neutral);
}

/* ---- Author social links (author-box footer line) ---- */
.njs-author-social-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-md);
	margin-top: var(--space-sm);
	font-size: var(--step-label);
}

.njs-author-social-links a {
	color: var(--color-ink);
	opacity: 0.65;
	text-decoration: none;
	font-weight: 500;
}

.njs-author-social-links a:hover {
	opacity: 1;
	text-decoration: underline;
}

/* ---- CTA heading + button row (lives inside .njs-cta-soft/-dark; the
   buttons themselves reuse the sitewide .njs-btn/-primary/-secondary
   component, not a separate style) ---- */
.njs-cta-heading {
	font-family: var(--font-heading);
	font-weight: 500;
	font-size: var(--step-heading);
	color: var(--color-ink);
	margin: 0 0 var(--space-sm);
}

.njs-cta-buttons {
	display: flex;
	gap: var(--space-md);
	justify-content: center;
	flex-wrap: wrap;
	margin-top: var(--space-md);
}

/* ---- Numbered steps list (step-list is a spelling variant of the same
   component, folded into this one target) ---- */
.njs-steps-list {
	list-style: none;
	margin: 0 0 var(--space-lg);
	padding: 0;
	counter-reset: njs-steps;
}

.njs-steps-list li {
	counter-increment: njs-steps;
	padding: var(--space-md) var(--space-md) var(--space-md) 52px;
	border-bottom: 1px solid var(--color-divider);
	position: relative;
}

.njs-steps-list li::before {
	content: counter(njs-steps);
	position: absolute;
	left: var(--space-md);
	top: var(--space-md);
	width: 24px;
	height: 24px;
	background: var(--color-ink);
	color: var(--color-bg);
	font-size: 0.75rem;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
}

.njs-steps-list li:last-child {
	border-bottom: none;
}

/* ---- Page footer + last-updated byline ---- */
.njs-page-footer {
	margin-top: var(--space-3xl);
	padding-top: var(--space-xl);
	border-top: 2px solid var(--color-divider);
	text-align: center;
	color: var(--color-ink);
	opacity: 0.75;
	font-size: var(--step-label);
}

.njs-page-footer p {
	margin: var(--space-xs) 0;
}

.njs-last-updated {
	font-style: italic;
	margin-top: var(--space-md) !important;
}

/* ---- FAQ section wrapper (trivial spacing only — the .njs-faq-item
   details/summary rules above carry all the real FAQ styling) ---- */
.njs-faq-section {
	margin: 0 0 var(--space-xl);
}

/* ---- Alternating-background section (procurement page) ---- */
.njs-section-alt {
	background: var(--color-neutral);
	margin: 0 calc(-1 * var(--space-md));
	padding: var(--space-xl) var(--space-md);
}

/* ---- Project showcase (county pages + flagship landing) ---- */
.njs-projects-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: var(--space-lg);
	margin: var(--space-xl) 0;
}

.njs-project-card {
	background: var(--color-neutral);
	border: 1px solid var(--color-divider);
	padding: var(--space-lg);
}

.njs-project-card p {
	margin: 0;
	font-size: var(--step-body);
}

.njs-project-figure {
	margin: 0;
}

.njs-project-figure img {
	width: 100%;
	height: 200px;
	object-fit: cover;
	display: block;
}

.njs-project-figure figcaption {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.65;
	padding: var(--space-sm) 0 0;
	font-style: italic;
}

.njs-project-meta {
	font-size: var(--step-label);
	color: var(--color-ink);
	opacity: 0.65;
	margin: var(--space-xs) 0 var(--space-sm);
}

.njs-project-testimonial {
	font-style: italic;
	color: var(--color-ink);
	opacity: 0.85;
	margin: var(--space-sm) 0;
	padding-left: var(--space-md);
	border-left: 3px solid var(--color-divider);
}

.njs-project-testimonial cite {
	display: block;
	margin-top: var(--space-xs);
	font-style: normal;
	font-size: var(--step-label);
	opacity: 0.75;
}

/* ---- Trust bar sub-elements (the .njs-trust-bar wrapper itself is
   already styled above — these are its two child tokens) ---- */
.njs-trust-bar-stars {
	color: var(--color-primary);
	white-space: nowrap;
}

.njs-trust-bar-divider {
	opacity: 0.5;
	white-space: nowrap;
}

/* ---- County / municipality name lists (flat lists of place names with
   no design source anywhere — previously fully unstyled) ---- */
.njs-county-grid,
.njs-municipality-grid {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-sm) var(--space-md);
	margin: var(--space-md) 0;
	font-size: var(--step-label);
}

/* ---- Turf sample gallery (artificial-turf-installation-nj only) ---- */
.njs-turf-lines {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--space-lg);
	margin: var(--space-lg) 0;
}

.njs-turf-line img {
	width: 100%;
	height: auto;
	display: block;
}

.njs-tl-label {
	padding: var(--space-sm) 0 0;
	font-size: var(--step-label);
}

.njs-tl-use {
	display: block;
	font-weight: 600;
	color: var(--color-ink);
}

.njs-tl-name {
	display: block;
	color: var(--color-ink);
	opacity: 0.65;
}

/* ============================================
   LAYERED CATEGORY-PAGE GUIDE (plan 18-14, D-CATEGORY-LAYERED-CONTENT)
   Below-grid buyer guide + jump-nav on product_cat archives. The guide body
   is wrapped in .njs-body so it inherits all component/heading typography;
   these rules only handle the container separation and the jump-nav chrome.
   ============================================ */
.njs-category-guide {
	margin-top: var(--space-2xl);
	padding-top: var(--space-xl);
	border-top: 2px solid var(--color-divider);
	clear: both;
}

.njs-category-guide__body {
	margin-top: var(--space-md);
}

/* First heading in the guide already carries the .njs-body top rule; the
   container border above is the separator from the grid, so drop the doubled
   line on the guide's opening H2. */
.njs-category-guide .njs-category-guide__body > h2:first-child {
	border-top: none;
	padding-top: 0;
	margin-top: 0;
}

.njs-guide-nav {
	margin: 0 0 var(--space-xl);
	padding: var(--space-md) var(--space-lg);
	background: var(--color-neutral);
	border-radius: var(--radius-md);
}

.njs-guide-nav__title {
	margin: 0 0 var(--space-sm);
	font-family: var(--font-heading);
	font-weight: 600;
	font-size: 0.95rem;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--color-ink);
	opacity: 0.7;
}

.njs-guide-nav__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-xs) var(--space-lg);
}

.njs-guide-nav__item {
	margin: 0;
}

.njs-guide-nav__item a {
	color: var(--color-primary);
	text-decoration: none;
	border-bottom: 1px solid transparent;
}

.njs-guide-nav__item a:hover,
.njs-guide-nav__item a:focus {
	border-bottom-color: currentColor;
}

/* ============================================
   QUICK SHIP CARD BADGE (plan 18-12, D-06b)
   Per-product badge on shop-loop cards; renders only when the product carries
   the pa_availability "quick-ship" term (see inc/woocommerce-hooks.php). The
   loop item is positioned so the badge can sit over the top-left of the card.
   ============================================ */
.njs-woo-page ul.products li.product {
	position: relative;
}

.njs-quick-ship-badge {
	position: absolute;
	top: var(--space-sm);
	left: var(--space-sm);
	z-index: 2;
	display: inline-block;
	padding: 2px var(--space-sm);
	font-family: var(--font-heading);
	font-size: 0.72rem;
	font-weight: 600;
	line-height: 1.5;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	color: #fff;
	background: var(--color-accent);
	border-radius: var(--radius-pill);
}

/* A variable product's parent holds no SKU by design -- a variant family has no
   single manufacturer part number. inc/product-sku-display.php empties
   WooCommerce's "N/A" placeholder rather than removing the element, because
   add-to-cart-variation.js writes the chosen variation's real part number into
   it. Hide the row only while it is genuinely empty. */
.sku_wrapper:has(.sku:empty) {
	display: none;
}

/* ---- Review summary + review cards (About page "What People Say", Jay
   2026-09-26: "its bland now"). Pattern from common review widgets: a rating
   header, cards with an initial avatar, name, date, stars and a topic tag, and
   pill links to the other review sites. No carousel -- every card is visible
   and keyboard-reachable. The CTA selector carries the `a` so it outranks
   `.njs-body a` (green, underlined). Stars are only rendered for reviews that are 5 stars
   in the source; the markup carries them, the CSS only colors them. ---- */
.njs-reviews-summary {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-lg);
	margin: 0 0 var(--space-md);
	padding: 20px var(--space-lg);
	background: var(--color-neutral);
	border-radius: var(--radius-md);
}

.njs-reviews-summary__score {
	font-family: var(--font-heading);
	font-size: 3rem;
	font-weight: 600;
	line-height: 1;
}

.njs-reviews-summary__meta {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.njs-reviews-summary__count {
	font-size: 0.95rem;
	color: #5f5f5f;
}

.njs-reviews-summary__source {
	display: inline-flex;
	align-items: center;
	gap: var(--space-sm);
	font-weight: 600;
}

.njs-reviews-summary a.njs-reviews-summary__cta,
.njs-reviews-summary a.njs-reviews-summary__cta:visited {
	margin-left: auto;
	padding: var(--space-sm) 18px;
	border: 2px solid var(--color-ink);
	border-radius: var(--radius-pill);
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--color-ink);
	text-decoration: none;
	white-space: nowrap;
}

.njs-reviews-summary a.njs-reviews-summary__cta:hover,
.njs-reviews-summary a.njs-reviews-summary__cta:focus-visible {
	background: var(--color-ink);
	color: #fff;
}

.njs-stars {
	color: var(--color-primary);
	font-size: 1.25rem;
	letter-spacing: 2px;
	line-height: 1;
}

.njs-review-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: var(--space-md);
	margin: 0 0 var(--space-md);
}

.njs-review-card {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin: 0;
	padding: 20px;
	background: var(--color-bg);
	border: 1px solid #e6e6e1;
	border-radius: var(--radius-md);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.njs-review-card__head {
	display: flex;
	align-items: center;
	gap: 12px;
}

.njs-review-card__avatar {
	display: grid;
	place-items: center;
	flex: none;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: var(--color-accent);
	color: #fff;
	font-weight: 600;
}

.njs-review-card__who {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
}

.njs-review-card__name {
	font-style: normal;
	font-weight: 600;
}

.njs-review-card__date {
	font-size: 0.8rem;
	color: #5f5f5f;
}

.njs-review-card__g {
	flex: none;
	margin-left: auto;
}

.njs-review-card .njs-stars {
	font-size: 1rem;
}

.njs-review-card blockquote {
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-size: 0.97rem;
	font-style: normal;
}

.njs-review-card blockquote p {
	margin: 0;
}

.njs-review-card__tag {
	align-self: flex-start;
	margin-top: auto;
	padding: 3px 10px;
	border-radius: var(--radius-pill);
	background: #eef6ea;
	color: #3f7a28;
	font-size: 0.75rem;
	font-weight: 600;
}

.njs-review-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-sm);
	margin: 0 0 var(--space-lg);
	font-size: 0.9rem;
	color: #5f5f5f;
}

.njs-review-links a,
.njs-review-links a:visited {
	padding: 5px 14px;
	border: 1px solid var(--color-divider);
	border-radius: var(--radius-pill);
	color: var(--color-ink);
	font-weight: 500;
	text-decoration: none;
}

.njs-review-links a:hover,
.njs-review-links a:focus-visible {
	border-color: var(--color-ink);
}

@media (max-width: 600px) {
	.njs-reviews-summary {
		gap: var(--space-md);
	}

	.njs-reviews-summary a.njs-reviews-summary__cta,
	.njs-reviews-summary a.njs-reviews-summary__cta:visited {
		margin-left: 0;
	}
}

/* ============================================
   261009-b55 — HEADER, TOP BAR, COMMERCIAL DROPDOWN, CONTACT US, FOOTER
   Jay's homepage walkthrough rulings 2026-10-08/09 (S1, S10, D2, D2 PHONES, D5).
   Site-wide, header/footer only. No :root token changes, nothing in the
   locked post/page column, rail or content header band.
   ============================================ */

/* ---- S1 top bar: one slim line (~36px) above the header ---- */
.njs-trust-bar.njs-trust-bar--top {
	border: 0;
	margin: 0;
	opacity: 1;
	flex-wrap: nowrap;
	padding: 0;
	color: #3a3a3a;
	white-space: nowrap;
}

.njs-trust-bar--top .njs-trust-bar__inner {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: var(--space-lg);
	min-height: 36px;
	padding-block: 6px;
	flex-wrap: nowrap;
	white-space: nowrap;
}

.njs-trust-bar--top a {
	color: inherit;
}

@media (max-width: 767px) {
	.njs-trust-bar.njs-trust-bar--top {
		flex-direction: row;
	}

	.njs-trust-bar--top .njs-trust-bar__inner {
		gap: 0;
		min-height: 32px;
		padding-block: 4px;
		font-size: 13px;
	}

	.njs-trust-bar--top .njs-trust-bar__item--family,
	.njs-trust-bar--top .njs-trust-bar__phone,
	.njs-trust-bar--top .njs-trust-bar__long {
		display: none;
	}

	.njs-trust-bar--top .njs-trust-bar__item--since::after {
		content: "·" / "";
		margin-inline: 0.45em;
	}
}

/* ---- S1 desktop header: six one-line labels, 88px (60 scrolled) ---- */
@media (min-width: 1025px) {
	.njs-primary-nav__list > li > a,
	.njs-primary-nav__list > li > .njs-nav-trigger,
	.njs-primary-nav__list > li > .njs-nav-label {
		white-space: nowrap;
	}

	/* Phase 29 (D1): the caret marks an item that opens a panel. A
	   mega-group gets it only when its panel printed (Commercial has none
	   while the bar shows), and an open-only button always has one. */
	.njs-primary-nav__list > li.menu-item-mega-group:has(> .mega-dropdown) > a::after,
	.njs-primary-nav__list > li > .njs-nav-trigger::after {
		content: "▾" / "";
		display: inline-block;
		margin-left: 0.3em;
		font-size: 0.9em;
	}

	.mega-dropdown__col-title a.mega-dropdown__col-link {
		color: inherit;
		text-decoration: none;
	}

	.mega-dropdown__col-title a.mega-dropdown__col-link:hover {
		color: var(--color-primary);
		text-decoration: underline;
	}

	.mega-dropdown a:focus-visible {
		outline: 2px solid var(--color-ink);
		outline-offset: 2px;
	}
}

/* Phone number visually hidden (clip pattern, keeps the accessible name) 1025-1279px. */
@media (min-width: 1025px) and (max-width: 1279px) {
	.njs-phone-link--desktop .njs-phone-link__number {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip: rect(0, 0, 0, 0);
		white-space: nowrap;
		border: 0;
	}
}

/* Width budget, measured at 1025-1920 against the local render harness. */
@media (min-width: 1025px) and (max-width: 1439px) {
	.njs-site-header__inner {
		gap: var(--space-md);
		padding-inline: clamp(0.75rem, 1.5vw, 1.5rem);
	}

	.njs-primary-nav__list {
		gap: clamp(10px, 2.2vw - 12px, 20px);
	}

	.njs-primary-nav__list > li > a,
	.njs-primary-nav__list > li > .njs-nav-trigger,
	.njs-primary-nav__list > li > .njs-nav-label {
		letter-spacing: 0.5px;
	}

	.njs-header-utility {
		gap: 2px;
	}

	.njs-header-utility .njs-icon-btn {
		min-width: 40px;
	}
}

@media (min-width: 1025px) and (max-width: 1279px) {
	.njs-site-header__logo-img {
		height: 38px;
	}

	.njs-primary-nav__list > li > a,
	.njs-primary-nav__list > li > .njs-nav-trigger,
	.njs-primary-nav__list > li > .njs-nav-label {
		font-size: 13px;
	}

	/* Phase 29 (CONTEXT Fit): the six-label row with two carets overflows
	   its padding by 7.6px at 1025, so a row of six or more items gets an
	   8px gap floor here. Today's four-item row keeps the gap above. */
	.njs-primary-nav__list:has(> li:nth-child(6)) {
		gap: clamp(8px, 2.2vw - 14.5px, 20px);
	}
}

/* ---- D2 Contact us: the homepage .njs-home-btn family (D5) ---- */
.njs-btn.njs-header-cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 40px;
	padding: 0 16px;
	border-radius: 6px;
	font-family: var(--font-heading);
	font-weight: 700;
	font-size: 15px;
	line-height: 1;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	white-space: nowrap;
	background-color: var(--color-primary);
	color: var(--color-ink);
	text-decoration: none;
	flex-shrink: 0;
}

.njs-btn.njs-header-cta--mobile {
	display: none;
}

@media (max-width: 1024px) {
	/* D2 PHONES: one row beside the logo at 375px. Floors: logo >= 96px wide,
	   tap targets >= 40x40, no overlap, nothing past the viewport. */
	.njs-btn.njs-header-cta--mobile {
		display: inline-flex;
		min-height: 40px;
		padding: 0 9px;
		font-size: 12px;
		margin-inline: 2px;
	}

	.njs-mobile-header__actions {
		gap: 0;
	}

	.njs-mobile-header .njs-icon-btn {
		min-width: 40px;
		min-height: 40px;
		padding: 0;
	}

	.njs-mobile-header__logo {
		min-width: 0;
		flex: 1 1 auto;
	}

	.njs-mobile-header__logo-img {
		height: auto;
		max-height: 34px;
		width: auto;
		max-width: 100%;
	}
}

@media (max-width: 420px) {
	.njs-mobile-header__logo-img {
		max-height: 27px;
	}
}

/* ---- S10 footer: green contact icons, Get Started in the primary button family ---- */
.njs-site-footer__contact-item .njs-icon {
	color: var(--color-accent);
}

.njs-btn.njs-site-footer__signup-btn,
.njs-btn.njs-site-footer__signup-btn[disabled] {
	opacity: 1;
	cursor: not-allowed;
	border-radius: 6px;
	font-family: var(--font-heading);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	background-color: var(--color-primary);
	color: var(--color-ink);
}

/* ============================================
   261009-idm — DESKTOP CATEGORY BAR
   Rulings CATEGORY BAR + CATEGORY BAR CONTENTS (Jay 2026-10-09). Its own
   row right after the sticky header, >=1025px only, NOT sticky (it scrolls
   away). 44px including the 1px borders (global border-box reset). Panels
   reuse .mega-dropdown and position against this nav. No :root token
   changes, nothing in the locked post/page column, rail or header band.
   ============================================ */
.njs-category-bar {
	display: none;
}

@media (min-width: 1025px) {
	.njs-category-bar {
		display: block;
		position: relative;
		z-index: 19;
		height: 44px;
		background-color: #ffffff;
		border-top: 1px solid #e4e4e4;
		border-bottom: 1px solid #e4e4e4;
	}

	.njs-category-bar__inner {
		height: 100%;
		padding-inline: 20px;
	}

	.njs-category-bar__list {
		display: flex;
		flex-wrap: nowrap;
		justify-content: center;
		align-items: stretch;
		gap: 22px;
		height: 100%;
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.njs-category-bar__list > li {
		display: flex;
		margin: 0;
		padding: 0;
	}

	.njs-category-bar__list > li > a {
		display: flex;
		align-items: center;
		height: 100%;
		font-family: var(--font-heading);
		font-weight: 700;
		font-size: 16px;
		line-height: 1.2;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		color: var(--color-ink);
		text-decoration: none;
		white-space: nowrap;
	}

	.njs-category-bar__list > li > a:hover,
	.njs-category-bar__list > li > a:focus-visible,
	.njs-category-bar__list > li:hover > a {
		box-shadow: inset 0 -2px 0 var(--color-primary);
	}

	.njs-category-bar__list > li > a:focus-visible {
		outline: 2px solid var(--color-ink);
		outline-offset: -2px;
	}

	/* Thin divider between Sports Courts and Swingsets (Version B). Decorative, no DOM text. */
	.njs-category-bar__list > li.njs-cb-divider-before::before {
		content: "";
		align-self: center;
		flex: 0 0 1px;
		width: 1px;
		height: 20px;
		margin-right: 22px;
		background-color: #bbbbbb;
	}

	/* Phase 29 (D1): the muted "Commercial:" lead-in, a menu item classed
	   njs-cb-lead rendered as a span by inc/nav-walker.php. Measured fit
	   (29-RESEARCH "Measured Fit"): 13px with a 12px visual gap after it
	   (the list's 22px gap + margin-right -10px). Inert until a bar item
	   carries the class. */
	.njs-category-bar__list > li.njs-cb-lead {
		display: flex;
		align-items: center;
		white-space: nowrap;
		margin-right: -10px;
	}

	/* Optical alignment (29-02 fit gate): centered as a box, the 13px
	   caps sit about 0.7px (layout) to 0.9px (Retina pixels) above the 16px
	   labels' caps, because Chrome rounds the font ascent and snaps glyphs
	   to whole device pixels. 0.5px down puts the lead's glyph ink on the
	   labels' center line: 0.0px delta on live headed Chrome at every
	   desktop width (29-04 lead-ink-optimum), where 1px read +0.5px. */
	.njs-category-bar__lead {
		position: relative;
		top: 0.5px;
		font-family: var(--font-heading);
		font-weight: 700;
		font-size: 13px;
		line-height: 1.2;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		color: #666;
	}

	.njs-category-bar__list > li:hover > .mega-dropdown,
	.njs-category-bar__list > li:focus-within > .mega-dropdown {
		display: block;
	}

	/* The bar's panels start flush at its bottom edge, so there is no gap to
	   bridge. The default 30px bridge would cover the lower part of the
	   neighbouring bar links and block moving from one item to the next. */
	.njs-category-bar .mega-dropdown::before {
		content: none;
	}
}

@media (max-width: 1024px) {
	.njs-category-bar {
		display: none;
	}
}
