/**
 * SimpleSites structural CSS.
 *
 * Consumes design tokens (CSS custom properties emitted in <head>) only —
 * no raw color/size values. Skins layer flourish in skin.css; sections own
 * their internals in sections/{key}/style.css. Vertical rhythm between
 * sections belongs to the framework classes here, never to sections.
 */

/* ==========================================================================
   Reset-lite
   ========================================================================== */

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

body {
	margin: 0;
	background: var(--ss-c-surface);
	color: var(--ss-c-text);
	font-family: var(--ss-t-body-ff);
	font-weight: var(--ss-t-body-w);
	font-size: var(--ss-t-body-sz);
	line-height: var(--ss-t-body-lh);
	letter-spacing: var(--ss-t-body-ls, normal);
	-webkit-font-smoothing: antialiased;
}

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

h1,
h2,
h3,
h4,
p,
ul,
ol,
figure {
	margin: 0 0 var(--ss-rhythm);
}

h1:last-child,
h2:last-child,
h3:last-child,
p:last-child {
	margin-bottom: 0;
}

a {
	color: var(--ss-c-link);
	text-decoration: none;
}

a:hover {
	color: var(--ss-c-link-hover);
}

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

:focus-visible {
	outline: 2px solid var(--ss-c-primary);
	outline-offset: 2px;
}

/* ==========================================================================
   Type roles
   ========================================================================== */

h1 {
	font-family: var(--ss-t-h1-ff);
	font-weight: var(--ss-t-h1-w);
	font-size: var(--ss-t-h1-sz);
	line-height: var(--ss-t-h1-lh);
	letter-spacing: var(--ss-t-h1-ls, normal);
	text-transform: var(--ss-t-h1-tt, none);
}

h2 {
	font-family: var(--ss-t-h2-ff);
	font-weight: var(--ss-t-h2-w);
	font-size: var(--ss-t-h2-sz);
	line-height: var(--ss-t-h2-lh);
	letter-spacing: var(--ss-t-h2-ls, normal);
	text-transform: var(--ss-t-h2-tt, none);
}

h3,
h4 {
	font-family: var(--ss-t-h3-ff);
	font-weight: var(--ss-t-h3-w);
	font-size: var(--ss-t-h3-sz);
	line-height: var(--ss-t-h3-lh);
	letter-spacing: var(--ss-t-h3-ls, normal);
	text-transform: var(--ss-t-h3-tt, none);
}

/* Headline highlight — the *word* convention in section headline fields
   (ss_headline()). Token-driven so one skin swaps the whole treatment:
   no `highlight` color means the words render as ordinary headline text.
   box-decoration-break:clone gives every wrapped line its own marker.
   The marker sits one layer BELOW the headline's own text (z-index -1
   inside an isolated parent): at tight display line-heights its box is
   taller than the line, and painted in normal order it would cover the
   bottom of the line above. Isolation keeps it above the section fill. */
.ss-highlight {
	position: relative;
	z-index: -1;
	background: var(--ss-c-highlight, transparent);
	color: var(--ss-c-highlight-tx, inherit);
	border-radius: var(--ss-r-highlight);
	padding: var(--ss-highlight-pad);
	-webkit-box-decoration-break: clone;
	box-decoration-break: clone;
}

:where(h1, h2, h3, h4, h5, h6, p, div, span):has(> .ss-highlight) {
	isolation: isolate;
}

.ss-subtitle {
	font-family: var(--ss-t-subtitle-ff);
	font-weight: var(--ss-t-subtitle-w);
	font-size: var(--ss-t-subtitle-sz);
	line-height: var(--ss-t-subtitle-lh);
	color: var(--ss-c-text-muted);
}

.ss-eyebrow {
	display: block;
	font-family: var(--ss-t-eyebrow-ff);
	font-weight: var(--ss-t-eyebrow-w);
	font-size: var(--ss-t-eyebrow-sz);
	line-height: var(--ss-t-eyebrow-lh);
	letter-spacing: var(--ss-t-eyebrow-ls);
	text-transform: var(--ss-t-eyebrow-tt, none);
	color: var(--ss-t-eyebrow-c, var(--ss-c-primary));
	margin-bottom: calc(var(--ss-rhythm) / 2);
}

.ss-body-sm {
	font-size: var(--ss-t-body-sm-sz);
	line-height: var(--ss-t-body-sm-lh);
	color: var(--ss-t-body-sm-c, var(--ss-c-text-muted));
}

/* ==========================================================================
   Layout: container, section rhythm, bands, grids
   ========================================================================== */

.ss-container {
	width: var(--ss-container-w);
	margin-inline: auto;
}

/* Sections own no outer spacing; the framework applies the inset tier.
   Backgrounds are internal padding, so adjacent bands butt seamlessly. */
.ss-section {
	padding-block: var(--ss-inset-std);
}

.ss-inset-roomy {
	padding-block: var(--ss-inset-roomy);
}

.ss-inset-hero {
	padding-block: var(--ss-inset-hero);
}

.ss-inset-tight {
	padding-block: calc(var(--ss-rhythm) * 2);
}

.ss-inset-none {
	padding-block: 0;
}

.ss-bg-surface {
	background: var(--ss-c-surface);
}

.ss-bg-surface-alt {
	background: var(--ss-c-surface-alt);
}

.ss-bg-primary {
	background: var(--ss-c-primary);
	color: var(--ss-c-primary-tx);
}

.ss-bg-primary h1,
.ss-bg-primary h2,
.ss-bg-primary h3,
.ss-bg-primary .ss-subtitle,
.ss-bg-primary .ss-eyebrow {
	color: inherit;
}

/* Muted copy on a coloured band is the band ink held back, not the page's
   grey — text-muted is tuned against surface and goes illegible on a dark
   band (and muddy on a bright one). */
.ss-bg-primary .ss-body-sm,
.ss-bg-primary p {
	color: inherit;
	opacity: 0.82;
}

.ss-bg-secondary {
	background: var(--ss-c-secondary);
	color: var(--ss-c-secondary-tx);
}

.ss-bg-secondary h1,
.ss-bg-secondary h2,
.ss-bg-secondary h3,
.ss-bg-secondary .ss-subtitle,
.ss-bg-secondary .ss-eyebrow {
	color: inherit;
}

/* Muted copy on a coloured band is the band ink held back, not the page's
   grey — text-muted is tuned against surface and goes illegible on a dark
   band (and muddy on a bright one). */
.ss-bg-secondary .ss-body-sm,
.ss-bg-secondary p {
	color: inherit;
	opacity: 0.82;
}

/* ...but an action row is a <p> too. The muting above was fading the band's
   own button along with the copy — the CTA's Contact Us washed out to 82%
   on every skin that composes a CTA on a brand band. Additive so the rule
   above still applies in engines without :has(). */
.ss-bg-primary p:has(.ss-btn),
.ss-bg-secondary p:has(.ss-btn) {
	opacity: 1;
}

/* A fourth band colour. `surface-alt` is the skin's one alternate ground,
   which is not enough for a palette that wants BOTH a tinted band and a
   plain neutral one (a cream alt plus a light grey, say). `muted` is that
   second neutral. The composition axis never validated its value — it
   sanitize_key()s whatever is written and emits `ss-bg-{value}` — so this
   is the rule and the token catching up with what the axis already did. */
.ss-bg-muted {
	background: var(--ss-c-muted);
	color: var(--ss-c-muted-tx);
}

.ss-bg-muted h1,
.ss-bg-muted h2,
.ss-bg-muted h3,
.ss-bg-muted .ss-subtitle,
.ss-bg-muted .ss-eyebrow {
	color: inherit;
}

.ss-bg-muted .ss-body-sm,
.ss-bg-muted p {
	color: inherit;
	opacity: 0.82;
}

.ss-bg-muted p:has(.ss-btn) {
	opacity: 1;
}

/* Brand-inked chrome on a brand band. Icons, process step numbers and ghost
   buttons are all drawn in --ss-c-primary — which, on a primary band, is
   exactly the colour they are sitting on. They follow the band ink instead.
   Specificity is deliberately .ss-section-qualified: the owning section
   stylesheets load AFTER base.css and their .ss-process .ss-process-number
   would otherwise win the tie. */
.ss-section.ss-bg-primary .ss-icon,
.ss-section.ss-bg-secondary .ss-icon,
.ss-section.ss-bg-muted .ss-icon,
.ss-section.ss-bg-primary .ss-process-number,
.ss-section.ss-bg-secondary .ss-process-number,
.ss-section.ss-bg-muted .ss-process-number,
.ss-section.ss-bg-primary .ss-btn-ghost,
.ss-section.ss-bg-secondary .ss-btn-ghost {
	color: inherit;
	border-color: currentColor;
}

/* Banded (non-surface) sections use the band inner padding. */
.ss-banded {
	padding-block: var(--ss-band-pad);
}

/* Two adjacent sections sharing a band keep their FULL padding — reduced
   merge padding pushed the second section's heading too close to the
   first section's content (client feedback, twice). The class remains on
   the markup for skins that want a tighter look. */
.ss-band-merge {
	padding-top: var(--ss-band-pad);
}

/* ---- Seams: one inset per gap, never two -------------------------------
   Every section owns its own padding-block, so where two PLAIN sections
   meet the page stacks both of them — 150-240px of white depending on the
   skin, which reads as doubled space (GUIDELINES General: "watch for
   doubled white space where section paddings meet"). The upper section
   gives its bottom padding up and the incoming section keeps its own top
   padding, so each gap is sized by the section it OPENS: `roomy` breathes,
   `tight` closes up deliberately.

   Three exclusions, all learned the hard way. A band is exempt on both
   sides — its padding sits inside the colour and contributes no white. So
   is a photo-band hero, whose padding sits inside the image: without that
   second exclusion every CPT hero's copy is crushed against the bottom of
   its own photo. And so is a SPLIT hero, for the same reason from the
   other direction: its image is stretched to the row, so the section's
   bottom padding IS the space under the photo. Collapsing it left the
   photo cut off hard against the next section and broke the GUIDELINES
   rule that a split hero's padding is always symmetric above and below
   the image — a rule skins are explicitly forbidden to patch one side of,
   so the default has to hold it. Covers both split rows: the hero
   section variant (`.ss-hero--split` on the section) and the interior
   heroes (`.ss-hero-split` on the row inside the container).

   A FILL block is exempt for the same reason a band is, one step in: it
   is an inset BOX — base.css already gives it its own inline padding and
   a radius — so its padding-block is the box's inner padding, not seam
   white. Collapsing it sat the block's last row of cards flat on its own
   bottom edge. (Every fill block until Academy's callout panel carried a
   non-surface background and so was `.ss-banded`, which the first
   exclusion already covered; a fill block on `surface` is what exposed
   this.)

   The seam has one more case, and it is handled on the far side of this
   rule rather than inside it (see the photo-CTA rule below): a CTA
   carrying a background photo is a full-bleed band in every way that
   matters, but it is not `.ss-banded`, so the section above collapsed
   into it. It cannot be excluded here — `:has()` may not contain another
   `:has()`, and writing one drops this entire selector at parse time,
   silently restoring every doubled gap on the site.

   That is about the CTA as the FOLLOWING sibling. The CTA as the SUBJECT of
   this rule is a separate bug, and it IS excluded here — the
   `:not(:has(> .ss-cta-bg))` clause added above. A photo CTA's padding sits
   inside its image exactly like a band hero's, but it is not `.ss-banded` and
   its background element is `.ss-cta-bg`, not `.ss-hero-band-bg`, so it
   matched every exclusion and gave up its OWN bottom padding whenever a plain
   section followed it — which on a case-study or product single is ALWAYS,
   because the flow is CTA then See More. The button ended up flush on the
   bottom edge of the photograph. Excluding the subject does not remove the
   need for the margin rule below: that one still fires, because a photo CTA is
   not `.ss-banded` and so still fails this rule's following-sibling test. */
.ss-section:not(.ss-banded):not(:has(> .ss-hero-band-bg)):not(:has(> .ss-cta-bg)):not(.ss-hero--split):not(:has(> .ss-container > .ss-hero-split)):not(.ss-width-fill):has(+ .ss-section:not(.ss-banded)) {
	padding-bottom: 0;
}

/* The FAQ list ends on a hairline, so it is the one section that still
   needs clearance under it — a collapsed seam puts that rule hard against
   the next section. It carries the SAME exclusion list as the collapse
   rule above, not a shorter one: this is an override that wins on source
   order, and it only wins while the two selectors weigh the same. Drop a
   clause and the rule above out-specifies it, silently, and the FAQ
   hairline goes back to touching the next section. Any future exclusion
   added above gets added here too. */
.ss-section.ss-faqs:not(.ss-banded):not(:has(> .ss-hero-band-bg)):not(:has(> .ss-cta-bg)):not(.ss-hero--split):not(:has(> .ss-container > .ss-hero-split)):not(.ss-width-fill):has(+ .ss-section:not(.ss-banded)) {
	padding-bottom: calc(var(--ss-rhythm) * 1.5);
}

/* ...and the photo CTA gets that clearance back as a MARGIN. A CTA with a
   background image is a full-bleed photo band whose padding sits inside
   the image — the same shape as a photo hero — so the plain section above
   it must not collapse into it, or its last card sits flush on the top
   edge of the photo. GUIDELINES has CTA bands ALWAYS carrying a
   background image, so this fired on every skin's home page. It is a
   margin on the CTA rather than an exclusion in the rule above because
   `:has()` cannot be nested; the preceding-sibling test repeats that
   rule's own exclusion list so the space is added ONLY where the collapse
   actually happened.

   `:not(.ss-banded)` on the CTA itself is part of that "only where it
   happened", and was missing. The collapse above fires only when the NEXT
   section is not banded; a CTA composed on a colour band therefore never
   causes one — the section above keeps its full bottom padding. Adding the
   margin anyway stacked 100px of white on 100px of white and put 200px above
   every banded CTA carrying a photo. GUIDELINES has CTA bands always carrying
   a background image, so this fired on every page whose CTA was composed with
   a background — measured on academy's About and case-study flows, where the
   client reported it as doubled spacing above the CTA. */
.ss-section:not(.ss-banded):not(:has(> .ss-hero-band-bg)):not(:has(> .ss-cta-bg)):not(.ss-hero--split):not(:has(> .ss-container > .ss-hero-split)):not(.ss-width-fill) + .ss-section:not(.ss-banded):has(> .ss-cta-bg) {
	margin-top: var(--ss-inset-std);
}

/* A fill block is inset on all four sides, so it needs real space around
   it. Against a plain section the neighbour's padding supplies that;
   against a full-bleed band there is no padding-white at all and the two
   blocks would touch. */
.ss-section.ss-width-fill:has(+ .ss-section.ss-banded:not(.ss-width-fill)) {
	margin-bottom: var(--ss-inset-std);
}

.ss-section.ss-banded:not(.ss-width-fill) + .ss-section.ss-width-fill {
	margin-top: var(--ss-inset-std);
}

/* Grid + two-column primitives */
.ss-grid {
	display: grid;
	gap: var(--ss-gap);
}

.ss-2col {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--ss-col-gap);
	align-items: center;
}

.ss-media-right .ss-2col .ss-col-media {
	order: 2;
}

@media (max-width: 767px) {
	.ss-container {
		width: 100%;
		padding-inline: var(--ss-side-pad);
	}

	.ss-2col {
		grid-template-columns: 1fr;
		gap: calc(var(--ss-rhythm) * 1.5);
	}

	.ss-media-right .ss-2col .ss-col-media {
		order: 0;
	}
}

/* ==========================================================================
   Buttons & forms
   ========================================================================== */

/* The core button's border follows `button-bg` unless a skin names it
   outright with the optional `button-border` colour slot. A ghost-button
   skin sets `button-bg: transparent` — which used to take the border with
   it, since one token drew both — and `button-border` to the ink. Skins
   that stay silent are unchanged. */
.ss-btn {
	display: inline-block;
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
	color: var(--ss-c-button-text);
	background: var(--ss-c-button-bg);
	padding: var(--ss-btn-pad);
	border: 1px solid var(--ss-c-button-border, var(--ss-c-button-bg));
	border-radius: var(--ss-r-btn);
	cursor: pointer;
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

/* The hover ink is the luminance-derived `button-hover-tx` the ghost button
   already used — NOT `button-text`. They are the same colour for every skin
   whose button is a dark fill with white type, but a skin whose button ink
   is dark (a ghost button, or a bright pill) painted dark type on its own
   dark hover fill. One contract, both button roles. */
.ss-btn:hover {
	background: var(--ss-c-button-hover-bg);
	border-color: var(--ss-c-button-hover-bg);
	color: var(--ss-c-button-hover-tx);
}

/* Secondary: transparent, BRAND text + thin brand border (GUIDELINES
   "Buttons"). Brand is the primary color — most skins put the same value
   in button-bg, but a skin whose button is an accent (a yellow pill on a
   forest brand) needs the border to follow the brand, not the pill. */
.ss-btn-ghost {
	background: transparent;
	border-color: var(--ss-c-primary);
	color: var(--ss-c-primary);
}

.ss-btn-ghost:hover {
	background: var(--ss-c-button-hover-bg);
	border-color: var(--ss-c-button-hover-bg);
	color: var(--ss-c-button-hover-tx);
}

input[type="text"],
input[type="email"],
input[type="url"],
input[type="tel"],
textarea,
select {
	font: inherit;
	width: 100%;
	padding: 12px 16px;
	border: 1px solid var(--ss-c-border);
	border-radius: var(--ss-r-field);
	/* `--ss-field-bg` exists so a skin that repaints its fields (a
	   transparent underline field, or one tinted to sit on a band) can say
	   so in ONE place that both this rule and the autofill override below
	   read. Unset by every existing skin, so they resolve to `surface`
	   exactly as before. */
	background: var(--ss-field-bg, var(--ss-c-surface));
	color: var(--ss-c-text);
}

/* Forms framework (SS_Forms shared renderer) */

.ss-form-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--ss-gap);
}

.ss-form-field {
	grid-column: span 2;
	margin: 0;
}

.ss-form-field-half {
	grid-column: span 1;
}

.ss-form-label {
	display: block;
	margin-bottom: 6px;
	font-family: var(--ss-t-eyebrow-ff);
	font-size: var(--ss-t-eyebrow-sz);
	font-weight: var(--ss-t-eyebrow-w);
	letter-spacing: var(--ss-t-eyebrow-ls);
	text-transform: var(--ss-t-eyebrow-tt, none);
}

.ss-form-required {
	color: var(--ss-c-primary);
}

.ss-form-hp {
	position: absolute !important;
	left: -9999px !important;
	margin: 0;
}

.ss-form-actions {
	margin: var(--ss-rhythm) 0 0;
}

.ss-form-notice {
	padding: 14px 18px;
	border-radius: var(--ss-r-field);
	margin-bottom: var(--ss-rhythm);
	font-weight: 500;
}

.ss-form-notice-ok {
	background: var(--ss-c-surface-alt);
	border: 1px solid var(--ss-c-border);
}

.ss-form-notice-error {
	background: var(--ss-c-surface-alt);
	border: 1px solid var(--ss-c-primary);
	color: var(--ss-c-primary);
}

@media (max-width: 767px) {
	.ss-form-field-half {
		grid-column: span 2;
	}
}

/* ==========================================================================
   Cards (base cards: flat, image-led — separation via whitespace)
   ========================================================================== */

.ss-card-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--ss-gap);
}

.ss-card {
	border-radius: var(--ss-r-card);
	box-shadow: var(--ss-card-shadow);
}

.ss-card-link {
	display: block;
	color: inherit;
}

.ss-card-link:hover {
	color: inherit;
}

.ss-card-media img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--ss-r-card);
}

.ss-card-body {
	padding-top: var(--ss-rhythm);
}

.ss-card-title {
	margin-bottom: calc(var(--ss-rhythm) / 3);
}

.ss-card-excerpt {
	margin-bottom: calc(var(--ss-rhythm) / 2);
}

.ss-card-more {
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
	color: var(--ss-c-link);
}

.ss-card-link:hover .ss-card-more {
	color: var(--ss-c-link-hover);
}

.ss-pagination {
	margin-top: calc(var(--ss-rhythm) * 2);
	text-align: center;
}

.ss-pagination .page-numbers {
	display: inline-block;
	padding: 8px 14px;
	margin: 0 2px;
	color: var(--ss-c-text);
}

.ss-pagination .page-numbers.current {
	background: var(--ss-c-primary);
	color: var(--ss-c-primary-tx);
}

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

@media (max-width: 767px) {
	.ss-card-grid {
		grid-template-columns: 1fr;
		gap: calc(var(--ss-gap) * 1.5);
	}
}

/* Carousel presentation of any card listing (every "carousel*" layout —
   the section carries ss-has-carousel): a scroll-snap row showing ~3
   cards, with arrow controls injected by theme.js when the row overflows.
   Side-content variants (carousel-left/right) narrow to 2 visible cards
   on desktop further down. */
.ss-has-carousel .ss-card-grid {
	display: grid;
	grid-template-columns: none; /* the base grid's explicit tracks would fight the column flow */
	grid-auto-flow: column;
	grid-auto-columns: calc( ( 100% - 2 * var(--ss-gap) ) / 3 );
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-bottom: 4px;
}

.ss-has-carousel .ss-card-grid::-webkit-scrollbar {
	display: none;
}

.ss-has-carousel .ss-card {
	scroll-snap-align: start;
}

.ss-carousel-nav {
	display: flex;
	justify-content: flex-end;
	gap: 8px;
	margin-top: var(--ss-rhythm);
}

.ss-carousel-btn {
	width: 44px;
	height: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--ss-c-border);
	border-radius: var(--ss-r-btn);
	background: var(--ss-c-surface);
	color: var(--ss-c-primary);
	font-size: 18px;
	cursor: pointer;
	transition: border-color 0.2s ease, color 0.2s ease;
}

.ss-carousel-btn:hover {
	border-color: var(--ss-c-primary);
}

.ss-carousel-btn:disabled {
	opacity: 0.35;
	cursor: default;
}

@media (max-width: 1024px) {
	.ss-has-carousel .ss-card-grid {
		grid-auto-columns: calc( ( 100% - var(--ss-gap) ) / 2 );
	}
}

@media (max-width: 767px) {
	.ss-has-carousel .ss-card-grid {
		grid-auto-columns: 100%;
	}
}

/* ==========================================================================
   Full-band background image (interior heroes) + dark scrim; a real <img>
   so srcset picks per-viewport files
   ========================================================================== */

.ss-hero-band-bg {
	position: absolute;
	inset: 0;
}

.ss-hero-band-bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* GUIDELINES sets this band at a 70% black overlay, and that stays the
   default — but it was a literal, and a skin whose hero photography is light
   or whose on-image type is fine needs to lean on it harder. One of the three
   hard-coded values base.css was carrying (see 0.28.0). Unset everywhere, so
   every existing skin renders identically. */
.ss-hero-band-bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--ss-hero-scrim, rgba(0, 0, 0, 0.7));
}

/* Copy sitting on a 70% scrim is white whatever band colour is underneath —
   headings included, or a band-colour rule like `.ss-bg-primary h2` wins
   over the inherited white and paints the heading into the photo. */
.ss-on-image,
.ss-on-image h1,
.ss-on-image h2,
.ss-on-image h3,
.ss-on-image .ss-subtitle {
	color: #fff;
	position: relative;
}

/* ==========================================================================
   Icons — bundled stroke SVGs inherit currentColor; skins set size,
   color, and stroke weight in CSS
   ========================================================================== */

.ss-icon {
	width: 44px;
	height: 44px;
	color: var(--ss-c-primary);
	stroke-width: 1.75;
}

img.ss-icon-custom {
	object-fit: contain;
}

/* ==========================================================================
   Image accent (skin signature move; value comes from tokens)
   ========================================================================== */

.ss-img-accent {
	box-shadow: var(--ss-accent-shadow);
}

/* ==========================================================================
   Header
   ========================================================================== */

.ss-header {
	background: var(--ss-header-bg);
}

.ss-header-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--ss-gap);
	min-height: var(--ss-header-h);
}

.ss-header-brand img {
	max-height: calc(var(--ss-header-h) - 24px);
	width: auto;
}

.ss-header-logo {
	display: inline-flex;
	align-items: center;
}

.ss-header-title {
	font-family: var(--ss-t-h3-ff);
	font-size: var(--ss-t-h3-sz);
	font-weight: var(--ss-t-h3-w);
	color: var(--ss-c-text);
}

/* Generic brand lockup — markup, not an image, so it inherits each
   context's ink (header title, footer brand ink, contact panel). The mark
   takes the brand colour on normal ground; a skin that wants something
   else retokens --ss-logo-mark-c. */
.ss-logo-lockup {
	display: inline-flex;
	align-items: center;
	gap: 10px;
}

.ss-logo-lockup .ss-logo-mark {
	display: inline-flex;
	color: var(--ss-logo-mark-c, var(--ss-c-primary));
}

.ss-logo-lockup .ss-logo-mark svg {
	width: 30px;
	height: 30px;
}

.ss-header-nav {
	display: flex;
	align-items: center;
	gap: calc(var(--ss-gap) * 1.75);
}

.ss-nav-menu {
	display: flex;
	align-items: center;
	/* A menu that cannot fit must WRAP, never overflow. A flex row defaults
	   to nowrap, so a long menu widened the whole DOCUMENT instead — and a
	   document wider than the viewport makes every full-bleed band render
	   narrower than the page (that is what "the footer is off" was). Two
	   lines is an ugly header; a broken page layout is worse. */
	flex-wrap: wrap;
	gap: calc(var(--ss-gap) * 1.75);
	list-style: none;
	margin: 0;
	padding: 0;
}

.ss-nav-menu a {
	font-family: var(--ss-t-nav-header-ff);
	font-size: var(--ss-t-nav-header-sz);
	font-weight: var(--ss-t-nav-header-w, 400);
	color: var(--ss-c-text);
}

/* The page you are on, and the one under the cursor, both take the brand
   colour and a 2px rule. The rule is not decoration: on skins whose brand
   colour IS a dark neutral (startup-3's #123333 is the body-text colour
   exactly, leroux and advitex are within a shade of it) a colour-only
   state is invisible, so the state has to carry a non-colour signal too.

   It is a pseudo-element rather than `text-decoration` because that
   cannot be animated — the rule wipes in from the left while the colour
   crossfades. The link's own padding sets both the breathing room either
   side and the distance from the text down to the rule. */
.ss-nav-menu a {
	position: relative;
	display: inline-block;
	padding: 6px 10px 10px;
	transition: color 0.3s ease;
}

.ss-nav-menu a::after {
	content: "";
	position: absolute;
	left: 10px;
	right: 10px;
	bottom: 0;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.3s ease;
}

/* The hover colour is `button-hover-bg` — the one colour every skin
   already nominates as "what an interactive thing turns into", so the nav
   matches its own buttons instead of introducing a second accent. It is
   distinct from body text on every skin but modern-startup, where the two
   are the same value and the skin overrides this to its brand indigo. */
/* NOT `current_page_parent`. WordPress puts that class on the POSTS PAGE
   item for any view that is not a page — every CPT archive, every CPT
   single, every blog single — so including it lit "Blog" up across the
   whole site. The four kept here all mean "this item, or something under
   it, is the page you are on". */
/* Scoped through `.ss-header-nav` purely for specificity. Most skins set
   `.ss-skin-x .ss-nav-menu a { color }`, which ties with a plain
   `.ss-nav-menu .current-menu-item > a` and wins on load order — so the
   state silently rendered as the resting colour on Executive, Launch and
   others. Three classes beats their two without reaching for !important. */
.ss-header-nav .ss-nav-menu a:hover,
.ss-header-nav .ss-nav-menu .current-menu-item > a,
.ss-header-nav .ss-nav-menu .current_page_item > a,
.ss-header-nav .ss-nav-menu .current-menu-ancestor > a,
.ss-header-nav .ss-nav-menu .current-menu-parent > a {
	color: var(--ss-c-button-hover-bg);
}

.ss-nav-menu a:hover::after,
.ss-nav-menu .current-menu-item > a::after,
.ss-nav-menu .current_page_item > a::after,
.ss-nav-menu .current-menu-ancestor > a::after,
.ss-nav-menu .current-menu-parent > a::after {
	transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
	.ss-nav-menu a,
	.ss-nav-menu a::after {
		transition: none;
	}
}

/* ---- Submenus (framework standard, every skin) ---------------------------
   A parent item carries a small chevron directly right of its text (on
   the LI, because the link's own ::after is the active underline).
   Desktop: hover/focus drops a light panel. Drawer: first tap opens the
   sub-list, a second tap on the parent follows its link (theme.js). */

.ss-nav-menu li {
	position: relative;
}

/* The chevron is a real element INSIDE the link, directly after the
   text (functions.php appends .ss-nav-caret via nav_menu_item_title) —
   so a skin whose link fills a whole nav cell highlights chevron and
   all, and the icon always hugs the label. currentColor keeps it in
   step with every link state. */
.ss-nav-caret {
	display: inline-block;
	width: 6px;
	height: 6px;
	margin-left: 7px;
	vertical-align: 2px;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform 0.2s ease;
	pointer-events: none;
}

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

.ss-nav-menu .sub-menu a::after {
	display: none; /* no wipe-rule inside the panel */
}

@media (min-width: 1025px) {
	.ss-nav-menu .sub-menu {
		position: absolute;
		top: 100%;
		left: 0;
		z-index: 300;
		min-width: 230px;
		display: grid;
		gap: 2px;
		padding: 8px;
		background: var(--ss-c-surface);
		border: 1px solid var(--ss-c-border);
		border-radius: 10px;
		box-shadow: 0 14px 34px rgba(15, 20, 25, 0.12);
		opacity: 0;
		visibility: hidden;
		transform: translateY(6px);
		transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
	}

	.ss-nav-menu li:hover > .sub-menu,
	.ss-nav-menu li:focus-within > .sub-menu {
		opacity: 1;
		visibility: visible;
		transform: translateY(0);
	}

	.ss-nav-menu li:hover > a .ss-nav-caret {
		transform: rotate(225deg);
	}

	.ss-nav-menu .sub-menu a {
		display: block;
		padding: 8px 12px;
		border-radius: 6px;
	}

	.ss-nav-menu .sub-menu a:hover {
		background: var(--ss-c-surface-alt);
	}
}

@media (max-width: 1024px) {
	.ss-nav-menu li.menu-item-has-children {
		flex-wrap: wrap;
	}

	.ss-nav-menu .sub-menu {
		display: none;
		width: 100%;
	}

	/* The open drawer submenu is an INDENT, not a panel (client, all skins).
	   It used to paint a surface-alt card with a radius behind the child
	   items, which reads as a floating box dropped into a flat list — and on
	   a skin whose drawer ground already IS surface-alt it read as nothing
	   at all, just an unexplained gap. The desktop hover panel at ≥1025
	   keeps its background, border and shadow: there the panel is doing real
	   work, separating an overlay from the page under it. In the drawer
	   there is nothing to separate from, so the hierarchy is carried by
	   indentation alone. */
	.ss-nav-menu li.ss-sub-open > .sub-menu {
		display: block;
		margin-top: 2px;
		padding: 2px 0 2px 16px;
	}

	.ss-nav-menu li.ss-sub-open > a .ss-nav-caret {
		transform: rotate(225deg);
	}

	.ss-nav-menu .sub-menu a {
		display: block;
		padding: 8px 10px;
	}
}

.ss-nav-toggle {
	display: none;
	background: none;
	border: 0;
	padding: 10px;
	cursor: pointer;
}

.ss-nav-toggle-bar {
	display: block;
	width: 22px;
	height: 2px;
	background: var(--ss-c-text);
	margin: 5px 0;
	transition: transform 0.2s ease, opacity 0.2s ease;
}

@media (max-width: 1024px) {
	.ss-nav-toggle {
		display: block;
	}

	.ss-header-nav {
		display: none;
		position: absolute;
		top: var(--ss-header-h);
		left: 0;
		right: 0;
		z-index: 40;
		flex-direction: column;
		align-items: flex-start;
		background: var(--ss-c-surface);
		border-bottom: 1px solid var(--ss-c-border);
		padding: var(--ss-side-pad);
	}

	.ss-header {
		position: relative;
	}

	body.ss-nav-open .ss-header-nav {
		display: flex;
	}

	.ss-nav-menu {
		flex-direction: column;
		align-items: flex-start;
	}

	/* In the drawer the items are stacked, so the horizontal treatment
	   works against them: the animated rule reads as a divider between
	   rows rather than an indicator, and the link padding plus a full
	   rhythm gap makes the list needlessly tall. Colour alone carries the
	   state here — there is no hover on touch to disambiguate it from.

	   Scoped through `.ss-header .ss-header-nav` for specificity: several
	   skins set `.ss-skin-x .ss-nav-menu { gap }` unscoped for the
	   horizontal bar, and a media query adds none, so a two-class rule
	   here would lose on load order and the skin's desktop gap would leak
	   into the drawer. */
	.ss-header .ss-header-nav .ss-nav-menu {
		gap: 2px;
	}

	.ss-header .ss-header-nav .ss-nav-menu a {
		padding: 8px 0;
	}

	.ss-header .ss-header-nav .ss-nav-menu a::after {
		content: none;
	}
}

/* ==========================================================================
   Footer
   ========================================================================== */

/* Default footer palette (client standard, every skin): the light
   surface-alt ground with ALL text — linked or not — in the brand ink;
   links warm to the button hover color. Skins restyle structure freely
   but do not fight this palette. */
.ss-footer {
	border-top: 1px solid var(--ss-c-border);
	background: var(--ss-c-surface-alt);
	color: var(--ss-c-footer-ink);
}

.ss-footer-title {
	font-family: var(--ss-t-h3-ff);
	font-weight: var(--ss-t-h3-w);
	color: var(--ss-c-footer-ink);
}

.ss-footer-menu {
	display: flex;
	gap: var(--ss-gap);
	list-style: none;
	margin: 0;
	padding: 0;
}

.ss-footer-menu a {
	font-family: var(--ss-t-nav-footer-ff);
	font-size: var(--ss-t-nav-footer-sz);
	color: var(--ss-c-footer-ink);
}

.ss-footer-fine {
	margin-top: var(--ss-rhythm);
	font-family: var(--ss-t-footer-fine-ff);
	font-size: var(--ss-t-footer-fine-sz);
	text-transform: var(--ss-t-footer-fine-tt, none);
	color: var(--ss-c-footer-ink);
}

/* Logos in the footer and the contact page's info column render at
   their largest within a 250×250 box, never cropped or distorted:
   width leads, height caps, contain letterboxes the remainder. */
.ss-footer .ss-footer-logo img,
.ss-contact-logo img {
	width: 250px;
	height: auto;
	max-height: 250px;
	object-fit: contain;
	object-position: left center;
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.ss-skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--ss-c-surface);
	color: var(--ss-c-text);
	padding: 12px 20px;
}

.ss-skip-link:focus {
	left: 0;
}

.ss-prose {
	max-width: 760px;
}

.ss-login-card {
	max-width: 420px;
	margin-inline: auto;
	text-align: center;
}

.ss-login-card .ss-login-title {
	margin-bottom: calc(var(--ss-rhythm) / 2);
}

.ss-login-card form {
	text-align: left;
	margin-top: calc(var(--ss-rhythm) * 1.5);
}

.ss-login-card form p {
	margin-bottom: var(--ss-rhythm);
}

.ss-login-card form label {
	display: block;
	margin-bottom: 6px;
	font-family: var(--ss-t-eyebrow-ff);
	font-size: var(--ss-t-eyebrow-sz);
	font-weight: var(--ss-t-eyebrow-w);
	letter-spacing: var(--ss-t-eyebrow-ls);
	text-transform: var(--ss-t-eyebrow-tt, none);
}

.ss-login-card input[type="password"] {
	font: inherit;
	width: 100%;
	padding: 12px 16px;
	border: 1px solid var(--ss-c-border);
	border-radius: var(--ss-r-field);
	background: var(--ss-c-surface);
	color: var(--ss-c-text);
}

.ss-login-card .login-remember label {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: inherit;
	font-size: var(--ss-t-body-sm-sz);
	text-transform: none;
	letter-spacing: normal;
}

.ss-login-card .button-primary {
	display: inline-block;
	width: 100%;
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
	color: var(--ss-c-button-text);
	background: var(--ss-c-button-bg);
	padding: var(--ss-btn-pad);
	border: 1px solid var(--ss-c-button-border, var(--ss-c-button-bg));
	border-radius: var(--ss-r-btn);
	cursor: pointer;
}

.ss-login-card .button-primary:hover {
	background: var(--ss-c-button-hover-bg);
	border-color: var(--ss-c-button-hover-bg);
}

.ss-center {
	text-align: center;
}

/* Split section intro: heading left, supporting text + link right. */
.ss-intro-split {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--ss-col-gap);
	align-items: end;
	margin-bottom: calc(var(--ss-rhythm) * 2);
}

.ss-intro-aside .ss-subtitle {
	margin-bottom: calc(var(--ss-rhythm) / 2);
}

.ss-intro-link {
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
}

@media (max-width: 767px) {
	.ss-intro-split {
		grid-template-columns: 1fr;
		gap: var(--ss-rhythm);
		align-items: start;
	}
}

/* ==========================================================================
   GUIDELINES v1 primitives (see GUIDELINES.md)
   ========================================================================== */

/* ---- Width axis: fill = the band itself spans 90% with inner padding --- */

.ss-width-fill {
	width: 90%;
	margin-inline: auto;
	padding-inline: clamp(40px, 6vw, 100px);
	border-radius: var(--ss-r-card, 0);
}

.ss-width-fill .ss-container {
	width: 100%;
}

/* ---- Buttons: core + secondary share one box; text button is bare ----- */

.ss-btn {
	border: 1px solid var(--ss-c-button-border, var(--ss-c-button-bg));
}

.ss-btn-ghost {
	border-width: 1px;
	border-style: solid;
}

.ss-btn-text {
	display: inline-block;
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	/* The Text button is the third member of the GUIDELINES button trio and
	   wears the same type as the other two. It was reading family/weight/size
	   but not case or tracking, so a skin with uppercase letterspaced buttons
	   got sentence-case text buttons beside uppercase cards and See-All links
	   (.ss-card-more / .ss-intro-link already take all five). */
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
	color: var(--ss-c-link);
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
	transition: color 0.25s ease;
}

.ss-btn-text::after {
	content: " \2192";
}

.ss-btn-text:hover {
	color: var(--ss-c-link-hover);
}

/* Core buttons carry a top-right arrow icon (GUIDELINES v1.1). */
.ss-btn:not(.ss-btn-ghost)::after {
	content: "\2197";
	margin-left: 8px;
	display: inline-block;
}

/* ---- Hero setups -------------------------------------------------------- */

.ss-hero--overlay {
	overflow: hidden;
}

.ss-hero--overlay .ss-hero-overlay-content {
	padding-right: 33%;
}

.ss-on-image .ss-eyebrow,
.ss-on-image p {
	color: rgba(255, 255, 255, 0.85);
}

.ss-hero--centered .ss-hero-solo,
.ss-hero-solo.ss-center {
	max-width: 760px;
	margin-inline: auto;
}

.ss-hero-solo.ss-center .ss-hero-actions {
	justify-content: center;
}

.ss-hero-actions,
.ss-cpt-hero-actions,
.ss-cta-actions,
.ss-content-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 20px;
}

.ss-hero-actions {
	margin-top: calc(var(--ss-rhythm) * 1.2);
}

.ss-cta-actions {
	justify-content: center;
	margin: 0;
}

/* ---- Logo marquee ------------------------------------------------------- */

.ss-marquee {
	overflow: hidden;
	width: 100%;
	mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%);
	-webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%);
}

.ss-marquee-track {
	display: flex;
	width: max-content;
	animation: ss-marquee 25s linear infinite;
}

.ss-marquee:hover .ss-marquee-track {
	animation-play-state: paused;
}

.ss-marquee .ss-logos-row {
	display: flex;
	align-items: center;
	gap: clamp(60px, 8vw, 125px);
	padding-right: clamp(60px, 8vw, 125px);
}

.ss-marquee .ss-logo img {
	height: 50px;
	width: auto;
	object-fit: contain;
	opacity: 0.55;
	transition: opacity 0.3s ease;
}

.ss-marquee .ss-logo img:hover {
	opacity: 1;
}

@keyframes ss-marquee {
	from { transform: translateX(0); }
	to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
	.ss-marquee-track {
		animation: none;
		flex-wrap: wrap;
	}

	.ss-marquee .ss-logos-row[aria-hidden="true"] {
		display: none;
	}
}

/* ---- Stacked loop item (default) --------------------------------------- */

.ss-card-eyebrow {
	display: block;
	font-size: 13px;
	color: var(--ss-c-text-muted);
	margin-bottom: 6px;
}

/* An event's date/time line — on its card (under the title) and on its
   single hero (under the H1). Skins may restyle; the default is a quiet
   emphasized line in the brand ink. */
.ss-card-when {
	margin: -2px 0 8px;
	font-size: 13px;
	font-weight: 600;
	color: var(--ss-c-primary);
}

.ss-hero-when {
	margin: 4px 0 10px;
	font-size: 15px;
	font-weight: 600;
}

/* The post card's categories, between the date and the title. Rendered
   always, shown only where a skin asks for them — a card that already
   carries a date eyebrow does not universally want a second meta line, so
   this is opt-in rather than a look imposed on every existing skin. */
.ss-card-terms {
	display: none;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 8px;
}

.ss-card-term {
	display: inline-block;
}

/* ---- Card loop item: overlay display ------------------------------------ */

.ss-display-card .ss-card {
	position: relative;
	border: 0;
	overflow: hidden;
	border-radius: var(--ss-r-card);
	aspect-ratio: 4 / 5;
	background: var(--ss-c-text);
}

.ss-display-card .ss-card-media {
	position: absolute;
	inset: 0;
}

.ss-display-card .ss-card-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

.ss-display-card .ss-card::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 0.75) 100%);
	transition: background-color 0.6s ease;
	z-index: 1;
}

.ss-display-card .ss-card:hover::after,
.ss-display-card .ss-card:focus-within::after {
	background-color: rgba(0, 0, 0, 0.55);
}

.ss-display-card .ss-card-body {
	position: absolute;
	inset: auto 0 0 0;
	z-index: 2;
	padding: calc(var(--ss-rhythm) * 1.1);
}

.ss-display-card .ss-card-title {
	color: #fff;
	margin: 0;
	transition: margin 0.6s ease;
}

/* A card-display loop item is an ON-IMAGE context: the gradient darkens to
   the bottom and the title is white there by contract (GUIDELINES, "CPT loop
   items / Card"). The eyebrow and excerpt sit in that same darkened corner and
   must take the same ink.

   These carry the extra `.ss-card` step deliberately. At `.ss-display-card
   .ss-card-eyebrow` (0,2,0) they tied with a skin's own `.ss-skin-{name}
   .ss-card-eyebrow` (0,2,0) and lost on source order, because skin.css loads
   last — so every skin that gave its eyebrow a muted on-surface colour
   silently repainted the ON-IMAGE eyebrow muted grey on a dark photograph.
   Academy and Construction had already hand-written the fix into their own
   sheets, which is what a too-weak default looks like from the outside. At
   (0,3,0) the default holds and a skin that genuinely wants something else
   still overrides it with the `.ss-skin-{name} .ss-display-card ...` form it
   already uses. Nothing here sets `display`, so startup-4's deliberate
   `display: none` on this eyebrow is untouched. */
.ss-display-card .ss-card .ss-card-eyebrow {
	color: rgba(255, 255, 255, 0.75);
}

.ss-display-card .ss-card .ss-card-excerpt,
.ss-display-card .ss-card .ss-card-more {
	display: block;
	color: rgba(255, 255, 255, 0.85);
	max-height: 0;
	opacity: 0;
	overflow: hidden;
	margin: 0;
	transition: max-height 0.6s ease, opacity 0.5s ease, margin 0.6s ease;
}

.ss-display-card .ss-card .ss-card-more {
	color: #fff;
	width: max-content;
}

.ss-display-card .ss-card:hover .ss-card-excerpt,
.ss-display-card .ss-card:focus-within .ss-card-excerpt {
	max-height: 8em;
	opacity: 1;
	margin-top: 8px;
}

.ss-display-card .ss-card:hover .ss-card-more,
.ss-display-card .ss-card:focus-within .ss-card-more {
	max-height: 2em;
	opacity: 1;
	margin-top: 10px;
}


/* ---- Carousels ---------------------------------------------------------- */

.ss-carousel-nav {
	display: flex;
	justify-content: flex-end;
	gap: 10px;
	margin-top: var(--ss-rhythm);
}

/* Bleed: the track runs to the viewport edges; visible cards align to the
   container; the overflow shows prev/next under soft masks. */
.ss-layout-carousel-bleed {
	overflow: hidden;
}

.ss-layout-carousel-bleed .ss-bleed-wrap {
	width: 100vw;
	margin-left: calc(50% - 50vw);
	overflow: hidden;
	mask-image: linear-gradient(to right, rgba(0, 0, 0, 0.35), black 12%, black 88%, rgba(0, 0, 0, 0.35));
	-webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0.35), black 12%, black 88%, rgba(0, 0, 0, 0.35));
}

.ss-layout-carousel-bleed .ss-card-grid {
	padding-inline: 5vw;
	scroll-padding-inline: 5vw;
}

/* Bleed-right: the track runs to the RIGHT viewport edge only, left-aligned
   to the container, and the nav sits in a leading gutter beside the cards
   instead of below them. The hard cut at the edge is the point — the next
   card is meant to be half-visible — so unlike `carousel-bleed` there is no
   softening mask. The container becomes a two-row grid (intro spans, then
   nav | track); JS already wrapped the row in .ss-bleed-wrap. */
.ss-layout-carousel-bleed-right {
	overflow: hidden;
}

.ss-layout-carousel-bleed-right > .ss-container {
	display: grid;
	grid-template-columns: var(--ss-carousel-gutter, 190px) minmax(0, 1fr);
	align-items: center;
}

.ss-layout-carousel-bleed-right > .ss-container > .ss-section-intro {
	grid-column: 1 / -1;
}

.ss-layout-carousel-bleed-right .ss-bleed-wrap {
	grid-column: 2;
	/* The container is 90% of the viewport, so the gutter beyond its right
	   edge is exactly 5vw. */
	width: calc(100% + 5vw);
	overflow: hidden;
}

/* Wider cards than the flush 3-up so the cut card at the edge reads as a
   PREVIEW of the next entry rather than a third column that lost its end.
   Desktop only — tablet/mobile keep the framework's 2/1 (the ≤1024 rule
   lives earlier in this file, so an unscoped rule here would outrank it). */
@media (min-width: 1025px) {
	.ss-layout-carousel-bleed-right .ss-card-grid {
		grid-auto-columns: calc( ( 100% - 2 * var(--ss-gap) ) / 2.25 );
	}
}

.ss-layout-carousel-bleed-right .ss-carousel-nav {
	grid-column: 1;
	grid-row: 2;
	flex-direction: column;
	justify-content: center;
	align-items: flex-start;
	margin-top: 0;
	padding-right: var(--ss-gap);
}

@media (max-width: 1024px) {
	/* Tablet keeps the right bleed but drops the gutter: nav returns below
	   the track, where the rest of the framework puts it. */
	.ss-layout-carousel-bleed-right > .ss-container {
		display: block;
	}

	.ss-layout-carousel-bleed-right .ss-carousel-nav {
		flex-direction: row;
		justify-content: flex-end;
		align-items: center;
		margin-top: var(--ss-rhythm);
		padding-right: 0;
	}
}

@media (max-width: 767px) {
	/* Mobile shows ONE full card and no peek (QA rule), so the bleed has
	   nothing left to do — the track goes flush with the container. */
	.ss-layout-carousel-bleed-right .ss-bleed-wrap {
		width: 100%;
	}
}

/* Content-beside carousels: intro takes a third, track fills the rest. */
.ss-layout-carousel-left .ss-carousel-split,
.ss-layout-carousel-right .ss-carousel-split {
	display: grid;
	grid-template-columns: 1fr 2fr;
	gap: calc(var(--ss-gap) * 2);
	align-items: start;
}

.ss-layout-carousel-right .ss-carousel-split {
	grid-template-columns: 2fr 1fr;
}

.ss-layout-carousel-right .ss-carousel-split .ss-section-intro {
	order: 2;
}

/* ---- 2-column content rhythm ------------------------------------------- */

.ss-2col {
	align-items: stretch;
}

.ss-2col .ss-col-media {
	position: relative;
	min-height: 320px;
	align-self: stretch;
}

.ss-2col .ss-col-media > img:only-child {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center center;
}

.ss-2col > :not(.ss-col-media) {
	padding-block: 50px;
	align-self: center;
}

.ss-inset-roomy .ss-2col > :not(.ss-col-media) {
	padding-block: 75px;
}

/* ...but a hero row is not a content row. The 50/75px is the GUIDELINES
   two-column contract — breathing room around a block of copy sitting
   beside a photo. A split hero reuses `.ss-2col` for its layout only, and
   the interior heroes are composed `roomy`, so they were picking up 150px
   of padding inside a section that already carries its own hero inset.
   The section's inset is the hero's spacing; the row adds nothing. */
.ss-hero-grid > :not(.ss-col-media) {
	padding-block: 0;
}



/* ---- Testimonial spotlight --------------------------------------------- */

.ss-testimonials--spotlight {
	position: relative;
	overflow: hidden;
}

.ss-spotlight {
	position: relative;
}

.ss-spotlight-mark {
	position: absolute;
	top: 0;
	right: 4%;
	line-height: 0.72;
	font-family: 'Libre Baskerville', Georgia, serif;
	font-size: clamp(260px, 28vw, 440px);
	color: currentColor;
	opacity: 0.08;
	pointer-events: none;
	user-select: none;
}

.ss-spotlight-inner {
	max-width: 80%;
	text-align: center;
}

.ss-spotlight-stars {
	color: #E8A33D;
	letter-spacing: 6px;
	font-size: 16px;
	margin-bottom: calc(var(--ss-rhythm) * 1.2);
}

.ss-spotlight-viewport {
	overflow: hidden;
}

.ss-spotlight-track {
	display: flex;
	transition: transform 0.55s cubic-bezier(0.33, 1, 0.68, 1);
}

.ss-spotlight-track .ss-testimonial-slide {
	flex: 0 0 100%;
	padding-inline: 8px;
}

.ss-testimonial-quote-lg {
	font-family: 'Libre Baskerville', Georgia, serif;
	font-weight: 400;
	font-style: italic;
	font-size: var(--ss-t-testimonial-lg-sz, 32px);
	line-height: 1.5;
	margin: 0 0 var(--ss-rhythm);
}

.ss-testimonial-slide .ss-testimonial-author {
	font-family: var(--ss-t-button-ff);
	font-weight: var(--ss-t-button-w);
	font-size: var(--ss-t-button-sz);
	letter-spacing: var(--ss-t-button-ls, normal);
	text-transform: var(--ss-t-button-tt, none);
}

.ss-spotlight-dots {
	display: flex;
	justify-content: center;
	gap: 0;
	margin-top: calc(var(--ss-rhythm) * 1.2 - 9px);
}

/* 6px of paint, 4px apart, inside a 22x24 touch target.
   Read this before changing the size: the padding is what sets the
   SPACING, not `gap`, so setting `width` alone moves the paint and leaves
   the dots where they were. (The previous revision claimed "9px dots, 8px
   apart" but shipped 16px apart — two adjacent 8px paddings — which is
   exactly that trap.) The negative inline margin pulls the paint edges to
   4px while keeping a real target: 8 - 6 - 6 + 8 = 4. */
.ss-spotlight-dot {
	width: 6px;
	height: 6px;
	box-sizing: content-box;
	border: 0;
	padding: 9px 8px;
	margin-inline: -6px;
	background: currentColor;
	background-clip: content-box;
	border-radius: 50%;
	opacity: 0.25;
	cursor: pointer;
	transition: opacity 0.25s ease;
}

.ss-spotlight-dot.is-active {
	opacity: 1;
}

.ss-spotlight-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	background: none;
	border: 0;
	font-size: 26px;
	color: currentColor;
	opacity: 0.3;
	cursor: pointer;
	padding: 10px;
	transition: opacity 0.25s ease;
	z-index: 2;
}

.ss-spotlight-arrow:hover {
	opacity: 0.9;
}

.ss-spotlight-prev { left: calc(2.5vw - 18px); }
.ss-spotlight-next { right: calc(2.5vw - 18px); }

.ss-spotlight.is-single .ss-spotlight-dots,
.ss-spotlight.is-single .ss-spotlight-arrow {
	display: none;
}

/* ---- Footer (4-column standard) ----------------------------------------- */

.ss-footer-grid {
	display: grid;
	grid-template-columns: 1.4fr 1fr 1fr 1fr;
	gap: calc(var(--ss-gap) * 2);
	align-items: start;
}

.ss-footer-heading {
	font-size: 18px;
	margin-bottom: var(--ss-rhythm);
}

.ss-footer-lines {
	list-style: none;
	margin: var(--ss-rhythm) 0 0;
	padding: 0;
	display: grid;
	gap: 12px;
}

.ss-footer-lines li {
	display: flex;
	align-items: center;
	gap: 10px;
}

.ss-line-icon {
	flex: none;
	width: 17px;
	height: 17px;
}

.ss-footer-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 10px;
}

.ss-social-row {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	margin-top: calc(var(--ss-rhythm) * 1.2);
}

.ss-social-icon {
	display: inline-flex;
	color: var(--ss-c-footer-ink);
	transition: color 0.25s ease, opacity 0.25s ease;
}

.ss-social-icon svg {
	width: 25px;
	height: 25px;
}

.ss-social-icon:hover {
	opacity: 0.75;
}

.ss-footer {
	padding-top: 80px;
}

.ss-footer-bottom {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	margin-top: calc(var(--ss-rhythm) * 2.4);
	padding-top: 16px;
	border-top: 1px solid var(--ss-c-border);
}

.ss-footer-legal-links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 8px 24px;
}


/* ---- Form width grid ---------------------------------------------------- */

.ss-form-grid {
	grid-template-columns: repeat(6, 1fr);
}

.ss-form-field {
	grid-column: span 6;
}

.ss-form-field-half {
	grid-column: span 3;
}

.ss-form-field-third {
	grid-column: span 2;
}

.ss-form-field-two-thirds {
	grid-column: span 4;
}

/* Every field takes its own line on mobile (the span-2 override in the
   legacy block above predates this 6-column grid and never wins). */
@media (max-width: 767px) {
	.ss-form-field-half,
	.ss-form-field-third,
	.ss-form-field-two-thirds {
		grid-column: span 6;
	}
}

/* ---- Responsive defaults (GUIDELINES.md) -------------------------------- */

@media (max-width: 1024px) {
	.ss-section {
		padding-block: 50px;
	}

	.ss-section-intro,
	.ss-hero-content,
	.ss-hero-solo,
	.ss-hero-overlay-content,
	.ss-cpt-hero-inner,
	.ss-archive-hero-inner,
	.ss-blog-hero-inner,
	.ss-faq-intro-stack,
	.ss-faq-seeall,
	.ss-intro-split .ss-intro-aside {
		text-align: center;
		align-items: center;
		margin-inline: auto;
	}

	.ss-2col > :not(.ss-col-media) {
		text-align: center;
	}

	.ss-2col .ss-faq-list,
	.ss-2col .ss-outline-card,
	.ss-2col .ss-about-avatar {
		text-align: left;
	}

	.ss-2col .ss-content-actions,
	.ss-2col .ss-hero-actions {
		justify-content: center;
		display: flex;
	}

	.ss-counter .ss-counter-item {
		text-align: center;
	}

	.ss-intro-split {
		flex-direction: column;
		align-items: center;
	}

	.ss-hero-actions,
	.ss-cpt-hero-actions,
	.ss-cta-actions,
	.ss-content-actions {
		justify-content: center;
	}

	.ss-cpt-hero,
	.ss-services-hero,
	.ss-industries-hero,
	.ss-resources-hero,
	.ss-blog-hero,
	.ss-hero--overlay {
		min-height: 380px;
	}

	.ss-2col {
		grid-template-columns: 1fr;
		gap: 50px;
	}

	.ss-2col .ss-col-media,
	.ss-media-right .ss-2col .ss-col-media,
	.ss-media-left .ss-2col .ss-col-media {
		order: -1;
	}

	.ss-2col .ss-col-media {
		position: static;
		min-height: 0;
	}

	.ss-2col .ss-col-media > img:only-child {
		position: static;
		height: auto;
		width: 100%;
	}

	.ss-2col .ss-col-media img {
		max-height: 400px;
	}

	/* The roomy variant must be named here too: its 75px rule is (0,3,0)
	   and this zero was (0,2,0), so every roomy-composed 2col kept its
	   desktop breathing room inside the stacked column — 75px of void
	   between a stacked photo and its copy (client, found on the FAQ
	   sections; academy/rivet about and additional-content had it too). */
	.ss-2col > :not(.ss-col-media),
	.ss-inset-roomy .ss-2col > :not(.ss-col-media) {
		padding-block: 0;
	}

	.ss-hero--overlay .ss-hero-overlay-content {
		padding-right: 0;
	}

	/* The tablet footer layout lives in sections/footer/style.css — its
	   .ss-footer .ss-footer-grid selectors out-rank anything here. */

	.ss-layout-carousel-left .ss-carousel-split,
	.ss-layout-carousel-right .ss-carousel-split {
		grid-template-columns: 1fr;
	}

	.ss-layout-carousel-right .ss-carousel-split .ss-section-intro {
		order: 0;
	}
}

@media (max-width: 767px) {
	.ss-section {
		padding-block: 50px;
	}

	/* This reads the token. It used to be a literal 25px — the GUIDELINES
	   mobile default, written out — and because it sits LATER in this file
	   than the token-driven rule up in the container block, it quietly won.
	   So `--ss-side-pad` was emitted for every skin, listed in
	   SKIN-AUTHORING's token table, declared in all thirteen skins' tokens
	   and read by nothing: the mobile gutter was 25px everywhere no matter
	   what a skin asked for. Found while lowering the gutter to 10px across
	   the board (client) and discovering the token had no effect. */
	.ss-container {
		padding-inline: var(--ss-side-pad);
	}

	.ss-2col {
		gap: 25px;
	}

	.ss-2col .ss-col-media img {
		max-height: 250px;
	}

	.ss-footer-grid {
		grid-template-columns: 1fr;
		text-align: center;
	}

	.ss-footer-grid .ss-social-row,
	.ss-footer-lines,
	.ss-footer-menu {
		justify-content: center;
		justify-items: center;
	}

	.ss-testimonial-quote-lg {
		font-size: 22px;
	}
}

/* ---- Spotlight below desktop -------------------------------------------
   These three relaxed only at ≤767, which left TABLET stacking all of
   them: the 90% container, the inner's 80% measure and the slide's 8%
   padding put the quote at ~60% of a 768px screen, and the arrows —
   positioned `calc(2.5vw - 18px)` — sat 1.2px from the viewport edge,
   overlapping the container. Swipe (theme.js) is the control below
   desktop, so the arrows go rather than being nudged. */
@media (max-width: 1024px) {
	.ss-spotlight-inner {
		max-width: 100%;
	}

	.ss-testimonials--spotlight .ss-testimonial-slide {
		padding-inline: 0;
	}

	.ss-spotlight-arrow {
		display: none;
	}
}

/* ---- Brand Kit reference page ------------------------------------------- */

.ss-bk-head {
	padding: calc(var(--ss-rhythm) * 2) 0 var(--ss-rhythm);
}

.ss-bk-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	padding-bottom: calc(var(--ss-rhythm) * 1.2);
	border-bottom: 1px solid var(--ss-c-border);
	margin-bottom: calc(var(--ss-rhythm) * 1.2);
}

.ss-bk-tab {
	border: 1px solid var(--ss-c-border);
	background: var(--ss-c-surface);
	color: var(--ss-c-text);
	font: inherit;
	font-size: 14px;
	padding: 8px 16px;
	border-radius: var(--ss-r-btn, 999px);
	cursor: pointer;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.ss-bk-tab.is-active {
	background: var(--ss-c-primary);
	border-color: var(--ss-c-primary);
	color: var(--ss-c-primary-tx);
}

.ss-bk-note {
	margin: calc(var(--ss-rhythm) * 1.6) auto 0;
	opacity: 0.75;
}

.ss-bk-panel-body {
	padding-block: var(--ss-rhythm) calc(var(--ss-rhythm) * 3);
}

.ss-bk-h {
	margin: calc(var(--ss-rhythm) * 1.8) 0 var(--ss-rhythm);
	padding-bottom: 8px;
	border-bottom: 1px solid var(--ss-c-border);
}

.ss-bk-type-row {
	display: grid;
	grid-template-columns: 260px 1fr;
	gap: var(--ss-gap);
	align-items: center;
	padding: 14px 0;
	border-bottom: 1px solid var(--ss-c-border);
}

.ss-bk-type-sample { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ss-bk-sample-h1 { font-family: var(--ss-t-h1-ff); font-weight: var(--ss-t-h1-w); font-size: var(--ss-t-h1-sz); letter-spacing: var(--ss-t-h1-ls, normal); text-transform: var(--ss-t-h1-tt, none); line-height: var(--ss-t-h1-lh); }
.ss-bk-sample-h2 { font-family: var(--ss-t-h2-ff); font-weight: var(--ss-t-h2-w); font-size: var(--ss-t-h2-sz); letter-spacing: var(--ss-t-h2-ls, normal); text-transform: var(--ss-t-h2-tt, none); line-height: var(--ss-t-h2-lh); }
.ss-bk-sample-h3 { font-family: var(--ss-t-h3-ff); font-weight: var(--ss-t-h3-w); font-size: var(--ss-t-h3-sz); letter-spacing: var(--ss-t-h3-ls, normal); text-transform: var(--ss-t-h3-tt, none); line-height: var(--ss-t-h3-lh); }
.ss-bk-sample-subtitle { font-family: var(--ss-t-subtitle-ff); font-weight: var(--ss-t-subtitle-w); font-size: var(--ss-t-subtitle-sz); line-height: var(--ss-t-subtitle-lh); }
.ss-bk-sample-eyebrow { font-family: var(--ss-t-eyebrow-ff); font-weight: var(--ss-t-eyebrow-w); font-size: var(--ss-t-eyebrow-sz); color: var(--ss-t-eyebrow-c, var(--ss-c-primary)); text-transform: var(--ss-t-eyebrow-tt, none); letter-spacing: var(--ss-t-eyebrow-ls, 0); line-height: var(--ss-t-eyebrow-lh); }
.ss-bk-sample-body { font-size: var(--ss-t-body-sz); line-height: var(--ss-t-body-lh); }
.ss-bk-sample-body-sm { font-size: var(--ss-t-body-sm-sz); color: var(--ss-c-text-muted); line-height: var(--ss-t-body-sm-lh); }
.ss-bk-sample-button { font-family: var(--ss-t-button-ff); font-weight: var(--ss-t-button-w); font-size: var(--ss-t-button-sz); line-height: var(--ss-t-button-lh); }
.ss-bk-sample-testimonial-lg { font-family: 'Libre Baskerville', Georgia, serif; font-style: italic; font-size: var(--ss-t-testimonial-lg-sz, 32px); }

.ss-bk-swatches {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: var(--ss-gap);
}

.ss-bk-swatch {
	display: flex;
	gap: 12px;
	align-items: flex-start;
}

.ss-bk-chip {
	width: 48px;
	height: 48px;
	flex: 0 0 48px;
	border-radius: 10px;
	border: 1px solid var(--ss-c-border);
}

.ss-bk-demo-row {
	display: flex;
	gap: 14px;
	align-items: center;
	flex-wrap: wrap;
}

.ss-bk-width-demo {
	display: grid;
	gap: 12px;
}

.ss-bk-width-bar {
	background: var(--ss-c-surface-alt);
	border: 1px dashed var(--ss-c-border);
	padding: 22px;
	text-align: center;
	font-size: 13px;
	color: var(--ss-c-text-muted);
}

.ss-bk-width-boxed { width: 100%; }
.ss-bk-width-fill { width: 90%; margin-inline: auto; border-radius: var(--ss-r-card, 0); }

.ss-bk-img-row {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--ss-gap);
}

.ss-bk-img-row img { width: 100%; height: 180px; object-fit: cover; border-radius: var(--ss-r-card, 0); }
.ss-bk-img-row figcaption { margin-top: 6px; }

.ss-bk-loop-demo {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: calc(var(--ss-gap) * 2);
	align-items: start;
}

.ss-bk-one.ss-card-grid { grid-template-columns: minmax(0, 360px); }

@media (max-width: 767px) {
	.ss-bk-type-row { grid-template-columns: 1fr; }
	.ss-bk-loop-demo, .ss-bk-img-row { grid-template-columns: 1fr; }
}

/* Intro subtitle rides the heading column; the aside is the View-All link. */
.ss-intro-split .ss-intro-heading {
	max-width: 620px;
}

.ss-intro-split .ss-intro-heading .ss-subtitle {
	margin-top: 10px;
}

.ss-carousel-split-track {
	min-width: 0;
}

/* ==========================================================================
   GUIDELINES v1.1 revisions (client review 2026-08-31)
   ========================================================================== */

/* Media-left was never flipping: media renders after content in most
   section DOMs, so the left side needs an explicit order. */
.ss-media-left .ss-2col .ss-col-media {
	order: -1;
}

/* Breathing room between 2-column body copy and its button. */
.ss-2col .ss-content-actions,
.ss-2col p:has(> .ss-btn),
.ss-faq-seeall {
	margin-top: var(--ss-rhythm);
}

.ss-2col .ss-hero-actions {
	margin-top: calc(var(--ss-rhythm) * 1.2);
}

/* About: the info card bottom sits flush with the image bottom. */
.ss-about .ss-2col > :not(.ss-col-media) {
	display: flex;
	flex-direction: column;
	align-self: stretch;
}

.ss-about .ss-outline-card {
	margin-top: auto;
}

/* ---- Hero setup 1 (overlay): white copy, luminance-picked buttons,
   Learn More scroller ------------------------------------------------------ */

.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-subtitle,
.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-eyebrow {
	color: #FFFFFF;
}

.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-btn:not(.ss-btn-ghost) {
	background: var(--ss-ov-btn-bg, #FFFFFF);
	border-color: var(--ss-ov-btn-bg, #FFFFFF);
	color: var(--ss-ov-btn-tx, var(--ss-c-primary));
}

.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-btn-ghost {
	background: transparent;
	border-color: #FFFFFF;
	color: #FFFFFF;
}

/* ---- Hero setup 3: keep every block truly centered. */
.ss-hero-solo.ss-center .ss-subtitle,
.ss-hero-solo.ss-center .ss-eyebrow {
	margin-inline: auto;
}

/* ---- Overlay card link: white at rest, warm on card hover. */
.ss-display-card .ss-card .ss-card-more {
	color: #FFFFFF;
	border-color: currentColor;
}

.ss-display-card .ss-card:hover .ss-card-more:hover {
	color: var(--ss-c-link-hover);
}

/* ---- CPT intro arrangements ---------------------------------------------
   Default (split): copy left, View-All bottom-right, both bottom-flush.
   Centered (entry option "intro": "centered"): everything centered. */

/* ---- Section intro measure (GUIDELINES: 66% of the section) ------------
   Left-aligned intros run to 66% from the left with the View-All button
   bottom-right; centred intros take the same 66% and open out to the full
   width below desktop. Both were px caps (640 / 720) that worked out at
   49% and 55% of a 90% container — narrower than the contract, and the
   720px version lived in four section stylesheets where it was easy to
   miss (the gallery never had one at all, so capping it later pinned its
   centred heading to the left). One rule each, keyed off classes the
   templates already emit. */

.ss-section-intro.ss-intro-split {
	display: grid;
	grid-template-columns: minmax(0, 66%) auto;
	justify-content: space-between;
	align-items: end;
	gap: var(--ss-gap) calc(var(--ss-gap) * 2);
	text-align: left;
}

.ss-section-intro.ss-center {
	max-width: 66%;
	margin-inline: auto;
}

@media (max-width: 1024px) {
	.ss-section-intro.ss-center {
		max-width: 100%;
	}
}

.ss-intro-split .ss-intro-heading {
	max-width: none;
}

.ss-intro-split .ss-intro-aside {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	max-width: none;
}

.ss-intro-centered .ss-section-intro.ss-intro-split {
	display: block;
	text-align: center;
}

.ss-intro-centered .ss-intro-split .ss-intro-heading {
	max-width: 700px;
	margin-inline: auto;
}

.ss-intro-centered .ss-intro-split .ss-intro-aside {
	align-items: center;
	margin-top: var(--ss-rhythm);
}

/* Side-content carousels: the intro stacks plainly and rides the bottom,
   flush with the card row (the nav sits below the cards). */
.ss-layout-carousel-left .ss-carousel-split,
.ss-layout-carousel-right .ss-carousel-split {
	align-items: end;
}

.ss-carousel-split .ss-section-intro.ss-intro-split {
	display: block;
	margin-bottom: 65px;
}

.ss-carousel-split .ss-intro-split .ss-intro-aside {
	align-items: flex-start;
	margin-top: var(--ss-rhythm);
}

/* ---- FAQ standard structure ---------------------------------------------
   Image fills its column top-to-bottom; content column carries eyebrow,
   H2, subtitle, accordions, See-All. */

.ss-faq-grid {
	align-items: stretch;
}

.ss-faq-grid .ss-faq-photo {
	height: 100%;
}

.ss-faq-grid .ss-faq-photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ss-faq-content {
	padding-block: 50px;
}

.ss-faq-content .ss-subtitle {
	margin-top: 10px;
}

.ss-faq-content .ss-faq-list {
	margin-top: calc(var(--ss-rhythm) * 1.2);
}

.ss-faq-item {
	padding-block: 26px;
}

.ss-faq-question {
	line-height: 1.4;
}

.ss-faq-answer {
	overflow: hidden;
	padding-top: 12px;
}

.ss-faqs--centered .ss-faq-grid {
	display: block;
}

.ss-faqs--centered .ss-faq-content {
	padding-block: 0;
}

.ss-faqs--centered .ss-faq-intro-stack {
	text-align: center;
	max-width: 680px;
	margin: 0 auto calc(var(--ss-rhythm) * 1.4);
}

.ss-faqs--centered .ss-faq-list {
	max-width: 820px;
	margin-inline: auto;
}

.ss-faqs--centered .ss-faq-seeall {
	text-align: center;
}

/* ---- FAQ split: the third arrangement (GUIDELINES "FAQ").
   No photo, but still two columns — the intro (eyebrow / H2 / subtitle /
   View-All) holds one side and the accordion column the other. The intro
   sits left by default because that is how the copy reads; `media: left`
   on the entry puts it on the right, the same axis the photo version uses.
   Both columns drop their 2-col padding: with no image to stretch past the
   copy, that padding only doubles the section's own inset. */
.ss-faq-grid--split {
	align-items: start;
}

.ss-faq-grid--split .ss-faq-content {
	padding-block: 0;
	/* The 2-col default centres a non-media column against its neighbour,
	   which here floats the intro halfway down the accordion stack. Both
	   columns start at the top instead — align-self on the item, because
	   that is what the default sets and align-items cannot out-rank it. */
	align-self: start;
}

.ss-faq-grid--split .ss-faq-list {
	margin-top: 0;
}

.ss-media-left .ss-faq-grid--split .ss-faq-intro-col {
	order: 2;
}

.ss-faq-grid--split .ss-faq-seeall {
	margin-top: var(--ss-rhythm);
}

@media (max-width: 1024px) {
	.ss-faq-grid--split .ss-faq-intro-col,
	.ss-media-left .ss-faq-grid--split .ss-faq-intro-col {
		order: 0;
	}
}

/* ---- CTA copy width: 90% of the band. */
.ss-cta .ss-cta-inner {
	width: 90%;
	max-width: none;
}

.ss-cta .ss-cta-title {
	max-width: none;
}

.ss-cta.ss-width-fill .ss-cta-inner {
	width: 100%;
}


.ss-footer-legal-links {
	gap: 0;
}

/* The separator between the legal links is the link's own right border, so
   its horizontal padding sets the gap. The VERTICAL padding is a tap
   target: at `line-height: 1` these links were 13px tall, well under the
   24px minimum, and they are the last row of every page on a phone. The
   border is inset by the same amount so the divider keeps its old height. */
.ss-footer-legal-links a {
	font-family: var(--ss-t-footer-fine-ff, inherit);
	font-size: var(--ss-t-footer-fine-sz, 13px);
	padding: 8px 12px;
	border-right: 1px solid currentColor;
	line-height: 1;
	background-clip: padding-box;
}

.ss-footer-legal-links a:last-child {
	border-right: 0;
}

@media (max-width: 1024px) {
	.ss-intro-centered .ss-intro-split .ss-intro-aside,
	.ss-intro-split .ss-intro-aside {
		align-items: center;
	}

	.ss-section-intro.ss-intro-split {
		display: block;
		text-align: center;
	}

	.ss-intro-split .ss-intro-aside {
		margin-top: var(--ss-rhythm);
	}

	.ss-faq-content {
		padding-block: 0;
	}

	.ss-carousel-split .ss-section-intro.ss-intro-split {
		margin-bottom: 0;
	}

	/* Side-content carousels centre with every other intro on tablet. The
	   desktop rule that left-aligns their See-All is three classes deep, so
	   the generic centring above lost the tie and the link sat alone on the
	   left under a centred heading. */
	.ss-carousel-split .ss-intro-split .ss-intro-aside {
		align-items: center;
	}
}

/* ---- v1.1 additions: interior band heroes match Setup 1 ---- */

/* Content spans 66% on every interior hero — with or without a photo
   band. Section files must not add their own px caps on top of this.

   The measure is a KNOB, not a constant: a skin whose interior heroes run the
   full width sets `--ss-hero-measure-pad: 0` on its root selector. It has to
   be a custom property rather than a skin override of this rule, because
   GUIDELINES forbids skins adding their own caps or measures here at all —
   without a knob the only way to get a full-width interior hero is to break
   that rule. Unset everywhere, so it resolves to 34% exactly as before. */
.ss-hero--overlay .ss-hero-overlay-content,
.ss-cpt-hero-inner,
.ss-archive-hero-inner,
.ss-blog-hero-inner {
	padding-right: var(--ss-hero-measure-pad, 34%);
}



/* Interior band heroes take an optional corner radius — all four corners, or
   just the bottom pair for a hero that sits under the header and curves off
   the band below it.

   The radius goes on the SECTION and the photo layer inherits it. The section
   paints no background of its own, so the radius is invisible there; what it
   does is give `.ss-hero-band-bg` — which is `position: absolute; inset: 0` —
   something to clip its photograph and scrim to. Doing it this way rather than
   with `overflow: hidden` on the section means nothing ELSE in the hero gets
   clipped: no skin's off-edge slab, bleed rail or overhanging control changes
   behaviour, and with the token unset the declaration resolves to `0` and no
   skin moves at all.

   This is also what makes a `"width": "fill"` interior hero work: that axis
   already gives the block 90% width and `--ss-r-card`, but the photo layer was
   square underneath it and overhung the rounded corners. */
.ss-cpt-hero,
.ss-services-hero,
.ss-industries-hero,
.ss-resources-hero,
.ss-case-studies-hero,
.ss-products-hero,
.ss-events-hero,
.ss-blog-hero,
.ss-hero--overlay,
.ss-section:has(> .ss-hero-band-bg) {
	border-radius: var(--ss-hero-radius, 0);
}

.ss-section.ss-width-fill:has(> .ss-hero-band-bg) {
	border-radius: var(--ss-hero-radius, var(--ss-r-card, 0));
}

/* `inherit` alone would round the box but not its contents — this element
   holds a real <img> at 100%/100% and the scrim ::after — so it clips too.
   With the radius token unset this resolves to a 0 radius and nothing
   overflows, so the clip is a no-op on every existing skin. */
.ss-hero-band-bg {
	border-radius: inherit;
	overflow: hidden;
}

.ss-cpt-hero,
.ss-services-hero,
.ss-industries-hero,
.ss-resources-hero,
.ss-case-studies-hero,
.ss-products-hero,
.ss-events-hero,
.ss-blog-hero,
.ss-hero--overlay,
.ss-section:has(> .ss-hero-band-bg) {
	position: relative;
	display: flex;
	align-items: center;
	min-height: 460px;
	padding-block: var(--ss-inset-std);
}

.ss-cpt-hero > .ss-container,
.ss-services-hero > .ss-container,
.ss-industries-hero > .ss-container,
.ss-resources-hero > .ss-container,
.ss-case-studies-hero > .ss-container,
.ss-products-hero > .ss-container,
.ss-events-hero > .ss-container,
.ss-blog-hero > .ss-container,
.ss-hero--overlay > .ss-container,
.ss-section:has(> .ss-hero-band-bg) > .ss-container {
	width: var(--ss-container-w);
}

/* ---- Interior heroes on a phone: full width, 25px of copy padding -------
   A framework contract, not a per-skin choice (client: "fairly consistent
   across all skins unless there is a good reason otherwise").

   Three things have to happen together at 375px, and they pull against each
   other if any one is left out:

   1. The BAND runs edge to edge. A skin whose interior heroes are composed
      `"width": "fill"` gets a 90% block with a radius and inline padding —
      right on a desktop, wrong on a phone, where a 90% band leaves 5vw of
      page showing down each side of a photograph and the corners round off
      a strip barely wider than the text inside it.
   2. The COPY sits 25px from the edge. The page gutter is now 10px
      (`--ss-side-pad`), which is right for a card grid and much too tight
      for a headline over a photograph, so the hero states its own.
   3. The measure lets go. `padding-right: 34%` reserves a third of the band
      for a photograph that is behind the text at this width, not beside it,
      so keeping it would squeeze the H1 into two thirds of an already narrow
      column. The knob is set to 0 rather than the rule being dropped, so a
      skin that has pinned its own measure still resolves through the same
      custom property.

   Vertical padding comes from the hero inset tier, which the mobile token
   already collapses to 50px. */
@media (max-width: 767px) {
	.ss-section.ss-width-fill:has(> .ss-hero-band-bg),
	.ss-section.ss-width-fill:has(> .ss-container > .ss-hero-split) {
		width: 100%;
		padding-inline: 0;
		border-radius: 0;
	}

	.ss-cpt-hero > .ss-container,
	.ss-services-hero > .ss-container,
	.ss-industries-hero > .ss-container,
	.ss-resources-hero > .ss-container,
	.ss-case-studies-hero > .ss-container,
	.ss-products-hero > .ss-container,
	.ss-events-hero > .ss-container,
	.ss-blog-hero > .ss-container,
	.ss-hero--overlay > .ss-container,
	.ss-section:has(> .ss-hero-band-bg) > .ss-container {
		/* Width too, not just padding. The interior-hero contract above sets
		   `> .ss-container { width: var(--ss-container-w) }` at (0,2,0), which
		   already beats the ≤767 `.ss-container { width: 100% }` at (0,1,0) —
		   so without this the container stays 90%, centres itself, and the
		   25px lands on top of an 18.75px auto margin: 43.75px of inset, not
		   25.

		   And this rule REPEATS that selector list rather than adding a class,
		   which means it ties on specificity and wins on SOURCE ORDER alone.
		   It therefore has to stay physically below the rule it overrides.
		   Moving this block earlier in the file silently restores the 90%
		   container — measured, on the first attempt at writing it. */
		width: 100%;
		padding-inline: 25px;
	}

	.ss-hero--overlay .ss-hero-overlay-content,
	.ss-cpt-hero-inner,
	.ss-archive-hero-inner,
	.ss-blog-hero-inner {
		--ss-hero-measure-pad: 0;
	}
}

/* ---- Interior hero, setup 2 (split) -----------------------------------
   An interior hero composed `"variant": "split"` puts its photo in a
   column instead of behind a scrim, so the band contract above — which
   matches on the section class and therefore fires either way — has to
   let go: no forced min-height, and the copy takes the full column rather
   than the 66% measure that only makes sense over a full-bleed photo.
   Keyed off a class the shared part emits, so it covers every hero
   section at once and any future one for free. */
.ss-section:has(> .ss-container > .ss-hero-split) {
	display: block;
	min-height: 0;
}

/* ...and it takes the inset it was COMPOSED with. The contract above sets
   padding-block from the standard inset as a floor for a band hero, and
   matches on section class, so it was overriding the composed inset on the
   split setup too — an interior hero asking for the hero measure still got
   the standard one. */
.ss-section:has(> .ss-container > .ss-hero-split).ss-inset-hero {
	padding-block: var(--ss-inset-hero);
}

.ss-section:has(> .ss-container > .ss-hero-split).ss-inset-roomy {
	padding-block: var(--ss-inset-roomy);
}

.ss-section:has(> .ss-container > .ss-hero-split).ss-inset-tight {
	padding-block: calc(var(--ss-rhythm) * 2);
}

.ss-hero-split .ss-hero-content .ss-cpt-hero-inner,
.ss-hero-split .ss-hero-content {
	padding-right: 0;
}

.ss-hero--overlay .ss-hero-title,
.ss-on-image h1 {
	max-width: none;
}

.ss-on-image .ss-subtitle {
	max-width: none;
}

/* Overlay-styled buttons on every scrimmed band. */
.ss-section .ss-on-image .ss-btn:not(.ss-btn-ghost) {
	background: var(--ss-ov-btn-bg, #FFFFFF);
	border-color: var(--ss-ov-btn-bg, #FFFFFF);
	color: var(--ss-ov-btn-tx, var(--ss-c-primary));
}

.ss-section .ss-on-image .ss-btn-ghost {
	background: transparent;
	border-color: #FFFFFF;
	color: #FFFFFF;
}

.ss-section .ss-on-image .ss-btn:not(.ss-btn-ghost):hover,
.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-btn:not(.ss-btn-ghost):hover {
	background: var(--ss-c-button-hover-bg);
	border-color: var(--ss-c-button-hover-bg);
	color: var(--ss-c-button-hover-tx);
}

.ss-section .ss-on-image .ss-btn-ghost:hover,
.ss-section.ss-hero--overlay .ss-hero-overlay-content .ss-btn-ghost:hover {
	background: var(--ss-c-button-hover-bg);
	border-color: var(--ss-c-button-hover-bg);
	color: var(--ss-c-button-hover-tx);
}

/* Stacked CPT grids breathe: 50px both axes (carousels keep the tight gap). */
.ss-section:not(.ss-has-carousel) .ss-card-grid {
	gap: 50px;
}

@media (max-width: 1024px) {
	.ss-hero--overlay .ss-hero-overlay-content,
	.ss-cpt-hero-inner,
	.ss-archive-hero-inner,
	.ss-blog-hero-inner {
		padding-right: 0;
	}

}

/* ...but these inners ARE the .ss-container, and on mobile the container
   carries its side padding rather than a 90% width. Dropping padding-right
   to 0 there left every interior hero with a 25px gutter on the left and
   none on the right — the copy sat visibly off-centre. Restore the right
   gutter below 767 only; tablet still wants the plain 0. */
@media (max-width: 767px) {
	.ss-hero--overlay .ss-hero-overlay-content,
	.ss-cpt-hero-inner,
	.ss-archive-hero-inner,
	.ss-blog-hero-inner {
		padding-right: 25px;
	}
}

.ss-bk-mini-masonry {
	columns: 3;
	max-width: 900px;
}

/* ---- Taxonomy/type filter bars — the Brand Kit tab pills ---- */

.ss-filter-bar {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-bottom: calc(var(--ss-rhythm) * 1.5);
}

.ss-filter-tab {
	display: inline-block;
	border: 1px solid var(--ss-c-border);
	background: var(--ss-c-surface);
	color: var(--ss-c-text);
	font: inherit;
	font-size: 14px;
	padding: 8px 16px;
	border-radius: var(--ss-r-btn, 999px);
	cursor: pointer;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.ss-filter-tab.is-active {
	background: var(--ss-c-primary);
	border-color: var(--ss-c-primary);
	color: var(--ss-c-primary-tx);
}

/* Filtered-out cards. This is a STATE, not a look: a skin that gives its
   cards a display (`flex` for equal-height bodies, say) writes a
   two-class selector that out-ranks a one-class rule, and the filter then
   toggles a class that changes nothing — the bar looks broken. `!important`
   is correct here precisely because no skin may win this one. */
[data-filter-item].ss-filter-hidden {
	display: none !important;
}

/* Side-content carousels show two cards in the track on desktop. */
@media (min-width: 1025px) {
	.ss-carousel-split .ss-card-grid {
		grid-auto-columns: calc((100% - var(--ss-gap)) / 2);
	}
}

/* ---- Gallery lightbox ---------------------------------------------------- */

.ss-lightbox {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(0, 0, 0, 0.88);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.25s ease;
}

.ss-lightbox.is-open {
	opacity: 1;
	pointer-events: auto;
}

.ss-lightbox img {
	max-width: min(1200px, 88vw);
	max-height: 86vh;
	object-fit: contain;
	border-radius: var(--ss-r-card);
}

.ss-lightbox-btn {
	position: absolute;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 1px solid rgba(255, 255, 255, 0.5);
	border-radius: 50%;
	background: transparent;
	color: #fff;
	font-size: 20px;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.ss-lightbox-btn:hover {
	background: rgba(255, 255, 255, 0.15);
}

.ss-lightbox-close {
	top: 24px;
	right: 24px;
}

.ss-lightbox-prev {
	left: 24px;
}

.ss-lightbox-next {
	right: 24px;
}

.ss-masonry-item img {
	cursor: zoom-in;
}

@media (max-width: 767px) {
	.ss-lightbox-prev {
		left: 8px;
	}

	.ss-lightbox-next {
		right: 8px;
	}
}

/* ---- Split hero drops its image on tablet/mobile -------------------------
   Both setups that use it: the hero section variant, and the interior
   heroes (CPT single + archives), which render the same row through
   parts/interior-hero.php and carry .ss-hero-split on it. Below desktop a
   split hero is a stack, and the photo is the half that goes. */

@media (max-width: 1024px) {
	.ss-hero--split .ss-hero-media,
	.ss-hero-split .ss-hero-media {
		display: none;
	}

	.ss-hero--split .ss-hero-grid,
	.ss-hero-split.ss-hero-grid {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   Overlay header (opt-in: components.header.overlay)
   The header is a transparent layer ON the first band rather than a bar
   above it. Both classes come from the body_class filter in functions.php:
   `ss-header-overlay` says the skin asked for it, `ss-hero-first` says
   THIS view actually opens on a full-bleed photo band. A page that opens
   on anything else (the contact role starts with `contact-us`) keeps a
   normal header, so nothing can slide underneath a transparent bar.

   Deliberately NOT wired to `components.header.position`: that key sits
   in every skin's tokens.json, has never been connected to anything, and
   construction declares "sticky" on it — connecting it would hand an
   approved skin a behaviour it has never had. This is its own key.
   ========================================================================== */

body.ss-header-overlay.ss-hero-first .ss-header {
	position: absolute;
	inset: 0 0 auto 0;
	z-index: 20;
	background: transparent;
}

/* The band underneath has to clear the bar. A band hero centres its copy
   vertically, so without this the eyebrow collides with the menu; a
   bottom-anchored hero (a skin may make its home hero one) is unaffected
   either way, since the extra top padding only moves space it is not
   using. */
body.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
	padding-top: calc(var(--ss-inset-hero) + var(--ss-header-h));
}

/* ...but on tablet and phone that sum is most of the screen. The hero inset
   is already 60px there and the header is another 100, so the copy started
   160px down a 812px viewport with the photograph doing nothing above it
   (client, three skins independently). Below 1025 the band clears the menu
   and adds a small gap, no more.

   The knob exists because "clears the menu" is the only part that is
   structural; how much air sits under it is taste, and a skin whose header
   floats a shadow or a rule needs a little more. Note the weight: this rule
   is (0,5,1), so a skin CANNOT override it with the two- or three-class
   selector it would reach for first — carepoint tried exactly that last
   round and the rule silently never applied. Set the knob instead. */
@media (max-width: 1024px) {
	body.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
		padding-top: calc(var(--ss-header-h) + var(--ss-hero-overlay-gap, 20px));
	}
}

/* Nav ink sits on photography here, so it follows the on-image contract
   rather than the page's text colour. The drawer at ≤1024 paints itself
   on `surface`, so it keeps the normal ink. The brand slot follows the
   same contract: the text-title fallback and the generic lockup (name AND
   mark) go white — a brand-coloured mark can't be trusted on a photo. */
@media (min-width: 1025px) {
	body.ss-header-overlay.ss-hero-first .ss-header-nav .ss-nav-menu > li > a {
		color: #FFFFFF;
	}
}

body.ss-header-overlay.ss-hero-first .ss-header-title {
	color: #FFFFFF;
}

body.ss-header-overlay.ss-hero-first .ss-header .ss-logo-lockup .ss-logo-mark {
	color: currentColor;
}

/* ==========================================================================
   Dark scheme (opt-in: "scheme": "dark" in tokens.json)
   Two things a colour token cannot express on its own. `color-scheme:
   dark` itself is emitted with the custom properties by SS_Tokens, which
   is what turns the browser's own chrome (scrollbars, the native select
   panel, date pickers) dark.
   ========================================================================== */

/* Chrome repaints autofilled fields with its own pale fill, overriding the
   field background entirely. The only way to cover it is an inset shadow,
   which needs an opaque colour — so it reads the same `--ss-field-bg` the
   field itself uses, and a skin that repaints its fields gets a matching
   autofill state for free. Scoped to dark schemes on purpose: doing this
   for every skin needs a per-skin value wherever fields are transparent or
   band-tinted, plus a contact-form pass on all of them — a separate,
   deliberate cleanup, not a side effect of adding a dark skin. */
body.ss-scheme-dark input:-webkit-autofill,
body.ss-scheme-dark input:-webkit-autofill:hover,
body.ss-scheme-dark input:-webkit-autofill:focus,
body.ss-scheme-dark textarea:-webkit-autofill,
body.ss-scheme-dark select:-webkit-autofill {
	-webkit-box-shadow: inset 0 0 0 1000px var(--ss-field-bg, var(--ss-c-surface));
	box-shadow: inset 0 0 0 1000px var(--ss-field-bg, var(--ss-c-surface));
	-webkit-text-fill-color: var(--ss-c-text);
	caret-color: var(--ss-c-text);
}

/* The submenu panel's lift is a soft dark shadow tuned for a light page;
   over a dark ground it renders nothing at all. On dark the separation is
   the surface step plus the hairline the panel already carries. */
@media (min-width: 1025px) {
	body.ss-scheme-dark .ss-nav-menu .sub-menu {
		box-shadow: none;
	}
}

/* ==========================================================================
   Revision round 3 — cross-skin defaults (client, "All Skins/General")
   ========================================================================== */

/* ---- Text stops short of the screen edge on a phone ---------------------
   The page gutter is 10px, which is right for a BLOCK — a card, a panel, a
   band — because those carry their own inner padding and the ink inside them
   already sits well clear of the edge. It is wrong for copy sitting straight
   in the container with nothing around it, which then runs to 10px and reads
   as though it is falling off the screen.

   So the gutter stays 10px and the TEXT WRAPPERS take the remaining 15px,
   landing every unboxed run of copy at 25px. Enumerated deliberately rather
   than applied with a `:not()` sweep: the client's warning was to leave alone
   anything that already has padding from a card, and a list of the wrappers
   that hold bare copy is auditable in a way that a negative selector is not.
   Anything inside `.ss-card`, `.ss-contact-main`, a fill block or a stats
   panel is untouched, because none of those are in this list. */
@media (max-width: 767px) {
	.ss-section-intro,
	.ss-about-content,
	.ss-mission-content,
	.ss-content-body,
	.ss-hero-solo,
	.ss-prose,
	.ss-blog-body,
	.ss-faq-intro-stack,
	.ss-2col > :not(.ss-col-media):not(.ss-card):not(.ss-contact-main) {
		padding-inline: 15px;
	}

	/* The list above was written from the sections the client named. These
	   were found by SCANNING every skin for bare copy sitting closer than
	   24px to the edge, which is the only way to be sure the list is
	   complete — the article body was doing it on all ten skins, the team
	   cards on nine. `skin-briefs/tools/edgescan.js` reproduces the scan and
	   the audit harness runs the same assertion, so a future section that
	   misses this shows up without anyone having to remember it.

	   Team takes the GRID, not the member: on a skin whose team cards are
	   boxed, padding the member would inset text that its own box already
	   holds clear, whereas insetting the grid moves the whole column and
	   stays consistent either way. */
	.ss-blog-content .ss-article-main,
	.ss-faqs .ss-faq-content,
	.ss-team .ss-team-grid,
	.ss-footer .ss-footer-grid {
		padding-inline: 15px;
	}

	/* ...and a text wrapper nested inside another one must not pay twice.
	   The article is the case that proves why this list has to be kept in
	   step with the one above: `.ss-article-body` also carries `.ss-prose`,
	   so once `.ss-article-main` was added it was paying the inset twice and
	   the body copy sat 15px further in than the title and the meta row above
	   it — the parts of one article reading as three different indents. */
	.ss-section-intro .ss-section-intro,
	.ss-2col > :not(.ss-col-media) .ss-section-intro,
	.ss-2col > :not(.ss-col-media) .ss-content-body,
	.ss-2col > :not(.ss-col-media) .ss-prose,
	.ss-article-main .ss-prose,
	.ss-article-main .ss-content-body,
	.ss-team-grid .ss-prose,
	.ss-faq-content .ss-prose {
		padding-inline: 0;
	}

	/* A fill block is the same pay-twice case one level up: it carries its
	   own inner padding (G5 exempts it on exactly that basis), so the
	   wrapper 15px inside one stacked a third indent on top of the band's —
	   startup-3's centered FAQ read 50px in (25 band + 10 gutter + 15
	   wrapper) where 25 is the spec. */
	.ss-width-fill .ss-section-intro,
	.ss-width-fill .ss-faq-content,
	.ss-width-fill .ss-content-body,
	.ss-width-fill .ss-prose {
		padding-inline: 0;
	}
}

/* ---- The copyright line centres on a phone ------------------------------
   The bottom bar is already a centred column at this width; only the fine
   print itself was still inheriting `text-align: start` from the footer
   grid's mobile rule. */
@media (max-width: 767px) {
	.ss-footer .ss-footer-fine,
	.ss-footer .ss-footer-legal-links {
		text-align: center;
	}
}

/* ---- Contact identity lines take the BUTTON colour ----------------------
   Client, all skins: the icon AND the text of the email / phone / calendar
   rows carry the button colour and warm to the button's hover colour; the
   location row takes the same ink and does NOT react, because it is not a
   link and nothing happens when you press it.

   Driven by a knob rather than reading `--ss-c-button-bg` directly, because
   "the button's colour" is not always its background: a ghost-button skin
   has `button-bg: transparent`, and a skin whose button is a white chip with
   coloured type (studio) identifies by its `button-text`. The default is the
   background — right for most skins — and the two that identify differently
   set the knob in one line. */
.ss-contact-us .ss-contact-lines a,
.ss-contact-us .ss-contact-lines .ss-line-icon,
.ss-contact-us .ss-contact-lines .ss-contact-line-static {
	color: var(--ss-contact-line-c, var(--ss-c-button-bg));
}

.ss-contact-us .ss-contact-lines a:hover,
.ss-contact-us .ss-contact-lines a:hover .ss-line-icon {
	color: var(--ss-contact-line-hover-c, var(--ss-c-button-hover-bg));
}

/* ---- The mobile drawer -------------------------------------------------
   25px of indent on every edge (client, mobile AND tablet) — the drawer is a
   panel in its own right and does not want the page's 10px gutter. The menu
   and its CTA close up: a 35px flex gap left a hole between the last link and
   the button, and the button takes the full width of the panel so it reads as
   the drawer's action rather than a stray chip. */
@media (max-width: 1024px) {
	.ss-header-nav {
		padding: 25px;
		gap: 18px;
	}

	.ss-header-nav .ss-header-cta {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 100%;
	}
}

/* ---- A filter bar sits evenly between the hero and its grid -------------
   The bar is the first thing in the archive section, so the space above it is
   the section's own top inset while the space below was a rhythm-and-a-half —
   two unrelated numbers that read as a misalignment. The bar now carries the
   same clearance under it that the section gives it above. */
.ss-filter-bar {
	margin-bottom: var(--ss-inset-std);
}

/* ---- One logo size on a phone ------------------------------------------
   The header logo is capped off the header's own height, so a skin with a
   tall header got a tall logo on a 375px screen. Client: one standard, all
   skins. A knob, so a skin whose mark is unusually wide can still say so. */
@media (max-width: 767px) {
	.ss-header-brand img {
		max-height: var(--ss-logo-h-mobile, 40px);
	}
}

/* ---- A long word never widens the page --------------------------------
   Headings are the one place a single unbreakable word can be wider than a
   375px screen: display type at 40-96px, often uppercase, often a compound
   noun out of a client's own copy. When that happens the heading does not
   clip, it widens the DOCUMENT — every section below it inherits the extra
   width and the whole page scrolls sideways, which is the one thing
   GUIDELINES says must never happen.

   Found on rivet's blog single, where a 62px uppercase H1 put the document
   at 424px against a 375px viewport. Sizing that heading down fixes that
   page; this fixes the category of bug, on every skin and any client's copy.
   `break-word` only breaks a word that could not otherwise fit, so normal
   headlines wrap on spaces exactly as before. */
h1,
h2,
h3,
h4,
.ss-hero-title,
.ss-card-title,
.ss-cta-title {
	overflow-wrap: break-word;
}

/* ==========================================================================
   Item-spacing contract (client, 2026-09-09)

   Tablet (768-1024): 50px from the screen edge and 50px between grid
   items, so the side margin and the gaps read as ONE system — the 5vw
   gutter gave 38px at 768 beside 50px gaps, which is exactly the
   unevenness the client flagged on rivet's services grid. The bleed
   tracks must follow the gutter number or their alignment edge drifts
   off the container's.

   Mobile (≤767): bare stacked items sit 25px apart; items DRAWN AS CARDS
   (a background or border around the content — the client's definition)
   sit 20px apart AND 20px from the screen (client, 2026-09-10 round 3 —
   was 10/10). The framework default is the bare 25; a skin that paints
   its items sets the knobs:
       .ss-skin-x .ss-card-grid { --ss-item-gap-m: 20px; --ss-item-pad-m: 10px; }
   (10px pad + the 10px container gutter = the 20px card line.)
   `display: card` listings (the gradient-overlay cards) and resource
   cards (typed, drawn on every skin) take the card values unconditionally.

   Card CAROUSELS keep their own tighter track spacing by design (client)
   at every breakpoint — re-pinned to --ss-gap in both blocks below.

   Like the hero contract under this one, the blocks sit late in the file
   on purpose: the gaps they supersede live in earlier media blocks at the
   same specificity, so source order is the tiebreak.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1024px) {
	.ss-container {
		width: 100%;
		padding-inline: 50px;
	}

	/* The selector weight matches "Stacked CPT grids breathe" above —
	   (0,3,0) — and this block sits later, so the knob wins here. */
	.ss-section:not(.ss-has-carousel) .ss-card-grid {
		gap: var(--ss-item-gap-t, 50px);
	}

	.ss-has-carousel .ss-card-grid {
		gap: var(--ss-gap);
	}

	.ss-layout-carousel-bleed .ss-card-grid {
		padding-inline: 50px;
		scroll-padding-inline: 50px;
	}

	.ss-layout-carousel-bleed-right .ss-bleed-wrap {
		width: calc(100% + 50px);
	}
}

@media (max-width: 767px) {
	/* Bare stacked CPT items sit 25px from the screen INCLUDING the image
	   (the grid takes 15px over the 10px gutter) and 50px apart (client,
	   2026-09-09 round 2 — was 25). A skin that DRAWS its items moves both
	   knobs to the 20px card line (round 3 — was 10). */
	.ss-section:not(.ss-has-carousel) .ss-card-grid {
		gap: var(--ss-item-gap-m, 50px);
		padding-inline: var(--ss-item-pad-m, 15px);
	}

	/* The knobs sit on the SECTION, not the grid, so the filter bar in the
	   same section inherits the pad and its pills share the cards' left
	   edge (client: the pills sat on the 10px container line while the
	   cards below started at 20/25). */
	.ss-section.ss-display-card:not(.ss-has-carousel) {
		--ss-item-gap-m: 20px;
		--ss-item-pad-m: 10px;
	}

	/* Resource cards are drawn on every skin (typed Link/PDF/Video cards),
	   so the resources grid takes the card values even on bare skins —
	   round 3: they measured 50px apart on the bare ones. */
	.ss-section.ss-resources-archive-grid:not(.ss-has-carousel) {
		--ss-item-gap-m: 20px;
		--ss-item-pad-m: 10px;
	}

	/* The pills line up with the first card's edge — same knob, same line. */
	.ss-filter-bar {
		padding-inline: var(--ss-item-pad-m, 15px);
	}

	/* Carousel cards follow the same edge rule: a bare card's content
	   starts 25px in. Carded skins zero the pad the same way. */
	.ss-has-carousel .ss-card-grid {
		gap: var(--ss-gap);
		padding-inline: var(--ss-item-pad-m, 15px);
		scroll-padding-inline: var(--ss-item-pad-m, 15px);
	}

	/* A DRAWN panel inside a padded text column pulls back to the card
	   line. The wrapper rule hands the 2col column 15px so BARE copy
	   lands at 25 — but the outline card is a bordered box carrying its
	   own 30px of padding, and the card rule wants the BOX on the 20px
	   card line (round 3 — was 10), not 25. Its text still sits 50px in. */
	.ss-about .ss-outline-card {
		margin-inline: -5px;
	}

	/* A photo that STACKS ON TOP of its section on a phone (the framework
	   puts every 2col's media first here) frames like a card: 10px above
	   it, matching its 10px sides — not the section's full 50px top pad
	   (client, 2026-09-09). Keyed to a 2col that is the container's FIRST
	   block, so a section whose intro renders above the columns keeps its
	   normal pad; heroes are first-child and excluded — their contract
	   owns them. The copy below the photo keeps its own spacing. */
	.ss-main > .ss-section:not(:first-child):has(> .ss-container > .ss-2col:first-child .ss-col-media) {
		padding-top: 10px;
	}
}

/* ==========================================================================
   Archive + filter spacing (client, 2026-09-10 round 3)

   Filtered archives (blog, resources, case studies): the hero band edge,
   the pills, and the first item read as one measured stack — hero → 50 →
   pills → 50 → grid on desktop, 25s on tablet and phone. Before this the
   bar took a full section inset on BOTH sides (80/80 on desktop): the
   generic `.ss-filter-bar { margin-bottom: var(--ss-inset-std) }` rule
   earlier in the file still serves the Brand Kit pills; these scoped
   rules out-rank it for the archive sections only.

   Archive LISTING sections on a phone: vertical padding equals the side
   value — 25 for bare listings, 20 for carded ones (the skin that draws
   its cards sets `--ss-archive-pad-m: 20px`, mirroring the card knobs).
   Archive HERO bands keep their own contract (client: listing only).

   Order inside this block matters: the filtered-archive padding-top rules
   come AFTER the phone vertical rule at the same weight so the 25 above
   the pills survives on carded (20px) archives.
   ========================================================================== */

.ss-main .ss-section[class*="-archive-grid"] .ss-filter-bar,
.ss-main .ss-section.ss-blog-posts .ss-filter-bar {
	margin-bottom: 50px;
}

.ss-main .ss-section[class*="-archive-grid"]:has(.ss-filter-bar),
.ss-main .ss-section.ss-blog-posts:has(.ss-filter-bar) {
	padding-top: 50px;
}

@media (max-width: 1024px) {
	.ss-main .ss-section[class*="-archive-grid"] .ss-filter-bar,
	.ss-main .ss-section.ss-blog-posts .ss-filter-bar {
		margin-bottom: 25px;
	}

	.ss-main .ss-section[class*="-archive-grid"]:has(.ss-filter-bar),
	.ss-main .ss-section.ss-blog-posts:has(.ss-filter-bar) {
		padding-top: 25px;
	}
}

@media (max-width: 767px) {
	.ss-main .ss-section[class*="-archive-grid"],
	.ss-main .ss-section.ss-blog-posts {
		padding-block: var(--ss-archive-pad-m, 25px);
	}

	/* display:card listings and the always-drawn resources grid take the
	   20px card value without a skin knob. */
	.ss-main .ss-section.ss-display-card[class*="-archive-grid"],
	.ss-main .ss-section.ss-display-card.ss-blog-posts,
	.ss-main .ss-section.ss-resources-archive-grid {
		--ss-archive-pad-m: 20px;
	}

	/* Filtered archives: 25 above the pills wins over the vertical rule. */
	.ss-main .ss-section[class*="-archive-grid"]:has(.ss-filter-bar),
	.ss-main .ss-section.ss-blog-posts:has(.ss-filter-bar) {
		padding-top: 25px;
	}

	/* Contact: the drawn form card keeps its tight line — 10px below it,
	   matching its 10px sides (client; the explicit exception to the 20px
	   drawn-card edge). */
	.ss-section.ss-contact-us {
		padding-bottom: 10px;
	}
}

/* ==========================================================================
   Hero spacing contract (client, 2026-09-09)

   One set of numbers for every hero on every skin:

     desktop   home 100px above/below, every other page 75px
     tablet    50px all round
     mobile    50px above/below, 25px at the sides

   These are VISIBLE numbers — the gap you can measure between the header's
   bottom edge and the first line of hero copy. That distinction is the whole
   point of the block: a skin with an OVERLAY header has the bar sitting on
   top of the hero band, so the band has to carry the header's height on top
   of the spacing or the copy lands underneath the menu. Adding the two is
   what makes the visible gap equal the spec; using the spec alone would tuck
   the copy under the header, and using a padding tuned by eye on top of the
   header height is what produced the doubled-looking gaps this replaces
   (160px above a carepoint hero, 80–114px below a rivet one).

   It lives at the END of base.css deliberately. Several of the rules it
   supersedes are same-weight selectors resolved by source order — the
   interior-hero band contract, the inset tiers, the overlay-header rule — so
   this has to come after all of them. Moving it earlier silently hands the
   heroes back to whichever of those rules is last.
   ========================================================================== */

:root {
	--ss-hero-pad-home: 100px;
	--ss-hero-pad-page: 75px;
	--ss-hero-pad-tablet: 50px;
	--ss-hero-pad-mobile: 50px;
}

.ss-hero,
.ss-cpt-hero,
.ss-services-hero,
.ss-industries-hero,
.ss-resources-hero,
.ss-case-studies-hero,
.ss-products-hero,
.ss-events-hero,
.ss-blog-hero,
.ss-section:has(> .ss-hero-band-bg) {
	padding-block: var(--ss-hero-pad-page);
}

body.home .ss-hero {
	padding-block: var(--ss-hero-pad-home);
}

/* An overlay header sits ON the first band, so that band carries the header's
   height as well and the visible gap comes out at the spec. Gated on
   `ss-hero-first`, which is set only when the view actually opens on a
   full-bleed photo band — a page whose flow starts with anything else keeps a
   normal header and wants no offset. */
body.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
	padding-top: calc(var(--ss-hero-pad-page) + var(--ss-header-h));
}

body.home.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
	padding-top: calc(var(--ss-hero-pad-home) + var(--ss-header-h));
}

@media (max-width: 1024px) {
	.ss-hero,
	.ss-cpt-hero,
	.ss-services-hero,
	.ss-industries-hero,
	.ss-resources-hero,
	.ss-case-studies-hero,
	.ss-products-hero,
	.ss-events-hero,
	.ss-blog-hero,
	.ss-section:has(> .ss-hero-band-bg),
	body.home .ss-hero {
		padding-block: var(--ss-hero-pad-tablet);
	}

	body.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child,
	body.home.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
		padding-top: calc(var(--ss-hero-pad-tablet) + var(--ss-header-h));
	}

	/* 50px all round: the sides come from the hero's own container, not the
	   page gutter, so a hero is inset further than the card grid beneath it. */
	.ss-hero > .ss-container,
	.ss-cpt-hero > .ss-container,
	.ss-services-hero > .ss-container,
	.ss-industries-hero > .ss-container,
	.ss-resources-hero > .ss-container,
	.ss-case-studies-hero > .ss-container,
	.ss-products-hero > .ss-container,
	.ss-events-hero > .ss-container,
	.ss-blog-hero > .ss-container,
	.ss-section:has(> .ss-hero-band-bg) > .ss-container {
		width: 100%;
		padding-inline: var(--ss-hero-pad-tablet);
	}
}

@media (max-width: 767px) {
	.ss-hero,
	.ss-cpt-hero,
	.ss-services-hero,
	.ss-industries-hero,
	.ss-resources-hero,
	.ss-case-studies-hero,
	.ss-products-hero,
	.ss-events-hero,
	.ss-blog-hero,
	.ss-section:has(> .ss-hero-band-bg),
	body.home .ss-hero {
		padding-block: var(--ss-hero-pad-mobile);
	}

	body.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child,
	body.home.ss-header-overlay.ss-hero-first .ss-main > .ss-section:first-child {
		padding-top: calc(var(--ss-hero-pad-mobile) + var(--ss-header-h));
	}

	.ss-hero > .ss-container,
	.ss-cpt-hero > .ss-container,
	.ss-services-hero > .ss-container,
	.ss-industries-hero > .ss-container,
	.ss-resources-hero > .ss-container,
	.ss-case-studies-hero > .ss-container,
	.ss-products-hero > .ss-container,
	.ss-events-hero > .ss-container,
	.ss-blog-hero > .ss-container,
	.ss-section:has(> .ss-hero-band-bg) > .ss-container {
		width: 100%;
		padding-inline: 25px;
	}
}

/* ==========================================================================
   Device mockup — parts/mockup.php. A framework primitive (the showcase
   slider and the project hero both render it), so it lives here rather
   than in one section's sheet, which only loads when that section is
   composed.
   ========================================================================== */

.ss-mockup {
	position: relative;
	width: 100%;
	/* Laptop 86% wide (1560x998 → 55% of the width tall); the phone is 30%
	   of the laptop's width, starts 70.5% across and hangs ~8% of the
	   laptop's height below its base, so the stage is ~59.4% tall. */
	aspect-ratio: 1000 / 594;
}

.ss-mockup-device {
	position: absolute;
}

.ss-mockup-laptop {
	left: 0;
	top: 0;
	width: 86%;
}

.ss-mockup-phone {
	left: 70.5%;
	bottom: 0;
	width: 25.8%;
	z-index: 3;
	filter: drop-shadow(-6px 10px 18px rgba(0, 0, 0, 0.18));
}

.ss-mockup-phone.is-alone {
	position: relative;
	width: 40%;
	margin-inline: auto;
}

.ss-mockup-frame {
	position: relative;
	display: block;
	width: 100%;
	height: auto;
	z-index: 2;
	pointer-events: none;
}

.ss-mockup-screen {
	position: absolute;
	overflow: hidden;
	z-index: 1;
	background: #fff;
}

/* Measured transparent holes of assets/img/frame-laptop.png (1560x998)
   and frame-phone.png (525x986), overshot by a hair so the screenshot
   runs under the bezel rather than leaving a sliver of screen ground.
   The phone's hole is measured BESIDE the notch: the page starts at the
   top of the glass and the notch simply covers it. */
.ss-mockup-laptop .ss-mockup-screen {
	left: 13.8%;
	top: 3.9%;
	width: 70.4%;
	height: 63.3%;
}

.ss-mockup-phone .ss-mockup-screen {
	left: 7.8%;
	top: 2.8%;
	width: 81%;
	height: 93.4%;
	border-radius: 12% / 6%;
}

.ss-mockup-screen img {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: auto;
	max-width: none;
	transform: translateY(0);
	transition: top 7s linear, transform 7s linear;
}

/* Hover: the page scrolls to its bottom edge (top:100% + translateY(-100%)
   parks the image's bottom on the screen's bottom whatever its height). */
.ss-mockup:hover .ss-mockup-screen img,
.ss-showcase-media:hover .ss-mockup-screen img,
.ss-showcase-media:focus-visible .ss-mockup-screen img {
	top: 100%;
	transform: translateY(-100%);
}

@media (prefers-reduced-motion: reduce) {
	.ss-mockup-screen img {
		transition: none;
	}
}

/* The mockup's hover hint: the scroll-on-hover only exists for a pointer
   that can hover, so the line is hidden everywhere else rather than
   promising a gesture the device does not have. */
.ss-mockup-hint {
	margin: 14px 0 0;
	text-align: center;
	font-size: 14px;
	font-style: italic;
	color: var(--ss-c-text-muted);
}

@media (max-width: 1024px), (hover: none) {
	.ss-mockup-hint {
		display: none;
	}
}
