/**
 * GrowthRefactor supplemental styles.
 *
 * SCOPE RULE: theme.json is the design system. Only add rules here that
 * theme.json genuinely cannot express (gradient text clipping, pseudo-elements,
 * :has(), state classes, marker styling). Everything else belongs in theme.json.
 *
 * AUTHORING RULE: mobile-first. Base rules target phones with no media query.
 * Enhance upward with `min-width` only. Never write a `max-width` query here.
 * This is a deliberate break from the old desktop-first sites/main/css/style.css.
 */

/* ---------------------------------------------------------------------------
 * 1. Gradient text (background-clip cannot be expressed in theme.json)
 * ------------------------------------------------------------------------ */

.is-style-gradient-text,
.gr-gradient-text {
	background: var(--wp--preset--gradient--sunrise);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
	/* Keeps descenders from being clipped by the text box. */
	padding-bottom: 0.06em;
}

/* An <em> inside a heading is the brand's emphasis device, not italics. */
.gr-hero h1 em,
.gr-emphasis em {
	font-style: normal;
	background: var(--wp--preset--gradient--sunrise);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
}

/* Forced-colors users get no gradient, so restore a real color. */
@media (forced-colors: active) {
	.is-style-gradient-text,
	.gr-gradient-text,
	.gr-hero h1 em,
	.gr-emphasis em {
		background: none;
		color: CanvasText;
		-webkit-text-fill-color: CanvasText;
	}
}

/* ---------------------------------------------------------------------------
 * 2. Buttons
 *
 * Contrast maths behind these choices:
 *   #FF5A5F on #FFFFFF = 3.05:1  -> fails AA for text
 *   #C6353B on #FFFFFF = 5.29:1  -> passes AA  (theme.json default button)
 *   #3A2E2E on sunrise = 4.27:1 to 5.40:1 -> gradient buttons use cocoa text
 * ------------------------------------------------------------------------ */

.wp-block-button.is-style-sunrise > .wp-block-button__link {
	background: var(--wp--preset--gradient--sunrise);
	color: var(--wp--preset--color--cocoa);
	border: 0;
}

.wp-block-button.is-style-sunrise > .wp-block-button__link:hover,
.wp-block-button.is-style-sunrise > .wp-block-button__link:focus-visible {
	filter: saturate(1.15) brightness(0.97);
	color: var(--wp--preset--color--cocoa);
}

/* Ghost buttons are token-driven so the DEFAULT is readable on a light page
   and dark bands opt in. The old version hardcoded white-on-transparent, which
   rendered a literally invisible button (1:1 contrast) the one time the style
   was used outside a cocoa band — in the proof section, of all places. */
.wp-block-button.is-style-ghost > .wp-block-button__link {
	background: transparent;
	color: var(--gr-ghost-fg, var(--wp--preset--color--cocoa));
	border: 1px solid var(--gr-ghost-edge, rgba(58, 46, 46, 0.45));
}

.wp-block-button.is-style-ghost > .wp-block-button__link:hover,
.wp-block-button.is-style-ghost > .wp-block-button__link:focus-visible {
	background: var(--gr-ghost-wash, rgba(58, 46, 46, 0.06));
	border-color: var(--gr-ghost-fg, var(--wp--preset--color--cocoa));
	color: var(--gr-ghost-fg, var(--wp--preset--color--cocoa));
}

.has-cocoa-background-color,
.gr-hero,
.gr-cta,
.gr-footer {
	--gr-ghost-fg: var(--wp--preset--color--white);
	--gr-ghost-edge: rgba(255, 255, 255, 0.5);
	--gr-ghost-wash: rgba(255, 255, 255, 0.1);
}

.wp-block-button__link {
	transition: transform 0.15s ease, background-color 0.15s ease, filter 0.15s ease;
}

.wp-block-button__link:hover {
	transform: translateY(-1px);
}

/* A visible focus ring everywhere, token-driven for contrast: coral-ink is
   5.3:1 on white but only 2.5:1 on cocoa, so the dark bands switch the ring
   to amber (7.9:1 on cocoa) — and light cards INSIDE a dark band (the audit
   form lives in the closing cocoa section) switch it straight back. */
:root {
	--gr-focus-ring: var(--wp--preset--color--coral-ink);
}

.gr-hero,
.gr-cta,
.gr-footer,
.has-cocoa-background-color,
.gr-nav.is-open {
	--gr-focus-ring: var(--wp--preset--color--amber);
}

.is-style-card,
.gr-form-thanks {
	--gr-focus-ring: var(--wp--preset--color--coral-ink);
}

:where(a, button, .wp-block-button__link, summary, input, textarea, select):focus-visible {
	outline: 3px solid var(--gr-focus-ring);
	outline-offset: 2px;
	border-radius: 3px;
}

/* Buttons stack full-width on phones, sit inline from small tablets up. */
.gr-hero .wp-block-buttons > .wp-block-button {
	width: 100%;
}

.gr-hero .wp-block-buttons > .wp-block-button > .wp-block-button__link {
	display: block;
	text-align: center;
}

@media (min-width: 480px) {
	.gr-hero .wp-block-buttons > .wp-block-button {
		width: auto;
	}

	.gr-hero .wp-block-buttons > .wp-block-button > .wp-block-button__link {
		display: inline-block;
	}
}

/* ---------------------------------------------------------------------------
 * 3. Eyebrow label ("// marketing automation Automation Studio")
 * ------------------------------------------------------------------------ */

.is-style-eyebrow {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--coral-ink);
	margin-bottom: 0.75rem;
}

.gr-hero .is-style-eyebrow {
	color: var(--wp--preset--color--amber);
}

/* ---------------------------------------------------------------------------
 * 3b. Measure wrapper
 *
 * WordPress constrained layout forces `margin-left/right: auto !important` onto
 * every child, so a nested constrained group with a narrower contentSize gets
 * CENTERED, not left-aligned. That reads as broken next to a full-width card
 * grid. So text blocks use a `layout:default` group with this class instead,
 * which keeps everything flush left.
 * ------------------------------------------------------------------------ */

/* Section headers: everything runs the full content width. The prose was
   briefly capped at 46rem for line-length comfort, but the client weighed the
   trade and chose to use the space — the empty right column read worse to
   them than longer lines. Line-height 1.6 on the intros does the remaining
   readability work.

   There was a second, still-capped `.gr-measure-wide` variant for a while, so
   the same section header rendered at two widths depending on which page you
   were on. It is gone: one class, one width. Long-form article bodies still get
   a comfortable measure, but from `.gr-prose` (section 15), which caps the
   running text and not the wrapper. */
.gr-measure > * {
	max-width: none;
	margin-left: 0;
	margin-right: 0;
}

/* ---------------------------------------------------------------------------
 * 4. Hero (cocoa field + radial sunrise glows)
 * ------------------------------------------------------------------------ */

.gr-hero {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

.gr-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		radial-gradient(60% 55% at 15% 10%, rgba(255, 90, 95, 0.22) 0%, transparent 60%),
		radial-gradient(50% 50% at 88% 85%, rgba(255, 134, 39, 0.16) 0%, transparent 60%);
	pointer-events: none;
}

.gr-hero :where(h1, h2, p) {
	color: var(--wp--preset--color--white);
}

/* Hero content sits in a `layout:default` group (.gr-hero-inner) rather than
   directly in the constrained wrapper. Direct children of a constrained layout
   get `margin-left/right: auto !important`, which silently centres anything
   given a max-width. Nesting one level escapes that entirely. */

/* The two hero measures are in em, not ch, and that is a Core Web Vitals fix
   rather than a style preference. `ch` is the advance width of the "0" glyph in
   the *current family*, so while a webfont is still loading the box is sized off
   the fallback and then physically resizes the moment the real face arrives.
   That is not text re-wrapping inside a stable box, it is the box changing
   width, and it moved everything below it: measured on /services/, the H1 went
   574px to 647px and the sub 615px to 720px, dragging the sub and the buttons up
   69px for a 0.13 layout shift on a page whose LCP element is that same H1.

   em depends only on font-size, which the swap does not change, so the box is
   stable from first paint. The values are the measured equivalents at the loaded
   faces, so the rendered width is unchanged to the sub-pixel:

     Space Grotesk 700  1ch = 0.64797em  ->  24ch = 15.551em  (646.96px at 66.56px)
     Inter 400          1ch = 0.63078em  ->  62ch = 39.108em  (719.68px at 18.40px)

   Recompute both if either family changes. Keeping em rather than moving to a
   fixed rem is deliberate: the H1 font-size is fluid, and the measure has to
   scale with it the way ch did. */

.gr-hero .gr-hero-sub {
	color: rgba(255, 255, 255, 0.82);
	max-width: 39.108em;
	margin-top: var(--wp--preset--spacing--50);
}

.gr-hero h1 {
	max-width: 15.551em;
	margin-top: var(--wp--preset--spacing--30);
}

/* ---------------------------------------------------------------------------
 * 5. Stat bar (gradient numerals + rule)
 * ------------------------------------------------------------------------ */

.gr-stat-bar {
	border-top: 1px solid rgba(255, 255, 255, 0.14);
	padding-top: var(--wp--preset--spacing--50);
}

/* WordPress grid layout emits repeat(auto-fill, ...), which keeps empty trailing
   tracks. In a wide container that renders three stats bunched into the left of
   a five-column grid with dead space beside them. auto-fit collapses the empty
   tracks so the stats spread across the full width whatever the count. The
   doubled class is only there to outrank WP's generated .wp-container-* rule
   without resorting to !important. */
.wp-block-group.gr-stat-bar {
	grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
}

/* Four proof cards stacked in a half-width column ran 636px tall against 348px
   of argument beside them, leaving a 288px void next to the text. Two per row
   brings the evidence roughly level with the claim it supports, so the pair
   reads as one thought rather than a short column beside a long one. Below
   900px the column is too narrow to split, so the cards stay stacked. */
@media (min-width: 900px) {
	.gr-spec.is-2col {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--wp--preset--spacing--30);
		align-items: start;
	}

	/* The group's blockGap emits margin-block-start on every child but the
	   first. Harmless while these were stacked; once they are grid items that
	   margin pushes each card down inside its own cell, so the second card in
	   row one sat 16px below the first and the second row gapped twice. */
	.gr-spec.is-2col > * {
		margin-top: 0;
	}
}

/* The home page's audience band is now a four-up icon row (.gr-steps-4up), so
   the wide-last-card span that used to close its ragged second row has gone.
   .gr-audience itself stays: the four service pages still use it. */

.gr-stat-value {
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 700;
	line-height: 1.05;
	background: var(--wp--preset--gradient--sunrise);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
}

.gr-stat-label {
	font-size: var(--wp--preset--font-size--small);
	color: rgba(255, 255, 255, 0.62);
	margin-top: 0.25rem;
}

/* On a light section the stat labels need the normal body colour. */
.gr-stat-bar.is-on-light {
	border-top-color: rgba(58, 46, 46, 0.12);
}

/* Standalone proof band under the hero: the band supplies its own rule, so the
   stat bar drops its top border and padding. */
.gr-proof .gr-stat-bar {
	border-top: 0;
	padding-top: 0;
}

.gr-proof .gr-stat-value {
	line-height: 1.1;
}

.gr-stat-bar.is-on-light .gr-stat-label {
	color: var(--wp--preset--color--taupe-ink);
}

/* ---------------------------------------------------------------------------
 * 6. Cards
 * ------------------------------------------------------------------------ */

.wp-block-group.is-style-card {
	background: var(--wp--preset--color--white);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--card);
	padding: var(--wp--preset--spacing--60);
	height: 100%;
	transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.wp-block-group.is-style-card:hover {
	transform: translateY(-2px);
	box-shadow: var(--wp--preset--shadow--pop);
}

/* Cards are flex columns so a trailing arrow-link can pin to the base: three
   pillar cards previously ended their CTAs on three different baselines, one
   per body length. The accent bar is clipped by the card's own radius. */
.wp-block-group.is-style-card {
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.wp-block-group.is-style-card > .gr-link-arrow {
	margin-top: auto;
	padding-top: var(--wp--preset--spacing--40);
}

/* The audit form is a card by style but not by behaviour: without this it
   inherited the hover lift, so all five inputs jumped 2px whenever the
   pointer approached the form. */
.wp-block-group.is-style-card.gr-close-form:hover {
	transform: none;
	box-shadow: var(--wp--preset--shadow--card);
}

.wp-block-group.is-style-card-accent {
	background: var(--wp--preset--color--mist);
	border-radius: var(--wp--custom--radius--base);
	border-left: 4px solid var(--wp--preset--color--coral);
	padding: var(--wp--preset--spacing--60);
	height: 100%;
	/* Mist-on-mist: in the pain, outcomes and audience sections these cards
	   sit on a mist band, where their own mist fill gave 1:1 card contrast and
	   fourteen "cards" read as floating text. A hairline and a soft shadow
	   make the card an object again on either background. */
	border-top: 1px solid rgba(58, 46, 46, 0.08);
	border-right: 1px solid rgba(58, 46, 46, 0.08);
	border-bottom: 1px solid rgba(58, 46, 46, 0.08);
	box-shadow: 0 1px 2px rgba(58, 46, 46, 0.04);
	overflow: hidden;
	/* Same hover language as the plain cards, so the two card families move
	   as one system: a small lift, a deeper shadow, and the coral edge
	   sharpening to its ink shade. Transform and shadow only, and the global
	   reduced-motion rule flattens it for users who ask for that. */
	transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.22s ease, border-color 0.22s ease;
}

.wp-block-group.is-style-card-accent:hover {
	transform: translateY(-2px);
	box-shadow: var(--wp--preset--shadow--pop);
	border-left-color: var(--wp--preset--color--coral-ink);
}

.has-mist-background-color .wp-block-group.is-style-card-accent {
	background: var(--wp--preset--color--white);
}

/* Mono index numeral on service cards ("01."). */
.gr-card-num {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 500;
	color: var(--wp--preset--color--taupe-ink);
	letter-spacing: 0.06em;
}

/* Pillar card head: the tile in a left column, the stage label and the heading
   stacked beside it, so the tile is not sitting on a line of its own with the
   rest of the card's width empty next to it. See the note in
   patterns/pillars-three.php for why this is a wrapper rather than a grid on
   the card itself.

   Top-aligned, not centred: the three headings are one, three and one lines
   long, and centring the tile against the whole stack left the middle card's
   tile floating beside the heading's second line, disconnected from the "02.
   Get chosen" label it belongs to. Aligned to the start it lands in the same
   place on all three. */
.gr-card-head {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: var(--wp--preset--spacing--30);
	align-items: start;
}

.gr-card-head > .gr-icon-tile {
	grid-column: 1;
	grid-row: 1 / span 2;
	margin-bottom: 0;
}

.gr-card-head > .gr-card-num {
	grid-column: 2;
	grid-row: 1;
	margin-block: 0;
}

.gr-card-head > h3 {
	grid-column: 2;
	grid-row: 2;
	margin-block: 0.2rem 0;
}

/* Rounded coral-tinted icon tile. */
.gr-icon-tile {
	width: 44px;
	height: 44px;
	display: grid;
	place-items: center;
	border-radius: var(--wp--custom--radius--sm);
	background: rgba(255, 90, 95, 0.12);
	color: var(--wp--preset--color--coral-ink);
	margin-bottom: var(--wp--preset--spacing--40);
}

.gr-icon-tile svg {
	width: 22px;
	height: 22px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* ---------------------------------------------------------------------------
 * 7. Process steps (gradient numeral circles, cocoa text for AA)
 * ------------------------------------------------------------------------ */

.gr-step-num {
	width: 52px;
	height: 52px;
	display: grid;
	place-items: center;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--gradient--sunrise);
	color: var(--wp--preset--color--cocoa);
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 700;
	font-size: 1.2rem;
	flex: none;
}

/* The circle used to sit alone on its own row with a card-width of dead space
   beside it. The heading now shares that row, vertically centred on the circle,
   and the body spans the full width beneath the pair. Applies to card steps and
   to plain (un-boxed) step groups alike, e.g. the "From Scope to Shipped" steps
   on the custom-software page. Scoped by :has(> .gr-step-num) so the pillar
   cards (mono "01." labels) keep their own stacked layout. */
.wp-block-group:has(> .gr-step-num) {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: var(--wp--preset--spacing--40);
	row-gap: var(--wp--preset--spacing--40);
	align-content: start;
	align-items: center;
}

.wp-block-group:has(> .gr-step-num) > * {
	margin-top: 0;
	margin-bottom: 0;
}

.wp-block-group:has(> .gr-step-num) > h3 {
	grid-column: 2;
}

.wp-block-group:has(> .gr-step-num) > p:not(.gr-step-num) {
	grid-column: 1 / -1;
	align-self: start;
}

/* A four-step process reads cleanly as 1 / 2x2 / 4-across. WordPress' grid
   layout (minimumColumnWidth) auto-fills columns, which at some widths fits
   only three and orphans the fourth step on a row of its own. Fixed column
   counts at explicit breakpoints keep the rows balanced on every screen. The
   two-class selector outranks WP's generated .wp-container-* grid rule, so this
   wins regardless of stylesheet order; the block keeps minimumColumnWidth as a
   no-CSS fallback. */
.wp-block-group.gr-steps-4up {
	grid-template-columns: 1fr;
}

@media (min-width: 600px) {
	.wp-block-group.gr-steps-4up {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 960px) {
	.wp-block-group.gr-steps-4up {
		grid-template-columns: repeat(4, 1fr);
	}
}

/* The same grid also carries three-step processes (marketing automation), where
   a four-track row leaves the last cell blank. Match the track count to the item
   count instead: at tablet width the odd third step spans the pair, and on
   desktop the row is three across. :last-child:nth-child(3) matches only a group
   of exactly three, so the four-step pages above are untouched, and the mobile
   single column is shared. */
@media (min-width: 600px) {
	.wp-block-group.gr-steps-4up:has(> :last-child:nth-child(3)) > :last-child {
		grid-column: 1 / -1;
	}
}

@media (min-width: 960px) {
	.wp-block-group.gr-steps-4up:has(> :last-child:nth-child(3)) {
		grid-template-columns: repeat(3, 1fr);
	}

	.wp-block-group.gr-steps-4up:has(> :last-child:nth-child(3)) > :last-child {
		grid-column: auto;
	}
}

/* ---------------------------------------------------------------------------
 * 8. Link with animated arrow
 * ------------------------------------------------------------------------ */

.gr-link-arrow a,
a.gr-link-arrow {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	font-weight: 600;
	font-family: var(--wp--preset--font-family--space-grotesk);
	text-decoration: none;
	/* These are the only links into the three money pages; at their natural
	   26px they were among the smallest tap targets on the site. */
	min-height: 44px;
}

.gr-link-arrow a::after,
a.gr-link-arrow::after {
	content: "\2192";
	transition: transform 0.18s ease;
}

.gr-link-arrow a:hover::after,
a.gr-link-arrow:hover::after {
	transform: translateX(4px);
}

/* ---------------------------------------------------------------------------
 * 9. FAQ accordion (native <details>, zero JS)
 * ------------------------------------------------------------------------ */

/* The list keeps the same content measure as every other section, so its left
   edge lines up with the headings above it, then splits into two columns on
   desktop so each answer holds a readable 65-75 character line. Single column
   on mobile. The width itself comes from the parent constrained layout, so
   there is deliberately no max-width override here. */
@media (min-width: 860px) {
	.gr-faq-list {
		display: grid;
		grid-template-columns: 1fr 1fr;
		column-gap: clamp(2.5rem, 5vw, 4.5rem);
		align-items: start;
	}
}

.gr-faq .wp-block-details {
	border-bottom: 1px solid rgba(58, 46, 46, 0.12);
	padding: var(--wp--preset--spacing--40) 0;
}

.gr-faq .wp-block-details summary {
	position: relative;
	cursor: pointer;
	list-style: none;
	padding-right: 2.25rem;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 600;
	color: var(--wp--preset--color--cocoa);
	line-height: 1.4;
	/* The row was 22px tall, well under the 44px touch minimum, on a control
	   that is tapped eleven times over on the densest section of the page.
	   Padding rather than height so multi-line questions still grow. */
	min-height: 44px;
	display: flex;
	align-items: center;
	padding-top: 0.6rem;
	padding-bottom: 0.6rem;
}

.gr-faq .wp-block-details summary::-webkit-details-marker {
	display: none;
}

.gr-faq .wp-block-details summary::after {
	content: "+";
	position: absolute;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 1.35rem;
	line-height: 1;
	color: var(--wp--preset--color--coral-ink);
}

.gr-faq .wp-block-details[open] summary::after {
	content: "\2212";
}

.gr-faq .wp-block-details > :not(summary) {
	margin-top: var(--wp--preset--spacing--30);
	max-width: 68ch;
}

/* ---------------------------------------------------------------------------
 * 10. Comparison table (scrolls on phones instead of breaking the layout)
 * ------------------------------------------------------------------------ */

.gr-table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

/* The comparison table scrolls inside itself rather than widening the page.
   Without this a phone gets a horizontal scrollbar on the whole document.
   (The cost table that used to share these rules is now an SVG chart.) */
.wp-block-table.gr-compare {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	margin: 0;
}

.wp-block-table.gr-compare table {
	border-collapse: collapse;
	width: 100%;
	min-width: 44rem;
}

.wp-block-table.gr-compare :where(th, td) {
	border: 1px solid rgba(58, 46, 46, 0.12);
	padding: 0.85rem 1rem;
	text-align: left;
	vertical-align: top;
}

.wp-block-table.gr-compare thead th {
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--space-grotesk);
	/* 700, not 600: with the static faces, 600 resolved up to the 700 file, so
	   this is what the headers have always rendered at. The variable face would
	   otherwise thin them out in the two tables under the most scrutiny. */
	font-weight: 700;
	vertical-align: bottom;
}

/* The shared is-style-compare rules mark column two as "ours". This table leads
   with the question a buyer should ask, so the emphasis sits one column across. */
.wp-block-table.gr-compare tbody td:nth-child(3) {
	background: rgba(255, 90, 95, 0.07);
	font-weight: 500;
}

.wp-block-table.gr-compare thead th:nth-child(3) {
	background: var(--wp--preset--color--coral-ink);
}

.wp-block-table.gr-compare tbody td:nth-child(2) {
	color: var(--wp--preset--color--taupe-ink);
}

/* On phones the 44rem table put the "Ours" column 118px past the right edge
   with no scroll affordance — a reader saw eight rows of criticism of other
   agencies and none of our answers. Below 782px each row becomes a labelled
   card: question on top, both answers beneath it, nothing hidden. Dropping
   native table semantics on mobile is the accepted cost of this pattern. */
@media (max-width: 781px) {
	.wp-block-table.gr-compare table,
	.wp-block-table.gr-compare tbody,
	.wp-block-table.gr-compare tbody tr,
	.wp-block-table.gr-compare tbody td {
		display: block;
		width: 100%;
	}

	.wp-block-table.gr-compare table {
		min-width: 0;
	}

	.wp-block-table.gr-compare thead {
		display: none;
	}

	.wp-block-table.gr-compare tbody tr {
		border: 1px solid rgba(58, 46, 46, 0.12);
		border-radius: var(--wp--custom--radius--base);
		margin-bottom: var(--wp--preset--spacing--40);
		overflow: hidden;
	}

	/* box-sizing matters here and only here. A table cell is content-box by
	   default, so once the collapse turns it into a display:block with
	   width:100% its 1rem side padding is added on top of the row width: the
	   cell measured 344px inside a 314px row and the last word or two of every
	   long line was pushed under the rounded edge, hidden behind the figure's
	   overflow-x. The document itself never overflowed, which is why the
	   360px check kept passing while the text was being cut. Border-box makes
	   the padding come out of the declared width instead. */
	.wp-block-table.gr-compare tbody td {
		border: 0;
		box-sizing: border-box;
	}

	.wp-block-table.gr-compare tbody td:first-child {
		background: var(--wp--preset--color--cocoa);
		color: var(--wp--preset--color--white);
		font-family: var(--wp--preset--font-family--space-grotesk);
		font-weight: 700;
	}

	.wp-block-table.gr-compare tbody td[data-label]::before {
		content: attr(data-label);
		display: block;
		font-family: var(--wp--preset--font-family--jetbrains-mono);
		font-size: 0.7rem;
		letter-spacing: 0.05em;
		text-transform: uppercase;
		color: var(--wp--preset--color--taupe-ink);
		margin-bottom: 0.25rem;
	}

	.wp-block-table.gr-compare tbody td[data-label="Ours"]::before {
		color: var(--wp--preset--color--coral-ink);
	}
}

/* Mobile reading order in the cost section.
   The desktop layout puts the closing line and the CTA in the left column so it
   matches the height of the two cards opposite. Stacked on a phone that means
   the reader met the big number, then the ask, and only afterwards the two cards
   that argue the number back down — which is the whole reason the section reads
   as honest rather than as a scare. `display: contents` drops the column boxes
   out of the layout so the six children can be ordered individually: table,
   both cards, then the conclusion and the ask. No markup or copy changes. */
@media (max-width: 781px) {
	.gr-cost-columns {
		display: flex;
		flex-direction: column;
		gap: var(--wp--preset--spacing--50);
	}

	.gr-cost-columns > .wp-block-column {
		display: contents;
	}

	.gr-cost-columns .gr-diagram {
		order: 1;
	}

	.gr-cost-columns .is-style-card-accent {
		order: 2;
		margin-top: 0;
	}

	.gr-cost-columns > .wp-block-column > p {
		order: 3;
		margin-top: 0;
	}

	.gr-cost-columns .wp-block-buttons {
		order: 4;
		margin-top: 0;
	}
}

/* The cost figures used to be a <table> styled here in the mono face. They are
   now an SVG bar chart (see cost-of-delay.php), which sets its own type and
   carries the whole data set in its aria-label — so the table rules that lived
   here have gone rather than sitting unused. */

/* Risk reversal restated under the final CTA, separated by a hairline so it
   reads as a footnote to the decision rather than another paragraph. */
.gr-risk-strip {
	border-top: 1px solid rgba(255, 255, 255, 0.14);
	padding-top: var(--wp--preset--spacing--40);
	max-width: 62ch;
	margin-top: var(--wp--preset--spacing--50);
}

/* Paired columns where the left runs short: stretch it and pin its closing
   element to the bottom, so the whitespace sits between the paragraphs and
   the anchor instead of pooling as a void under the column. Why-us pins the
   automation link (107px void); the closing section pins the risk strip,
   which otherwise floated 144px above the form at the decision moment. */
@media (min-width: 782px) {
	.gr-why-cols > .wp-block-column:first-child,
	.gr-close .wp-block-columns > .wp-block-column:first-child {
		align-self: stretch;
		display: flex;
		flex-direction: column;
	}

	.gr-why-cols > .wp-block-column:first-child > .gr-link-arrow,
	.gr-close .wp-block-columns > .wp-block-column:first-child > .gr-risk-strip {
		margin-top: auto;
		padding-top: var(--wp--preset--spacing--40);
	}
}

/* ---------------------------------------------------------------------------
 * 13b. Homepage closing section
 *
 * The audit form inline, so the ask does not cost a page load. Five stacked
 * fields make a very tall column, which left the copy beside it trailing off
 * into empty space; pairing the four short fields two-up on wide screens brings
 * the two columns to roughly the same height without touching the shortcode.
 * ------------------------------------------------------------------------ */

.gr-close-steps {
	padding-left: 1.1rem;
	margin-bottom: var(--wp--preset--spacing--50);
}

.gr-close-steps li {
	margin-bottom: 0.45rem;
}

.gr-close-steps li::marker {
	color: var(--wp--preset--color--amber);
}

.gr-close-form {
	padding: var(--wp--preset--spacing--50);
}

@media (min-width: 900px) {
	/* Hidden inputs are display:none and the honeypot is absolutely positioned,
	   so neither becomes a grid item. The six paragraphs are the only children
	   that lay out here. */
	.gr-close-form .gr-form {
		display: grid;
		grid-template-columns: 1fr 1fr;
		column-gap: 1rem;
	}

	.gr-close-form .gr-form > p:nth-of-type(5),
	.gr-close-form .gr-form > p:nth-of-type(6) {
		grid-column: 1 / -1;
	}
}

.wp-block-table.is-style-compare table {
	border-collapse: collapse;
	min-width: 34rem;
}

.wp-block-table.is-style-compare :where(th, td) {
	border: 1px solid rgba(58, 46, 46, 0.12);
	padding: 0.85rem 1rem;
	text-align: left;
	vertical-align: middle;
}

.wp-block-table.is-style-compare thead th {
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 600;
}

.wp-block-table.is-style-compare tbody tr:nth-child(odd) td {
	background: var(--wp--preset--color--mist);
}

/* Highlight the "ours" column. */
.wp-block-table.is-style-compare :where(th, td):nth-child(2) {
	background: rgba(255, 90, 95, 0.07);
	font-weight: 500;
}

.wp-block-table.is-style-compare thead th:nth-child(2) {
	background: var(--wp--preset--color--coral-ink);
}

/* ---------------------------------------------------------------------------
 * 11. Lists
 * ------------------------------------------------------------------------ */

.wp-block-list.is-style-check,
.wp-block-list.is-style-arrow {
	list-style: none;
	padding-left: 0;
}

.wp-block-list.is-style-check li,
.wp-block-list.is-style-arrow li {
	position: relative;
	padding-left: 1.6em;
	margin-bottom: 0.5em;
}

.wp-block-list.is-style-check li::before {
	content: "\2713";
	position: absolute;
	left: 0;
	color: var(--wp--preset--color--coral-ink);
	font-weight: 700;
}

.wp-block-list.is-style-arrow li::before {
	content: "\2192";
	position: absolute;
	left: 0;
	color: var(--wp--preset--color--amber);
	font-weight: 700;
}

/* ---------------------------------------------------------------------------
 * 12. Sticky header
 * ------------------------------------------------------------------------ */

.gr-header {
	transition: box-shadow 0.2s ease;
}

.gr-header.is-scrolled {
	box-shadow: var(--wp--preset--shadow--nav);
}

/* Site Editor sticky-position fallback: a sticky Group inside a template part
   only sticks to its wrapper, so promote the wrapper itself. */
.wp-site-blocks > header:has(.gr-header) {
	position: sticky;
	top: 0;
	z-index: 100;
}

/* The sticky header otherwise covers whatever a fragment jump or sequential
   focus lands on: the in-page CTAs point at #contact-form, the thank-you
   redirect targets #gr-form-thanks, and tabbing must never put focus under
   the bar. Values track the measured header heights (~87px desktop, ~69px
   mobile) plus breathing room. */
html {
	scroll-padding-top: 104px;
}

@media (max-width: 781px) {
	html {
		scroll-padding-top: 84px;
	}
}

/* Sized by height so the lockup scales predictably. The trimmed artwork is a
   4.4:1 wordmark, so it grows wide fast and it shares a nowrap row with the
   menu toggle and the CTA. At 360px a 44px logo left the CTA only 58px, which
   wrapped "Get a Free Audit" onto four lines and made a 157px-tall button.
   The logo steps down and the CTA shortens to "Free Audit" to prevent that. */
.gr-header .wp-block-site-logo img {
	height: 36px;
	width: auto;
	max-width: none;
}

/* 320px is the WCAG reflow floor and the row still has to hold logo, toggle
   and CTA. A 36px logo is 159px wide, which pushed the row to 355px; 30px
   brings it to ~132px and the whole row back inside the viewport. The inner
   header row also gets a tighter gap at this width. */
@media (max-width: 399.98px) {
	.gr-header .wp-block-site-logo img {
		height: 30px;
	}

	.gr-header .wp-block-group.is-nowrap {
		gap: 0.5rem;
	}
}

@media (min-width: 480px) {
	.gr-header .wp-block-site-logo img {
		height: 44px;
	}
}

@media (min-width: 600px) {
	.gr-header .wp-block-site-logo img {
		height: 52px;
	}
}

/* The header CTA must never wrap: a squeezed multi-line pill is the single
   ugliest thing a visitor sees first. Below the desktop breakpoint it drops the
   "Get a " and tightens, so it stays one line and stays tappable at 44px. */
.gr-header .wp-block-button__link {
	white-space: nowrap;
}

/* The menu toggle rendered at 24x24: the primary navigation control on mobile,
   at about a quarter of the recommended tap area. The icon keeps its size, the
   hit area grows around it.

   The static nav below replaced the core navigation block and its 135KB
   Interactivity API runtime. Progressive enhancement runs in the safe
   direction: without JS the toggle stays hidden and the menu renders in full,
   so no script failure can ever lose the navigation. interactions.js adds
   .gr-nav-js and drives the drawer. */
.gr-nav-toggle {
	min-width: 44px;
	min-height: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: transparent;
	border: 0;
	padding: 0;
	color: var(--wp--preset--color--cocoa);
	cursor: pointer;
}

.gr-nav-toggle[hidden] {
	display: none;
}

@media (min-width: 782px) {
	.gr-nav-toggle {
		display: none !important;
	}
}

.gr-nav-menu,
.gr-nav-sub {
	list-style: none;
	margin: 0;
	padding: 0;
}

.gr-nav-menu > li > a,
.gr-nav-sub-btn {
	color: var(--wp--preset--color--cocoa);
	text-decoration: none;
	font-weight: 500;
	background: transparent;
	border: 0;
	padding: 0;
	font-size: inherit;
	font-family: inherit;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 0.35em;
}

/* Desktop: inline row with a hover / focus-within dropdown. */
@media (min-width: 782px) {
	.gr-nav-menu {
		display: flex;
		align-items: center;
		gap: var(--wp--preset--spacing--50);
	}

	.gr-nav-has-sub {
		position: relative;
	}

	.gr-nav-sub {
		position: absolute;
		top: calc(100% + 10px);
		left: 50%;
		transform: translateX(-50%);
		background: var(--wp--preset--color--cocoa);
		border: 1px solid rgba(255, 255, 255, 0.12);
		border-radius: 10px;
		padding: 6px 0;
		box-shadow: 0 18px 40px rgba(58, 46, 46, 0.28);
		min-width: 232px;
		display: none;
		z-index: 60;
		/* The full-service menu carries a dozen items. Cap the panel to the
		   viewport and let it scroll rather than run off the bottom of a short
		   laptop screen. */
		max-height: calc(100vh - 84px);
		overflow-y: auto;
	}

	/* Hover bridge: without it the pointer falls into the 10px gap between the
	   trigger and the panel and the menu snaps shut mid-travel. */
	.gr-nav-has-sub::after {
		content: "";
		position: absolute;
		inset: 100% 0 -12px 0;
		display: none;
	}

	.gr-nav-has-sub:hover::after,
	.gr-nav-has-sub:focus-within::after,
	.gr-nav-has-sub:hover > .gr-nav-sub,
	.gr-nav-has-sub:focus-within > .gr-nav-sub {
		display: block;
	}

	.gr-nav-sub a {
		display: flex;
		align-items: center;
		padding: 9px 18px;
		color: var(--wp--preset--color--white);
		text-decoration: none;
	}

	.gr-nav-sub a:hover,
	.gr-nav-sub a:focus-visible {
		color: var(--wp--preset--color--amber);
	}
}

/* Mobile: with JS, the menu is a drawer under the header; the Services group
   renders always-open, so there is no second tap and no sub-toggle script. */
@media (max-width: 781.98px) {
	.gr-nav-js .gr-nav-menu {
		display: none;
	}

	.gr-nav.is-open .gr-nav-menu {
		display: block;
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		background: var(--wp--preset--color--cocoa);
		padding: var(--wp--preset--spacing--50) var(--wp--custom--gutter) var(--wp--preset--spacing--60);
		box-shadow: 0 24px 40px rgba(58, 46, 46, 0.35);
		z-index: 90;
		/* The full service list makes the drawer taller than a phone screen.
		   Cap it to the space below the header and scroll inside the drawer. */
		max-height: calc(100vh - 64px);
		overflow-y: auto;
		-webkit-overflow-scrolling: touch;
	}

	.gr-header .wp-block-group.is-nowrap {
		position: relative;
	}

	.gr-nav-menu > li {
		border-bottom: 1px solid rgba(255, 255, 255, 0.12);
	}

	.gr-nav-menu > li > a {
		display: flex;
		align-items: center;
		width: 100%;
		min-height: 48px;
		padding-block: 0.65rem;
		color: var(--wp--preset--color--white);
		font-size: var(--wp--preset--font-size--lg);
	}

	/* Group label, not a control, in the drawer. */
	.gr-nav-sub-btn {
		pointer-events: none;
		color: rgba(255, 255, 255, 0.6);
		font-family: var(--wp--preset--font-family--jetbrains-mono);
		font-size: 0.72rem;
		letter-spacing: 0.08em;
		text-transform: uppercase;
		padding-block: 0.65rem 0.15rem;
	}

	.gr-nav-sub-btn svg {
		display: none;
	}

	.gr-nav-sub a {
		display: flex;
		align-items: center;
		width: 100%;
		min-height: 48px;
		padding: 0.5rem 0 0.5rem 0.9rem;
		color: var(--wp--preset--color--white);
		font-size: var(--wp--preset--font-size--lg);
		text-decoration: none;
	}
}

/* No-JS mobile: the menu simply renders stacked below the logo row — plain,
   but complete and usable. */
@media (max-width: 781.98px) {
	.gr-nav:not(.gr-nav-js) .gr-nav-menu > li > a,
	.gr-nav:not(.gr-nav-js) .gr-nav-sub a {
		color: var(--wp--preset--color--cocoa);
	}

	.gr-nav:not(.gr-nav-js) .gr-nav-sub-btn {
		color: var(--wp--preset--color--taupe-ink);
	}
}

/* "All Services" hub link: a view-all affordance at the foot of the Services
   dropdown so /services/ — and the supporting service pages it links — stays one
   click from the nav. Divider + weight set it apart from the pillar links. */
.gr-nav-sub-all {
	border-top: 1px solid rgba(255, 255, 255, 0.12);
	margin-top: 4px;
}

.gr-nav-sub-all a {
	font-weight: 600;
}

/* A 1x1 skip link is technically present and practically unusable for the
   keyboard users it exists to serve. It stays visually hidden until focused,
   then becomes a real control. */
.skip-link:focus,
.skip-link:focus-visible {
	position: fixed !important;
	top: 12px;
	left: 12px;
	z-index: 1000;
	width: auto !important;
	height: auto !important;
	clip: auto !important;
	clip-path: none !important;
	padding: 0.75rem 1.1rem;
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
	border-radius: var(--wp--custom--radius--sm);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

@media (max-width: 781px) {
	.gr-header .gr-cta-long {
		display: none;
	}

	.gr-header .wp-block-button__link {
		font-size: 0.82rem !important;
		padding: 11px 14px !important;
		/* Tightening the padding to fit the row dropped the pill to 38px tall.
		   44px is the floor for a touch target, so it is enforced here rather
		   than left to whatever the font and padding happen to produce. */
		min-height: 44px;
		display: inline-flex;
		align-items: center;
	}
}

/* Inline links inside running text get an underline, so they are distinguishable
   without relying on colour (WCAG link-in-text-block). Arrow-links, buttons, and
   nav are excluded: those are distinguishable by position or shape.
   The list-item half is scoped to content areas on purpose. WCAG 1.4.1 is about
   links sitting inside a block of text, where colour alone leaves them ambiguous.
   In the footer columns and the Services dropdown every item is a link, so there
   is nothing to disambiguate and the underlines are just noise. */
:where(.gr-prose, .gr-faq, main .wp-block-column, .entry-content) p:not(.gr-link-arrow) a,
:where(.gr-prose, .gr-faq, main .wp-block-column, .entry-content) li a:not(.wp-block-navigation-item__content) {
	text-decoration: underline;
	text-underline-offset: 0.15em;
	text-decoration-thickness: 1px;
}

/* The full-size logo waits until 900px: at exactly 782px the inline menu and
   the 62px logo (274px wide) together overflowed the row by one pixel. */
@media (min-width: 900px) {
	.gr-header .wp-block-site-logo img {
		height: 62px;
	}
}

/* ---------------------------------------------------------------------------
 * 13. Footer
 * ------------------------------------------------------------------------ */

/* The CTA band and the footer are both cocoa, so the default block gap between
   <main> and the footer template part showed up as a white sliver dividing two
   identical dark surfaces. Close it so the page ends in one continuous dark
   zone, and mark the boundary with a hairline instead: the CTA is the decision
   moment, the footer is navigation, and they still need to read as separate. */
.wp-site-blocks > footer {
	margin-block-start: 0;
}

.gr-footer {
	border-top: 1px solid rgba(255, 255, 255, 0.1);
}

/* Five columns on one row only work at the top of the range. "info@growth
   refactor.com" is a single 22-character word that needs 174px, and above
   782px WordPress puts all five columns across at whatever the constrained
   content width allows: 181px each at the 1120px cap, but 171px at a 1200px
   viewport and 105px at 782px. So the address lost its final "m" to a second
   line on every desktop width, and the link labels were breaking mid-phrase
   next to it.

   Below 1160px five across cannot be made to fit at all, so the brand column
   takes its own row and the four link/contact columns split the full width;
   below 860px even four is too narrow and they pair up. WordPress core pins
   .wp-block-columns to flex-wrap:nowrap above 782px with !important, which is
   what these declarations are overriding. */
@media (min-width: 782px) and (max-width: 1159.98px) {
	.gr-footer .wp-block-columns {
		flex-wrap: wrap !important;
	}

	.gr-footer .wp-block-columns > .wp-block-column:first-child {
		flex-basis: 100% !important;
	}

	.gr-footer .wp-block-columns > .wp-block-column:not(:first-child) {
		flex-basis: calc((100% - 3 * var(--wp--preset--spacing--60)) / 4) !important;
		flex-grow: 0;
	}
}

@media (min-width: 782px) and (max-width: 859.98px) {
	.gr-footer .wp-block-columns > .wp-block-column:not(:first-child) {
		flex-basis: calc((100% - var(--wp--preset--spacing--60)) / 2) !important;
	}
}

.gr-footer .wp-block-image img {
	height: 64px;
	width: auto;
	max-width: none;
}

.gr-footer :where(p, li, a) {
	color: rgba(255, 255, 255, 0.72);
}

/* Link columns are navigation, not prose: no bullets, flush left. */
.gr-footer .wp-block-list {
	list-style: none;
	padding-left: 0;
	margin-left: 0;
}

/* Belt and braces against any inherited underline in the two link lists. Hover
   and focus still change colour, and the global focus ring is untouched, so
   these stay distinguishable without the rules. */
.gr-footer a,
.gr-footer a:hover,
.gr-footer a:focus-visible,
.gr-header .wp-block-navigation__submenu-container a,
.gr-header .wp-block-navigation__submenu-container a:hover,
.gr-header .wp-block-navigation__submenu-container a:focus-visible {
	text-decoration: none;
}

.gr-footer a:hover {
	color: var(--wp--preset--color--white);
}

.gr-footer h2,
.gr-footer h3 {
	color: var(--wp--preset--color--white);
	font-size: var(--wp--preset--font-size--small);
	text-transform: uppercase;
	letter-spacing: 0.08em;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-weight: 500;
}

/* Social profiles. A list because it is one, with its own reset: the rule above
   only unbullets .wp-block-list, and this is raw markup inside a wp:html block.
   Sized to the 44px minimum tap target rather than to the 20px glyph, so the
   hit area is honest on a phone even though the icon looks smaller. */
.gr-social {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	list-style: none;
	margin: var(--wp--preset--spacing--40) 0 0;
	padding-left: 0;
}

.gr-social__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: var(--wp--custom--radius--sm);
	color: rgba(255, 255, 255, 0.72);
	transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}

.gr-social__link:hover,
.gr-social__link:focus-visible {
	color: var(--wp--preset--color--white);
	border-color: rgba(255, 255, 255, 0.5);
	background: rgba(255, 255, 255, 0.1);
}

/* ---------------------------------------------------------------------------
 * 14. Forms
 * ------------------------------------------------------------------------ */

.gr-form :where(input[type="text"], input[type="email"], input[type="tel"], input[type="url"], textarea, select) {
	/* Form controls do not inherit the document's border-box sizing, so
	   width:100% plus 1.8rem of padding and 2px of border made every field
	   about 31px wider than the column holding it. In a single-column form that
	   only spilled past the edge; side by side it made the fields overlap each
	   other outright. */
	box-sizing: border-box;
	width: 100%;
	font-family: var(--wp--preset--font-family--inter);
	font-size: var(--wp--preset--font-size--base);
	color: var(--wp--preset--color--cocoa);
	background: var(--wp--preset--color--white);
	border: 1px solid rgba(58, 46, 46, 0.18);
	border-radius: var(--wp--custom--radius--sm);
	padding: 0.75rem 0.9rem;
	/* 16px minimum prevents iOS Safari from zooming on focus. */
	min-height: 44px;
}

/* Full-strength ring: the old 25%-alpha wash measured 1.47:1 against white,
   invisible to exactly the low-vision users a focus ring exists for. */
.gr-form :where(input, textarea, select):focus {
	border-color: var(--wp--preset--color--coral-ink);
	outline: 2px solid var(--wp--preset--color--coral-ink);
	outline-offset: 2px;
}

.gr-form label {
	display: block;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	color: var(--wp--preset--color--cocoa);
	margin-bottom: 0.35rem;
}

/* Required marker. Coral-ink rather than plain coral so the small text still
   clears AA on both white and mist, and the whole thing reads as one phrase
   with the label rather than as a floating symbol. */
.gr-form .gr-req {
	font-weight: 400;
	font-size: 0.78em;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--coral-ink);
	white-space: nowrap;
}

.gr-form .gr-optional {
	font-weight: 400;
	font-size: 0.78em;
	color: var(--wp--preset--color--taupe-ink);
	white-space: nowrap;
}

/* Validation errors render in place above the fields, get focus, and link to
   the fields they name. Coral-ink on a pale wash clears AA. */
.gr-form-error {
	grid-column: 1 / -1;
	background: rgba(198, 53, 59, 0.07);
	border: 1px solid rgba(198, 53, 59, 0.35);
	border-radius: var(--wp--custom--radius--sm);
	padding: 0.9rem 1.1rem;
	margin-bottom: var(--wp--preset--spacing--30);
}

.gr-form-error p {
	margin: 0 0 0.35rem;
	color: var(--wp--preset--color--coral-ink);
}

.gr-form-error ul {
	margin: 0;
	padding-left: 1.1rem;
}

.gr-form-error a {
	color: var(--wp--preset--color--coral-ink);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.gr-form-error:focus {
	outline: 3px solid var(--wp--preset--color--coral-ink);
	outline-offset: 3px;
}

.gr-form :where(input, textarea)[aria-invalid="true"] {
	border-color: var(--wp--preset--color--coral-ink);
}

/* The data-handling note spans both columns of the form grid; half-width it
   would reintroduce the whitespace imbalance beside the button. */
.gr-form-note {
	grid-column: 1 / -1;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--taupe-ink);
	line-height: 1.6;
	margin-top: 0.25rem;
}

/* Focus lands on the thank-you heading programmatically after the redirect,
   so this uses :focus (not :focus-visible, which script focus does not
   always trigger). */
.gr-form-thanks-title:focus {
	outline: 3px solid var(--wp--preset--color--coral-ink);
	outline-offset: 4px;
}

.gr-form p {
	margin: 0 0 1rem;
}

.gr-form button {
	cursor: pointer;
	border: 0;
	width: 100%;
}

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

.gr-form-thanks {
	background: var(--wp--preset--color--mist);
	border-left: 4px solid var(--wp--preset--color--coral);
	border-radius: var(--wp--custom--radius--base);
	padding: var(--wp--preset--spacing--60);
}

.gr-form-thanks p:last-child {
	margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
 * 14b. Inline SVG diagrams
 *
 * On-brand vector illustrations built in place, in the Sunrise Coral palette.
 * Deliberately used instead of stock photography: crisp at any size, a few KB,
 * no external request, and a better fit for an engineer-led brand than a
 * generic photo. A max-width keeps them from ballooning on wide screens.
 * ------------------------------------------------------------------------ */

.gr-diagram {
	max-width: 760px;
	margin-inline: 0;
}

.gr-diagram svg {
	width: 100%;
	height: auto;
}

/* On a cocoa section the node fills and text need to stay legible; these
   diagrams are authored for light sections, so keep them on mist/white bands. */

.gr-diagram figcaption {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--taupe-ink);
	margin-top: var(--wp--preset--spacing--30);
}

/* ---------------------------------------------------------------------------
 * 14c. Product mockups (app-window screenshots with sample data)
 *
 * Honest alternative to a faked screenshot: a real HTML/CSS representation of
 * the software, always paired with a visible "sample data" caption. This is how
 * you show what a system looks like without leaking a customer's private data
 * or inventing a screenshot. Every .gr-mock must sit next to a .gr-mock-note.
 * ------------------------------------------------------------------------ */

.gr-mock {
	background: var(--wp--preset--color--white);
	border: 1px solid rgba(58, 46, 46, 0.14);
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: var(--wp--preset--shadow--pop);
	overflow: hidden;
}

.gr-mock-bar {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.7rem 0.9rem;
	background: var(--wp--preset--color--mist);
	border-bottom: 1px solid rgba(58, 46, 46, 0.1);
}

.gr-mock-bar i {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: rgba(58, 46, 46, 0.18);
}

.gr-mock-bar span {
	margin-left: 0.4rem;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.7rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-mock-body {
	padding: 1.1rem;
}

.gr-mock-tiles {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 0.7rem;
	margin-bottom: 1rem;
}

.gr-mock-tile {
	background: var(--wp--preset--color--mist);
	border-radius: var(--wp--custom--radius--sm);
	padding: 0.7rem 0.8rem;
}

.gr-mock-tile b {
	display: block;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-size: 1.15rem;
	color: var(--wp--preset--color--cocoa);
	line-height: 1.1;
}

.gr-mock-tile b.pos {
	color: #2e7d52;
}

.gr-mock-tile b.neg {
	color: var(--wp--preset--color--coral-ink);
}

.gr-mock-tile small {
	font-size: 0.7rem;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-mock table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.78rem;
}

.gr-mock th,
.gr-mock td {
	text-align: left;
	padding: 0.5rem 0.55rem;
	border-bottom: 1px solid rgba(58, 46, 46, 0.08);
}

.gr-mock th {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.66rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-mock .pill {
	display: inline-block;
	padding: 0.1rem 0.5rem;
	border-radius: var(--wp--custom--radius--pill);
	font-size: 0.68rem;
	font-weight: 600;
}

.gr-mock .pill.done {
	background: rgba(46, 125, 82, 0.12);
	/* Darkened from #2e7d52 (4.29:1) to pass AA on the light-green pill. */
	color: #1f6a42;
}

.gr-mock .pill.due {
	background: rgba(255, 182, 39, 0.18);
	color: #8a6400;
}

.gr-mock-note {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--taupe-ink);
	margin-top: var(--wp--preset--spacing--30);
	font-style: italic;
}

/* ---------------------------------------------------------------------------
 * 14d. Mechanism flow (the hero illustration)
 *
 * A sequence diagram, not a screenshot. It replaced a dashboard of invented
 * performance figures, so the one rule that matters here is that it must never
 * become convincing as a captured conversation: no carrier bar, no battery
 * icon, no avatars, no chat bubbles, no green/blue message tinting. Timestamps
 * are set in the mono "instrumentation" face to read as annotation, and the
 * connecting rule makes it read as a flow rather than a transcript.
 * ------------------------------------------------------------------------ */

.gr-flow-steps {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The marker and its spine live in the gutter between the timestamp and the
   text. Positioning them inside the timestamp column overlaps the figures and
   eats a digit, which is easy to miss at a glance and unreadable up close. */
.gr-flow-steps li {
	position: relative;
	display: grid;
	grid-template-columns: 4rem 1fr;
	gap: 1.6rem;
	padding: 0 0 var(--wp--preset--spacing--30) 0;
}

.gr-flow-steps li:last-child {
	padding-bottom: 0;
}

.gr-flow-steps li::after {
	content: "";
	position: absolute;
	left: 4.7rem;
	top: 0.42rem;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--wp--preset--color--coral-ink);
}

.gr-flow-steps li:not(:last-child)::before {
	content: "";
	position: absolute;
	left: calc(4.7rem + 3px);
	top: 1.1rem;
	bottom: 0.1rem;
	width: 1px;
	background: rgba(58, 46, 46, 0.16);
}

.gr-flow-time {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.68rem;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--taupe-ink);
	padding-top: 0.15em;
}

.gr-flow-text {
	font-size: 0.86rem;
	line-height: 1.5;
	color: var(--wp--preset--color--cocoa);
}

/* The reply is the turn that matters, so it carries the only emphasis. */
.gr-flow-steps li:nth-child(3) .gr-flow-text {
	font-weight: 600;
}

/* Narrow phones: the fixed 4.4rem timestamp gutter squeezed the text to
   ~16-character lines in the block that carries the hero's whole explanation.
   The timestamp stacks above the text and the spine/marker hide, since their
   fixed offsets no longer line up with anything. */
@media (max-width: 480px) {
	.gr-flow .gr-flow-steps li {
		grid-template-columns: 1fr;
		gap: 0.15rem;
		padding-left: 0;
	}

	.gr-flow .gr-flow-steps li::before,
	.gr-flow .gr-flow-steps li::after {
		display: none;
	}
}

/* On a phone the hero has to stay short enough that the primary CTA is not
   pushed under the fold, so the diagram drops its last beat. The three that
   remain still carry the whole mechanism: missed, answered, replied. */
@media (max-width: 781px) {
	.gr-flow-steps li:last-child {
		display: none;
	}

	.gr-flow-steps li:nth-last-child(2) {
		padding-bottom: 0;
	}

	.gr-flow-steps li:nth-last-child(2)::before {
		display: none;
	}
}

/* ---------------------------------------------------------------------------
 * 15. Prose measure on long-form content
 * ------------------------------------------------------------------------ */

.gr-prose > :where(p, ul, ol, h2, h3, h4, blockquote) {
	max-width: 68ch;
}

/* ===========================================================================
 * PREMIUM VISUAL LAYER (depth, grain, mesh, bento, device frame, type)
 * The redesign's "material" rules. Warm developer-tooling, set editorially.
 * ======================================================================== */

/* --- Film grain: kills gradient banding, adds tactile richness on cocoa --- */
.gr-hero,
.gr-cta,
.gr-dark {
	position: relative;
	isolation: isolate;
}

/* Grain is deferred to post-load (html.gr-motion-ready) so its blended layer
   never competes with the hero's LCP paint. No-JS still gets a clean hero. */
html.gr-motion-ready .gr-hero::after,
html.gr-motion-ready .gr-cta::after,
html.gr-motion-ready .gr-dark.gr-grain::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: 0.5;
	mix-blend-mode: soft-light;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Keep hero/CTA content above the grain + glow layers. */
.gr-hero > *,
.gr-cta > * {
	position: relative;
	z-index: 1;
}

/* --- Animated sunrise mesh drift behind cocoa heroes (barely perceptible) --- */
.gr-hero::before {
	background:
		radial-gradient(60% 55% at 15% 10%, rgba(255, 90, 95, 0.26) 0%, transparent 60%),
		radial-gradient(52% 50% at 88% 85%, rgba(255, 134, 39, 0.18) 0%, transparent 60%),
		radial-gradient(40% 40% at 60% 40%, rgba(255, 90, 95, 0.10) 0%, transparent 70%);
	transform: translate3d(var(--gr-px, 0), var(--gr-py, 0), 0);
}

/* The mesh only drifts once the page is interactive, so it never gates LCP.
   motion.js adds .gr-motion-ready after init. */
html.gr-motion-ready .gr-hero::before {
	background-size: 160% 160%, 170% 170%, 150% 150%;
	animation: gr-mesh 26s ease-in-out 1s infinite alternate;
}

@keyframes gr-mesh {
	0%   { background-position: 0% 0%, 100% 100%, 50% 50%; }
	100% { background-position: 20% 15%, 80% 85%, 60% 40%; }
}

/* Faint precision grid on cocoa surfaces (the "engineered" texture).
   Deferred to post-load so the masked layer never gates the hero LCP paint. */
html.gr-motion-ready .gr-hero .gr-hero-split::before,
html.gr-motion-ready .gr-hero .gr-hero-inner::before {
	content: "";
	position: absolute;
	inset: -40px 0;
	z-index: -1;
	pointer-events: none;
	background-image:
		linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
		linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
	background-size: 44px 44px;
	mask-image: radial-gradient(75% 75% at 25% 40%, #000 0%, transparent 78%);
	-webkit-mask-image: radial-gradient(75% 75% at 25% 40%, #000 0%, transparent 78%);
}

.gr-hero-inner,
.gr-hero-split {
	position: relative;
}

/* --- Depth tokens: longer, warmer, cocoa-tinted shadows --- */
.gr-shadow-lift {
	box-shadow: 0 18px 50px -18px rgba(58, 46, 46, 0.28), 0 4px 14px -8px rgba(58, 46, 46, 0.18);
}

/* --- Type: louder display, tighter tracking --- */
.gr-hero h1 {
	font-size: clamp(2.4rem, 5.2vw, 4.4rem) !important;
	line-height: 1.03;
	letter-spacing: -0.025em;
	max-width: 15ch;
}

/* --- Split hero (asymmetric on desktop, stacked on mobile) --- */
@media (min-width: 900px) {
	.gr-hero-split {
		display: grid;
		grid-template-columns: 1.15fr 0.85fr;
		gap: clamp(2rem, 5vw, 4.5rem);
		align-items: center;
	}
}

.gr-hero-visual {
	position: relative;
	display: flex;
	justify-content: center;
}

/* --- Phone device frame + live SMS demo (product = our "photography") --- */
.gr-phone {
	position: relative;
	width: min(300px, 78vw);
	aspect-ratio: 300 / 620;
	background: #241c1c;
	border-radius: 40px;
	padding: 12px;
	box-shadow: 0 40px 80px -30px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

.gr-phone::before {
	content: "";
	position: absolute;
	top: 14px;
	left: 50%;
	transform: translateX(-50%);
	width: 42%;
	height: 20px;
	background: #241c1c;
	border-radius: 0 0 14px 14px;
	z-index: 3;
}

.gr-phone-screen {
	height: 100%;
	border-radius: 30px;
	background: linear-gradient(180deg, #fbf4f1 0%, #ffffff 100%);
	overflow: hidden;
	display: flex;
	flex-direction: column;
}

.gr-phone-top {
	background: var(--wp--preset--color--cocoa);
	color: #fff;
	padding: 30px 16px 12px;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 600;
	font-size: 0.9rem;
	display: flex;
	align-items: center;
	gap: 8px;
}

.gr-phone-top small {
	display: block;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-weight: 400;
	font-size: 0.62rem;
	color: rgba(255, 255, 255, 0.55);
}

.gr-phone-thread {
	flex: 1;
	padding: 14px 12px;
	display: flex;
	flex-direction: column;
	gap: 9px;
	overflow: hidden;
}

.gr-missed {
	align-self: center;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.6rem;
	letter-spacing: 0.03em;
	color: var(--wp--preset--color--coral-ink);
	background: rgba(255, 90, 95, 0.1);
	padding: 4px 10px;
	border-radius: 999px;
}

.gr-bubble {
	max-width: 78%;
	padding: 9px 12px;
	border-radius: 16px;
	font-size: 0.78rem;
	line-height: 1.35;
	opacity: 0;
	transform: translateY(8px);
	animation: gr-bubble-in 0.5s ease forwards;
}

.gr-bubble.out {
	align-self: flex-end;
	background: var(--wp--preset--gradient--sunrise);
	color: var(--wp--preset--color--cocoa);
	border-bottom-right-radius: 5px;
}

.gr-bubble.in {
	align-self: flex-start;
	background: var(--wp--preset--color--mist);
	color: var(--wp--preset--color--cocoa);
	border: 1px solid rgba(58, 46, 46, 0.08);
	border-bottom-left-radius: 5px;
}

.gr-bubble.b1 { animation-delay: 0.6s; }
.gr-missed   { animation: gr-bubble-in 0.5s ease forwards; animation-delay: 0.2s; opacity: 0; }
.gr-bubble.b2 { animation-delay: 1.5s; }
.gr-bubble.b3 { animation-delay: 2.6s; }
.gr-bubble.b4 { animation-delay: 3.6s; }

.gr-bubble .t {
	display: block;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.55rem;
	opacity: 0.6;
	margin-top: 3px;
}

@keyframes gr-bubble-in {
	to { opacity: 1; transform: translateY(0); }
}

/* --- Mini growth bar chart (for the hero results dashboard) --- */
.gr-bars {
	display: flex;
	align-items: flex-end;
	gap: 7px;
	height: 84px;
	margin-top: 4px;
}

.gr-bars span {
	flex: 1;
	border-radius: 4px 4px 0 0;
	background: linear-gradient(180deg, rgba(255, 90, 95, 0.25), rgba(255, 134, 39, 0.25));
	position: relative;
	min-height: 8px;
}

.gr-bars span:last-child {
	background: var(--wp--preset--gradient--sunrise);
}

/* --- Bento grid for services --- */
.gr-bento {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--wp--preset--spacing--50);
}

@media (min-width: 640px) {
	.gr-bento { grid-template-columns: repeat(2, 1fr); }
	.gr-bento .gr-span-2 { grid-column: span 2; }
}

@media (min-width: 1000px) {
	.gr-bento { grid-template-columns: repeat(3, 1fr); }
	.gr-bento .gr-span-2 { grid-column: span 2; }
}

/* Spec-sheet variant: hairline rows instead of card chrome. Used where the
   heading is the payload and the box around it was pure weight — six bordered
   cards in a row read as another wall, six hairline rows read as a list you
   can scan. */
.gr-bento.is-spec > * {
	border-top: 1px solid rgba(58, 46, 46, 0.12);
	padding-top: var(--wp--preset--spacing--40);
}

/* ---------------------------------------------------------------------------
 * Icon beside the heading, in the bare icon grids
 *
 * Stacked, the 44px tile sat alone on a line the full width of its cell with
 * nothing next to it. On a phone the cell is the whole viewport, so the tile
 * left roughly 250px of empty rule-to-rule space above every heading. Pairing
 * them puts the tile and the claim it illustrates on one line, and the
 * sentence hangs under the heading's left edge, so each cell reads as one unit
 * rather than three stacked fragments.
 *
 * Keyed on the shape rather than on a list of section classes: a tile whose
 * very next sibling is the heading is exactly the arrangement being fixed, and
 * it holds across all four sections that have it (outcomes, audience,
 * pain-cards, proof-promise) without naming any of them. Anything else keeps
 * its own layout for free -- the numbered process rows sharing .gr-steps-4up
 * have a .gr-step-num paragraph and no tile, and the pillar cards put their
 * tile inside .gr-card-head followed by a "01. Get found" label rather than
 * the heading, so neither matches.
 * ------------------------------------------------------------------------ */
.wp-block-group:has(> .gr-icon-tile + .wp-block-heading) {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: var(--wp--preset--spacing--30);
	align-items: center;
}

.wp-block-group:has(> .gr-icon-tile + .wp-block-heading) > .gr-icon-tile {
	grid-column: 1;
	grid-row: 1;
	margin-bottom: 0;
}

.wp-block-group:has(> .gr-icon-tile + .wp-block-heading) > h3 {
	grid-column: 2;
	grid-row: 1;
	margin-block: 0;
}

/* 0.35rem is the gap the heading used to carry itself; it moves to the
   paragraph because the heading no longer sits directly above it. */
.wp-block-group:has(> .gr-icon-tile + .wp-block-heading) > p {
	grid-column: 2;
	margin-block-start: 0.35rem;
}

/* The two accent-card sets carry about forty words each, not one clause, so
   their body runs the full width of the card rather than indenting to the
   heading. At three-up the card is roughly 270px inside its padding, and the
   56px indent would have cost a fifth of every line. */
.wp-block-group.is-style-card-accent:has(> .gr-icon-tile + .wp-block-heading) > p {
	grid-column: 1 / -1;
	margin-block-start: var(--wp--preset--spacing--30);
}

/* --- Ghosted oversized numerals for editorial depth --- */
.gr-ghost-num {
	position: absolute;
	top: -0.35em;
	right: 0.1em;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 700;
	font-size: 5.5rem;
	line-height: 1;
	color: var(--wp--preset--color--cocoa);
	opacity: 0.05;
	pointer-events: none;
	z-index: 0;
}

/* --- Data chips / spec-sheet --- */
.gr-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.72rem;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--cocoa);
	background: var(--wp--preset--color--white);
	border: 1px solid rgba(58, 46, 46, 0.12);
	border-radius: 999px;
	padding: 0.4rem 0.85rem;
}

.gr-chip::before {
	content: "";
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--wp--preset--gradient--sunrise);
}

/* --- Enhanced card hover (lift + coral hairline + shadow) --- */
.wp-block-group.is-style-card {
	position: relative;
	border: 1px solid rgba(58, 46, 46, 0.08);
	transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.22s ease, border-color 0.22s ease;
}

.wp-block-group.is-style-card:hover {
	transform: translateY(-4px);
	border-color: rgba(255, 90, 95, 0.4);
	box-shadow: 0 22px 50px -20px rgba(58, 46, 46, 0.3);
}

/* Gradient top-accent that grows on hover. */
.wp-block-group.is-style-card::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	height: 3px;
	width: 0;
	border-radius: 3px 3px 0 0;
	background: var(--wp--preset--gradient--sunrise);
	transition: width 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.wp-block-group.is-style-card:hover::after {
	width: 100%;
}

/* ---------------------------------------------------------------------------
 * 17. Motion: no-flash reveal states
 *
 * The inline head guard (functions.php) adds html.gr-motion pre-paint ONLY when
 * JS is on and motion is allowed. So reveal targets are born hidden with no
 * flash; motion.js (GSAP) reveals them. Only opacity is set here so GSAP fully
 * owns the transform (no CSS/GSAP translate conflict). The failsafe and the
 * absence of gr-motion (no-JS / reduced-motion) both leave content visible.
 * ------------------------------------------------------------------------ */

html.gr-motion .gr-reveal {
	opacity: 0;
}

html.gr-motion-failsafe .gr-reveal {
	opacity: 1 !important;
	transform: none !important;
}

/* Numeric stats hold their width while counting up, so CLS stays 0. */
.gr-stat-value {
	font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
 * 16. Motion preferences
 * ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ---------------------------------------------------------------------------
 * 18. How-It-Works journey flow
 *
 * Reuses the hero's .gr-flow-steps primitive. The hero trims its last beat
 * below 781px to stay above the fold (section 14d); the journey visual is not
 * the hero and wants all four beats, so .gr-flow-journey opts back in. Split at
 * 480px because below that the flow is single-column and its connector spine is
 * hidden, so only the row is restored there, never the mis-aligned spine.
 * ------------------------------------------------------------------------ */

@media (min-width: 481px) and (max-width: 781px) {
	.gr-flow-steps.gr-flow-journey li:last-child {
		display: grid;
	}

	.gr-flow-steps.gr-flow-journey li:nth-last-child(2) {
		padding-bottom: var(--wp--preset--spacing--30);
	}

	.gr-flow-steps.gr-flow-journey li:nth-last-child(2)::before {
		display: block;
	}
}

@media (max-width: 480px) {
	.gr-flow-steps.gr-flow-journey li:last-child {
		display: grid;
	}

	.gr-flow-steps.gr-flow-journey li:nth-last-child(2) {
		padding-bottom: var(--wp--preset--spacing--30);
	}
}

/* ---------------------------------------------------------------------------
 * 19. Per-page hero visuals
 *
 * Each service/landing hero carries a right-column illustration matched to that
 * page's subject, built from the same .gr-mock / .gr-phone / .gr-flow primitives
 * as the home hero so the set reads as one system. Same honesty rule as section
 * 14d: every panel shows a mechanism or a clearly-labelled example, never a
 * fabricated result. Only the pieces the shared primitives do not already cover
 * are defined here.
 * ------------------------------------------------------------------------ */

/* Custom Software: a neutral "not started yet" pill, alongside .done / .due. */
.gr-mock .pill.wait {
	background: rgba(58, 46, 46, 0.08);
	color: var(--wp--preset--color--taupe-ink);
}

/* Social Media: an example post card. No follower or engagement counts — the
   honesty rule forbids inventing numbers, so it shows only the content style. */
.gr-post-head {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	margin-bottom: 0.9rem;
}

.gr-post-avatar {
	flex: none;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--wp--preset--gradient--sunrise);
	color: var(--wp--preset--color--cocoa);
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 700;
	font-size: 0.85rem;
	letter-spacing: 0.02em;
}

.gr-post-name {
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 600;
	font-size: 0.9rem;
	color: var(--wp--preset--color--cocoa);
	line-height: 1.2;
}

.gr-post-name small {
	display: block;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-weight: 400;
	font-size: 0.62rem;
	color: var(--wp--preset--color--taupe-ink);
	margin-top: 2px;
}

.gr-post-photo {
	aspect-ratio: 16 / 9;
	border-radius: var(--wp--custom--radius--sm);
	background:
		linear-gradient(135deg, rgba(255, 134, 39, 0.16), rgba(255, 90, 95, 0.14)),
		var(--wp--preset--color--mist);
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 0.8rem;
}

.gr-post-photo span {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.66rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-post-caption {
	font-size: 0.82rem;
	line-height: 1.5;
	color: var(--wp--preset--color--cocoa);
	margin: 0 0 0.7rem;
}

.gr-post-stars {
	font-size: 0.76rem;
	line-height: 1.4;
	color: var(--wp--preset--color--taupe-ink);
	margin: 0;
}

.gr-post-stars .gr-stars {
	color: #e0982f;
	letter-spacing: 0.08em;
	margin-right: 0.25rem;
}

/* About: marketing and software as one system, joined at the seam the page
   argues is where the expensive problems hide. A diagram, not a metric. */
.gr-system-node {
	border: 1px solid rgba(58, 46, 46, 0.14);
	border-radius: var(--wp--custom--radius--sm);
	background: var(--wp--preset--color--mist);
	padding: 0.7rem 0.9rem;
	text-align: center;
}

.gr-system-node b {
	display: block;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-size: 1.05rem;
	color: var(--wp--preset--color--cocoa);
	line-height: 1.15;
}

.gr-system-node small {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.64rem;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-system-seam {
	position: relative;
	display: flex;
	justify-content: center;
	padding: 0.55rem 0;
}

.gr-system-seam::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 2px;
	transform: translateX(-50%);
	background: repeating-linear-gradient(
		to bottom,
		var(--wp--preset--color--coral-ink) 0,
		var(--wp--preset--color--coral-ink) 4px,
		transparent 4px,
		transparent 8px
	);
}

.gr-system-seam span {
	position: relative;
	background: var(--wp--preset--color--white);
	border: 1px solid rgba(255, 90, 95, 0.35);
	border-radius: var(--wp--custom--radius--pill);
	padding: 0.2rem 0.7rem;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.62rem;
	letter-spacing: 0.03em;
	color: var(--wp--preset--color--coral-ink);
}

/* ---------------------------------------------------------------------------
 * 20. Corner dock: back to top + guided helper
 *
 * One fixed stack owns the bottom-right corner, so nothing here can end up
 * sitting on top of anything else there. Order inside .gr-dock-controls is
 * deliberate: back-to-top is above the helper launcher, so the 44px it reserves
 * while hidden is reserved ABOVE, and the launcher stays pinned to the corner
 * instead of floating off it.
 *
 * Back-to-top is a real anchor to #top (the HTML spec's "top of the document"
 * fragment), so it works with no JS and needs no extra markup to anchor
 * against. JS only upgrades it: reveal on scroll, smooth scroll through
 * whichever scroller is live, and move focus to the header afterwards. It is
 * hidden by default rather than by a hidden attribute, because the reveal is a
 * scroll state; the <noscript> override in the footer markup is what keeps the
 * control usable when the script never runs.
 * ------------------------------------------------------------------------ */

.gr-dock {
	position: fixed;
	right: 16px;
	/* Clear of the iOS Safari bottom bar; the flat value is the fallback. */
	bottom: 16px;
	bottom: calc(16px + env(safe-area-inset-bottom, 0px));
	z-index: 90;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 12px;
	/* The stack reserves space for a hidden back-to-top, so the container itself
	   must not swallow clicks aimed at the page behind that gap. */
	pointer-events: none;
}

.gr-dock > *,
.gr-dock-controls > * {
	pointer-events: auto;
}

.gr-dock-controls {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
}

/* The consent notice occupies the bottom of the viewport and is a question the
   visitor has to answer. Everything in the dock yields until it is answered. */
html[data-gr-consent="pending"] .gr-dock {
	display: none;
}

@media (min-width: 782px) {
	.gr-dock {
		right: 24px;
		bottom: 24px;
	}
}

.gr-to-top {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 44px is the same touch-target floor the header pill enforces. */
	width: 44px;
	height: 44px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
	box-shadow: 0 6px 18px rgba(58, 46, 46, 0.28);
	text-decoration: none;
	opacity: 0;
	visibility: hidden;
	transform: translateY(10px);
	transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s ease,
		background-color 0.2s ease;
}

.gr-to-top.is-visible {
	opacity: 1;
	visibility: visible;
	transform: none;
}

.gr-to-top:hover,
.gr-to-top:focus-visible {
	background: var(--wp--preset--color--coral-ink);
	color: var(--wp--preset--color--white);
}

.gr-to-top svg {
	display: block;
	pointer-events: none;
}

/* Hidden but still occupying its slot in the dock, on purpose: collapsing it
   would slide the helper launcher up and down the corner every time the reveal
   threshold is crossed. */
.gr-to-top:not(.is-visible) {
	pointer-events: none;
}

/* ---------------------------------------------------------------------------
 * 21. Cookie consent
 *
 * The notice is in the markup for everyone but only displays while consent is
 * pending, which the inline head script decides before paint from the
 * gr_consent cookie. Two consequences worth knowing:
 *   - returning visitors never see a flash of the notice;
 *   - with JS off the attribute is never set, so the notice stays hidden - and
 *     correctly so, because the scripts it gates are never activated either.
 * ------------------------------------------------------------------------ */

.gr-consent {
	display: none;
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 200;
	padding: var(--wp--preset--spacing--40);
	padding-bottom: calc(var(--wp--preset--spacing--40) + env(safe-area-inset-bottom, 0px));
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
	box-shadow: 0 -8px 28px rgba(58, 46, 46, 0.3);
	/* Amber focus rings, matching every other cocoa surface. */
	--gr-focus-ring: var(--wp--preset--color--amber);
}

html[data-gr-consent="pending"] .gr-consent {
	display: block;
}

.gr-consent-inner {
	max-width: var(--wp--style--global--wide-size, 1200px);
	margin: 0 auto;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.gr-consent-eyebrow {
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.7rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--amber);
	margin: 0;
}

.gr-consent-copy {
	margin: 0;
	font-size: 0.9rem;
	line-height: 1.55;
	max-width: 68ch;
}

.gr-consent-copy a {
	color: var(--wp--preset--color--white);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.gr-consent-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}

/* Accept and reject are the same size and weight on purpose: a reject that is
   visually cheaper than accept is not a free choice. */
.gr-consent-btn {
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-size: 0.85rem;
	font-weight: 600;
	line-height: 1.2;
	min-height: 44px;
	padding: 0.7rem 1.15rem;
	border-radius: var(--wp--custom--radius--pill);
	border: 1px solid transparent;
	cursor: pointer;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--cocoa);
	transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.gr-consent-btn:hover {
	background: var(--wp--preset--color--amber);
	color: var(--wp--preset--color--cocoa);
}

.gr-consent-btn.is-secondary {
	background: transparent;
	color: var(--wp--preset--color--white);
	border-color: rgba(255, 255, 255, 0.5);
}

.gr-consent-btn.is-secondary:hover {
	background: rgba(255, 255, 255, 0.1);
	color: var(--wp--preset--color--white);
	border-color: var(--wp--preset--color--white);
}

.gr-consent-btn.is-quiet {
	background: transparent;
	border-color: transparent;
	color: var(--wp--preset--color--white);
	text-decoration: underline;
	text-underline-offset: 0.15em;
	padding-left: 0.35rem;
	padding-right: 0.35rem;
}

@media (min-width: 782px) {
	.gr-consent {
		padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
	}

	.gr-consent-inner {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--50);
	}

	.gr-consent-actions {
		flex-shrink: 0;
	}
}

/* --- Preferences dialog -------------------------------------------------- */

.gr-consent-modal {
	position: fixed;
	inset: 0;
	z-index: 300;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	background: rgba(58, 46, 46, 0.6);
}

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

.gr-consent-panel {
	width: 100%;
	max-height: 88vh;
	overflow-y: auto;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--cocoa);
	border-radius: var(--wp--custom--radius--lg) var(--wp--custom--radius--lg) 0 0;
	padding: var(--wp--preset--spacing--50);
	/* The sticky action row supplies the bottom padding instead, so nothing
	   scrolls into a gap underneath it. */
	padding-bottom: 0;
}

.gr-consent-panel h2 {
	font-size: 1.3rem;
	margin: 0 0 0.5rem;
}

.gr-consent-intro {
	font-size: 0.9rem;
	line-height: 1.6;
	margin: 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--taupe-ink);
}

.gr-consent-group {
	border: 1px solid rgba(58, 46, 46, 0.14);
	border-radius: var(--wp--custom--radius--sm);
	background: var(--wp--preset--color--mist);
	padding: 0.85rem 1rem;
	margin: 0 0 0.7rem;
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: 0.7rem;
	row-gap: 0.25rem;
	align-items: start;
}

.gr-consent-group input[type="checkbox"] {
	width: 20px;
	height: 20px;
	margin: 2px 0 0;
	accent-color: var(--wp--preset--color--coral-ink);
}

.gr-consent-group label {
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 600;
	font-size: 0.95rem;
	line-height: 1.3;
	cursor: pointer;
}

.gr-consent-group .gr-consent-note {
	grid-column: 2;
	margin: 0;
	font-size: 0.82rem;
	line-height: 1.5;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-consent-group.is-locked label,
.gr-consent-group.is-locked input[type="checkbox"] {
	cursor: default;
}

/* The category notes are long enough to push the buttons off a 360px screen,
   which would leave the dialog looking like it has no way out. Sticking the
   action row to the bottom of the panel's own scroll keeps Save, Accept and
   Reject reachable at every scroll position. */
.gr-consent-panel .gr-consent-actions {
	position: sticky;
	bottom: 0;
	margin-top: var(--wp--preset--spacing--40);
	padding: 0.75rem 0 var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--white);
	border-top: 1px solid rgba(58, 46, 46, 0.12);
}

.gr-consent-panel .gr-consent-btn {
	background: var(--wp--preset--color--cocoa);
	color: var(--wp--preset--color--white);
}

.gr-consent-panel .gr-consent-btn:hover {
	background: var(--wp--preset--color--coral-ink);
	color: var(--wp--preset--color--white);
}

.gr-consent-panel .gr-consent-btn.is-secondary {
	background: transparent;
	color: var(--wp--preset--color--cocoa);
	border-color: rgba(58, 46, 46, 0.45);
}

.gr-consent-panel .gr-consent-btn.is-secondary:hover {
	background: rgba(58, 46, 46, 0.06);
	color: var(--wp--preset--color--cocoa);
	border-color: var(--wp--preset--color--cocoa);
}

/* On the light panel the quiet button has to re-state itself: the panel's own
   .gr-consent-btn rule is written later at equal specificity, so without this
   Close renders as a solid cocoa pill and reads as the primary action. */
.gr-consent-panel .gr-consent-btn.is-quiet {
	background: transparent;
	border-color: transparent;
	color: var(--wp--preset--color--cocoa);
}

.gr-consent-panel .gr-consent-btn.is-quiet:hover {
	background: rgba(58, 46, 46, 0.06);
	color: var(--wp--preset--color--cocoa);
}

@media (min-width: 600px) {
	.gr-consent-modal {
		align-items: center;
		padding: var(--wp--preset--spacing--40);
	}

	.gr-consent-panel {
		max-width: 620px;
		border-radius: var(--wp--custom--radius--lg);
	}
}

/* The one place a consent-gated third-party embed shows itself: the placeholder
   that stands in for a video until marketing cookies are allowed. */
.gr-consent-placeholder {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.6rem;
	min-height: 220px;
	aspect-ratio: 16 / 9;
	padding: var(--wp--preset--spacing--40);
	text-align: center;
	border: 1px dashed rgba(58, 46, 46, 0.3);
	border-radius: var(--wp--custom--radius--base);
	background: var(--wp--preset--color--mist);
	font-size: 0.85rem;
	line-height: 1.5;
	color: var(--wp--preset--color--taupe-ink);
}

/* ---------------------------------------------------------------------------
 * 22. Guided helper (corner panel + launcher)
 *
 * Desktop only. Below 782px the launcher is hidden here and helper.js never arms
 * the timer, so a phone gets nothing at all: a 340px panel on a 360px screen is
 * not a helper, it is an interstitial.
 *
 * Non-modal by construction - no backdrop, no focus trap, page stays scrollable.
 * The questions are native <details>, so opening an answer costs no JavaScript.
 * ------------------------------------------------------------------------ */

.gr-helper-launcher {
	display: none;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--coral-ink);
	color: var(--wp--preset--color--white);
	box-shadow: 0 6px 18px rgba(58, 46, 46, 0.28);
	cursor: pointer;
	transition: background-color 0.2s ease, transform 0.2s ease;
}

.gr-helper-launcher svg {
	display: block;
	pointer-events: none;
}

@media (min-width: 782px) {
	.gr-helper-launcher {
		display: inline-flex;
	}
}

.gr-helper-launcher:hover,
.gr-helper-launcher:focus-visible {
	background: var(--wp--preset--color--cocoa);
	transform: translateY(-1px);
}

.gr-helper {
	width: min(340px, calc(100vw - 48px));
	max-height: min(70vh, 560px);
	overflow-y: auto;
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--cocoa);
	border: 1px solid rgba(58, 46, 46, 0.12);
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: 0 14px 40px rgba(58, 46, 46, 0.22);
	opacity: 0;
	transform: translateY(8px);
	transition: opacity 0.22s ease, transform 0.22s ease;
}

.gr-helper.is-open {
	opacity: 1;
	transform: none;
}

/* Never on phones, even if a stale cookie or a resize left it open. */
.gr-helper {
	display: none;
}

@media (min-width: 782px) {
	.gr-helper:not([hidden]) {
		display: block;
	}
}

.gr-helper-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	margin-bottom: 0.35rem;
}

.gr-helper-eyebrow {
	margin: 0;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: 0.68rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--coral-ink);
}

.gr-helper-close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Smaller than the 44px floor because it sits inside an already-opened panel
	   with a second exit (Escape) and is not a primary action; 32px is still
	   comfortably above the 24px minimum-target guidance. */
	width: 32px;
	height: 32px;
	margin: -4px -4px -4px 0;
	padding: 0;
	border: 0;
	border-radius: var(--wp--custom--radius--pill);
	background: transparent;
	color: var(--wp--preset--color--taupe-ink);
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.gr-helper-close:hover,
.gr-helper-close:focus-visible {
	background: rgba(58, 46, 46, 0.07);
	color: var(--wp--preset--color--cocoa);
}

.gr-helper-intro {
	margin: 0 0 0.85rem;
	font-size: 0.85rem;
	line-height: 1.5;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-helper-topics {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

.gr-helper-topic {
	border: 1px solid rgba(58, 46, 46, 0.12);
	border-radius: var(--wp--custom--radius--sm);
	background: var(--wp--preset--color--mist);
	overflow: hidden;
}

.gr-helper-topic > summary {
	display: flex;
	align-items: flex-start;
	gap: 0.5rem;
	padding: 0.6rem 0.75rem;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-size: 0.88rem;
	font-weight: 600;
	line-height: 1.35;
	cursor: pointer;
	list-style: none;
}

.gr-helper-topic > summary::-webkit-details-marker {
	display: none;
}

/* Own marker so the affordance is a shape, not a browser default that changes
   per engine. Rotates rather than swapping glyphs. */
.gr-helper-topic > summary::before {
	content: "";
	flex: 0 0 auto;
	width: 7px;
	height: 7px;
	margin-top: 0.42em;
	border-right: 2px solid var(--wp--preset--color--coral-ink);
	border-bottom: 2px solid var(--wp--preset--color--coral-ink);
	transform: rotate(-45deg);
	transition: transform 0.2s ease;
}

.gr-helper-topic[open] > summary::before {
	transform: rotate(45deg);
}

.gr-helper-topic[open] > summary {
	background: var(--wp--preset--color--white);
}

.gr-helper-answer {
	padding: 0 0.75rem 0.7rem;
	background: var(--wp--preset--color--white);
}

.gr-helper-answer p {
	margin: 0 0 0.5rem;
	font-size: 0.83rem;
	line-height: 1.55;
}

.gr-helper-answer p:last-child {
	margin-bottom: 0;
}

.gr-helper-answer .gr-link-arrow a {
	font-size: 0.83rem;
}

.gr-helper-foot {
	margin: 0.9rem 0 0;
	padding-top: 0.7rem;
	border-top: 1px solid rgba(58, 46, 46, 0.12);
	font-size: 0.8rem;
	line-height: 1.5;
	color: var(--wp--preset--color--taupe-ink);
}

.gr-helper-foot a {
	color: var(--wp--preset--color--coral-ink);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

/* ---------------------------------------------------------------------------
 * 23. Service-page SEO furniture: breadcrumb, contents, page meta, sources
 *
 * Added for the /seo/ pillar and written to be reusable by the other eleven
 * service pages without change. No new colours, radii or type: everything below
 * resolves to tokens already in theme.json, so this section adds structure and
 * nothing to the design system.
 * ------------------------------------------------------------------------ */

/* Breadcrumb. Lives inside the cocoa hero, so it inherits the hero's light-on-
   dark treatment rather than defining its own. The separator is a pseudo
   element on the <li> so it is never read out as content by a screen reader. */
.gr-crumbs {
	margin: 0 0 var(--wp--preset--spacing--50);
}

.gr-crumbs ol {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	margin: 0;
	padding: 0;
	list-style: none;
	font-family: var(--wp--preset--font-family--jetbrains-mono);
	font-size: var(--wp--preset--font-size--eyebrow);
	letter-spacing: 0.04em;
}

.gr-crumbs li {
	display: flex;
	align-items: center;
	gap: 0.5em;
	margin: 0;
}

.gr-crumbs li + li::before {
	content: "/";
	color: rgba(255, 255, 255, 0.38);
}

.gr-crumbs a {
	color: rgba(255, 255, 255, 0.72);
	text-decoration: none;
	/* 44px would push the hero's first line too far down; the trail sits in a
	   low-density corner with generous gaps, so 32 is the honest compromise
	   between AAA target size and not wrecking the hero rhythm. */
	min-height: 32px;
	display: inline-flex;
	align-items: center;
}

.gr-crumbs a:hover,
.gr-crumbs a:focus-visible {
	color: var(--wp--preset--color--white);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.gr-crumbs [aria-current="page"] {
	color: var(--wp--preset--color--amber);
}

/* "On this page". A card by style, so it needs the card's own list reset back:
   is-style-arrow already handles the markers. */
.gr-toc {
	position: sticky;
	/* 104px is the same clearance the global scroll-padding-top uses for the
	   sticky header, plus a little air. Only engages where there is room for it
	   to matter; below 782px the columns stack and sticky would trap the card. */
	top: 120px;
}

@media (max-width: 781px) {
	.gr-toc {
		position: static;
	}
}

.gr-toc .wp-block-list {
	margin-top: var(--wp--preset--spacing--40);
	margin-bottom: 0;
}

.gr-toc .wp-block-list a {
	color: var(--wp--preset--color--cocoa);
	text-decoration: none;
}

.gr-toc .wp-block-list a:hover,
.gr-toc .wp-block-list a:focus-visible {
	color: var(--wp--preset--color--coral-ink);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

/* Byline / freshness / service-area line. Reads as metadata, not body copy. */
.gr-pagemeta {
	margin-top: var(--wp--preset--spacing--50);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid rgba(58, 46, 46, 0.12);
	color: var(--wp--preset--color--taupe-ink);
	line-height: 1.7;
}

/* Attribution under a cited figure or table. */
.gr-source {
	color: var(--wp--preset--color--taupe-ink);
	line-height: 1.7;
	max-width: 68ch;
}

/* ---------------------------------------------------------------------------
 * Row-header support for .gr-compare
 *
 * The comparison table on the homepage puts its row label in a <td>, so the
 * mobile card collapse targets `tbody td:first-child`. The Core Web Vitals
 * table labels each row with <th scope="row"> instead, which is the correct
 * markup for a table whose first column names the row, and which the existing
 * rules therefore miss entirely: the th stayed table-cell while its siblings
 * went display:block. These rules give a row header the same treatment the td
 * version gets, on both layouts.
 * ------------------------------------------------------------------------ */

.wp-block-table.gr-compare tbody th[scope="row"] {
	border: 1px solid rgba(58, 46, 46, 0.12);
	padding: 0.85rem 1rem;
	text-align: left;
	vertical-align: top;
	font-family: var(--wp--preset--font-family--space-grotesk);
	font-weight: 700;
}

.wp-block-table.gr-compare .gr-cell-sub {
	display: block;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.78rem;
	font-weight: 400;
	color: var(--wp--preset--color--taupe-ink);
	letter-spacing: 0;
}

.wp-block-table.gr-compare caption.gr-table-caption {
	caption-side: bottom;
	margin-top: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.6;
	color: var(--wp--preset--color--taupe-ink);
	text-align: left;
}

@media (max-width: 781px) {
	.wp-block-table.gr-compare tbody th[scope="row"] {
		display: block;
		width: 100%;
		/* Same reason as the td rule above: width:100% plus 1rem side padding
		   overflows a content-box cell and clips the row label. */
		box-sizing: border-box;
		border: 0;
		background: var(--wp--preset--color--cocoa);
		color: var(--wp--preset--color--white);
	}

	.wp-block-table.gr-compare tbody th[scope="row"] .gr-cell-sub {
		color: rgba(255, 255, 255, 0.72);
	}

	/* caption-side is meaningless once .gr-compare's mobile rules take the table
	   out of display:table, and a table-caption inside a block box shrink-wraps
	   to its longest word: the caption rendered as a ten-character column. Make
	   it a plain block and it fills the width like any other paragraph. Moved
	   above the cards too, because at this width it is read as an intro rather
	   than a footnote. */
	.wp-block-table.gr-compare caption.gr-table-caption {
		display: block;
		width: 100%;
		caption-side: top;
		margin: 0 0 var(--wp--preset--spacing--40);
	}
}
