/* ==========================================================================
   Bright Path — foundation layer

   OWNER: Main only. Gutter, stacking order, footer geometry, nav breakpoint, decorative shape colours.

   One shard of what used to be a single style.css. The split exists so that
   parallel work cannot collide: `.design-core/` is not under version control,
   so two agents editing one file means one of them is lost, not merged.
   Do not move rules between shards without saying so.
   ========================================================================== */

/* ==========================================================================
   Bright Path theme stylesheet

   Deliberately small. theme.json owns colour, type, spacing and layout.
   main.css from the prototype is NOT ported here — it carries 63 dead class
   names, the dead tabs/toast/modal code, and a duplicate of every token
   theme.json now owns. That selective port is a later plan.

   Contents
     1  Gutter step-down (the two rungs theme.json cannot express)
     2  Stacking order tokens
     3  Footer middle rung
     4  core/navigation breakpoint override
     5  Decorative shape colours (color-mix refactor)
   ========================================================================== */


/* --------------------------------------------------------------------------
   1  Gutter step-down

   theme.json root padding takes ONE value and cannot express a media query,
   so 2rem is the base and these two queries step it down.

   Selector is `body` because that is what this install actually emits. Read
   back from WP_Theme_JSON::get_stylesheet() on WordPress 7.1.1:

     body{--wp--style--root--padding-top: 0;
          --wp--style--root--padding-right: 2rem;
          --wp--style--root--padding-bottom: 0;
          --wp--style--root--padding-left: 2rem;}

   Both rules are specificity (0,0,1), so ONLY source order decides. This
   stylesheet declares 'global-styles' as a dependency in functions.php so it
   always prints after. Do not drop that dependency.

   Contract 3: three rungs, boundaries 640/641 and 899/900. There is NO 768px
   gutter rung -- 768 is the utility-bar message breakpoint and nothing else.
   -------------------------------------------------------------------------- */

@media (max-width: 899px) {
	body {
		--wp--style--root--padding-left: 1.5rem;
		--wp--style--root--padding-right: 1.5rem;
	}
}

@media (max-width: 640px) {
	body {
		--wp--style--root--padding-left: 1.25rem;
		--wp--style--root--padding-right: 1.25rem;
	}
}


/* --------------------------------------------------------------------------
   2  Stacking order

   These map to no editor control, so they are not settings.custom -- putting
   them there would imply a control that will never exist.

   NOTE: WordPress's admin bar is z-index 99999. --z-skip is the top of THIS
   theme's stack, not the top of the page's stack on the built site.
   -------------------------------------------------------------------------- */

:root {
	--z-base: 1;
	--z-dropdown: 100;
	--z-header: 200;
	--z-mobile-nav: 300;
	--z-modal: 400;
	--z-toast: 500;
	--z-skip: 600;
}


/* --------------------------------------------------------------------------
   3  Footer middle rung

   core/columns only knows "stack below 782px". The design's footer is
   1 column below 641, 2 columns from 641 to 899, and 4 columns from 900.
   This query supplies the middle rung core cannot express.
   -------------------------------------------------------------------------- */

@media (min-width: 641px) and (max-width: 899px) {
	.wp-block-columns.brightpath-footer__columns {
		flex-wrap: wrap !important;
	}

	.wp-block-columns.brightpath-footer__columns > .wp-block-column {
		/* Two columns share one 48px gap, so each gives up half of it.
		   Do NOT compute this from --wp--style--block-gap: on this element it
		   resolves to 24px while the rendered column-gap is 48px, which
		   subtracts 12px instead of 24px, overflows by 8px and wraps to four
		   rows. That shipped once and measured as four rows at 641-899. */
		flex-basis: calc(50% - 24px) !important;
		flex-grow: 0;
	}
}

@media (max-width: 640px) {
	.wp-block-columns.brightpath-footer__columns > .wp-block-column {
		flex-basis: 100% !important;
	}
}



/* --------------------------------------------------------------------------
   3b  Footer column geometry at >=900px

   Prototype source: .footer__grid { gap: var(--space-8) }  -> 48px
                     grid-template-columns: 1.6fr 1fr 1fr 1.3fr
   Measured on the prototype at 1440: 336.969 / 210.609 / 210.625 / 273.797,
   summing to 1032 inside a 1176 content box -- exactly three 48px gaps.
   Ratios: 1.6/4.9, 1/4.9, 1/4.9, 1.3/4.9.

   core/columns writes a plain percentage flex-basis, which ignores the gaps and
   renders every column proportionally narrow. Take the gaps out first.
   -------------------------------------------------------------------------- */
@media (min-width: 900px) {
	.wp-block-columns.brightpath-footer__columns {
		column-gap: 48px;
		flex-wrap: nowrap;
	}

	.wp-block-columns.brightpath-footer__columns > .wp-block-column {
		flex-grow: 0;
	}

	.brightpath-footer__columns > .wp-block-column:nth-child(1) {
		flex-basis: calc((100% - 144px) * 1.6 / 4.9) !important;
	}

	.brightpath-footer__columns > .wp-block-column:nth-child(2),
	.brightpath-footer__columns > .wp-block-column:nth-child(3) {
		flex-basis: calc((100% - 144px) * 1 / 4.9) !important;
	}

	.brightpath-footer__columns > .wp-block-column:nth-child(4) {
		flex-basis: calc((100% - 144px) * 1.3 / 4.9) !important;
	}
}

@media (min-width: 641px) and (max-width: 899px) {
	.wp-block-columns.brightpath-footer__columns {
		column-gap: 48px;
		row-gap: 48px;
	}
}

/* --------------------------------------------------------------------------
   4  core/navigation breakpoint override

   core/navigation's own overlay breakpoint is 600px. The design swaps the nav
   at 1200px, because eight nav items plus phone and CTA need about 1356px.

   main.js hardcodes the same value as DESKTOP_MQ = '(min-width: 75rem)'
   (75rem = 1200px). Moving this number without moving that one breaks the nav
   silently, in the direction where neither nav is visible.
   -------------------------------------------------------------------------- */

@media (max-width: 1199px) {
	.wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}

	.wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}
}

@media (min-width: 1200px) {
	.wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: none;
	}

	.wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: block;
		position: relative;
		width: 100%;
		z-index: auto;
		background-color: inherit;
	}
}


/* --------------------------------------------------------------------------
   5  Decorative shape colours

   Replaces the five --rgb-* channel triplets, which no theme.json slot
   accepts. No --rgb-* token survives anywhere in this theme.

   DISCREPANCY FLAGGED TO MAIN -- read before changing these.
   Contract 4 writes the replacement as
     color-mix(in srgb, var(--wp--preset--color--forest-700) 32%, transparent)
   but the call-sites it is describing do not use forest. Measured from
   design/assets/css/main.css:
     line  339  .swash::after            rgba(var(--rgb-terracotta), 0.32)
     line 1571  .cta--soft .cta__shape   rgba(var(--rgb-terracotta), 0.3)
                                         rgba(var(--rgb-sage), 0.2)
   and --rgb-terracotta is 168, 80, 47 = terracotta-600 (#A8502F),
       --rgb-sage       is  74, 115, 85 = sage-600       (#4A7355).
   Using forest-700 would change the rendered colour of all three. The
   percentages below are the contract's; the hues are the ones the prototype
   actually paints. Main to confirm.

   .modal__backdrop is NOT ported -- dead per contract 11.1.
   The base .cta__shape (sage 0.55 / terracotta 0.22) still uses --rgb-* in
   the prototype and is out of scope for this plan; it belongs to the later
   selective main.css port.
   -------------------------------------------------------------------------- */

.swash::after {
	background-color: color-mix(in srgb, var(--wp--preset--color--terracotta-600) 32%, transparent);
}

.cta--soft .cta__shape {
	background: radial-gradient(
		circle at 30% 30%,
		color-mix(in srgb, var(--wp--preset--color--terracotta-600) 30%, transparent),
		color-mix(in srgb, var(--wp--preset--color--sage-600) 20%, transparent)
	);
}

/* --------------------------------------------------------------------------
   6  Links on dark surfaces

   theme.json `elements.link.color.text` is forest-700, which is correct on the
   sand and white surfaces and close to invisible on forest-900: measured
   rgb(31,74,58) on rgb(15,42,33) is roughly 1.3:1. It reached the utility bar
   and the breadcrumbs, which sit on the dark band on most interior pages.

   The prototype's own answer, main.css:564 and :580-581:
       .on-dark .link       { color: var(--color-terracotta-100); }
       .on-dark .link-arrow { color: var(--color-text-invert); }

   Keyed off `has-forest-900-background-color`, the class core prints for the
   only dark background in this palette, so a band becomes dark-aware by
   choosing the dark background rather than by carrying an extra class. This
   lives in the foundation shard because its first victims are the header and
   footer template parts, which Main owns.
   -------------------------------------------------------------------------- */

.has-forest-900-background-color a:where(:not(.wp-element-button)),
.has-forest-900-background-color a:where(:not(.wp-element-button)):visited {
	color: var(--wp--preset--color--terracotta-100);
}

.has-forest-900-background-color a:where(:not(.wp-element-button)):hover,
.has-forest-900-background-color a:where(:not(.wp-element-button)):focus {
	color: var(--wp--preset--color--sand-50);
}

/* The focus ring inverts too -- forest-700 on forest-900 is the same problem
   the ring is meant to solve. */
.has-forest-900-background-color :focus-visible {
	outline-color: var(--wp--custom--color--focus-invert);
}

/* --------------------------------------------------------------------------
   7  Header chrome — sticky, and the two heights

   Measured against the prototype at 1440, like for like:
       utility bar   prototype 60px   built 38.1px
       header row    prototype 73px   built 89.3px
       total chrome  prototype 133px  built 151px
   Two errors in opposite directions, which is why the total looked like one
   small discrepancy. The prototype's own rules are main.css:855 and :877.

   The header is `position: sticky` on the prototype and was `static` here —
   design-QA measured ZERO fixed or sticky elements on the built site at every
   width. That is the defect; the heights are the detail.
   -------------------------------------------------------------------------- */

.brightpath-utility-bar {
	min-height: 60px;
	display: flex;
	align-items: center;
}

.brightpath-header__row {
	min-height: 73px;
	display: flex;
	align-items: center;
	position: sticky;
	top: 0;
	z-index: var(--z-header);
	background-color: color-mix(in srgb, var(--wp--preset--color--sand-50) 92%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	border-bottom: 1px solid transparent;
	transition:
		box-shadow var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base),
		background-color var(--wp--custom--transition--base);
}

/* The scrolled state. `.is-scrolled` is set by assets/js/chrome.js. */
.brightpath-header__row.is-scrolled {
	border-bottom-color: var(--wp--preset--color--sand-200);
	box-shadow: var(--wp--custom--shadow--sm);
}

/* --------------------------------------------------------------------------
   8  Current-page navigation state

   inc/nav-state.php adds the class by comparing the rendered href with the
   current request, rather than by post ID, so it survives a rebuild and works
   on any install. Ancestor matching is what lights Services on a service page.
   Prototype: main.css:925-926.
   -------------------------------------------------------------------------- */

/* core ships `.wp-block-navigation .wp-block-navigation-item__content
   .wp-block-navigation-item__content { color: inherit }` -- a doubled class at
   (0,3,0) purely to win the cascade. A plain descendant selector here reaches
   (0,2,1), loses the colour, and still wins font-weight and the underline, so
   the link goes bold and gains its rule while staying body-coloured. Matching
   core's own trick is the honest fix; !important would win too and would be
   harder to reason about the next time core changes. */
.wp-block-navigation .current-menu-item > a.wp-block-navigation-item__content.wp-block-navigation-item__content,
.wp-block-navigation a.current-menu-item.wp-block-navigation-item__content.wp-block-navigation-item__content,
.wp-block-navigation .current-menu-ancestor > a.wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--custom--color--primary);
	font-weight: 600;
	position: relative;
}

.wp-block-navigation .current-menu-item > a::after,
.wp-block-navigation a.current-menu-item::after {
	content: '';
	position: absolute;
	left: var(--wp--preset--spacing--30);
	right: var(--wp--preset--spacing--30);
	bottom: 5px;
	height: 2px;
	background-color: var(--wp--preset--color--terracotta-600);
	border-radius: var(--wp--custom--radius--full);
}

/* On the dark utility bar the underline would disappear into the surface. */
.has-forest-900-background-color .current-menu-item > a::after {
	background-color: var(--wp--preset--color--terracotta-100);
}

/* --------------------------------------------------------------------------
   9  Floating chrome — back-to-top and the mobile sticky CTA

   Both are injected by assets/js/chrome.js, so a page with JavaScript blocked
   simply does not have them rather than having two dead controls. Prototype:
   main.css .scroll-top and .sticky-cta.
   -------------------------------------------------------------------------- */

.bp-scroll-top {
	position: fixed;
	right: var(--wp--preset--spacing--50);
	bottom: var(--wp--preset--spacing--50);
	z-index: var(--z-dropdown);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	padding: 0;
	color: var(--wp--custom--color--text-invert);
	background-color: var(--wp--preset--color--forest-700);
	border: 0;
	border-radius: 50%;
	box-shadow: var(--wp--custom--shadow--lg);
	cursor: pointer;
	opacity: 0;
	visibility: hidden;
	transform: translateY(10px);
	transition:
		opacity var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base),
		visibility var(--wp--custom--transition--base),
		background-color var(--wp--custom--transition--base);
}

.bp-scroll-top.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.bp-scroll-top:hover {
	background-color: var(--wp--custom--color--primary-hover);
}

/* The sticky CTA is mobile-only on the prototype: it is the counterpart of the
   header CTA, which is hidden below the 1200px nav rung. */
.bp-sticky-cta {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: var(--z-dropdown);
	display: none;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--30);
	background-color: color-mix(in srgb, var(--wp--preset--color--sand-50) 96%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	border-top: 1px solid var(--wp--preset--color--sand-200);
	transform: translateY(100%);
	transition: transform var(--wp--custom--transition--base);
}

.bp-sticky-cta.is-visible {
	transform: translateY(0);
}

.bp-sticky-cta > a {
	flex: 1 1 auto;
	text-align: center;
}

.bp-sticky-cta__close {
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	font-size: 22px;
	line-height: 1;
	color: var(--wp--custom--color--text-muted);
	background: none;
	border: 0;
	cursor: pointer;
}

@media (max-width: 1199px) {
	.bp-sticky-cta { display: flex; }
}

@media (prefers-reduced-motion: reduce) {
	.bp-scroll-top,
	.bp-sticky-cta { transition-duration: 0.01ms; }
}

/* --------------------------------------------------------------------------
   10  The lede role

   The prototype has three body tones and the build had one, which collapsed the
   hierarchy between lede, body and caption and made every page read heavier.
   theme.json now carries body=ink-700 and headings=ink-900; the lede is the
   third tone and has no theme.json slot of its own.

   Prototype main.css:313-317 — .lede is --text-lg, line-height 1.65,
   colour ink-600, max-width 60ch. On the built site a lede is a paragraph
   carrying the `large` size preset, so that is what this matches.
   -------------------------------------------------------------------------- */

p.has-large-font-size {
	color: var(--wp--custom--color--text-muted);
	line-height: 1.65;
	max-width: 60ch;
}

/* On a dark band the muted tone inverts, as the prototype does at main.css:319. */
.has-forest-900-background-color p.has-large-font-size {
	color: var(--wp--custom--color--text-invert-muted);
}

/* --------------------------------------------------------------------------
   11  The utility-bar message

   The header part's own comment says the stylesheet hides this below 768px.
   It did not -- there was no such rule anywhere, so the message wrapped and the
   bar measured 84.2px at 390 against the prototype's 60px at every width.
   A comment describing behaviour that does not exist is worse than no comment.

   768px (47.9375rem) is the utility-bar rung and the ONLY thing it governs.
   It is not a gutter rung and not a system breakpoint -- contract 3.
   -------------------------------------------------------------------------- */

@media (max-width: 767px) {
	.brightpath-utility-bar__message {
		display: none;
	}
}
