/* ==========================================================================
   SaaScada — Ascent (Theme 1a) global CSS
   Covers everything theme.json settings can't express: keyframe animations,
   responsive grid collapses, the hero/header/footer interaction mechanics,
   and the Component States rules (hover-gating, focus-visible, disabled,
   tap targets). Loaded via a <link> tag in parts/header.html because PHP
   (wp_enqueue_style) is currently blocked on this host — see WordPress
   Change Log for the PHP-write blocker note. Move this to a proper enqueue
   once PHP access is restored.
   ========================================================================== */

:root {
  --c-midnight:#101436; --c-plum:#3A1A4E; --c-coral:#FF6B4A; --c-coral-hover:#EC5330; --c-coral-active:#E4522F;
  --c-amber:#FFC46B; --c-violet:#6D5DF6; --c-violet-hover:#5A49E8; --c-violet-active:#4C3DD6;
  --c-ink:#171233; --c-slate:#4E4866; --c-muted:#756F8A;
  --c-paper:#FFFFFF; --c-mist:#FAFAFC;
  --radius-sm:4px; --radius-md:10px; --radius-lg:16px; --radius-xl:24px;
  --sp-micro:4px; --sp-xs:8px; --sp-sm:12px; --sp-md:16px; --sp-lg:32px; --sp-xl:48px; --sp-2xl:64px; --sp-3xl:96px; --sp-4xl:128px;
  --bp-mobile:640px; --bp-tablet:1023px; --bp-desktop:1439px;
  --w-video-promo:947px;
  --sp-testimonial-gap:80px;
}

/* ---------- base / resets ---------- */
* { box-sizing: border-box; }
/* Fixes a site-wide 9px horizontal-scroll artifact on every page using the
   .alignfull full-bleed technique (calc(50% - 50vw) margins, see .saas-cta-final.alignfull
   and .saas-page-banner.alignfull below). Root cause: the 100vw unit is measured against
   the viewport including the vertical scrollbar's own width, but the page's actual visible
   area (documentElement.clientWidth) excludes it — so 100vw is wider than clientWidth by
   exactly the scrollbar's width, and that sliver renders as horizontal overflow. Confirmed
   present on Careers (26 July, oldest .alignfull instance) and all 5 dark banners (5 August)
   equally, so this is a fix to the shared technique, not to any one component. overflow-x:
   hidden simply clips that already off-screen sliver; it does not affect any in-view layout,
   vertical scrolling, or the full-bleed elements' own appearance. Added 5 August 2026. */
html, body { overflow-x: hidden; }
/* GENERAL FIX for the recurring "full-width section renders boxed, not edge-to-edge"
   bug (hit repeatedly across this build: Careers on 26 July, the CTA band, the page
   banners, and now the Platform video promo, always the same root cause). This
   theme doesn't load WordPress core's block-library CSS, so the block editor's "Full
   width" setting (align:"full" -> the .alignfull class) has NO effect on its own here.
   Normally core's own CSS gives every .alignfull block the calc(50% - 50vw) breakout
   for free; on this theme that breakout only ever existed as one-off rules hand-written
   per component (see .saas-cta-final.alignfull and .saas-page-banner.alignfull below),
   so every new full-width section needed its own matching CSS rule added here, and it
   was easy to forget. That's exactly what happened on the Platform page's video promo
   section: align:"full" was set correctly in the block editor, but no matching CSS
   rule existed for its classes, so it just sat at the normal content width.
   This rule fixes the root cause instead of the symptom: it makes .alignfull work
   universally for any top-level block in the page/post content column, matching how
   WordPress core behaves by default. THE GENERAL RULE GOING FORWARD: set a section to
   "Full width" in the block editor and it will render full width, full stop, no new
   CSS needed, for this or any future section. The two older component-specific rules
   below are left in place (harmless: same computed result, just more specific) rather
   than removed. Added 10 August 2026. */
.entry-content > .alignfull { width:100vw; max-width:100vw; margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw); }
img { max-width: 100%; height: auto; }
.saas-on-dark, .saas-on-dark p { color: var(--c-paper); }
/* Core Philosophy is a real Gutenberg group block (columns + video + heading), unlike the
   raw-HTML dark sections (Segments/Use Cases/Ecosystem/Client stories) which set their own
   background via a one-off inline style. Kept as a shared class instead of an inline style
   here so the block's className stays in sync with its saved attributes (see Change Log
   entry 21 — a mismatch here is exactly what broke Site Editor validation last time).
   h2/h3/list colour on dark sections was previously only ever set via one-off inline
   overrides per section; generalised into the cascade so future dark sections (like this
   one) don't need to touch individual heading/list block attributes to go dark. Added 24
   July 2026 (Phase 2e). */
.saas-dark-gradient { background: linear-gradient(135deg,#101436 0%,#241645 48%,#3A1A4E 100%); }
.saas-on-dark h2, .saas-on-dark h3 { color: var(--c-paper); }
.saas-on-dark ul { color: rgba(255,255,255,0.82); }
/* Angled section divider, matching "Homepage - Theme 1a - Full (standalone)" exactly:
   a mostly flat top and bottom, each with a small triangular notch — an "uptick" cut
   into the top-left corner, a "downtick" cut into the bottom-right corner — plus a long
   gentle diagonal spanning the rest of each edge. The top edge rises left-to-right, the
   bottom edge falls left-to-right, so each section reads as a wedge rather than a
   parallel-sided tilt. Previously a single plain 4-point diagonal, always sloping the
   same way (bottom-left to top-right) with no notches at all — replaced 23 July 2026 to
   match the confirmed mockup's exact clip-path values (Segments, Use Cases, Ecosystem
   sections; hero and the final pre-footer CTA each have their own variant, see below). */
.saas-angled { position: relative; clip-path: polygon(0 0, 10% 62px, 100% 0, 100% calc(100% - 62px), 90% 100%, 0 calc(100% - 62px)); }
.saas-eyebrow { font-size: 14px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--c-violet); margin-bottom: var(--sp-sm); }
.saas-on-dark .saas-eyebrow { color: var(--c-amber); }

/* ---------- shared section content-width wrapper ----------
   Every homepage section converges on the same 1200px content column, 64px side
   padding and 96px vertical padding (a couple of "tighter" sections use 64px
   vertical instead). Until 24 July 2026 this was three inline style declarations
   copy-pasted into every section's own HTML rather than one shared rule — which is
   exactly how the pre-footer CTA section ended up missing an earlier width fix
   applied to its siblings (see Change Log Entries 31 and 36): there was no single
   place that "content width" lived, just several hand-typed copies of the same
   numbers. Centralised here so every section reads from one source and a future
   change (or fix) only has to happen once.
   Usage: full-bleed dark sections (background needs to span edge to edge) apply
   this class to an inner wrapper <div>, so the outer <section> keeps the
   background/clip-path and this div only constrains the content. Plain light
   sections with no separate background layer apply it directly to the <section>
   itself. Add "is-tight" alongside it for the couple of sections that use 64px
   vertical padding instead of the standard 96px.
   Platform and Core Philosophy are the two exceptions: they're built as real
   Gutenberg blocks using WordPress's own layout/spacing attributes (contentSize
   1200px, padding 96px/64px) rather than raw HTML, so they already have a single
   source of truth of their own and don't use this class — but they resolve to the
   same visual width, so the page still reads as one consistent column throughout. */
.saas-content-width { max-width:1200px; margin:0 auto; padding:var(--sp-3xl) var(--sp-2xl); }
.saas-content-width.is-tight { padding-top:var(--sp-2xl); padding-bottom:var(--sp-2xl); }
@media (max-width:1023px) {
  .saas-content-width { padding-left:var(--sp-xl); padding-right:var(--sp-xl); }
}
@media (max-width:640px) {
  .saas-content-width { padding-top:var(--sp-2xl); padding-bottom:var(--sp-2xl); padding-left:var(--sp-lg); padding-right:var(--sp-lg); }
  .saas-content-width.is-tight { padding-top:var(--sp-xl); padding-bottom:var(--sp-xl); }
}

/* Resources page (14 August 2026): the gap between the "Ask us anything" block and the
   Category/Topic filters below it is the sum of two stacked paddings, the ask block's own
   bottom padding (.is-tight, 64px) plus the next block's top padding (plain
   .saas-content-width, 96px) = 160px. Jeremy asked for this specific gap halved. Scoped to
   these two page-717-only classes rather than editing .saas-content-width/.is-tight
   directly, which are reused across the whole site and would shift vertical rhythm
   everywhere else. Each side's padding is halved individually (32px + 48px = 80px), same
   proportions carried through the 640px breakpoint (24px + 32px = 56px, half of 112px). */
.saas-content-width.is-tight.saas-ask-section { padding-bottom:calc(var(--sp-2xl) / 2); }
.saas-resources-directory-wrap { padding-top:calc(var(--sp-3xl) / 2); }
@media (max-width:640px) {
  .saas-content-width.is-tight.saas-ask-section { padding-bottom:calc(var(--sp-xl) / 2); }
  .saas-resources-directory-wrap { padding-top:calc(var(--sp-2xl) / 2); }
}

/* ---------- component states (buttons / links / tabs) ---------- */
.saas-btn { display:inline-flex; align-items:center; justify-content:center; gap:8px; font-family:inherit; font-size:16px; font-weight:600; padding:12px 22px; border-radius:var(--radius-md); border:none; text-decoration:none; cursor:pointer; transition:background 150ms ease, transform 120ms ease, box-shadow 150ms ease; min-height:44px; }
.saas-btn-primary { color:var(--c-ink); background:var(--c-coral); }
.saas-btn-primary:active { background:var(--c-coral-active); transform:scale(0.96); }
.saas-btn-secondary { color:#fff; background:var(--c-violet); }
.saas-btn-secondary:active { background:var(--c-violet-active); transform:scale(0.96); }
.saas-btn-tertiary { color:var(--c-ink); background:transparent; border:1.5px solid rgba(23,18,51,0.28); }
.saas-btn-tertiary:active { background:rgba(23,18,51,0.1); transform:scale(0.96); }
@media (hover:hover) and (pointer:fine) {
  .saas-btn-primary:hover { background:var(--c-coral-hover); }
  .saas-btn-secondary:hover { background:var(--c-violet-hover); }
  .saas-btn-tertiary:hover { background:rgba(23,18,51,0.06); }
}
.saas-btn:focus-visible { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 5px var(--c-violet); }
.saas-on-dark .saas-btn:focus-visible { box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
.saas-btn[aria-disabled="true"], .saas-btn:disabled { opacity:0.4; cursor:not-allowed; pointer-events:none; }

a.saas-link { font-size:15px; font-weight:600; color:var(--c-violet); text-decoration:none; padding:2px 4px; border-radius:4px; min-height:44px; display:inline-flex; align-items:center; }
@media (hover:hover) and (pointer:fine) { a.saas-link:hover { color:var(--c-ink); text-decoration:underline; text-underline-offset:3px; } }
a.saas-link:active { color:var(--c-ink); }
a.saas-link:focus-visible { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 5px var(--c-violet); }

/* ---------- find-out-more / card links ---------- */
.saas-card { display:flex; flex-direction:column; }
.saas-card h3 { font-size:26px; font-weight:600; margin:0 0 var(--sp-sm); }
.saas-card p { color:var(--c-slate); margin:0 0 var(--sp-sm); }
.saas-on-dark .saas-card p { color:rgba(255,255,255,0.78); }

/* Video caption (Core Philosophy): previously just a plain paragraph sitting at the end of
   the text column, disconnected from the video it was actually describing. Moved directly
   under the video block itself and styled down (smaller size, muted colour, tight top
   margin) so it reads as a caption rather than body copy. Kept usable on either a light or
   dark section, since the light default (var(--c-muted)) would be invisible if this pattern
   is ever reused somewhere still on a white background. Added 24 July 2026 (Phase 2e). */
.saas-video-caption { font-size:14px; line-height:1.5; margin-top:14px; color:var(--c-muted); }
.saas-on-dark .saas-video-caption { color:rgba(255,255,255,0.65); }

/* Platform section's two-pillar layout: the second column ("Products you flex") sits
   64px lower than the first, matching the confirmed mockup's staggered pair. Targeted via
   the Group block's own className attribute (saas-platform-section) rather than an
   inline style on the column, so the block's saved attributes and rendered markup stay in
   sync — an inline style added directly to a wp:column wrapper without a matching
   attribute would reintroduce the same block-validation mismatch fixed at Change Log
   entry 21. Added 23 July 2026 (Phase 2e). */
@media (min-width:641px) {
  .saas-platform-section .wp-block-column:nth-child(2) { margin-top:64px; }
}

/* ---------- testimonials (Testimonial Card / Block) ----------
   Container-free by default: checked every testimonial instance in the confirmed
   "Homepage - Theme 1a - Full" mockup (paired with a stat, paired with a CTA heading,
   paired with a button, and standalone) and none of them carry a visible box — only the
   stat/CTA callout beside them does. Previously every .saas-testimonial had a background,
   padding and border-radius regardless of context. The box itself is kept as an opt-in
   "is-boxed" modifier (unused on the homepage currently) so a genuinely boxed testimonial
   remains available for a future page without re-deriving these values. Changed 23 July
   2026 (Phase 2e). */
.saas-testimonial { display:flex; flex-direction:column; justify-content:center; height:100%; }
.saas-testimonial blockquote { margin:0; font-size:23px; font-weight:500; line-height:1.5; letter-spacing:-0.01em; }
.saas-testimonial figcaption { font-size:15px; margin-top:22px; }
.saas-testimonial.is-light blockquote { color:var(--c-ink); }
.saas-testimonial.is-light figcaption { color:var(--c-muted); }
.saas-testimonial.is-dark blockquote { color:#fff; }
.saas-testimonial.is-dark figcaption { color:var(--c-amber); }
.saas-testimonial.is-boxed { padding:44px 46px; border-radius:22px; }
.saas-testimonial.is-boxed.is-light { background:var(--c-mist); box-shadow:inset 0 0 0 1px rgba(23,18,51,0.08); }
.saas-testimonial.is-boxed.is-dark { background:
    radial-gradient(95% 130% at 90% 104%, rgba(255,138,88,0.5), transparent 54%),
    radial-gradient(70% 80% at 4% -6%, rgba(109,93,246,0.34), transparent 55%),
    linear-gradient(140deg, var(--c-midnight) 0%, #241645 52%, var(--c-plum) 100%); }

/* ---------- non-homepage testimonial standard: centred quote, right-aligned attribution ----------
   Standardised 6 August 2026, promoting the one-off inline treatment first applied to the
   Stakeholders page (centred quote, right-aligned attribution, tighter 8px gap to the
   attribution vs the base 22px) into the shared .saas-testimonial rule, so it's now the
   standing default for every testimonial on any page other than the homepage, including
   future pages, without needing an inline style each time.
   The homepage's own testimonials keep their original left-aligned, paired-with-a-stat/CTA
   layout — a genuinely different context, not an oversight — via the .is-homepage exception
   class below, applied to every testimonial instance in front-page.html. */
.saas-testimonial { text-align:center; }
.saas-testimonial figcaption { text-align:right; margin-top:8px; }
.saas-testimonial.is-homepage { text-align:left; }
.saas-testimonial.is-homepage figcaption { text-align:left; margin-top:22px; }

/* ---------- Testimonial top spacing -- SITE-WIDE STANDING RULE, updated 10 August 2026. ----------
   Superseded the 6 August adjacency-only rule (`.saas-key-callout + .saas-testimonial`) and
   the 7 August Cloud Native page-specific override below: Jeremy asked for the same gap above
   every testimonial that sits directly in a page's content column, regardless of whether the
   immediately preceding element is body copy (a plain paragraph) or a `.saas-key-callout` --
   one standard space, one place to change it. Scoped to a direct-child selector so it reaches
   every single-testimonial instance (Solutions, Transactional, Segments, Stakeholders, Use
   Cases, Become a Partner, Cloud Native) without affecting the Clients page's testimonial
   pyramid/duo groups, which nest their figures inside their own wrapper divs and manage their
   own spacing. Value (80px) carried over unchanged from the rule(s) this replaces. To change
   the gap everywhere at once, edit --sp-testimonial-gap in :root. */
.saas-content-width > .saas-testimonial { margin-top:var(--sp-testimonial-gap); }
/* align-items:center (was stretch): Jeremy flagged that wherever a testimonial sits beside
   a stat/CTA callout, both were starting flush at the same top edge rather than reading as
   a balanced pair — stretch was forcing both flex items to the row's full height, which is
   only visible on the boxed stat-strip since testimonials carry no background of their own.
   Centring instead means the shorter of the two sits vertically centred against the taller
   one. Applies site-wide to every current and future testimonial/stat-strip pairing (one
   section, Why SaaScada, already had this as a one-off inline override — now the default,
   so that override is redundant but harmless). Changed 23 July 2026 (Phase 2e). */
.saas-tb-row { display:flex; align-items:center; flex-wrap:wrap; gap:36px; }
.saas-tb-row > * { flex:1 1 340px; }

/* ---------- Clients page: testimonial "pyramid" and duo rows ----------
   Bespoke to the Clients page (/why-saascada/clients/): one testimonial centred on its
   own, two more side by side beneath it (a "building pyramid"), then later on the page a
   plain two-up row. Not a new block type, just two small layouts built from the existing
   .saas-testimonial component, targeted via each group's own className rather than an
   inline style, matching the .saas-platform-section approach elsewhere in this file. Added
   7 August 2026. */
.saas-testimonial-pyramid { display:flex; flex-direction:column; align-items:center; gap:var(--sp-2xl); }
.saas-testimonial-pyramid-top { max-width:640px; }
.saas-testimonial-pyramid-row { display:flex; flex-wrap:wrap; justify-content:center; gap:36px; width:100%; }
.saas-testimonial-pyramid-row > .saas-testimonial,
.saas-testimonial-duo > .saas-testimonial { flex:1 1 340px; max-width:480px; }
.saas-testimonial-duo { display:flex; flex-wrap:wrap; justify-content:center; gap:36px; margin-top:var(--sp-2xl); }
@media (max-width:640px) {
  .saas-testimonial-pyramid-row, .saas-testimonial-duo { flex-direction:column; align-items:center; }
}

/* ---------- stat / CTA strip ----------
   Top padding reduced from a flat 48px to 32px: Jeremy flagged these containers as feeling
   too bulky, specifically too much empty space between the container's top edge and its
   first line of text. Kept asymmetric (32 top / 52 sides / 48 bottom) rather than reducing
   all four sides evenly — the bottom and sides still need to hold their own next to the
   CTA button and the container's rounded corners, and a heading's own line-height already
   carries some visual space above its cap-height, so the top edge reads correctly balanced
   at a smaller value than the other three sides. Changed 23 July 2026 (Phase 2e). */
.saas-stat-strip { border-radius:22px; padding:32px 52px 48px; }
.saas-stat-strip .stat-num { font-size:52px; font-weight:700; line-height:1; }
.saas-stat-strip .stat-label { font-size:20px; font-weight:600; color:var(--c-amber); }
/* .saas-stat-strip.saas-on-light removed 10 August 2026: added earlier the same day as a
   light-page counterpart to .saas-on-dark for the video/graphic card on pages with a pale
   banner, then Jeremy asked for the dark Ascent Glow treatment on that card instead (its
   only use, the Data You Own page). No page uses this rule any longer, so it's removed
   rather than left as dead code. */

/* ---------- responsive grids ---------- */
.saas-grid { display:grid; gap:var(--sp-lg); }
.saas-grid-5 { grid-template-columns:repeat(5,1fr); }
.saas-grid-4 { grid-template-columns:repeat(4,1fr); }
.saas-grid-3 { grid-template-columns:repeat(3,1fr); }
.saas-grid-6 { grid-template-columns:repeat(3,1fr); }
.saas-grid-8 { grid-template-columns:repeat(4,1fr); }
@media (max-width:1023px) {
  .saas-grid-5, .saas-grid-4, .saas-grid-3, .saas-grid-6, .saas-grid-8 { grid-template-columns:repeat(2,1fr); }
}
@media (max-width:640px) {
  .saas-grid-5, .saas-grid-4, .saas-grid-3, .saas-grid-6, .saas-grid-8 { grid-template-columns:1fr; }
  .saas-hero-inner { flex-direction:column !important; align-items:stretch; }
  .saas-hero-visual { order:2; margin-top:var(--sp-lg); width:100%; }
  .saas-hero-copy { order:1; }
}
/* WordPress core's global styles give every child of a "flow"-layout Group block an
   automatic 24px top margin, with the first child alone reset to 0 (:where(.is-layout-flow)
   > *, and > :first-child). These grids are Group blocks left on the default flow layout
   type, then turned into a real CSS grid here — the leftover margin is invisible in normal
   flow but, once every item sits on the same grid row, it pushes every item down except the
   first, making the first item look "raised" above its siblings. Found 5 August 2026 on the
   Management Team Leadership row (first card) and the Platform page's "On a Winning
   Platform" .saas-grid-5 section (first column) — same mechanism, same fix. Spacing between
   items is already handled by this grid's own `gap`, so the margin is pure redundant
   WordPress default; resetting it to 0 removes the conflict without affecting layout. */
.saas-grid > *, .saas-team-grid > * { margin-top:0; }

/* ---------- section headers ("Outpace your market...") ----------
   theme.json defines a 40px "H2" preset but nothing actually referenced it, so these
   headings were rendering at the browser's unstyled default (roughly 25-32px given the
   17px body size) rather than a set size. Values below (46px / 700 / 1.06) match the
   confirmed "Homepage - Theme 1a - Full" mockup exactly. max-width is set per section
   inline, since the mockup's own value varies section to section (640-720px) — that
   width is what forces the natural two-line wrap, rather than a manual line break.
   Covers the seven "Outpace your market..." headings (Platform, Segments, Products, Use
   Cases, Why SaaScada, Ecosystem, Stakeholders). Deliberately excludes the differently
   worded final CTA heading ("Ready to outpace...", already its own 50px treatment) and
   the Core Philosophy heading, neither of which follow this pattern in the mockup either.
   Added 23 July 2026 (Phase 2e). */
.saas-h2-outpace { font-size:46px; font-weight:700; line-height:1.06; margin-top:14px; }
/* .saas-h2-platform removed 29 July 2026: the Platform section was rebuilt as plain HTML
   (matching every other homepage section), which removes the WordPress core auto-margin
   behaviour this rule existed to override. See Project-Status.md/Change Log for the full
   diagnosis and rebuild. */

/* ---------- card colour flash + row/column offset ----------
   A small 3px accent-colour bar above each card's heading ("colour flash"), plus a
   staggered vertical offset across the row or grid so cards read as a wave rather than
   sitting flush ("offset") — both matching the confirmed mockup exactly. Previously
   .saas-card had neither: no flash element and no offset at all. The colour/offset
   sequence isn't a single repeating formula in every section (e.g. Core Use Cases'
   4th card breaks the colour pattern its column would otherwise suggest), so each card
   is addressed directly by its nth-child position against the mockup's own values,
   rather than an approximated generic rule. Added 23 July 2026 (Phase 2e). */
.saas-card-flash { display:block; width:34px; height:3px; border-radius:2px; margin-bottom:var(--sp-sm); }

/* Core Segments — 5 cards, flex row */
#segments .saas-card:nth-child(1) .saas-card-flash { background:var(--c-amber); }
#segments .saas-card:nth-child(2) .saas-card-flash { background:var(--c-coral); }
#segments .saas-card:nth-child(3) .saas-card-flash { background:var(--c-violet); }
#segments .saas-card:nth-child(4) .saas-card-flash { background:var(--c-amber); }
#segments .saas-card:nth-child(5) .saas-card-flash { background:var(--c-coral); }
#segments .saas-card:nth-child(2), #segments .saas-card:nth-child(4) { margin-top:40px; }

/* Banking Products — 4 cards, flex row; flash bar is 28px here (sits beside a glyph icon) */
#products .saas-card-flash { width:28px; }
#products .saas-card:nth-child(1) .saas-card-flash { background:var(--c-violet); }
#products .saas-card:nth-child(2) .saas-card-flash { background:var(--c-coral); }
#products .saas-card:nth-child(3) .saas-card-flash { background:var(--c-amber); }
#products .saas-card:nth-child(4) .saas-card-flash { background:var(--c-plum); }
#products .saas-card:nth-child(2), #products .saas-card:nth-child(4) { margin-top:36px; }

/* Core Use Cases — 6 cards, 3-column grid; offset is per column via transform (not
   margin, since a grid row would otherwise stretch to match its tallest cell) */
#use-cases .saas-card:nth-child(1) .saas-card-flash { background:var(--c-amber); }
#use-cases .saas-card:nth-child(2) .saas-card-flash { background:var(--c-coral); }
#use-cases .saas-card:nth-child(3) .saas-card-flash { background:var(--c-violet); }
#use-cases .saas-card:nth-child(4) .saas-card-flash { background:var(--c-coral); }
#use-cases .saas-card:nth-child(5) .saas-card-flash { background:var(--c-amber); }
#use-cases .saas-card:nth-child(6) .saas-card-flash { background:var(--c-violet); }
#use-cases .saas-card:nth-child(1), #use-cases .saas-card:nth-child(4) { transform:translateY(0); }
#use-cases .saas-card:nth-child(2), #use-cases .saas-card:nth-child(5) { transform:translateY(40px); }
#use-cases .saas-card:nth-child(3), #use-cases .saas-card:nth-child(6) { transform:translateY(20px); }

/* Core Stakeholders — 8 cards, 4-column grid; colour and offset both repeat per column */
#stakeholders .saas-card:nth-child(4n+1) .saas-card-flash { background:var(--c-plum); }
#stakeholders .saas-card:nth-child(4n+2) .saas-card-flash { background:var(--c-violet); }
#stakeholders .saas-card:nth-child(4n+3) .saas-card-flash { background:var(--c-coral); }
#stakeholders .saas-card:nth-child(4n+4) .saas-card-flash { background:var(--c-amber); }
#stakeholders .saas-card:nth-child(4n+1) { transform:translateY(0); }
#stakeholders .saas-card:nth-child(4n+2) { transform:translateY(34px); }
#stakeholders .saas-card:nth-child(4n+3) { transform:translateY(17px); }
#stakeholders .saas-card:nth-child(4n+4) { transform:translateY(51px); }

/* News & Insights — 4 cards, flex row. No flash bar in the mockup here: each card's image
   placeholder carries its own accent tint instead of the flat grey all four previously
   shared, plus the same alternating-card offset used in the other four sections. */
.saas-grid-news > .saas-card:nth-child(2), .saas-grid-news > .saas-card:nth-child(4) { margin-top:32px; }
.saas-grid-news > .saas-card:nth-child(1) .saas-card-thumb { background:repeating-linear-gradient(135deg,rgba(109,93,246,0.12) 0 15px,rgba(109,93,246,0.03) 15px 30px); }
.saas-grid-news > .saas-card:nth-child(2) .saas-card-thumb { background:repeating-linear-gradient(135deg,rgba(58,26,78,0.13) 0 15px,rgba(58,26,78,0.03) 15px 30px); }
.saas-grid-news > .saas-card:nth-child(3) .saas-card-thumb { background:repeating-linear-gradient(135deg,rgba(255,138,88,0.14) 0 15px,rgba(255,138,88,0.03) 15px 30px); }
.saas-grid-news > .saas-card:nth-child(4) .saas-card-thumb { background:repeating-linear-gradient(135deg,rgba(255,196,107,0.16) 0 15px,rgba(255,196,107,0.03) 15px 30px); }

/* The mockup is a fixed-width desktop canvas and doesn't define mobile/tablet behaviour
   (consistent with how the hero links row is already handled the same way above) — reset
   the wave offsets once the grids themselves collapse below the mockup's column count,
   so cards don't end up staggered against a layout that no longer has that many columns. */
@media (max-width:1023px) {
  #segments .saas-card, #products .saas-card, #use-cases .saas-card, #stakeholders .saas-card, .saas-grid-news > .saas-card {
    margin-top:0 !important; transform:none !important;
  }
}

/* ---------- hero ---------- */
.saas-hero { position:relative; overflow:hidden; color:#fff; padding:var(--sp-4xl) var(--sp-2xl) var(--sp-3xl); background:
    radial-gradient(85% 92% at 92% 106%, rgba(255,138,88,0.55), transparent 55%),
    radial-gradient(58% 66% at 66% 96%, rgba(255,196,107,0.36), transparent 55%),
    radial-gradient(70% 80% at 8% -6%, rgba(109,93,246,0.32), transparent 55%),
    linear-gradient(135deg, var(--c-midnight) 0%, #241645 48%, var(--c-plum) 100%);
  /* Hero-specific variant of the angled divider (see .saas-angled above): flat top since
     it's the first thing on the page, diagonal+downtick bottom only. Matches the
     confirmed mockup's own Hero shape exactly. Replaced 23 July 2026 (was a plain
     diagonal sloping the opposite way, with no notch). */
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 62px), 90% 100%, 0 calc(100% - 62px)); }
.saas-hero-inner { display:flex; gap:56px; align-items:center; max-width:1200px; margin:0 auto; }
.saas-hero-copy { flex:1.3; }
.saas-hero-visual { flex:1; }
.saas-hero-graphic { position:relative; width:100%; aspect-ratio:1092/680; border-radius:24px; overflow:hidden; }
.saas-hero-frame { position:absolute; inset:0; display:block; opacity:0; }
.saas-hero-frame img { display:block; width:100%; height:100%; object-fit:cover; }
.saas-hero-frame-1 { opacity:1; }
.saas-hero-frame-2 { animation:saasHeroFrame2 0.5s ease-in-out 2.25s 1 forwards; }
.saas-hero-frame-3 { visibility:hidden; animation:saasHeroFrame3 0.5s ease-in-out 4.25s 1 forwards; }
/* One-way build, no cross-fade: frame 1 is visible from the start (it's part of
   the hero's own entrance), then frame 2 and frame 3 each fade in once and stay,
   never fading back out. Because the layer underneath is always already fully
   opaque, there is no moment where nothing is painted -- this is what removes
   the previous cross-fade's momentary dark flicker, rather than just papering
   over it. Timed to start only after the rest of the hero (copy, links, badges)
   has finished its own entrance animation at ~1.75s, so the image build reads
   as a distinct second wave of attention instead of competing with the text
   for it: a 0.5s beat, a 0.5s fade to frame 2, a 1.5s dwell so the change
   registers, a 0.5s fade to frame 3, which then settles permanently as the
   clickable frame 3 link. */
@keyframes saasHeroFrame2 {
  0% { opacity:0; }
  100% { opacity:1; }
}
@keyframes saasHeroFrame3 {
  0% { opacity:0; visibility:hidden; }
  1% { visibility:visible; }
  100% { opacity:1; visibility:visible; }
}
.saas-hero-eyebrow { font-size:14px; font-weight:700; letter-spacing:0.16em; text-transform:uppercase; margin-bottom:20px; }
.saas-hero-eyebrow .dim { color:rgba(255,255,255,0.85); }
.saas-hero-eyebrow .gold { color:var(--c-amber); }
.saas-hero-headline { font-size:68px; font-weight:700; line-height:1; letter-spacing:-0.015em; margin:0 0 20px; }
.saas-hero-headline .accent { background:linear-gradient(100deg,var(--c-coral) 0%,var(--c-amber) 100%); -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; color:transparent; display:inline-block; }
.saas-hero-sub { font-size:25px; font-weight:300; max-width:560px; margin:0 0 18px; }
.saas-hero-trust { display:flex; align-items:center; gap:10px; font-size:15px; margin-bottom:24px; }
/* Simplified 17 August 2026: this was previously three spans ("Cloud native", a middle-dot
   separator, "Provider agnostic") inside the single a.saas-hero-link wrapper added 11 August
   2026, each coloured individually so the link's hover/active colour would still show through.
   Two reviewers read the middle dot as a hyphen and the statement stopped making sense to
   them, so it's now one plain string, "Cloud native. Provider agnostic.", inside the same
   link — no separator, no spans, colour comes from a.saas-hero-link directly below. */

a.saas-hero-link { color:#fff; text-decoration:none; outline:none; border-radius:6px; transition:color 120ms ease; white-space:nowrap; }
a.saas-hero-link:active { color:var(--c-amber); }
a.saas-hero-link:focus-visible { box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
@media (hover:hover) and (pointer:fine) { a.saas-hero-link:hover { color:var(--c-amber); } }
@media (hover:none), (pointer:coarse) { a.saas-hero-link { color:var(--c-amber); min-height:44px; min-width:44px; display:inline-flex; align-items:center; } }

.saas-hero-badges { display:flex; gap:10px; align-items:center; }
.saas-hero-badges a { display:flex; border-radius:8px; outline:none; transition:transform 150ms ease, box-shadow 150ms ease, filter 150ms ease; }
/* Without an explicit width, these images (only height was set inline) collapse to 0px
   wide inside this nested flex layout (row > link > span > img, none with a set width),
   leaving just the white pill-shaped span background visible with no badge artwork
   showing. width:auto alone doesn't resolve it here — the images now carry an explicit
   pixel width inline (matching each badge's real proportions at 22px tall). flex-shrink:0
   kept as a safety net so they can't be squeezed later. Found and fixed 22 July 2026
   (Phase 2e).

   Update, 17 August 2026: the same white-pill-no-artwork symptom reappeared, this time
   only in Safari, even with the inline width above still in place. The width was being set
   via the CSS style attribute only, with no HTML width/height attributes and no
   aspect-ratio, so Safari had nothing to reserve the image's box with before it finished
   decoding inside this nested flex layout. Both images now also carry real HTML
   width/height attributes (front-page.html) matching each badge's true proportions. This
   also caught a genuine mismatch: the SOC2 badge is a square 360x360 source image but was
   set to 26x22 (the ISO badge's ratio, not its own) — corrected to 22x22.

   Further update, same day: that width/height attribute fix turned out not to be the
   actual cause of the Safari failure (real, but a separate issue). Confirmed via Safari's
   own Web Inspector: the image was loading and decoding correctly (Safari reported its
   correct natural 360x360 size), but its laid-out box measured 0x22 — width zero. Traced
   to the site-wide `img { max-width:100%; }` rule (below, general reset for all images):
   inside this triple-nested flex layout (row > link > pill span > img), none of which has
   a width of its own, Safari resolves that 100% against zero before the real available
   width is known, capping the image at 0px regardless of its own explicit width. Chrome
   resolves the same layout without hitting this. Confirmed live in Safari's inspector by
   disabling max-width on this element, which made both badges appear immediately.
   max-width:none added below to cancel the site-wide rule for these two images only,
   which is safe since they are fixed-size icons, never meant to shrink responsively. */
.saas-hero-badges img { flex-shrink:0; display:block; max-width:none; }
@media (hover:hover) and (pointer:fine) { .saas-hero-badges a:hover { transform:translateY(-2px); filter:brightness(1.06); } }
.saas-hero-badges a:focus-visible { box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }

/* Hero client-logo wave: distinct from the "In good company" client logo carousel further
   down the page — each logo carries its own resting offset (--rest-y) so the row sits in a loose
   wave shape, and the whole row flexes further on hover with a staggered per-logo ripple.
   Matches "Hero Animation - Theme 1a (standalone)" confirmed mockup. One link, whole row,
   to the general clients page (confirmed with Jeremy, not per-logo links). Added 22 July
   2026 (Phase 2e). */
.saas-hero-clients-row { max-width:1200px; margin:40px auto 0; padding:0 var(--sp-2xl); }
a.saas-hero-clients { display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; text-decoration:none; outline:none; border-radius:12px; }
a.saas-hero-clients img { height:56px; width:auto; opacity:0.92; filter:brightness(0) invert(1); transform:translateY(var(--rest-y,0px)); transition:transform 320ms cubic-bezier(.22,.61,.36,1); }
a.saas-hero-clients:focus-visible { box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
@media (hover:hover) and (pointer:fine) {
  a.saas-hero-clients:hover img { transform:translateY(calc(var(--rest-y,0px) * 1.55)); }
  a.saas-hero-clients:hover img:nth-child(2) { transition-delay:26ms; }
  a.saas-hero-clients:hover img:nth-child(3) { transition-delay:52ms; }
  a.saas-hero-clients:hover img:nth-child(4) { transition-delay:78ms; }
  a.saas-hero-clients:hover img:nth-child(5) { transition-delay:104ms; }
  a.saas-hero-clients:hover img:nth-child(6) { transition-delay:130ms; }
  a.saas-hero-clients:hover img:nth-child(7) { transition-delay:156ms; }
  a.saas-hero-clients:hover img:nth-child(8) { transition-delay:182ms; }
  a.saas-hero-clients:hover img:nth-child(9) { transition-delay:208ms; }
  a.saas-hero-clients:hover img:nth-child(10) { transition-delay:234ms; }
}

/* Per-logo staggered pop-in on page load: each logo fades in and overshoots slightly past
   its resting size before settling, one after another, matching the confirmed mockup's
   per-logo entrance (distinct from the row-level fade every other hero element uses).
   Replaces the previous whole-row .saas-anim-clients fade for this row only. Added 22 July
   2026 (Phase 2e).
   IMPORTANT: a CSS animation with fill-mode:both keeps owning the transform property
   forever once it finishes, which silently blocked the hover-wave rule above from ever
   taking effect after the entrance played (found and fixed 22 July 2026). saascada.js
   listens for each image's animationend event and clears its animation property once
   done, handing transform back to the plain resting/hover rules above — no visual jump,
   since the animation's own end state and the plain rule's resting state are identical. */
@keyframes saasHeroLogoIn {
  0%   { opacity:0; transform:translateY(calc(var(--rest-y,0px) + 14px)) scale(0.72); }
  60%  { opacity:1; transform:translateY(var(--rest-y,0px)) scale(1.12); }
  100% { opacity:0.92; transform:translateY(var(--rest-y,0px)) scale(1); }
}
a.saas-hero-clients img { animation:saasHeroLogoIn 0.66s cubic-bezier(.22,.61,.36,1) both; animation-delay:0.95s; }
a.saas-hero-clients img:nth-child(2) { animation-delay:1.29s; }
a.saas-hero-clients img:nth-child(3) { animation-delay:1.59s; }
a.saas-hero-clients img:nth-child(4) { animation-delay:1.85s; }
a.saas-hero-clients img:nth-child(5) { animation-delay:2.09s; }
a.saas-hero-clients img:nth-child(6) { animation-delay:2.31s; }
a.saas-hero-clients img:nth-child(7) { animation-delay:2.53s; }
a.saas-hero-clients img:nth-child(8) { animation-delay:2.75s; }
a.saas-hero-clients img:nth-child(9) { animation-delay:2.97s; }
a.saas-hero-clients img:nth-child(10) { animation-delay:3.19s; }

/* Hero segments/products/badges row: full-width, single line on desktop (matches the
   confirmed mockup's flex-wrap:nowrap + space-between), wraps gracefully below 1100px
   since the mockup itself is a fixed-width desktop canvas and doesn't specify mobile
   behaviour. Only Banking Products carry icons — confirmed against the mockup, segments
   are plain text. Added 22 July 2026 (Phase 2e). */
.saas-hero-links-row { max-width:1200px; margin:28px auto 0; padding:0 var(--sp-2xl); display:flex; align-items:center; justify-content:space-between; gap:22px; flex-wrap:nowrap; }
.saas-hero-links-group { display:flex; gap:24px; align-items:center; flex-wrap:nowrap; }
.saas-hero-links-set { display:flex; gap:12px; align-items:center; flex-wrap:nowrap; }
.saas-hero-links-label { font-size:11px; font-weight:700; letter-spacing:0.12em; text-transform:uppercase; color:rgba(255,255,255,0.55); white-space:nowrap; }
.saas-hero-links-dot { color:rgba(255,255,255,0.5); }
a.saas-hero-link-icon { display:inline-flex; align-items:center; gap:8px; }
a.saas-hero-link-icon svg { flex:none; }
@media (max-width:1100px) {
  .saas-hero-links-row { flex-wrap:wrap; }
  .saas-hero-links-group { flex-wrap:wrap; }
  .saas-hero-links-set { flex-wrap:wrap; }
}

[data-anim] { opacity:0; }
@keyframes saasRiseFade { from{opacity:0; transform:translateY(22px);} to{opacity:1; transform:translateY(0);} }
@keyframes saasScaleIn { from{opacity:0; transform:scale(0.95);} to{opacity:1; transform:scale(1);} }
@keyframes saasImgIn { from{opacity:0; transform:translateX(26px) scale(0.97);} to{opacity:1; transform:translateX(0) scale(1);} }
.saas-anim-eyebrow { animation:saasRiseFade 0.7s cubic-bezier(.22,.61,.36,1) 0.3s both; }
.saas-anim-headline { animation:saasRiseFade 0.75s cubic-bezier(.22,.61,.36,1) 0.42s both; }
.saas-anim-sub { animation:saasRiseFade 0.7s cubic-bezier(.22,.61,.36,1) 0.62s both; }
.saas-anim-trust { animation:saasRiseFade 0.7s cubic-bezier(.22,.61,.36,1) 0.73s both; }
.saas-anim-cta { animation:saasScaleIn 0.6s cubic-bezier(.34,1.56,.64,1) 0.85s both; }
.saas-anim-visual { animation:saasImgIn 0.85s cubic-bezier(.22,.61,.36,1) 0.5s both; }
.saas-anim-links { animation:saasRiseFade 0.7s cubic-bezier(.22,.61,.36,1) 1.05s both; }

@media (prefers-reduced-motion: reduce) {
  [data-anim] { animation:none !important; opacity:1 !important; transform:none !important; }
  .saas-marquee-track { animation:none !important; }
  .saas-flip-inner { transition:none !important; }
  a.saas-hero-clients img { animation:none !important; opacity:0.92 !important; transform:translateY(var(--rest-y,0px)) !important; }
  .saas-hero-frame-1, .saas-hero-frame-2 { animation:none !important; opacity:0 !important; }
  .saas-hero-frame-3 { animation:none !important; opacity:1 !important; visibility:visible !important; pointer-events:auto !important; }
}

/* ---------- client logo carousel ("In good company") ----------
   Single continuously auto-scrolling, seamlessly looping strip used at every breakpoint —
   previously split into a static desktop row (a.saas-client-wave, retired below) plus a
   separate, manually-duplicated mobile-only marquee. The editable logo list now lives in
   a native Group of Image blocks (.saas-client-carousel-source, hidden from the rendered
   page — see front-page.html) so Jeremy can add, remove, and drag-reorder logos directly
   in the Site Editor, no code involved. saascada.js reads whatever images are actually in
   that block at page load, builds the visible track from them, and duplicates the whole
   set once so the translateX(-50%) loop stays seamless regardless of how many logos are
   present, scaling the animation duration to keep a roughly constant visual speed however
   many are added. Logos render in their natural colour: previously inverted to solid
   white via brightness(0) invert(1), which made them invisible against this section's
   light background — found and fixed alongside this rebuild. Added 23 July 2026 (Phase 2e). */
/* !important below: WordPress core prints its own inline global-styles rule for flex-layout
   groups ("body .is-layout-flex { display:flex; }"), which at specificity (0,1,1) beats a
   plain single-class selector like .saas-client-carousel-source (0,1,0) — confirmed live via
   matched CSSOM rules, not assumed (same class of bug as the mega-menu submenu-width fix
   above). Without this, the hidden source block rendered fully visible on the page at its
   images' natural 600x500px size. Found and fixed 23 July 2026 (Phase 2e). */
.saas-client-carousel-source { display:none !important; }
.saas-marquee-link { display:block; text-decoration:none; outline:none; border-radius:12px; }
.saas-marquee-link:focus-visible { box-shadow:0 0 0 2px #fff, 0 0 0 5px var(--c-violet); }
.saas-marquee-viewport { overflow:hidden; }
.saas-marquee-track { display:flex; align-items:center; gap:32px; width:max-content; animation:saasMarquee 32s linear infinite; }
@keyframes saasMarquee { from{transform:translateX(0);} to{transform:translateX(-50%);} }
.saas-marquee-viewport:hover .saas-marquee-track { animation-play-state:paused; }
/* Height chosen so 7 logos (at these source images' uniform 600x500/1.2 aspect ratio) plus
   6 gaps fill the ~1072px content width (1200px section max-width minus its 64px side
   padding) almost exactly: 7 x ~125px + 6 x 32px =~ 1072px. Previously 34px, far smaller
   than the confirmed mockup and Jeremy's "seven visible at once" sizing brief. Changed 23
   July 2026 (Phase 2e). */
.saas-marquee-track img { height:104px; width:auto; opacity:0.72; }

/* ---------- final pre-footer CTA (reusable) ----------
   Extracted 26 July 2026 (Phase 3) from the homepage's own final "Ready to outpace your
   market?" section, which had its background/clip-path/decorative blob written as one-off
   inline styles (fine when only one page existed, not once every Phase 3 page needed the
   same treatment). Centralised here as a named class so every page's closing CTA reads from
   one source and a future adjustment only has to happen once — same reasoning as
   .saas-content-width above. Visual output is unchanged from the original homepage section;
   only where the values live has changed. Angled top only, flat bottom (the hero uses the
   same top-only pattern, in reverse) since this section always sits directly above the
   footer, never has another section below it. Testimonial is optional: Jeremy may not have
   one for every page yet, and the confirmed homepage mockup already includes a standalone
   (no-testimonial) variant of this exact CTA alongside the paired ones, so a page with just
   the heading and button is a confirmed design state, not a placeholder. */
.saas-cta-final { position:relative; overflow:hidden; clip-path:polygon(0 0, 10% 62px, 100% 0, 100% 100%, 0 100%); background:
    radial-gradient(70% 130% at 88% 104%, rgba(255,138,88,0.5), transparent 55%),
    radial-gradient(60% 74% at 58% 100%, rgba(255,196,107,0.3), transparent 55%),
    radial-gradient(74% 90% at 4% -6%, rgba(109,93,246,0.36), transparent 55%),
    linear-gradient(135deg, var(--c-midnight) 0%, #241645 50%, var(--c-plum) 100%); }
/* Homepage's CTA is raw HTML sitting directly in a full-width <main>, so it's full-bleed
   for free. The Phase 3 subpages build this as a native Gutenberg group instead (so Jeremy
   can edit it), which WordPress nests inside the normal 1200px content column — this theme
   doesn't load core's block-library CSS, so the standard "alignfull" class has no actual
   effect here. This rule gives alignfull real teeth, scoped to this component only, so the
   subpages' CTA band stretches edge-to-edge exactly like the homepage's. Added 26 July 2026. */
.saas-cta-final.alignfull { width:100vw; max-width:100vw; margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw); }
.saas-cta-final-blob { position:absolute; bottom:-40px; right:16%; width:540px; height:360px; background:radial-gradient(closest-side, rgba(255,160,100,0.4), transparent); filter:blur(40px); pointer-events:none; }
.saas-cta-final .wp-block-columns { align-items:center; gap:36px; position:relative; }
.saas-cta-final h2 { font-size:50px; font-weight:700; line-height:1.06; margin:0 0 32px; color:#fff; max-width:640px; position:relative; }
/* Standalone pages (no testimonial yet — see note above) use a plain native Button block
   rather than the raw <a class="saas-btn saas-btn-primary"> pattern used elsewhere, so the
   link text/URL stay editable in the block inspector. Core's Button block puts a custom
   className on the outer wrapping div, not the inner link, so .saas-btn-primary's existing
   rule (written for a plain anchor) doesn't reach it directly — this targets the block's
   real markup instead, matching the same values exactly (padding/radius/weight/colours) so
   the two button styles are visually identical site-wide. Added 26 July 2026 (Phase 3). */
.saas-cta-final .wp-block-button.saas-btn-primary .wp-block-button__link { display:inline-flex; align-items:center; justify-content:center; gap:8px; font-family:inherit; font-size:16px; font-weight:600; padding:12px 22px; border-radius:var(--radius-md); border:none; text-decoration:none; min-height:44px; color:var(--c-ink); background:var(--c-coral); transition:background 150ms ease; }
@media (hover:hover) and (pointer:fine) { .saas-cta-final .wp-block-button.saas-btn-primary .wp-block-button__link:hover { background:var(--c-coral-hover); } }
.saas-cta-final .wp-block-button.saas-btn-primary .wp-block-button__link:active { background:var(--c-coral-active); }
.saas-cta-final .wp-block-button.saas-btn-primary .wp-block-button__link:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
/* Built as native Gutenberg blocks (heading, buttons, quote) rather than mirroring the
   homepage's raw-HTML section, so Jeremy can add, edit or remove a page's testimonial
   himself directly in the block editor once one exists, without needing a code change —
   see the reasoning note in Project-Status.md. The core Quote block's own markup
   (blockquote > p + cite) differs from the raw-HTML testimonial pattern used elsewhere
   (figure.saas-testimonial > blockquote + figcaption), so this is a distinct, purpose-built
   rule set rather than a reuse of .saas-testimonial — the visual result matches it exactly. */
.saas-cta-final blockquote.saas-testimonial-quote { margin:0; border:none; padding:0; font-size:23px; font-weight:500; line-height:1.5; letter-spacing:-0.01em; color:rgba(255,255,255,0.92); }
.saas-cta-final blockquote.saas-testimonial-quote p { margin:0; }
.saas-cta-final blockquote.saas-testimonial-quote cite { display:block; margin-top:22px; font-size:15px; font-style:normal; color:var(--c-amber); }
@media (max-width:1023px) {
  .saas-cta-final .wp-block-columns { flex-wrap:wrap; }
}

/* ---------- header ---------- */
.saas-header { position:fixed; top:0; left:0; right:0; z-index:40; transition:transform 220ms ease, background 200ms ease, box-shadow 200ms ease, padding 200ms ease; padding:24px 40px; background:transparent; }
/* Admin-bar clearance: only affects logged-in preview, never public visitors */
@media screen and (min-width:783px) { body.admin-bar .saas-header { top:32px; } }
@media screen and (max-width:782px) { body.admin-bar .saas-header { top:46px; } }
.saas-header.is-condensed { padding:15px 40px; background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%); box-shadow:0 14px 34px rgba(0,0,0,0.5); border-bottom:1px solid rgba(255,255,255,0.1); }
.saas-header.is-hidden { transform:translateY(-115%); }
/* Dark-at-rest header on every page except the homepage, added 26 July 2026 (Phase 3).
   The homepage keeps the transparent-over-hero effect (a deliberate, confirmed design
   choice) because the header sits on the dark hero image at rest, and only switches to
   this same dark gradient once condensed past 40px of scroll (see .is-condensed above).
   Every other page has no dark hero behind the header, so the same transparent style
   left the white logo/nav invisible at rest — confirmed live 26 July 2026, flagged
   since 21 July. Fix reuses the exact .is-condensed background/shadow/border rather
   than a new colour, scoped with WordPress core's own `.home` body class (added
   automatically by body_class() only on the actual front page, whichever template
   renders it) rather than a template name, so every future page/template inherits the
   correct dark-at-rest header with no further work needed. Scroll hide/condense/reveal
   behaviour (saascada.js) is unchanged everywhere. */
body:not(.home) .saas-header { background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%); box-shadow:0 14px 34px rgba(0,0,0,0.5); border-bottom:1px solid rgba(255,255,255,0.1); }
/* WordPress core adds a 24px top margin to MAIN, as the second block inside
   .wp-site-blocks (after the header template part) — spacing that's meant to separate
   stacked page sections. Since .saas-header is position:fixed, it doesn't occupy any
   flow space for MAIN to be spaced away from, so on every page this 24px sits unused
   above MAIN. It's invisible everywhere else because .saas-header always has its own
   solid background at rest (see the dark-at-rest rule above) that covers that same
   strip. The homepage is the one exception: its header stays deliberately transparent
   at rest so the hero shows through it (see the comment above), so here the 24px
   became a visible plain-white strip between the header and the hero's dark
   background, worst seen with the WP admin bar showing. The exact same WordPress
   default was already found and fixed for the footer on 23 July 2026 (see "footer"
   section below) — this is that same fix, scoped to the homepage's main content block.
   Confirmed live: this specific gap traces back to 21 July 2026, when the header first
   became position:fixed, and no fix for it (only the footer's) exists anywhere earlier
   in this file's history. None of today's other header/menu changes touch this area.
   Found and fixed 17 August 2026. */
body.home main.wp-block-group { margin-top:0; }
.saas-header-row { display:flex; align-items:center; gap:34px; max-width:1240px; margin:0 auto; }
.saas-header-logo img, .saas-header-logo svg { height:26px; width:auto; display:block; }
.saas-header .wp-block-navigation { flex:1; }
/* Targets the top-level nav container by its own class combination rather than an
   exact ">" ancestor chain from .wp-block-navigation: on this WordPress version
   (7.0.2, Interactivity-API navigation) the real markup nests .wp-block-navigation__container
   several wrapper divs deeper inside .wp-block-navigation__responsive-container, so a
   direct-child chain from .wp-block-navigation never matched — confirmed live via
   getComputedStyle (links were rendering in the default dark body-text colour, not
   this rule's white). Fixed 22 July 2026 (Phase 2e). */
.saas-header .wp-block-navigation__container.saas-primary-nav > .wp-block-navigation-item > .wp-block-navigation-item__content.wp-block-navigation-item__content { color:rgba(255,255,255,0.72); font-size:15px; font-weight:500; }
.saas-header .wp-block-navigation__container.saas-primary-nav > .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content.wp-block-navigation-item__content { color:#fff; }
@media (hover:hover) and (pointer:fine) { .saas-header .wp-block-navigation__container.saas-primary-nav > .wp-block-navigation-item > .wp-block-navigation-item__content.wp-block-navigation-item__content:hover { color:var(--c-amber); } }
.saas-header-actions { display:flex; align-items:center; gap:14px; flex:none; }
.saas-search-toggle { width:42px; height:42px; border-radius:999px; border:1px solid rgba(255,255,255,0.18); background:rgba(255,255,255,0.08); display:flex; align-items:center; justify-content:center; cursor:pointer; color:#fff; }
.saas-search-toggle:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
/* Header search drop-down, widened to every screen size 17 August 2026 — this was
   previously the mobile-only (below 550px) treatment; the field used to expand in place
   from 0 to 246px above this width instead, which worked on wide desktop screens but at
   most ordinary desktop window widths there isn't 246px of spare room in the header row
   alongside the logo, nav and Contact us button, so opening the field squeezed the nav
   into wrapping onto a second line. Found live, 17 August 2026, when Jeremy opened the
   search field on a normal desktop window and watched the nav wrap. Dropping the field
   below the header instead, at every width, removes any interaction between the field's
   own size and the nav row's available width, so this can't happen again regardless of
   window size. .saas-header is already position:fixed, so it's the positioning context
   here with no extra wrapper needed. */
/* Fixed-width, right-aligned on desktop, added later on 17 August 2026 — the field
   originally spanned the full header width edge-to-edge at every size, which Jeremy
   found clumsy: clicking the search icon on the right, then having to look all the way
   over to the left edge of the screen to start typing. 480px comfortably fits a search
   query without needing the full header width, and sits under the icon that opens it
   rather than away from it. right:40px matches .saas-header's own horizontal padding,
   so its right edge lines up with the Contact us button above it rather than running
   to the true screen edge (the field's containing block is .saas-header's padding box,
   which extends to the header's outer edge). max-width keeps it clear of the logo on
   narrower desktop/tablet windows; the mobile override below restores the original
   full-width behaviour, unchanged. */
.saas-search-field {
  position:absolute; top:100%; left:auto; right:40px; width:480px; max-width:calc(100% - 80px); overflow:visible;
  padding:14px 20px; background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%);
  box-shadow:0 14px 24px rgba(0,0,0,0.35); border-bottom:1px solid rgba(255,255,255,0.1);
  border-radius:0 0 16px 16px;
  opacity:0; transform:translateY(-8px); pointer-events:none;
  transition:opacity 200ms ease, transform 200ms ease;
}
@media (max-width:640px) {
  .saas-search-field { left:0; right:0; width:auto; max-width:none; border-radius:0; }
}
.saas-search-field.is-open { opacity:1; transform:translateY(0); pointer-events:auto; }
.saas-search-field input { width:100%; background:rgba(255,255,255,0.1); border:1px solid rgba(255,255,255,0.2); border-radius:999px; padding:12px 16px; color:#fff; font-family:inherit; outline:none; font-size:16px; } /* 16px prevents iOS auto-zoom on focus, harmless on desktop */
.saas-search-field input:focus-visible { border-color:rgba(255,255,255,0.4); }

/* ---------- MxChat: header search bar is the sole visible entry point (14 August 2026) ----------
   append_to_body is 'on' so MxChat's chat panel is present on every page, but the plugin's own
   floating launcher button (bottom-right round icon) and its pre-chat teaser bubble are hidden
   here so they don't compete with the header search bar. The panel itself is opened
   programmatically from the header field instead — see saascada.js "header: ask MxChat". */
.floating-chatbot-button,
.pre-chat-message {
    display: none !important;
}

/* ---------- MxChat: brand restyle (14 August 2026) ----------
   Panel colours (top bar, message bubbles, input, icons) are set via MxChat's own native
   options (mxchat_options, changed via WordPress settings, not CSS) so they render as
   inline styles with no !important fights and survive plugin updates. Two things aren't
   covered by those options and need a CSS override here:
   1. .chatbot-title hardcodes 'Plus Jakarta Sans' in the plugin's own CSS; overridden to
      Lexend for brand consistency with the rest of the site.
   2. .bot-message a hardcodes white link text, which assumed MxChat's default dark bubble.
      Bot message bubbles are now white (bot_message_bg_color), so links need a visible
      colour against a light background — set to SaaScada violet. */
.chatbot-title {
    font-family: 'Lexend', sans-serif !important;
}
.bot-message a {
    color: var(--c-violet, #6D5DF6);
}
/* Close (X) button, header floating panel only (14 August 2026): the title, the "..."
   menu icon and the close icon all share one option (close_button_color in MxChat's own
   settings), so it can't be recoloured on its own via a setting without also recolouring
   the title. Given a coral !important override here instead, so it reads clearly as its
   own dedicated action against the new dark glow top bar, distinct from the title and
   the "..." menu, which stay white. The plugin's own CSS already sets opacity:0.8 on this
   element inline; overridden to fully opaque so it doesn't fade into a busy background. */
.exit-chat {
    color: var(--c-coral, #FF6B4A) !important;
    opacity: 1 !important;
}

/* ---------- footer ---------- */
/* WordPress core gives every template-part element a default 24px top margin (block-spacing
   support), which isn't visible between light sections but shows up as a plain white strip
   here specifically, since both the pre-footer CTA section above it and the footer itself
   are dark — confirmed live via computed style (footer.wp-block-template-part had
   margin-top:24px despite zero margin/padding on the CTA section itself). Removed so the
   two dark sections sit flush. Found and fixed 23 July 2026 (Phase 2e). */
footer.wp-block-template-part { margin-top:0; }
.saas-footer { background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%); color:#fff; padding:var(--sp-3xl) var(--sp-2xl) var(--sp-xl); position:relative; }
.saas-footer a { color:rgba(255,255,255,0.66); text-decoration:none; }
@media (hover:hover) and (pointer:fine) { .saas-footer a:hover { color:var(--c-amber); } }
.saas-footer .saas-footer-col h3 { font-size:13px; font-weight:700; letter-spacing:0.06em; color:#fff; margin-top:9px; margin-bottom:var(--sp-sm); }
/* Banking Products footer column: icon + label per link, reusing the same four product
   glyphs already confirmed and live elsewhere (hero links row, header mega-menu), not new
   artwork. currentColor means each icon automatically picks up the link's own colour and
   hover-to-amber transition from the existing ".saas-footer a" rule, no separate icon colour
   rule needed. Added 24 July 2026 (Phase 2f).
   Row-height bug, found and fixed 25 July 2026: the link was originally display:inline-flex,
   which measured exactly 26px tall on its own (matching the plain-text columns' line-height)
   but still added ~2px to its parent <p>'s own line box every row — an inline-flex element is
   an atomic inline-level box, and its fallback baseline (no flex item established one) is its
   margin-bottom edge, which the browser then hangs slightly below the surrounding text's own
   baseline, reserving extra descender space the plain-text rows never needed. Confirmed live
   via getBoundingClientRect() (29px vs 26px per row) before guessing at a fix, and confirmed
   the fix the same way (all three columns now compute identical 26px row heights) rather than
   assumed. Switched the link back to plain inline with the icon vertical-aligned and spaced
   by margin instead of flex, which removes the atomic-box baseline behaviour entirely. */
.saas-footer-col-icons a { display:inline; }
.saas-footer-col-icons svg { vertical-align:middle; margin-right:8px; }
.saas-footer details.saas-acc summary { list-style:none; cursor:pointer; display:flex; align-items:center; justify-content:space-between; min-height:44px; outline:none; }
.saas-footer details.saas-acc summary::-webkit-details-marker { display:none; }
.saas-footer details.saas-acc summary::marker { content:""; }
.saas-footer details.saas-acc summary:focus-visible { outline:2px solid var(--c-amber); outline-offset:-2px; }
.saas-footer .saas-chev { transition:transform 200ms ease; }
.saas-footer details.saas-acc[open] .saas-chev { transform:rotate(180deg); }
.saas-footer-legal a { min-height:44px; display:flex; align-items:center; }
/* Found 17 August 2026, real-device Safari check: the desktop flat-column list and the
   mobile accordion were both showing at once on an actual phone, duplicating all twelve
   footer links. Cause: the desktop wrapper's flex layout was set as an inline style
   (style="display:flex;...") in footer.html, which always beats an external stylesheet
   rule regardless of selector specificity, so the max-width:640px rule below that sets
   display:none on it was silently losing every time. Moved the layout into this class rule
   instead, so the more specific ".saas-footer .saas-acc-desktop-only" override below can
   actually win at mobile widths. footer.html's inline style attribute on that div removed
   to match. */
.saas-acc-desktop-only { display:flex; flex-wrap:wrap; gap:30px; flex:3; }
@media (max-width:640px) {
  .saas-footer .saas-acc-desktop-only { display:none; }
  /* Mobile-only fix, 16 August 2026: the accordion body's plain links (Banking Products,
     Explore, Company) were measuring ~21.7px tall here, under the 24px WCAG 2.5.8 minimum
     tap-target size, even though the equivalent desktop columns already sit at a confirmed
     26px (see the row-height bug note above). First tried a plain line-height bump alone;
     checked live rather than assumed, and it computed correctly (line-height:24px) but the
     link's own measured box stayed 21.5px regardless, since plain inline elements don't
     reliably grow their box to the full line-height in every browser. Switched to
     display:inline-block with an explicit min-height instead, which does establish a real
     box at the stated height. Each link is alone on its own line (one per <p>, or separated
     by <br> in the contact-details paragraph), and it still contains real text/icon content
     of its own to establish a proper baseline, so this doesn't reintroduce the flex fallback-
     baseline bug fixed above (that was specific to flex's own baseline algorithm, not
     inline-block's). Scoped to this breakpoint only, so the already-correct desktop row
     height is untouched. */
  .saas-footer a { display:inline-block; min-height:24px; line-height:24px; }
}
@media (min-width:641px) {
  .saas-footer .saas-acc-mobile-only { display:none; }
}

/* ---------- back to top ---------- */
.saas-back-to-top {
  position:fixed; left:50%; bottom:var(--sp-lg); z-index:30;
  width:48px; height:48px; border-radius:50%; border:none; padding:0;
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  background:var(--c-coral); color:var(--c-ink); box-shadow:0 12px 28px rgba(0,0,0,0.28);
  opacity:0; pointer-events:none;
  transform:translateX(-50%) translateY(16px);
  transition:opacity 220ms ease, transform 220ms ease, background 160ms ease;
}
.saas-back-to-top.is-visible { opacity:1; pointer-events:auto; transform:translateX(-50%) translateY(0); }
@media (hover:hover) and (pointer:fine) { .saas-back-to-top:hover { background:var(--c-coral-hover); } }
.saas-back-to-top:active { background:var(--c-coral-active); transform:translateX(-50%) scale(0.94); }
.saas-back-to-top:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
@media (max-width:640px) {
  .saas-back-to-top { width:44px; height:44px; bottom:var(--sp-md); }
}

/* ---------- header: mega-menu dropdowns (desktop) ----------
   Targets WordPress core's own Navigation/Navigation-submenu block
   markup directly (.wp-block-navigation-item__content etc.), confirmed
   against the real rendered output via parse_blocks/render_block, not
   assumed. Colours/spacing/shadow values pulled from the confirmed
   Site Header - Theme 1a mockup (mm-panel / mm-item / mm-cat rules).
   First pass — flagged for a visual check once the real browser QA
   pass runs (nested-flyout vs promo-panel overlap in particular). */
.saas-header .wp-block-navigation-item.wp-block-navigation-submenu { position:relative; }
/* !important below: WordPress core prints its own inline block-support styles (e.g.
   ".wp-block-navigation .has-child .wp-block-navigation__submenu-container") with equal
   or higher specificity than a plain two-class selector can reach (its open-state rule
   alone is five selectors deep), so width/min-width/max-width here would otherwise be
   silently overridden back to the core default (0 closed / auto open) — confirmed by
   inspecting matched CSSOM rules directly, not assumed. */
.saas-header .wp-block-navigation__submenu-container {
  position:absolute; top:calc(100% + 12px); left:0; z-index:50; padding:8px;
  width:max-content !important; min-width:220px !important; max-width:360px !important;
  border-radius:14px; background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%);
  border:1px solid rgba(255,255,255,0.14); box-shadow:0 26px 60px rgba(0,0,0,0.5);
  display:flex; flex-direction:column; gap:2px;
}
.saas-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  display:flex; align-items:center; justify-content:space-between; gap:10px; min-height:44px;
  padding:10px 12px; border-radius:9px; color:rgba(255,255,255,0.86); font-size:14.5px; font-weight:500;
}
.saas-header .wp-block-navigation__submenu-container .wp-block-navigation-item {
  background:transparent;
}
@media (hover:hover) and (pointer:fine) {
  .saas-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover { background:rgba(255,255,255,0.09); color:#fff; }
}
.saas-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible {
  outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber);
}
.saas-header .wp-block-navigation-submenu__toggle { color:rgba(255,255,255,0.72); background:none; border:none; padding:6px; border-radius:8px; cursor:pointer; }
/* WCAG 2.2 SC 2.5.8 (Target Size, AA) fix, Phase 5 sign-off, 15 August 2026: the padding:6px
   rule above never actually applied. Core's own block-library default for this exact button
   (it carries both .wp-block-navigation-submenu__toggle AND .wp-block-navigation__submenu-icon)
   sets width:0.6em; height:0.6em; padding:0px — same specificity (two classes each) as the rule
   above, so it won a same-specificity tiebreak on source order, rendering a 12x12px hit area
   against the 24x24px minimum. Confirmed live via getComputedStyle before writing this fix, not
   assumed. Combining both classes on one selector below raises specificity so this always wins
   regardless of load order (same pattern as the .alignfull fix, 10 August 2026). Arrow glyph's
   own visual size is untouched — only the invisible clickable box around it grows. */
.saas-header .wp-block-navigation__submenu-icon.wp-block-navigation-submenu__toggle {
  width:24px; height:24px; padding:0; box-sizing:border-box;
  display:inline-flex; align-items:center; justify-content:center;
}
.saas-header .wp-block-navigation-submenu__toggle svg { transition:transform 180ms ease; }
.saas-header .wp-block-navigation-submenu__toggle[aria-expanded="true"] { color:var(--c-amber); }
.saas-header .wp-block-navigation-submenu__toggle[aria-expanded="true"] svg { transform:rotate(180deg); }
.saas-header .wp-block-navigation-submenu__toggle:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
.saas-header .wp-block-navigation__container.saas-primary-nav > li.wp-block-navigation-item > a.wp-block-navigation-item__content:focus-visible {
  outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); border-radius:6px;
}

/* ---------- header: Solutions mega-panel (bespoke, JS-built — see saascada.js) ----------
   Rebuilt 21 July 2026 (Phase 2d): the native nested wp:navigation-submenu approach only
   supports cascading flyouts, not the confirmed mockup's master/detail switcher panel, and
   caused the promo panel to visually collide with the second-level flyout. Solutions now
   keeps its native top-level toggle/aria-expanded (unchanged, already fixed and verified),
   but its dropdown content is injected by JS as one flat custom panel matching the
   confirmed "Site Header - Theme 1a" mockup's mm-panel/mm-cat/mm-detail-group structure. */
/* !important + higher specificity here so this beats the generic !important rule above
   (which would otherwise force width back to the 220–360px simple-dropdown range). Left/
   width are ultimately set precisely in JS (see positionPanel() in saascada.js) because
   WordPress core makes the <li> itself position:relative, so a plain percentage calc()
   here resolves against the narrow nav item, not the ~1240px header row — these values
   are just a sane pre-JS fallback. */
.saas-header .saas-solutions-submenu > .wp-block-navigation__submenu-container {
  width:auto !important; min-width:0 !important; max-width:none !important;
  left:max(24px, calc((100% - 1240px) / 2)); right:max(24px, calc((100% - 1240px) / 2));
  padding:0; overflow:hidden;
}
.saas-mm-solutions { display:flex; align-items:stretch; width:100%; }
.saas-mm-cats { flex:none; width:240px; padding:20px 16px; border-right:1px solid rgba(255,255,255,0.1); display:flex; flex-direction:column; gap:4px; }
.saas-mm-cats-label { font-size:11px; font-weight:700; letter-spacing:0.16em; text-transform:uppercase; color:var(--c-amber); padding:4px 14px 10px; }
.saas-mm-cat { display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; text-align:left; background:none; border:none; cursor:pointer; font-family:Lexend,sans-serif; font-size:15px; font-weight:500; color:rgba(255,255,255,0.82); padding:11px 14px; border-radius:10px; white-space:nowrap; text-decoration:none; }
.saas-mm-cat[data-active="true"] { background:rgba(255,255,255,0.09); color:#fff; }
.saas-mm-cat-chev { color:rgba(255,255,255,0.5); transition:color 150ms ease, transform 150ms ease; flex:none; }
.saas-mm-cat[data-active="true"] .saas-mm-cat-chev { color:var(--c-amber); transform:translateX(3px); }
@media (hover:hover) and (pointer:fine) { .saas-mm-cat:hover { background:rgba(255,255,255,0.06); color:#fff; } }
.saas-mm-cat:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
.saas-mm-detail { flex:1; min-width:0; }
.saas-mm-group { display:none; flex-direction:column; gap:14px; padding:22px 26px 24px; }
.saas-mm-group.is-active { display:flex; }
.saas-mm-group-label { font-size:11px; font-weight:700; letter-spacing:0.16em; text-transform:uppercase; color:rgba(255,255,255,0.5); }
.saas-mm-grid { display:grid; grid-template-columns:1fr 1fr; gap:2px 16px; align-content:start; }
.saas-mm-item { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:10px 12px; border-radius:9px; color:rgba(255,255,255,0.86); font-size:14.5px; font-weight:500; text-decoration:none; white-space:nowrap; }
.saas-mm-item-chev { opacity:0; transform:translateX(-4px); color:var(--c-amber); transition:opacity 150ms ease, transform 150ms ease; flex:none; }
@media (hover:hover) and (pointer:fine) {
  .saas-mm-item:hover { background:rgba(255,255,255,0.09); color:#fff; }
  .saas-mm-item:hover .saas-mm-item-chev { opacity:1; transform:none; }
}
.saas-mm-item:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
.saas-mm-item:focus-visible .saas-mm-item-chev { opacity:1; transform:none; }

/* Promo panel: fixed width/font, height flexes to fit whichever item is showing.
   No auto-summarising of quotes — length is Jeremy's editorial call, not the system's. */
.saas-mm-promo { flex:none; width:340px; padding:18px; border-left:1px solid rgba(255,255,255,0.1); background:rgba(255,255,255,0.03); display:flex; align-items:stretch; }
.saas-mm-promo-card { margin:0; width:100%; box-sizing:border-box; padding:28px 26px; border-radius:16px; color:#fff; display:flex; flex-direction:column; justify-content:center; background:
    radial-gradient(95% 130% at 90% 104%, rgba(255,138,88,0.5), transparent 54%),
    radial-gradient(70% 80% at 4% -6%, rgba(109,93,246,0.34), transparent 55%),
    linear-gradient(140deg, var(--c-midnight) 0%, #241645 52%, var(--c-plum) 100%); }
.saas-mm-promo-quote { margin:0; font-size:17px; font-weight:500; line-height:1.5; letter-spacing:-0.01em; }
.saas-mm-promo-attribution { font-size:14px; color:var(--c-amber); margin-top:16px; display:block; }
.saas-mm-promo-stat-value { margin:0; font-size:40px; font-weight:700; line-height:1.1; }
.saas-mm-promo-stat-label { font-size:15px; color:rgba(255,255,255,0.75); margin-top:8px; display:block; }
@media (prefers-reduced-motion: no-preference) { .saas-mm-promo-card { animation:hd-rise 240ms ease both; } }
@keyframes hd-rise { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } }

/* ---------- header: mobile responsive overlay (native Navigation block, overlayMenu:"mobile") ---------- */
/* Compact/hamburger range widened from 1023px to 1199px, 17 August 2026 — once the
   previous fix above made the full desktop menu hold correctly from 1024px up, a
   second, distinct problem showed up in that same territory: the five top-level items
   (Platform, Solutions, Why SaaScada, Ecosystem, Resources) don't all fit on one line
   in the space the header row leaves for them until the window is roughly 1140px wide,
   so from ~1024px to ~1140px the nav's own items wrapped onto two lines, growing the
   fixed header's height and covering more of the page underneath it. Confirmed live
   via a width sweep: header row stayed a single ~97px line at every width once the
   nav toggle covers this range instead of the full inline menu, and only switches to
   the full menu once there's genuinely enough room (from ~1200px) to fit it without
   wrapping. 1200px is a deliberate ~60px buffer above the measured ~1140px cutoff, so
   minor font-metric differences across browsers/updates don't reopen the same gap. */
@media (max-width:1199px) {
  .saas-header .wp-block-navigation__responsive-container-open {
    display:flex; align-items:center; justify-content:center; width:44px; height:44px; border-radius:999px;
    border:1px solid rgba(255,255,255,0.18); background:rgba(255,255,255,0.08); color:#fff; cursor:pointer;
  }
  .saas-header .wp-block-navigation__responsive-container-open:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
  .saas-header .wp-block-navigation__responsive-container {
    background:linear-gradient(135deg,#16123A 0%,#241645 70%,#2E1746 100%);
  }
  .saas-header .wp-block-navigation__responsive-dialog { height:100%; }
  .saas-header .wp-block-navigation__responsive-container-content { padding:76px 24px 40px; height:100%; overflow-y:auto; }
  .saas-header .wp-block-navigation__responsive-container-close {
    position:absolute; top:20px; right:20px; width:44px; height:44px; display:flex; align-items:center; justify-content:center;
    border-radius:999px; background:rgba(255,255,255,0.08); border:1px solid rgba(255,255,255,0.18); color:#fff; cursor:pointer;
  }
  .saas-header .wp-block-navigation__responsive-container-close:focus-visible { outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); }
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation__container { display:flex; flex-direction:column; gap:2px; }
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation-item__content {
    min-height:44px; display:flex; align-items:center; color:#fff; font-size:16px; font-weight:500; padding:11px 4px;
  }
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation-item__content:focus-visible {
    outline:none; box-shadow:0 0 0 2px var(--c-midnight), 0 0 0 5px var(--c-amber); border-radius:6px;
  }
}
@media (min-width:1200px) {
  .saas-header .wp-block-navigation__responsive-container-open { display:none; }
}
/* Collapsed menu forced to hold from 600px to 1199px (widened from 1023px 17 August
   2026, see note above) — WordPress core's own navigation block stylesheet
   (block-library/style.min.css) hardcodes
   "@media (min-width:600px) { .wp-block-navigation__responsive-container:not(.is-menu-open)
   { display:block; position:relative; width:100% } }", which reverts the menu to plain,
   uncollapsed inline flow from 600px upward regardless of what any theme wants. This
   theme keeps the compact hamburger-toggle menu (see the max-width:1199px rules above and
   below) all the way up to 1199px, so from 600px to 1199px the two rules would otherwise
   fight each other: WordPress forcing the full, unstyled navigation list to render inline
   in the header row (all links, all submenus, no collapsing), while this theme's own
   toggle button sat there uselessly alongside it. That's the "menu behaves erratically
   between desktop and phone" Jeremy found by resizing a browser window and confirmed with
   Chrome's device toolbar: correct compact menu below 600px, correct full desktop menu
   above 1199px, broken in between on any tablet or a resized desktop window. This rule
   re-asserts display:none on the closed (:not(.is-menu-open)) state specifically for that
   600-1199px gap, so the toggle-button behaviour already built for it actually holds
   throughout. !important is used deliberately, since it's countering a WordPress core
   default rather than another theme rule, and source order between core and theme
   stylesheets isn't something to rely on across WordPress updates. Confirmed live: the
   menu collapses correctly throughout 600-1199px, and the toggle button still opens the
   overlay correctly afterwards. */
@media (min-width:600px) and (max-width:1199px) {
  .saas-header .wp-block-navigation__responsive-container:not(.is-menu-open) { display:none !important; }
}
@media (max-width:1199px) {
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation__submenu-container {
    position:static; background:transparent; border:none; box-shadow:none; padding:0 0 4px 18px; margin:0; min-width:0;
  }
  .saas-header .wp-block-navigation-submenu__toggle[aria-expanded="false"] + .wp-block-navigation__submenu-container { display:none; }
  .saas-header .wp-block-navigation-submenu__toggle[aria-expanded="true"] + .wp-block-navigation__submenu-container { display:flex; }
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation__submenu-icon { display:inline-block !important; }
}
@media (max-width:1199px) {
  .saas-header .wp-block-navigation__responsive-container .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    color:rgba(255,255,255,0.78); font-size:15px; min-height:40px;
  }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-promo { display:none; }
  .saas-mm-promo { display:none; }
  /* Solutions mega-panel becomes a plain accordion on mobile: category buttons toggle
     their own group open/closed, one column, no promo panel (confirmed desktop-only). */
  .saas-header .wp-block-navigation__responsive-container .saas-mm-solutions { flex-direction:column; width:100%; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-cats { width:100%; border-right:none; border-bottom:1px solid rgba(255,255,255,0.1); padding:6px 4px 12px; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-cat { font-size:16px; min-height:44px; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-detail { width:100%; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-group { padding:8px 4px 16px 18px; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-grid { grid-template-columns:1fr; }
  .saas-header .wp-block-navigation__responsive-container .saas-mm-item { min-height:44px; }
}

/* ---------- Page Banner (interior pages) ----------
   One shared page-top banner for every interior page (Platform/Solutions hubs and
   subpages, Segments, Stakeholders, Use Cases, Ecosystem, Resources, legal pages), per
   the confirmed "Page Banner - Theme 1a" mockup: eyebrow, H1, an optional intro
   paragraph, an optional CTA, then a separate "slot" block immediately beneath (jump-nav
   pills / a filter bar / a search box / nothing) that sits in normal page flow rather
   than nested inside the banner, so it can become sticky once scrolled past. Reuses
   .saas-content-width.is-tight for the horizontal padding/max-width/vertical rhythm
   already established site-wide, rather than the mockup's own one-off 1180px/72px
   figures — a deliberate small deviation to keep one consistent spacing system instead
   of a second, near-identical set of numbers (72px vs the existing 64px "is-tight"
   token is an 8px difference, not visually meaningful). Eyebrow reuses .saas-eyebrow
   as-is — its values (14px/600/uppercase/0.16em/violet) already match the mockup
   exactly. Added 26 July 2026 (Phase 3, Platform hub build) — first use of this
   component; every page built from here on that needs a plain content-page top should
   use this same markup rather than a bespoke one-off. */
/* padding-top:112px clears the fixed .saas-header (measured ~97px tall), which the
   homepage hero handles with its own 128px top padding — this component needs the same
   kind of clearance since, unlike the homepage, there's no dark hero behind the header
   for it to sit on. Found live 26 July 2026 (first Page Banner use, Platform hub): without
   it, the eyebrow/H1 rendered directly underneath/behind the fixed header, visually
   overlapping the logo. */
.saas-page-banner { background:linear-gradient(180deg, var(--c-paper) 0%, var(--c-mist) 100%); padding-top:112px; }
.saas-page-banner h1 { font-size:52px; font-weight:700; color:var(--c-ink); line-height:1.05; letter-spacing:-0.01em; margin-top:var(--sp-md); max-width:900px; }
.saas-page-banner-intro { font-size:20px; font-weight:400; color:var(--c-slate); line-height:1.5; margin-top:var(--sp-md); max-width:640px; }
.saas-page-banner-cta { margin-top:var(--sp-lg); }
@media (max-width:1023px) {
  .saas-page-banner h1 { font-size:38px; }
}
/* padding-top increased from 96px to 195px at this breakpoint, 17 August 2026: the 96px
   figure assumed the same single-row, ~97px-tall header used on desktop, but confirmed by
   directly measuring the live rendered header at phone widths (375-550px), .saas-header
   doesn't shrink at this breakpoint, it wraps onto two rows (logo/menu-toggle, then
   search/Contact us) because .saas-header-row is a Group block with the default flex
   layout, which allows wrapping rather than shrinking its children. That makes the real
   header height about 175px on a phone, not ~97px, so 96px of clearance left the eyebrow
   underneath it. 195px matches the measured wrapped height plus a small margin, the same
   approach used for the original 97px-based figure above. Found live, 17 August 2026,
   when Jeremy spotted the header covering the eyebrow on every top-level nav page. */
@media (max-width:640px) {
  .saas-page-banner { padding-top:195px; }
  .saas-page-banner h1 { font-size:30px; }
  .saas-page-banner-intro { font-size:18px; }
}

/* ---------- page banner, dark glow variant ----------
   Added 5 August 2026, top-level nav pages (Platform, Solutions, Why SaaScada,
   Ecosystem, Resources), to make the primary nav destinations visually distinct from
   the subpages beneath them. Jeremy specifically wanted the multi-radial-gradient
   "backlit glow" composite already proven in .saas-cta-final (confirmed via a live
   screenshot of the Ecosystem page's own pre-footer CTA), not the flatter
   .saas-dark-gradient utility used elsewhere (homepage sections, footer) — this reuses
   .saas-cta-final's exact background/blob values rather than inventing a new gradient,
   applied to the top banner instead of the pre-footer CTA. Compound selector
   (.saas-page-banner.saas-page-banner-dark) used deliberately instead of a single new
   class, so it reliably overrides the base .saas-page-banner rule above regardless of
   stylesheet order (the same order issue found and avoided for .saas-dark-gradient
   during the feasibility check for this request). Blob is a separate absolutely
   positioned element (markup: placed as the first child inside the banner, before the
   text column) rather than a background layer, matching .saas-cta-final-blob's own
   structure exactly; .saas-content-width gets position:relative here (scoped to this
   variant only) so the text stacks above the blob, the same stacking approach
   .saas-cta-final already uses for its heading/columns. */
.saas-page-banner.saas-page-banner-dark {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(70% 130% at 88% 104%, rgba(255,138,88,0.5), transparent 55%),
    radial-gradient(60% 74% at 58% 100%, rgba(255,196,107,0.3), transparent 55%),
    radial-gradient(74% 90% at 4% -6%, rgba(109,93,246,0.36), transparent 55%),
    linear-gradient(135deg, var(--c-midnight) 0%, #241645 50%, var(--c-plum) 100%);
}
.saas-page-banner.saas-page-banner-dark .saas-content-width { position: relative; }
.saas-page-banner.saas-page-banner-dark .saas-eyebrow { color: var(--c-amber); }
.saas-page-banner.saas-page-banner-dark h1 { color: #fff; }
.saas-page-banner.saas-page-banner-dark .saas-page-banner-intro { color: rgba(255,255,255,0.82); }
.saas-page-banner-dark-blob { position:absolute; bottom:-40px; right:16%; width:540px; height:360px; background:radial-gradient(closest-side, rgba(255,160,100,0.4), transparent); filter:blur(40px); pointer-events:none; }
/* Full-bleed dark banner, added 5 August 2026: Jeremy compared the new dark banner
   against the homepage hero (naturally edge-to-edge, since it's raw HTML sitting
   directly in a full-width <main>) and wanted the same edge-to-edge width — the banner
   was still confined to the page template's normal constrained content column. Same
   root cause and same fix already used for .saas-cta-final.alignfull above: this theme
   doesn't load core's block-library CSS, so WordPress's own "alignfull" class has no
   effect until a rule gives it one, scoped to this component only. .saas-content-width
   inside the banner keeps its own max-width, so the inner eyebrow/H1/intro text still
   sits in the normal 1200px reading column — only the dark background stretches full
   width, matching the CTA band and hero exactly. */
.saas-page-banner.alignfull { width:100vw; max-width:100vw; margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw); }

/* Reserved content slot beneath the banner (jump-nav pills / filter bar / search) — its
   own block in normal page flow, not nested inside the banner, so it can be made sticky
   once scrolled past. Pages with no slot simply omit this element — no gap results. */
.saas-page-slot { background:var(--c-paper); border-top:1px solid rgba(23,18,51,0.09); border-bottom:1px solid rgba(23,18,51,0.09); }
.saas-page-slot-inner { padding-top:var(--sp-sm); padding-bottom:var(--sp-sm); }
/* top:80px (not 0) so the sticky slot settles just below the fixed .saas-header once its
   condensed height is reached, rather than sliding underneath it; z-index:20 keeps it
   below the header's own z-index:40. Approximate — check against the live condensed
   header height and adjust if a gap or overlap is visible. */
.saas-page-slot.is-sticky { position:sticky; top:80px; z-index:20; }

/* ---------- Jump-nav / filter pills (first use: Segments/Stakeholders "explore by"
   pill row, 27 July 2026) — fills the reserved .saas-page-slot above with a row of
   pill links to each in-page section, matching the mega-menu's flyout labels for the
   same anchors so the two navigation paths agree. Plain anchor links, plain browser
   #hash jump — no JS scroll override (see note below).
   Changed 3 Aug 2026: was overflow-x:auto (horizontal scroll) with the scrollbar
   hidden, so overflowing pills had no visible affordance and just vanished off the
   right edge (confirmed on Security and Resilience — "Incident Response" clipped,
   silently scrollable via trackpad/wheel but with zero visual hint). Switched to
   flex-wrap so every pill is always visible, no hidden content. Applies to all
   current and future uses of this component, including the Resources page category
   filter pills. */
.saas-jump-pills { display:flex; gap:10px; flex-wrap:wrap; }
.saas-jump-pill { flex:0 0 auto; display:inline-flex; align-items:center; padding:8px 18px; border-radius:999px; background:var(--c-mist); color:var(--c-ink); font-size:14px; font-weight:600; text-decoration:none; white-space:nowrap; transition:background 150ms ease, color 150ms ease; }
@media (hover:hover) and (pointer:fine) { .saas-jump-pill:hover { background:var(--c-violet); color:#fff; } }
.saas-jump-pill:active { background:var(--c-violet-active); color:#fff; }
.saas-jump-pill:focus-visible { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--c-violet); }
/* Persistent highlight for whichever pill is the currently-applied filter
   (Resources page category pills) — distinct from :hover/:active, which are
   momentary. Added 3 August 2026. */
.saas-jump-pill.is-active { background:var(--c-violet); color:#fff; }

/* ---------- Resources page "Ask" box (3 August 2026, wired to MxChat 14 August 2026) ----------
   Was deliberately inert plain <div>/<span> markup while the answer engine wasn't chosen yet.
   Now a real <input>/<button>, submitting into MxChat's own panel embedded inline just below
   (Option C: the real MxChat panel, positioned here, not floating — see saascada.js "Resources
   page: ask MxChat inline"). This page's floating auto-append is turned off via MxChat's own
   per-page visibility meta (_mxchat_page_visibility = 'hide'), so only this one inline instance
   exists here, avoiding duplicate-id collisions with the header's floating panel elsewhere. */
.saas-ask-box { display:flex; align-items:center; gap:12px; background:var(--c-mist); border-radius:999px; padding:10px 10px 10px 24px; max-width:640px; }
.saas-ask-box-input { flex:1; color:var(--c-ink); font-size:16px; font-family:inherit; background:none; border:none; outline:none; padding:0; min-height:24px; }
.saas-ask-box-input::placeholder { color:var(--c-muted); }
/* Brand colour + soft coral glow, matching .saas-btn-primary's palette (14 August 2026,
   Jeremy: bring the "Ask" button into brand colours with the Ascent glow treatment). The
   full multi-blob Ascent Glow composite (see .saas-cta-final) is a section-scale background
   effect, not proportionate on a 44px pill, so this reads it down to a coral fill plus a
   matching soft box-shadow halo, same colour language, button scale. */
.saas-ask-box-btn { flex:0 0 auto; display:inline-flex; align-items:center; padding:10px 22px; border-radius:999px; background:var(--c-coral); border:none; cursor:pointer; color:var(--c-ink); font-weight:600; font-size:14px; font-family:inherit; box-shadow:0 4px 18px rgba(255,107,74,0.45); transition:background 150ms ease, box-shadow 150ms ease; }
@media (hover:hover) and (pointer:fine) { .saas-ask-box-btn:hover { background:var(--c-coral-hover); box-shadow:0 4px 22px rgba(255,107,74,0.55); } }
.saas-ask-box-btn:active { background:var(--c-coral-active); }
.saas-ask-box-badge { display:inline-flex; align-items:center; margin-top:14px; padding:4px 12px; border-radius:999px; background:var(--c-amber); color:var(--c-ink); font-size:12px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; }

/* MxChat's inline (floating="no") panel, hidden until the ask box is first used, then revealed
   in place. Sizing follows the plugin's own inline-mode default (500px height); width capped to
   match the ask box above it. Brand colours applied via MxChat's own settings (14 August 2026),
   the same options used everywhere the bot renders, not a separate override here. */
.resources-ask-panel { display:none; margin-top:16px; max-width:640px; }
.resources-ask-panel.is-open { display:block; }
/* Collapse control (14 August 2026): MxChat hides its own close button on embedded panels
   like this one, so this is a small control of our own, sitting above the panel rather than
   inside MxChat's markup, to avoid fighting its internal top-bar layout. Text link rather than
   an icon button, since "Hide answer" needs to read clearly as distinct from MxChat's own UI
   directly below it. */
.resources-ask-collapse { display:block; margin:0 0 8px auto; padding:4px 8px; background:none; border:none; font-family:inherit; font-size:13px; font-weight:600; color:var(--c-violet); cursor:pointer; }
@media (hover:hover) and (pointer:fine) { .resources-ask-collapse:hover { color:var(--c-violet-hover); text-decoration:underline; text-underline-offset:3px; } }
.resources-ask-collapse:focus-visible { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--c-violet); border-radius:4px; }

/* ---------- Resources page: combinable Category + Topic filters (13 August 2026),
   [saascada_resource_directory] shortcode, functions.php — supersedes the 3 August
   2026 single-select Category pill row + native Query Loop block. Filter pill look
   and behaviour deliberately mirror .saas-partner-pill (see the Ecosystem page block
   below) rather than reusing those classes directly, so the two features can evolve
   independently even though they look alike today. New here vs. the partner
   directory: an .is-unavailable pill state for symmetric grey-out (partners never
   needed this, since Type/Category there are mutually exclusive, not combinable),
   and a "Show more" reveal since 231 resources is enough to be worth not painting
   all at once (51 partners was not). No publish date is shown on cards — unchanged
   from the previous design decision that visible dates make otherwise-relevant
   content look stale over time. */
.saas-resource-filters { display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--sp-xl); margin-bottom:var(--sp-lg); }
.saas-resource-filter-group { display:flex; flex-direction:column; gap:8px; flex:1 1 100%; }
.saas-resource-filter-label { font-size:13px; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--c-muted); margin:0; }
.saas-resource-pill-row { display:flex; gap:10px; flex-wrap:wrap; }
.saas-resource-pill { flex:0 0 auto; display:inline-flex; align-items:center; gap:6px; padding:8px 16px; border-radius:999px; background:var(--c-mist); color:var(--c-ink); font-size:14px; font-weight:600; white-space:nowrap; cursor:pointer; transition:background 150ms ease, color 150ms ease, opacity 150ms ease; }
.saas-resource-pill input { position:absolute; opacity:0; width:1px; height:1px; }
@media (hover:hover) and (pointer:fine) { .saas-resource-pill:hover { background:var(--c-violet); color:#fff; } }
.saas-resource-pill:has(input:checked) { background:var(--c-violet); color:#fff; }
.saas-resource-pill:has(input:focus-visible) { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--c-violet); }
/* Symmetric grey-out: an unpicked pill that would return zero results given the
   OTHER facet's current picks. Same visual language as disabled buttons elsewhere
   on the site (.saas-btn:disabled) rather than a new opacity value. */
.saas-resource-pill.is-unavailable { opacity:0.4; cursor:not-allowed; }
@media (hover:hover) and (pointer:fine) { .saas-resource-pill.is-unavailable:hover { background:var(--c-mist); color:var(--c-ink); } }
.saas-resource-clear { align-self:flex-end; margin-left:auto; }

.saas-resource-count { font-size:14px; color:var(--c-muted); margin:0 0 var(--sp-md); }

.saas-resource-grid { display:grid; grid-template-columns:repeat(3, 1fr); gap:32px 24px; }
.saas-resource-card[hidden] { display:none; }
.saas-resource-card-thumb { display:block; margin-bottom:12px; }
.saas-resource-card-thumb img { display:block; border-radius:12px; aspect-ratio:16/9; object-fit:cover; width:100%; }
.saas-resource-card-title { font-size:19px; line-height:1.3; margin:0 0 8px; }
.saas-resource-card-title a { color:var(--c-ink); text-decoration:none; }
.saas-resource-card-excerpt { color:var(--c-slate); font-size:15px; line-height:1.5; margin:0; }

/* single-resource.html: the fixed .saas-header (position:fixed, see above) needs
   112px of clearance below it or content collides with it at the very top of the
   page. Every other template gets this for free via .saas-page-banner's own
   padding-top:112px, since a banner section is always their first element.
   single-resource.html is the only template using the bare post-title block
   directly as its first element, with no such banner, so it needs the same
   clearance value applied explicitly here. Found live, 13 August 2026, when
   Jeremy spotted the header overlapping the article title.

   Side padding added 17 August 2026: this wrapper only ever had padding-top set, so the
   title and body text ran edge-to-edge on narrower screens with no left/right margin at
   all. Every other template gets this for free from .saas-content-width, the shared class
   used site-wide for a max-width plus responsive side padding — single-resource.html's
   bare post-title/post-content blocks don't use that class, so this theme has no root
   padding of its own (no useRootPaddingAwareAlignments in theme.json) to fall back on.
   Values below match .saas-content-width's own responsive scale exactly, so the reading
   column keeps the same side margin as every other page. */
.saas-resource-main { padding-top:112px; padding-left:var(--sp-2xl); padding-right:var(--sp-2xl); }
@media (max-width:1023px) {
  .saas-resource-main { padding-left:var(--sp-xl); padding-right:var(--sp-xl); }
}
/* padding-top increased to 195px at this breakpoint, 17 August 2026: same cause and same
   fix as .saas-page-banner's mobile padding-top above — the fixed .saas-header wraps onto
   two rows at phone widths instead of shrinking, making it ~175px tall rather than the
   ~97px the 112px base figure assumes, so the article title was still getting covered
   even after the scroll-hide fix. Found live, 17 August 2026, when Jeremy spotted the
   header still covering the article title on a phone. */
@media (max-width:640px) {
  .saas-resource-main { padding-left:var(--sp-lg); padding-right:var(--sp-lg); padding-top:195px; }
}

/* Related resources block on single-resource.html (13 August 2026): reuses the
   existing saas-resource-grid/card/thumb/title classes above exactly, so a
   related card looks identical to a directory card. Only new rule needed is
   this wrapper's own top spacing/divider, since it sits after post-content. */
.saas-related-resources { margin-top:var(--sp-2xl); padding-top:var(--sp-2xl); border-top:1px solid rgba(23,18,51,0.09); }
.saas-related-resources .wp-block-heading { margin:0 0 var(--sp-md); }

.saas-resource-empty { text-align:center; color:var(--c-muted); font-size:16px; padding:var(--sp-2xl) 0; }
.saas-resource-empty[hidden] { display:none; }

.saas-resource-more-row { display:flex; justify-content:center; margin-top:var(--sp-lg); }

@media (max-width:1023px) {
  .saas-resource-grid { grid-template-columns:repeat(2, 1fr); }
}
@media (max-width:640px) {
  .saas-resource-grid { grid-template-columns:1fr; }
  .saas-resource-clear { align-self:flex-start; margin-left:0; }
}

/* Contact page: HubSpot form container (3 August 2026). HubSpot's own
   script renders the actual form fields into this div; styling here just
   controls spacing, not the fields themselves. */
.saas-hubspot-form { max-width:640px; margin-top:8px; }

/* Anchor-jump targets (Segments/Stakeholders section groups carrying an "anchor" block
   attribute): without this, the browser's native #hash jump aligns the target flush with
   the very top of the viewport, hiding it behind the fixed header. Reverted 27 July 2026
   — a JS layer that instead centred the target section on screen was built, then Jeremy
   asked for it to be undone: landing mid-section shows the tail end of whatever came
   before at the top of the screen, which reads as out of context. Plain top-of-viewport
   (this rule, native browser behaviour, no JS) is the deliberate, confirmed choice. */
[id^="segment-"], [id^="stakeholder-"], [id^="usecase-"], [id^="product-"] { scroll-margin-top:112px; }

/* ---------- client stories flip-to-reveal ---------- */
.saas-flip-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:36px; }
/* Height raised from 424px to 450px 9 August 2026: the homepage cards now carry the
   same real case study titles as the Clients page (was generic short taglines before),
   and NEXA's and Relio's real titles run long enough to overflow the original 424px by
   ~18px once the logo panel above them is locked to a fixed height (flex-shrink:0, see
   below) instead of being allowed to quietly shrink to make room. Checked in a live
   browser test against the real CSS before committing. The Clients page overrides this
   again to 520px for its own, even longer four-card layout (see .page-id-869 rule further
   down), so this 450px only really governs the homepage's three cards in practice. */
.saas-flip-outer { position:relative; height:450px; perspective:1500px; }
.saas-flip-inner { position:relative; width:100%; height:100%; transform-style:preserve-3d; transform:rotateY(180deg) translateZ(0.01px); transition:transform 720ms cubic-bezier(.2,.75,.25,1.05); }
.saas-flip-outer.is-flipped .saas-flip-inner { transform:rotateY(0deg) translateZ(0.01px); }
.saas-flip-front, .saas-flip-back { position:absolute; inset:0; border-radius:18px; backface-visibility:hidden; -webkit-backface-visibility:hidden; }
.saas-flip-front { background:#fff; padding:8px; display:flex; flex-direction:column; text-decoration:none; color:inherit; }
.saas-flip-back { transform:rotateY(180deg); background:radial-gradient(120% 90% at 50% 8%, rgba(109,93,246,0.42), transparent 60%), var(--c-ink); border:1px solid rgba(255,255,255,0.1); display:flex; align-items:center; justify-content:center; }
@media (max-width:768px) {
  .saas-flip-grid { display:flex; flex-direction:column; gap:24px; }
  .saas-flip-outer, .page-id-869 .saas-flip-outer { height:auto; perspective:none; }
  .saas-flip-inner { transform:none !important; transition:opacity 600ms cubic-bezier(.22,.61,.36,1), transform 600ms cubic-bezier(.22,.61,.36,1); transform-style:flat; }
  /* position:static added 17 August 2026: height:auto above only works if something inside
     .saas-flip-outer actually occupies normal document flow. .saas-flip-front (the only
     face left visible once .saas-flip-back is hidden below) was still position:absolute;
     inset:0 from the desktop rule further up, and an absolutely positioned child is taken
     out of flow entirely, so it never contributed to its auto-height parent — the parent
     collapsed to 0px and the three cards' visible content stacked on top of one another
     with only their 24px gap between each card's top edge. Confirmed live: switching the
     front face to normal flow lets it establish real height, so the cards stack and follow
     one another as three separate blocks, exactly as they visually appear to. Found live
     when Jeremy spotted the client story cards overlapping on his phone. */
  .saas-flip-front { position:static; }
  .saas-flip-back { display:none; }
  .saas-flip-outer:not(.is-visible) .saas-flip-inner { opacity:0; transform:translateY(24px); }
  .saas-flip-outer.is-visible .saas-flip-inner { opacity:1; transform:translateY(0); }
}
/* .page-id-869 .saas-flip-outer's own 520px height (added above, 9 August 2026) has
   higher specificity than the plain .saas-flip-outer rule two lines up, so without this
   explicit override this page's cards would stay locked at 520px on mobile too, instead
   of collapsing to auto height like every other flip-card grid once stacked to a single
   column below. */

/* ---------- Clients page case study grid, added 9 August 2026 ----------
   Reuses the homepage's .saas-flip-grid/-outer/-inner flip-to-reveal component exactly
   as-is, only widening it from three teaser cards to four: the "Case Study" resource
   taxonomy now has four real posts (Allica Bank has two distinct case studies, alongside
   NEXA and Relio), where before there were only three placeholder cards. Scoped to this
   page only, via body class, so the homepage's own three-card "Client stories" grid is
   untouched. Four-across on desktop per Jeremy's preference; drops to a 2x2 grid on
   tablet widths so cards don't get too narrow, then to the existing single-column stack
   below 768px (that breakpoint's rule above already handles this page too). */
.page-id-869 .saas-flip-grid { grid-template-columns:repeat(4,1fr); }
@media (max-width:1023px) {
  .page-id-869 .saas-flip-grid { grid-template-columns:repeat(2,1fr); }
}
.page-id-869 .saas-flip-front { justify-content:flex-start; }

/* Card height increased 9 August 2026, alongside the fix directly below: NEXA's and
   Relio's titles run to 3-4 lines, longer than Allica's two 2-line titles, and the
   original 424px card (shared with the homepage's shorter 3-card version) didn't have
   enough room for a full-height logo panel plus a 4-line title without flexbox
   shrinking something to make it fit. Scoped to this page so the homepage's own
   flip-card height is untouched. */
.page-id-869 .saas-flip-outer { height:520px; }

/* Logo panel background revised 9 August 2026: the flat #F5F4FB placeholder read as
   bland and low-contrast next to the rest of the page, and the logos sat too small
   inside it. Replaced with the same dark-ink + coral/violet radial-glow accent treatment
   already used on the homepage's .saas-stat-strip.saas-on-dark (same colour stops, same
   gradient recipe, just reused here rather than a new one invented for this card), so
   the card front now carries real brand colour instead of a neutral box. Since client
   logos vary between dark-on-transparent and colour marks, a white rounded "plate" sits
   centred on the glow so every logo keeps contrast regardless of its own colours, and
   the logo itself is allowed to render noticeably larger (was max-height:72px, now 96px).
   flex-shrink:0 added 9 August 2026: without it, .saas-flip-front's flex layout was
   squashing this panel's height on NEXA and Relio specifically, since flex items shrink
   by default when a taller title needs more room than the fixed-height card has spare —
   the panel was silently losing up to 70px of height while nothing visibly clipped, so it
   looked like a rendering bug (an oddly narrow, pinched logo panel) rather than a layout
   one. Fixed by combining flex-shrink:0 (this panel never shrinks) with the taller card
   above (so there's enough room for a full panel plus a long title without shrinking
   anything). */
.saas-flip-logo {
  display:flex; align-items:center; justify-content:center; height:208px; border-radius:16px;
  flex-shrink:0;
  background:
    radial-gradient(95% 130% at 90% 104%, rgba(255,138,88,0.5), transparent 54%),
    radial-gradient(70% 80% at 4% -6%, rgba(109,93,246,0.34), transparent 55%),
    linear-gradient(140deg,#101436 0%,#241645 52%,#3A1A4E 100%);
}
.saas-flip-logo-plate { background:#fff; border-radius:14px; padding:20px 28px; display:flex; align-items:center; justify-content:center; }
.saas-flip-logo img { max-width:180px; max-height:96px; width:auto; height:auto; }

/* ---------- Prominent subsection heading, added 28 July 2026 ----------
   Per "Key Message Callout - Theme 1a" and "Graphic Backdrop - Theme 1a" mockups: every
   subsection heading in the repeated is-tight/H3 pattern (Segments, Stakeholders, and every
   Platform/Solutions subpage) steps up from the 26px H3 preset to the 40px H2 preset, same
   wording, no eyebrow label added. font-weight:600 already comes from the global "heading"
   element style in theme.json, so only size/line-height/tracking are set here. Scoped to
   h3.wp-block-heading specifically (not the bare .wp-block-heading class) so this cannot
   reach the page-banner H1 (also inside a .saas-content-width.is-tight wrapper) or the
   homepage's raw-HTML News & Insights card headings (h3 with no wp-block-heading class). */
.saas-content-width.is-tight h3.wp-block-heading { font-size:40px; line-height:1.08; letter-spacing:-0.01em; }

/* ---------- Legal pages heading-hierarchy accessibility fix, added 17 August 2026 ----------
   The six /legal/ pages skipped straight from H1 to H3 with no H2, which fails WCAG's
   heading-hierarchy requirement - flagged by an external content reviewer and confirmed with
   Jeremy, who asked for a genuine semantic fix rather than a cosmetic one. Section headings on
   these six pages only (targeted by page ID, not sitewide) were changed from h3 to real h2 in
   post_content. Visual size is kept identical to the existing h3.wp-block-heading pattern
   above (40px/1.08/-0.01em) so nothing about the page's appearance changes, only the
   underlying tag/semantics. Scoped by page-id so this cannot affect the unrelated
   h3.wp-block-heading pattern used elsewhere (Segments, Stakeholders, Platform/Solutions
   subpages), which still intentionally uses h3. */
.page-id-117 h2.wp-block-heading, .page-id-119 h2.wp-block-heading,
.page-id-853 h2.wp-block-heading, .page-id-854 h2.wp-block-heading,
.page-id-855 h2.wp-block-heading, .page-id-867 h2.wp-block-heading {
  font-size:40px; line-height:1.08; letter-spacing:-0.01em;
}
/* Modern Slavery Statement (page 855) also had two H4 sub-headings nested one level under an
   H3 section heading ("Our supply chain"). Since that H3 became H2 above, the sub-headings
   were moved to H3 to keep the hierarchy unbroken (H1->H2->H3). Without an override they'd
   inherit the 40px rule above (same h3.wp-block-heading selector, and this selector is more
   specific so it wins) and become visually indistinguishable from the section heading above
   them, so they're set to the theme's existing 26px H3 preset instead - a genuine
   secondary-heading size already defined in theme.json, not a new number invented for this
   fix. */
.page-id-855 .saas-content-width.is-tight h3.wp-block-heading.saas-legal-subheading {
  font-size:26px; line-height:1.2; letter-spacing:normal;
}

/* ---------- Key Message Callout, added 28 July 2026 ----------
   Per "Key Message Callout - Theme 1a" mockup: a single unattributed emphasis sentence
   beneath a section's body paragraph — 4px Violet accent bar, 24px gap, text at 24px/500
   weight Ink, no box/border/quote marks/attribution. One per section, maximum. Bar height
   matches the text block automatically via align-items:stretch (default), not a fixed
   height, so it works for one-line or wrapped multi-line sentences alike. First use:
   converting the existing bold takeaway line already present in each Segments and
   Stakeholders subsection. */
.saas-key-callout { display:flex; gap:24px; margin-top:34px; }
.saas-key-callout-bar { width:4px; flex:none; border-radius:2px; background:var(--c-violet); }
.saas-key-callout-text { margin:0; font-size:24px; font-weight:500; line-height:1.45; letter-spacing:-0.01em; color:var(--c-ink); text-wrap:pretty; }

/* ---------- Graphic Block + Graphic Backdrop, added 2 August 2026, mat treatment 3 August 2026 ----------
   Per "Graphic Block - Theme 1a" and "Graphic Backdrop - Theme 1a" mockups (Round-1-Mockups):
   a graphic paired with a short text column inside an existing section, in three placements
   (full width / graphic left / graphic right — default markup order is text-then-graphic,
   i.e. graphic right; add .is-graphic-left to reverse) and, so far, one confirmed ratio in
   use, wide graphic (graphic gets 2fr, text 1fr — add .is-ratio-wide-graphic); even (1:1) is
   the unmodified default. This is an inner row, not a second outer wrapper — nest inside the
   page's existing .saas-content-width(.is-tight) group, the same as .saas-key-callout above.
   Intended first use: Segments page, BaaS section, entity-level data separation screenshot
   (T1-01) — not yet placed on any live page. Stacks to a single column at 900px per the
   confirmed spec, source order preserved either way.
   Backdrop treatment superseded twice, both times by Jeremy directly:
   1. A subtle two-stop glow (Rising/Amber) read as a plain grey shadow on a light page —
      too faint to register as brand colour.
   2. A stronger four-gradient dawn-glow composite behind the artwork was still "too subtle"
      once seen at real screenshot scale: against an opaque screenshot, a fixed 56px halo
      margin is a small fraction of the graphic's own width, so almost the whole composite
      sits hidden behind the artwork and only a faint edge survives — a geometry problem,
      not an opacity one, confirmed against a live comparison in the mockup file.
   3 August 2026, current: the "solid colour mat" — the graphic sits INSET inside a rounded
   rectangle filled with Violet → Coral → Amber at full strength (opacity 1, no blur). Fixed
   56px padding on every side regardless of graphic width, so the colour band can't thin out
   as the graphic scales, unlike the glow. This needs a real markup wrapper (padding, not a
   decorative ::before) — .saas-graphic-block-mat, sitting inside the figure, around the img,
   with the figcaption after it (outside the mat, on plain Paper — per the mockup's own rule,
   no text ever sits on the mat, no single text colour clears AA across its full gradient).
   Mirrors with placement per the mockup: .saas-graphic-block-mat is the graphic-right
   composite by default (markup order text-then-graphic); .is-graphic-left swaps in the
   mirrored graphic-left composite. Narrower-column padding (32px, for a graphic under 400px
   wide, e.g. a future wide-text ratio) is documented in the mockup but not yet implemented —
   no placement needs it yet. */
.saas-graphic-block { display:flex; align-items:center; gap:var(--sp-2xl); margin-top:var(--sp-xl); }
.saas-graphic-block-text { flex:1 1 0; min-width:0; }
.saas-graphic-block-figure { flex:1 1 0; min-width:0; margin:0; }
.saas-graphic-block.is-ratio-wide-graphic .saas-graphic-block-figure { flex:2 1 0; }
/* Flex items default to min-width:auto, which lets a deep fixed-width descendant (a
   screenshot's own internal markup, or later a wide <img>) override the flex-basis ratio
   entirely — exactly what happened in the first Segments/BaaS preview, where the text
   column collapsed to a sliver. min-width:0 on both columns forces the 1:2 (or 1:1) ratio
   to actually hold regardless of what's inside either side. Found and fixed 2 August 2026,
   before this pattern went live anywhere. */
.saas-graphic-block.is-ratio-wide-graphic .saas-graphic-block-text p { font-size:17px; line-height:1.55; }
.saas-graphic-block.is-graphic-left { flex-direction:row-reverse; }
.saas-graphic-block-mat {
  border-radius:28px; padding:56px;
  background:
    radial-gradient(84% 104% at 12% 106%, var(--c-coral) 0%, rgba(255,107,74,0) 58%),
    radial-gradient(76% 96% at 92% -8%, var(--c-violet) 0%, rgba(109,93,246,0) 60%),
    radial-gradient(58% 68% at 40% 100%, var(--c-amber) 0%, rgba(255,196,107,0) 52%),
    linear-gradient(225deg, var(--c-violet) 0%, var(--c-coral) 56%, var(--c-amber) 100%);
}
.saas-graphic-block.is-graphic-left .saas-graphic-block-mat {
  background:
    radial-gradient(84% 104% at 88% 106%, var(--c-coral) 0%, rgba(255,107,74,0) 58%),
    radial-gradient(76% 96% at 8% -8%, var(--c-violet) 0%, rgba(109,93,246,0) 60%),
    radial-gradient(58% 68% at 60% 100%, var(--c-amber) 0%, rgba(255,196,107,0) 52%),
    linear-gradient(135deg, var(--c-violet) 0%, var(--c-coral) 56%, var(--c-amber) 100%);
}
.saas-graphic-block-figure img { display:block; width:100%; border-radius:14px; box-shadow:0 26px 54px rgba(23,18,51,0.28); }
.saas-graphic-block-figure figcaption { font-size:15px; color:var(--c-muted); line-height:1.55; margin-top:18px; }
@media (max-width:900px) {
  .saas-graphic-block, .saas-graphic-block.is-graphic-left { flex-direction:column; }
  .saas-graphic-block-text, .saas-graphic-block-figure, .saas-graphic-block.is-ratio-wide-graphic .saas-graphic-block-figure { flex:1 1 auto; }
}

/* ---------- Video paired with text, first use: Stakeholders, Technology / Data ----------
   Jeremy flagged the full-width video card (below) as too heavy for a supporting, in-section
   video: at the content column's full width it ran over 600px tall for a single aside beside
   one paragraph. First use of .saas-graphic-block for video rather than a screenshot; the
   card's own padding (32px 52px 48px, tuned for the full-width case below) reads heavy once
   the card only holds half the row, so tightened here, scoped to this nesting only, so the
   whole-page cards keep their original padding. Added 10 August 2026. */
.saas-graphic-block-figure .saas-stat-strip { padding:20px; border-radius:16px; }

/* ---------- Whole-page ("hero") video card width cap ----------
   Added 10 August 2026 for Data You Own and Why SaaScada's videos: each page's single video
   moment, so these kept the full-width stacked card treatment rather than the paired layout
   above, at a width capped narrower and centred (via --w-video-promo) so the card reads as a
   deliberately placed feature rather than a wall.
   SUPERSEDED 11 August 2026 for Data You Own: it moved to the paired .saas-graphic-block.
   is-graphic-left layout (thumbnail-card left, eyebrow+heading right), same change as the
   bare .saas-video-preview-cap pages above -- its .saas-stat-strip.saas-on-dark card now sizes
   from the graphic-block figure column instead of this cap, so .saas-video-hero was dropped
   from its markup.
   This rule remains live only for Why SaaScada's two videos, not yet converted -- see the
   note on .saas-video-preview-cap above for why, and the open question for Jeremy. */
.saas-stat-strip.saas-video-hero { max-width:var(--w-video-promo); margin-left:auto; margin-right:auto; }

/* Page-level video promo width -- confirmed 10 August 2026, Phase 3w.
   SUPERSEDED 11 August 2026 for Platform, Ecosystem, Solutions and Data You Own: their
   page-level video promos moved to the paired .saas-graphic-block.is-graphic-left layout
   below (thumbnail left, eyebrow+heading right, heading demoted h2->h3), per Jeremy's request
   after finding the old full-width stacked video too deep on the page. That layout sizes its
   video from the graphic-block's own flex column, not this cap.
   This rule and --w-video-promo remain live only for Why SaaScada's two videos (still via
   .saas-video-hero below) -- not yet converted, since those videos sit beside full paragraphs
   of body copy rather than a short eyebrow+heading, a different shape to the other four; open
   question for Jeremy. If Why SaaScada converts too, this rule and --w-video-promo become
   fully dormant and can be removed.
   Original intent, for context: every page-level video promo was capped to the same width via
   --w-video-promo, regardless of dark full-bleed background (Platform, via this class) or a
   card on a light/dark section background (via .saas-video-hero below). Value set from
   Jeremy's reference point on Platform: the video's right edge level with the end of
   "consectetur" in the heading above it. */
.saas-video-preview-cap { max-width:var(--w-video-promo); }

/* ---------- Ecosystem page: partner directory (search + Type/Category filter,
   [saascada_partner_directory] shortcode, functions.php) — 4 August 2026.
   Search input and filter pills reuse the .saas-jump-pill look (see above) rather
   than a new pattern; the card reuses .saas-card conventions (h3/p spacing). New
   pieces are the Type-chip row (a partner can carry more than one Type, so this is
   a row of chips, not a single badge) and the Category tag row underneath the
   description. */
.saas-partner-search-row { margin-bottom:var(--sp-lg); }
.saas-partner-search { width:100%; max-width:420px; padding:12px 16px; border-radius:999px; border:1px solid rgba(23,18,51,0.16); background:var(--c-paper); color:var(--c-ink); font-family:inherit; font-size:15px; }
.saas-partner-search::placeholder { color:var(--c-muted); }
.saas-partner-search:focus-visible { outline:none; border-color:var(--c-violet); box-shadow:0 0 0 3px rgba(109,93,246,0.22); }

.saas-partner-filters { display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--sp-xl); margin-bottom:var(--sp-lg); }
.saas-partner-filter-group { display:flex; flex-direction:column; gap:8px; }
.saas-partner-filter-label { font-size:13px; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--c-muted); margin:0; }
.saas-partner-pill-row { display:flex; gap:10px; flex-wrap:wrap; }
.saas-partner-pill { flex:0 0 auto; display:inline-flex; align-items:center; gap:6px; padding:8px 16px; border-radius:999px; background:var(--c-mist); color:var(--c-ink); font-size:14px; font-weight:600; white-space:nowrap; cursor:pointer; transition:background 150ms ease, color 150ms ease; }
.saas-partner-pill input { position:absolute; opacity:0; width:1px; height:1px; }
@media (hover:hover) and (pointer:fine) { .saas-partner-pill:hover { background:var(--c-violet); color:#fff; } }
.saas-partner-pill:has(input:checked) { background:var(--c-violet); color:#fff; }
.saas-partner-pill:has(input:focus-visible) { outline:none; box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--c-violet); }
.saas-partner-clear { align-self:flex-end; margin-left:auto; }

.saas-partner-count { font-size:14px; color:var(--c-muted); margin:0 0 var(--sp-md); }

.saas-partner-grid { display:grid; grid-template-columns:repeat(3, 1fr); gap:var(--sp-lg); }
.saas-partner-card { display:flex; flex-direction:column; padding:28px; border-radius:var(--radius-lg); background:var(--c-mist); }
.saas-partner-card[hidden] { display:none; }
.saas-partner-card-logo { display:flex; align-items:center; height:40px; margin-bottom:var(--sp-md); }
.saas-partner-card-logo img { max-height:40px; max-width:150px; width:auto; height:auto; object-fit:contain; }
.saas-partner-card h3 { font-size:20px; font-weight:600; margin:0 0 var(--sp-sm); color:var(--c-ink); }
.saas-partner-card-types { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:var(--sp-sm); }
.saas-partner-type-chip { display:inline-flex; align-items:center; padding:4px 12px; border-radius:999px; background:rgba(109,93,246,0.12); color:var(--c-violet); font-size:12px; font-weight:600; }
.saas-partner-card-desc { font-size:15px; color:var(--c-slate); line-height:1.5; margin:0 0 var(--sp-sm); flex:1 1 auto; }
.saas-partner-card-categories { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:var(--sp-sm); }
.saas-partner-category-tag { display:inline-flex; align-items:center; padding:3px 10px; border-radius:6px; background:rgba(23,18,51,0.06); color:var(--c-muted); font-size:12px; font-weight:500; }
.saas-partner-card-link { align-self:flex-start; margin-top:auto; }

.saas-partner-empty { text-align:center; color:var(--c-muted); font-size:16px; padding:var(--sp-2xl) 0; }
.saas-partner-empty[hidden] { display:none; }

@media (max-width:1023px) {
  .saas-partner-grid { grid-template-columns:repeat(2, 1fr); }
}
@media (max-width:640px) {
  .saas-partner-grid { grid-template-columns:1fr; }
  .saas-partner-clear { align-self:flex-start; margin-left:0; }
}

/* ---------- Management Team page: person cards ----------
   Simple photo + name + role card, used for both the Leadership and Board
   grids on the Management Team page (built 4 August 2026). No existing
   card pattern in the design system included a photo, so this is a small,
   contained addition — native Gutenberg group/image/heading blocks plus
   this CSS only, no PHP, no plugin. Three people (Nelson Wootton, Steve
   Round, Belinda Wrigley) sit in both grids and reuse the same media
   library image in each — this is a plain content decision, nothing
   special in the CSS accounts for it. */
.saas-team-grid { display:grid; grid-template-columns:repeat(5, 1fr); gap:var(--sp-lg); margin:var(--sp-lg) 0 var(--sp-2xl); }
.saas-team-card { display:flex; flex-direction:column; }
.saas-team-card img { width:100%; aspect-ratio:5/3; object-fit:cover; border-radius:var(--radius-lg); margin-bottom:var(--sp-sm); }
.saas-team-card h3 { font-size:20px; font-weight:600; margin:0 0 4px; color:var(--c-ink); }
.saas-team-card p { font-size:14px; color:var(--c-muted); margin:0; }
/* Bio paragraph, added 5 August 2026: always the second <p> in a card (role is the
   first), so it's targeted via the adjacent-sibling selector rather than a new class —
   no change needed to the role paragraph's own existing markup. Larger and darker than
   the role label so it reads as body copy, not a second label. */
.saas-team-card p + p { margin-top:8px; font-size:15px; line-height:1.5; color:var(--c-slate); }

@media (max-width:1023px) {
  .saas-team-grid { grid-template-columns:repeat(3, 1fr); }
}
@media (max-width:640px) {
  .saas-team-grid { grid-template-columns:repeat(2, 1fr); }
}
