/* RedSprout — design system
   Brand: red #C40808, charcoal #1A1A1C, off-white paper.
   Signature: the sourced figure. Every number carries its source, so the
   design makes an unsourced claim physically impossible to render.
   No framework. No utility classes. ~1 request. */

/* ---------------------------------------------------------- tokens */
:root {
  --rsd-red:        #C40808;
  --rsd-red-ink:    #980606;
  --rsd-charcoal:   #1A1A1C;
  --rsd-paper:      #F7F6F4;
  --rsd-white:      #FFFFFF;
  --rsd-line:       #E3E0DA;
  --rsd-muted:      #63636A;

  /* D-24: display and body both self-host the same variable file,
     inter-tight.woff2 (inc/enqueue.php) — one @font-face, weight axis
     100-900, so every existing font-weight declaration throughout this
     file (h1-h4's 700, the many display-role rules' 600, a bare <th>'s
     browser-default bold, etc.) renders natively rather than through a
     second family. Only a generic fallback after it now, deliberately —
     Archivo and Plex Sans are gone, not demoted to a fallback position. */
  --rsd-display: "Inter Tight", sans-serif;
  --rsd-body:    "Inter Tight", sans-serif;
  /* D-24's instrument voice (figures, eyebrows, source lines, table
     numerals) — untouched by the Inter Tight switch above. No .woff2
     file exists yet, so this still falls back to the system monospace
     stack until one is added. */
  --rsd-mono:    "IBM Plex Mono", ui-monospace, "SF Mono", Consolas, monospace;

  /* Type scale — widened for clearer hierarchy. Each step now clamps
     between a mobile-floor and a desktop-ceiling computed with the same
     fluid formula (minVP 375px → maxVP 1280px), so the ratio between
     levels holds at every width instead of compressing toward ~1.26 at
     the narrow end the way the old scale did. Ratio to the step below:
     lg~1.13, h3/base~1.3-1.65, h2/h3~1.3-1.43, h1/h2~1.25-1.6 — was as
     tight as ~1.26 across the board at mobile widths before. --rsd-t-base
     stays exactly where it was: body copy wasn't the thing reading flat. */
  --rsd-t-xs:  0.78rem;
  --rsd-t-sm:  0.875rem;
  /* --rsd-t-base / --rsd-t-h1/h2/h3 — Stage 1 of the RedSprout Typography
     Customizer (inc/typography.php). base now resolves through
     --rsd-t-body-size (a plain admin-controlled number, since body was
     already deliberately non-fluid); h1/h2/h3 now resolve through a
     calc()-based fluid interpolation between admin-controlled
     --rsd-t-h{n}-min/-max endpoints, using the SAME fixed 375px/1280px
     viewport anchors the original hand-tuned clamp() values already used
     (verified: this formula reproduces the original clamp(2.4rem, 2.83vw +
     1.74rem, 4rem) etc. to within floating-point rounding at every
     viewport). All interpolation math still happens here, in CSS, at
     paint time — inc/typography.php only ever emits the two numeric
     endpoints per level, never a clamp()/calc() string of its own. Every
     var() fallback below is the exact literal this token used to be, so
     with no Customizer save at all (theme freshly activated, or this
     file's wp_head callback not running for any reason) every one of
     these renders byte-identical to before Stage 1. */
  --rsd-t-base: var(--rsd-t-body-size, 1.0625rem);
  --rsd-t-lg:  clamp(1.2rem,  0.27vw + 1.14rem, 1.35rem);
  /* Section intro — the paragraph under a section's H2 (.rsd-section-head /
     .rsd-showcase__head .rsd-lede). A step quieter than --rsd-t-lg, which
     .rsd-lede keeps everywhere else (page heroes, the Hero lead): 16px on
     phones, ~16.3–17px on tablets, 17px at 1024 rising to 18px at 1440. */
  --rsd-t-intro: clamp(1rem, 0.25vw + 0.9rem, 1.125rem);
  --rsd-t-h3:  clamp(var(--rsd-t-h3-min, 1.4rem), calc(var(--rsd-t-h3-min, 1.4rem) + (var(--rsd-t-h3-max, 1.75rem) - var(--rsd-t-h3-min, 1.4rem)) * ((100vw - 375px) / (1280px - 375px))), var(--rsd-t-h3-max, 1.75rem));
  --rsd-t-h2:  clamp(var(--rsd-t-h2-min, 1.85rem), calc(var(--rsd-t-h2-min, 1.85rem) + (var(--rsd-t-h2-max, 2.5rem) - var(--rsd-t-h2-min, 1.85rem)) * ((100vw - 375px) / (1280px - 375px))), var(--rsd-t-h2-max, 2.5rem));
  --rsd-t-h1:  clamp(var(--rsd-t-h1-min, 2.4rem), calc(var(--rsd-t-h1-min, 2.4rem) + (var(--rsd-t-h1-max, 4rem) - var(--rsd-t-h1-min, 2.4rem)) * ((100vw - 375px) / (1280px - 375px))), var(--rsd-t-h1-max, 4rem));
  /* H4/H5/H6 — Typography Phase 2. Fixed (not fluid/Customizer-driven,
     unlike H1-H3 above), sourced from real-browser measurement of this
     theme's current, unstyled rendering: before this phase h4/h5/h6 had
     no font-size rule of their own anywhere in this file and rendered
     via the browser's own UA-default relative sizing (1em/.83em/.67em
     of whatever font-size their container happened to inherit). These
     three values are that same measurement, fixed to rem so H4-H6 now
     render the same size everywhere rather than continuing to float with
     whatever ambient font-size context they happen to sit inside — the
     one deliberate behavior change this phase makes, flagged in this
     phase's own report rather than left silent. 16px root, unscaled
     (no html{font-size} override exists in this file — confirmed). */
  --rsd-t-h4: 1.25rem;    /* 20px, measured */
  --rsd-t-h5: 1.0375rem;  /* 16.6px, measured */
  --rsd-t-h6: 0.8375rem;  /* 13.4px, measured */

  --rsd-shell: 1180px;
  --rsd-read:  68ch;

  /* Vertical rhythm — one scale, three tiers, all fluid.
     --rsd-gap-sm  (small)  — between related items inside one group: cards
                              in a row, points/steps siblings, a badge list.
     --rsd-gap     (medium) — between a heading and the content under it,
                              and between the two sides of a two-column split.
     --rsd-block   (large)  — between one major section and the next.
     Applied consistently below via .rsd-shell + .rsd-shell (large) and the
     existing/standardized heading-adjacent and item-grid rules (medium/
     small) — not per pattern, so every pattern inherits it automatically. */
  --rsd-gap-sm: clamp(.75rem, 1.5vw, 1.1rem);
  --rsd-gap:   clamp(1.25rem, 3vw, 2.5rem);
  --rsd-block: clamp(3rem, 6vw, 5.5rem);
  --rsd-radius: 4px;
  /* Names the pill shape (.rsd-pill, .rsd-badge, the eyebrow "pill" style,
     the header/CTA pill buttons) already used at 999px in five places —
     a second, distinct radius tier from --rsd-radius above, not a
     replacement for it. Values unchanged; this only gives the existing
     number a name. */
  --rsd-radius-pill: 999px;

  /* Shadow scale — names the neutral (charcoal-based) elevation values
     already in use (mega menu panel, the floating CTA button's mobile/
     circular state, the proposal-CTA modal), each carried over verbatim
     from its existing selector. Not every existing box-shadow maps onto
     one of these three cleanly (a couple of one-off values and the brand-
     red CTA hover glow stay hardcoded rather than be nudged onto the
     nearest tier and quietly change) — see the shadow comments further
     down this file for those. .rsd-pill's own scroll-driven shadow is
     deliberately NOT tokenized here: it's a calc()-composed value tied to
     --rsd-st, not a static one, and forcing it through a static token
     would require flattening that formula. */
  --rsd-shadow-subtle:    0 8px 30px rgba(26, 26, 28, .06);
  --rsd-shadow-medium:    0 12px 32px rgba(26, 26, 28, .10);
  --rsd-shadow-prominent: 0 12px 32px rgba(26, 26, 28, .16);

  /* Names the four weights this design already uses (verified against
     every font-weight declaration in this file) — not the full 100-900
     range the variable font technically supports. Matches
     rsd_typography_weights() (inc/typography.php) exactly, so the same
     four names mean the same thing in the Customizer and here. Values
     unchanged everywhere they're applied below; this only gives the
     existing numbers names. The Customizer-driven --rsd-t-*-weight
     variables (body/H1-H3/menu) and their main.css var() fallback
     literals are untouched — those belong to that system, not this
     token layer, and already resolve to one of these same four numbers. */
  --rsd-weight-regular:  400;
  --rsd-weight-medium:   500;
  --rsd-weight-semibold: 600;
  --rsd-weight-bold:     700;

  /* Color System Phase 1 — the one genuinely new token this phase adds.
     rgba(26,26,28,.55) (--rsd-charcoal at 55% alpha) was already the
     drawer scrim's and the CTA modal's backdrop-dimming color,
     independently, at the exact same value — a real repeated semantic
     role ("dim what's behind an open overlay"), not just a coincidence,
     so it's named here. Every other repeated-looking rgba() in this file
     (the --rsd-paper-at-various-alphas footer text hierarchy, the
     --rsd-red-at-various-alphas hover/glow set) was deliberately left
     alone: each of those is a hand-tuned set of genuinely DIFFERENT
     alpha values for different purposes, not one value reused, and
     forcing them into shared tokens would either invent single-use
     variables or quietly merge values that were never meant to match. */
  --rsd-overlay: rgba(26, 26, 28, .55);

  /* Spacing & Layout Foundation Phase 1 — two tokens, both already
     documented, repeated, single-role values in this file; not a new
     4/8 scale.
     --rsd-tap-target names the 44px accessible hit-area/min-height floor
     already called out by name in this file's own comments (.rsd-btn,
     the sidebar search field/button, the Gutenberg button bridges) —
     applied only where that's genuinely the role. Deliberately NOT
     applied to the visually-identical 44px avatar images (.rsd-author
     img, .rsd-feedback__media — a decorative size, not a tap target) or
     to any 44px inside the mobile drawer/hamburger/menu-toggle cluster
     (.rsd-call, .rsd-hamburger, .rsd-drawer__close, .rsd-menu__toggle,
     .rsd-drawer__actions) — left as literals out of the same caution
     this phase was told to apply to mobile-only rules, even though the
     substitution would be byte-identical.
     --rsd-shell-gutter names the 2.5rem horizontal gutter already
     reused verbatim by .rsd-shell/.rsd-shell--narrow/.rsd-shell--wide
     and the home-section self-constraint (copied from .rsd-shell "not
     re-derived", per that rule's own comment). Deliberately NOT applied
     to .rsd-pill's own width calc, which uses the same 2.5rem value but
     is Header/Mega-Menu geometry — left alone per "if uncertain, leave
     them alone." */
  --rsd-tap-target: 44px;
  --rsd-shell-gutter: 2.5rem;
  /* The existing wide container width (.rsd-shell--wide), named so the
     RedSprout Section's Wide option reuses the same value. */
  --rsd-shell-wide: 1400px;

  /* Interaction motion — one duration and one curve for button and nav
     hovers. The curve is the one .rsd-pill's own sticky transition and
     the mega-menu panel already use: quick start, soft settle. */
  --rsd-motion-fast: .2s;
  --rsd-ease-out: cubic-bezier(.2, .8, .2, 1);
  /* The two longer tiers the theme already uses as literals — .3s for a
     state change (the sticky header, panel swaps), .6s for an image easing
     in — named so new components reuse them instead of inventing a fourth
     value. The reveal engine (assets/js/scroll-reveal.js) keeps its own
     GSAP durations; this is the CSS-transition side only. */
  --rsd-motion-base: .3s;
  --rsd-motion-slow: .6s;
}
@media (prefers-reduced-motion: reduce) {
  :root { --rsd-motion-fast: .01s; --rsd-motion-base: .01s; --rsd-motion-slow: .01s; }
}

/* ---------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
/* scroll-behavior was missing entirely — an in-page anchor jump (a TOC
   link on a blog post, any #id href) snapped instantly with no smooth
   scroll at all. The prefers-reduced-motion:reduce override further down
   this file (the *,*::before,*::after block forcing scroll-behavior:auto
   !important) already existed before this did, which only made sense as
   a safety override for a smooth default that was never actually set —
   this is what that rule was always meant to be overriding. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
/* While Lenis (assets/js/lenis-init.js) drives the scroll it writes
   scrollTop every frame; under scroll-behavior:smooth each write starts a
   native smooth scroll, so the page trails Lenis by thousands of px and
   catches up late — the scroll jank and late-rendering sections. Lenis's
   own stylesheet ships this rule; the theme loads only its JS. Anchor
   jumps with Lenis idle keep the smooth default above. */
html.lenis.lenis-smooth { scroll-behavior: auto !important; }
body {
  margin: 0;
  background: var(--rsd-body-bg, var(--rsd-paper));
  color: var(--rsd-body-text, var(--rsd-charcoal));
  font-family: var(--rsd-t-body-family, var(--rsd-body));
  font-weight: var(--rsd-t-body-weight, 400);
  /* Direct reference to the Customizer's own leaf variable, not the
     --rsd-t-base intermediary below — matches every other property in
     this rule (all single-hop) and fixes the one property that wasn't:
     the two-level --rsd-t-body-size -> --rsd-t-base -> font-size chain
     didn't reactively update in the Customizer's live-preview iframe,
     even though the underlying --rsd-t-body-size value itself was set
     correctly (see the Body Font-Size Live Preview Bug diagnosis).
     --rsd-t-base itself is untouched — .rsd-hero__aside h2 and any other
     consumer of --rsd-t-base still resolves through it exactly as before. */
  font-size: var(--rsd-t-body-size, 1.0625rem);
  line-height: var(--rsd-t-body-line-height, 1.6);
  letter-spacing: var(--rsd-t-body-letter-spacing, 0em);
  -webkit-font-smoothing: antialiased;
}
img, svg, video { max-width: 100%; height: auto; }
/* line-height 1.12 was already inside the requested 1.1-1.2 band; margin
   nudged 0.5em→0.6em for a touch more room under every heading (the
   "medium" gap before whatever follows — an intro paragraph, a card grid
   — reads a little pinched at 0.5em once the type scale above got wider). */
/* Split for Stage 1 of the RedSprout Typography Customizer
   (inc/typography.php): line-height/margin stay shared across all four
   levels (not in this stage's control scope) — family/weight/letter-
   spacing become independently variable-driven for h1/h2/h3 only. h4 is
   deliberately left as a plain literal, byte-identical to what the old
   shared rule gave it (Inter Tight/700/-0.02em) — H4/H5/H6 are out of
   scope for this stage entirely, pending a separate design pass. Every
   var() fallback below reproduces the exact value the old single shared
   rule used, so with no Customizer save this renders identically. */
h1, h2, h3, h4 { line-height: 1.12; margin: 0 0 0.6em; }
/* font-size (Phase 1 foundation): a plain semantic heading — a core
   Heading block with no RedSprout style picked, a bare <h2> in content —
   now gets its proper fluid scale step instead of the browser's UA default
   (which read as body-sized text at H2/H3). Element selectors, so every
   existing class-based size (.rsd-eyebrow, .rsd-card__title,
   .rsd-hero__aside h2, .rsd-footer__col h2, …) still wins exactly as
   before; audited — every classless h1-h3 the theme's own templates print
   already sits under one of those rules. */
h1 { font-size: var(--rsd-t-h1); font-family: var(--rsd-t-h1-family, var(--rsd-display)); font-weight: var(--rsd-t-h1-weight, 700); letter-spacing: var(--rsd-t-h1-letter-spacing, -0.02em); }
h2 { font-size: var(--rsd-t-h2); font-family: var(--rsd-t-h2-family, var(--rsd-display)); font-weight: var(--rsd-t-h2-weight, 700); letter-spacing: var(--rsd-t-h2-letter-spacing, -0.02em); }
h3 { font-size: var(--rsd-t-h3); font-family: var(--rsd-t-h3-family, var(--rsd-display)); font-weight: var(--rsd-t-h3-weight, 700); letter-spacing: var(--rsd-t-h3-letter-spacing, -0.02em); }
h4 { font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold); letter-spacing: -0.02em; font-size: var(--rsd-t-h4); }
/* H5/H6 — no margin rule here deliberately: only font-size/line-height/
   weight/family were measured this phase, so only those are formalized.
   Margin stays whatever it already renders as today (not bundled into
   the shared h1-h4 rule above), same reasoning as leaving letter-spacing
   unset below — inherited/UA behavior this phase didn't measure is left
   exactly as it already is, not guessed at. */
h5, h6 { line-height: 1.12; font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold); }
h5 { font-size: var(--rsd-t-h5); }
h6 { font-size: var(--rsd-t-h6); }
/* RedSprout Colors (inc/colors.php) — H1-H3 get their color from the
   .rsd-h1/.rsd-h2/.rsd-h3 component classes below (the selectors every
   template actually uses), not here. H4-H6 have no such class anywhere in
   this theme, so their color lives on the bare element instead — scoped
   with :not(.rsd-footer *) because .rsd-footer__col h4 has no color rule
   of its own and currently gets --rsd-paper by inheritance from .rsd-footer;
   an unscoped h4{color} would win over that inherited value (a direct
   match always beats inheritance, regardless of specificity) and silently
   break the footer's heading color. */
h4:not(.rsd-footer *) { color: var(--rsd-h4, var(--rsd-charcoal)); }
h5:not(.rsd-footer *) { color: var(--rsd-h5, var(--rsd-charcoal)); }
h6:not(.rsd-footer *) { color: var(--rsd-h6, var(--rsd-charcoal)); }
p { margin: 0 0 1.1em; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--rsd-red); }
/* Link Color / Link Hover Color (RedSprout Colors) are scoped to body-copy
   links only, not the sitewide `a{color:inherit}` rule above — that rule
   is deliberate (e.g. white links in .rsd-cta's dark band inherit white),
   and a blanket override would break it. .rsd-prose is the one context
   these two controls cleanly apply to. */
.rsd-prose a:not(.rsd-btn) { color: var(--rsd-link, inherit); }
.rsd-prose a:not(.rsd-btn):hover { color: var(--rsd-link-hover, inherit); }
/* Applies to every interactive element by default. Four components used
   to override this with a tighter 1px offset (form/capture inputs, the
   modal close button) or a different colour entirely (.rsd-cta-btn, which
   used charcoal — presumably to avoid a red-on-red clash, but
   outline-offset:3px places the ring on the page background outside the
   button, not over its red fill, so that concern doesn't actually apply).
   All four removed rather than reconciled individually, so this one rule
   is genuinely the only definition of what focus looks like. */
:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 3px; }

.rsd-skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--rsd-charcoal); color: var(--rsd-white); padding: .75rem 1rem;
}
.rsd-skip:focus { left: 0; }

/* ---------------------------------------------------------- layout */
.rsd-shell { width: min(100% - var(--rsd-shell-gutter), var(--rsd-shell)); margin-inline: auto; }
.rsd-shell--narrow { width: min(100% - var(--rsd-shell-gutter), 820px); }
.rsd-shell--wide { width: min(100% - var(--rsd-shell-gutter), var(--rsd-shell-wide)); }
/* Full: the whole available width, keeping only the standard side gutter
   (RedSprout Section's "Full width" content option). */
.rsd-shell--full { width: calc(100% - var(--rsd-shell-gutter)); }
/* overflow-x:clip guards against the one full-bleed element in this theme
   (.rsd-hero-service, further down this file) — its 100vw breakout can run
   ~15-17px past the true viewport edge on Windows/Chrome, where a classic
   (non-overlay) scrollbar's own width counts inside 100vw. clip (not
   hidden) so it doesn't create a new scroll container or block any
   position:sticky element inside main — there isn't one today, but hidden
   would silently break one if added later. */
.rsd-main { padding-block: clamp(1.5rem, 4vw, 2.75rem) var(--rsd-block); overflow-x: clip; }

/* Large-tier section rhythm — every pattern wraps each of its major
   sections in its own top-level .rsd-shell (hero, cards, cta, faq, all of
   it — see inc/patterns.php, inc/patterns-services-hub.php,
   inc/patterns-page-types.php), so one adjacent-sibling rule here gives
   every one of the 31 patterns consistent large spacing between sections
   without touching a single pattern file. Only fires between siblings —
   the first section in a page never gets extra top space it doesn't need.
   Where an inner element (e.g. .rsd-home-section) already carries its own
   var(--rsd-block) top margin, this collapses with it rather than adding
   to it (same value, adjoining margins collapse to the larger/equal one,
   not the sum) — so sections that already had rhythm keep exactly the
   same spacing; the ones that had none (.rsd-cta, .rsd-strip, a bare
   .rsd-shell wrapping a shortcode) are the ones this actually fixes. */
.rsd-shell + .rsd-shell { margin-top: var(--rsd-block); }

/* .rsd-shell nested inside .rsd-prose — Case Study alignment audit fix.
   .rsd-shell's own width:min(100% - 2.5rem, var(--rsd-shell)) formula
   assumes "100%" is the page-level container (.rsd-main / .rsd-layout__main),
   which is true for every top-level use of this class. But every RS
   Content and RS Section pattern (inc/shared-blocks.php) carries .rsd-shell
   on its own outer group, and when such a pattern is inserted into
   the_content() on a template that wraps the_content() in <div
   class="rsd-prose"> (e.g. single-case_studies.php), .rsd-shell's "100%"
   resolves against .rsd-prose's own already-narrower, already-correctly-
   positioned box instead — reapplying the same width/centering math a
   second time and producing a phantom ~20px inset on both edges, relative
   to every other section on the page (confirmed by direct DOM/CSS trace:
   the pattern's own .rsd-shell root is always a direct child of the
   template's .rsd-prose wrapper, since the_content() inserts each
   top-level block with no extra wrapper of its own).
   .rsd-prose already IS the correct rail in this context — flush with
   .rsd-layout__main, capped at --rsd-read — so .rsd-shell nested inside it
   should fill that rail exactly rather than carving out a second, narrower
   one. Same approach as .rsd-main > .rsd-home-section further down this
   file: a context-scoped selector that engages only for the specific
   nested case, leaving every top-level .rsd-shell — the overwhelming
   majority of its usage, everywhere else on the site — untouched. */
.rsd-prose > .rsd-shell { width: 100%; margin-inline: 0; }

/* The same phantom-inset fix, generalised (Phase 1 foundation): any
   .rsd-shell inside another .rsd-shell fills its parent rather than
   re-applying the gutter math a second time. Needed now that dynamic
   blocks and the Services Showcase carry their own .rsd-shell (so a block
   is correctly contained on the un-shelled homepage) — on page.php, which
   already wraps the_content() in a .rsd-shell, that would otherwise inset
   every such block ~20px per side from the page heading above it. The
   header uses no .rsd-shell; the footer's single .rsd-shell is never
   nested. */
.rsd-shell .rsd-shell { width: 100%; }

/* ---------------------------------------------------------- layout engine (RedSprout Layouts)
   One grid, three modifiers — rsd-layout--full/sidebar-right/sidebar-left
   (inc/layout.php, rsd_layout_class()) — instead of three separate
   templates. Markup order is always main-then-sidebar regardless of mode;
   sidebar-left only reorders visually via `order`, and only above the
   breakpoint where a left/right split exists at all — so the mobile
   single-column fallback already reads main content first with zero extra
   CSS. --rsd-sidebar-w comes from the Sidebar Width Customizer setting
   (inc/layout.php, wp_head) — never hardcoded here. */
.rsd-layout { display: grid; grid-template-columns: 1fr; gap: var(--rsd-block); align-items: start; }
.rsd-layout__main, .rsd-layout__sidebar { min-width: 0; }

/* Sidebar widget system — shared, generic styling for whatever
   dynamic_sidebar() renders (register_sidebar()'s own areas take "any
   block or widget", inc/layout.php), so a sidebar reads as one clean,
   editorial column instead of unrelated widgets running together, without
   needing to know in advance what any individual widget is. Deliberately
   restrained: no per-widget "card" background — the sidebar container's
   own --rsd-sidebar-bg/--rsd-sidebar-text (below) already carry surface
   color; a second, opaque background per widget would fight that and
   read as a stack of heavy boxes instead of one calm column. Separation
   comes from spacing, a hairline border, and typography only. */
.rsd-layout__widget { min-width: 0; }
/* Root cause of the excessive Search-to-next-widget gap (audited, not
   guessed): this used to be margin-top:var(--rsd-block) AND
   padding-top:var(--rsd-block) — the SAME large token (clamp(3rem,6vw,
   5.5rem), up to 88px) applied twice, once on each side of the border-top
   hairline, compounding to as much as 176px of empty space between two
   widgets. wp-block-library/wp-block-library-theme/global-styles/
   classic-theme-styles are all dequeued (inc/cleanup.php) and classic
   widgets (Search included) ship no CSS of their own, so there is no
   browser- or WordPress-default margin anywhere in this picture — the
   entire gap traced back to this one rule doubling itself. Fixed by
   splitting the theme's existing, more moderate --rsd-gap token evenly
   across margin-top and padding-top (calc(...)/2 each side, same
   calc()-on-an-existing-token pattern the divider rule below already uses
   for its own offset) so the border-top divider sits with roughly equal
   breathing room above and below it, totaling --rsd-gap rather than
   2x --rsd-block. */
.rsd-layout__widget + .rsd-layout__widget {
  margin-top: calc(var(--rsd-gap) / 2);
  padding-top: calc(var(--rsd-gap) / 2);
  border-top: 1px solid var(--rsd-line);
}
.rsd-layout__widget > :last-child { margin-bottom: 0; }

/* Lists — Categories, Archives, Pages, Nav Menu, Latest Posts: core block
   or classic widget, all render a plain <ul>/<ol>. No default browser
   bullet indentation; a hairline divider between items instead; enough
   line-height that a wrapped, long title stays easy to scan rather than
   feeling cramped. Scoped to .rsd-layout__widget only, so this can never
   reach an .rsd-cta or similar module's own list styling if one is ever
   dropped into a sidebar — that module's own, more specific rules, further
   down this file, keep winning exactly as they already do everywhere else
   (same reasoning as .rsd-prose > .rsd-shell above: a scoped rule for one
   context, the general one left alone everywhere else). */
.rsd-layout__widget ul,
.rsd-layout__widget ol {
  list-style: none;
  margin: 0;
  padding: 0;
}
.rsd-layout__widget li {
  padding-block: .55rem;
  line-height: 1.5;
  overflow-wrap: break-word;
}
.rsd-layout__widget li + li { border-top: 1px solid var(--rsd-line); }
.rsd-layout__widget li ul,
.rsd-layout__widget li ol {
  margin-top: .4rem;
  padding-left: 1rem; /* a modest child-category indent, not the browser default */
}
.rsd-layout__widget li > a { display: block; }

/* Search — the core Search block and the classic Search widget render
   different markup for the same control; both are styled so the result
   looks identical regardless of which an admin drops in. This base rule
   is mobile's own behavior (<768px — unedited by the 768px+ override
   below): flex-wrap is the overflow safeguard, so if the sidebar column
   is ever narrower than input+button can share, the button drops to its
   own line instead of being crushed; min-width:0 on the flexed input is
   what stops it from refusing to shrink below its content/default size,
   the standard flexbox cause of exactly this kind of overflow. */
.rsd-layout__widget .search-form,
.rsd-layout__widget .wp-block-search__inside-wrapper {
  display: flex; flex-wrap: wrap; gap: .5rem; width: 100%;
}
.rsd-layout__widget .search-form label { flex: 1 1 160px; min-width: 0; }
.rsd-layout__widget .search-field,
.rsd-layout__widget .wp-block-search__input {
  flex: 1 1 160px; min-width: 0; width: 100%; box-sizing: border-box;
  height: var(--rsd-tap-target); padding: 0 .85rem;
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
  font: inherit; font-size: var(--rsd-t-sm);
  background: var(--rsd-surface, var(--rsd-white)); color: inherit;
}
.rsd-layout__widget .search-submit,
.rsd-layout__widget .wp-block-search__button {
  flex: 0 0 auto; height: var(--rsd-tap-target); padding: 0 1.1rem;
  border: 1px solid transparent; border-radius: var(--rsd-radius);
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm);
  background: var(--rsd-button-bg, var(--rsd-red)); color: var(--rsd-button-text, #fff);
  cursor: pointer;
}
.rsd-layout__widget .search-submit:hover,
.rsd-layout__widget .wp-block-search__button:hover {
  background: var(--rsd-button-hover-bg, var(--rsd-red-ink));
  color: var(--rsd-button-hover-text, #fff);
}

/* Desktop/tablet only (768px+ — the same breakpoint the two-column
   sidebar itself already begins at, .rsd-layout--sidebar-right above) —
   forces the search row onto one line instead of the mobile rule's
   wrap-to-two-lines fallback. Root cause of the reported wrap: the base
   rule's flex-basis:160px on the input was a soft target width the
   flexbox algorithm tries to honor before shrinking, which — combined
   with flex-wrap:wrap — pushed the button to its own line rather than
   letting the input shrink below 160px on a narrow sidebar column.
   flex:1 1 auto (dropping the 160px basis) plus the existing min-width:0
   removes that floor, so the input freely shrinks to fill whatever space
   is left after the button's own compact, content-sized width — no
   overflow is possible regardless of how narrow the column gets, since
   min-width:0 lets it shrink arbitrarily rather than forcing a wrap. The
   button needs no override here: flex:0 0 auto (base rule, above) already
   keeps it compact and content-sized at every width. Existing gap/height/
   colors/radius are untouched — only wrapping and the input's own flex
   sizing change. */
@media (min-width: 768px) {
  .rsd-layout__widget .search-form,
  .rsd-layout__widget .wp-block-search__inside-wrapper {
    flex-wrap: nowrap;
  }
  .rsd-layout__widget .search-form label,
  .rsd-layout__widget .search-field,
  .rsd-layout__widget .wp-block-search__input {
    flex: 1 1 auto;
    min-width: 0;
  }
}

/* Defensive overflow guard for whatever else gets dropped in (an image, an
   embedded iframe, a table, a code block) — width/box-sizing only for the
   handful of elements that can actually force horizontal overflow, not a
   blanket rule on every descendant. */
.rsd-layout__widget img,
.rsd-layout__widget iframe,
.rsd-layout__widget table,
.rsd-layout__widget pre {
  max-width: 100%;
  height: auto;
}

/* CTA audit: template-parts/modules/m14-cta.php (.rsd-cta) is invoked only
   via hardcoded get_template_part() calls in page templates' own
   main-content module list — never through rsd_layout_render_sidebar()/
   dynamic_sidebar() (confirmed by grepping every call site) — so it can
   never render inside .rsd-layout__widget and needs no rule here.
   .rsd-cta-capture (the "CTA — Capture band" block pattern,
   inc/patterns-services-hub.php) is the one CTA-shaped component that CAN
   end up here: block patterns are insertable from any block-editor
   context, including the Widgets screen's sidebar areas. Its own base
   rule (further down this file) is display:grid; grid-template-columns:
   11fr 9fr — a wide, page-band layout (heading+lede left, capture form
   right) — with its only single-column fallback gated behind
   @media (max-width:1023px, was 900px), a VIEWPORT breakpoint. On a desktop
   viewport (>=1024px) with a 220-320px sidebar column, that query
   never fires, and bare fr grid tracks don't shrink below their content's
   min-content size — a real, provable overflow, not an assumption from
   proximity to the sidebar edge. Fixed by reusing that same existing
   1fr fallback value (not a new one) whenever .rsd-cta-capture is nested
   in a sidebar widget, regardless of viewport width — this is what the
   pattern already renders as below 900px anyway, so it changes nothing
   about its color, typography, or reveal behavior, and nothing about how
   it looks anywhere else it's used (services hub, page-level bands). */
.rsd-layout__widget .rsd-cta-capture {
  grid-template-columns: 1fr;
}

/* Positioning context for the sidebar/content divider below only —
   no offsets, so this doesn't move or resize the sidebar itself.
   Deliberately the same (0,1,0) specificity as
   .rsd-layout__sidebar--sticky's own position rules and placed before
   them in source order, so a sticky sidebar's existing static
   (<1024px) / sticky (1024px+) behavior still wins exactly as before —
   this is a fallback for the common, non-sticky case only. */
.rsd-layout__sidebar {
  position: relative;
  /* RedSprout Colors — new rules; no background/color existed on this
     element before, so defaults (--rsd-sidebar-bg: paper, --rsd-sidebar-text:
     charcoal — see inc/colors.php) reproduce exactly what already shows
     through today rather than introducing a visible box. */
  background: var(--rsd-sidebar-bg, transparent);
  color: var(--rsd-sidebar-text, inherit);
  /* Unconditional — applies at every tier (mobile included; this used to
     be mobile-only, inside a max-width:767px query further down, and was
     moved up here rather than duplicated, since desktop/tablet needed the
     exact same var(--rsd-gap) value: without it, the sidebar's own
     background (above) sat flush against the grid track's edges at every
     width above 767px, reading as a raw colored rectangle with content
     stuck to its edge rather than a padded content column. box-sizing is
     the sitewide border-box reset (top of this file) — this padding never
     changes the column's own width, only the sidebar's own content inset. */
  padding: var(--rsd-gap);
}

/* Sticky sidebar (rsd_sidebar_is_sticky(), inc/layout.php) — static by
   default, so a JS-free, CSS-only page load never briefly shows a stuck
   sidebar before a breakpoint check; the 1024px rule below is what actually
   turns it on, at the same width the Sidebar Width setting itself starts
   applying (desktop tier only — the 768px tablet tier stays static).
   align-self:start is already guaranteed by .rsd-layout's own
   align-items:start above (every grid child, sidebar included), so it
   isn't restated here. --rsd-sticky-top comes from the Sticky Top Offset
   Customizer setting (inc/layout.php, wp_head) — never hardcoded here.
   .rsd-main's own overflow-x:clip (this file, near .rsd-shell) is
   confirmed safe for position:sticky descendants — see that rule's own
   comment; nothing here works around it because nothing needs to. */
.rsd-layout__sidebar--sticky { position: static; }

@media (min-width: 768px) {
  /* Tablet tier: sidebar sits beside main content already, at a reduced,
     fixed width — the full Sidebar Width setting only applies at the
     1024px desktop tier below. Sticky stays off at this tier — see
     .rsd-layout__sidebar--sticky above and inside the 1024px rule below. */
  .rsd-layout--sidebar-right, .rsd-layout--sidebar-left {
    grid-template-columns: 1fr minmax(220px, 260px);
    gap: var(--rsd-gap);
  }
  .rsd-layout--sidebar-left { grid-template-columns: minmax(220px, 260px) 1fr; }
  .rsd-layout--sidebar-left > .rsd-layout__sidebar { order: -1; }

  /* Sidebar/content divider — one subtle 1px rule centered in the grid
     gap above, reusing --rsd-line (this theme's existing hairline-rule
     token, already used for every other subtle border on the site) —
     not a new color. Anchored to the sidebar's own edge and offset by
     half of --rsd-gap (a known, fixed value) rather than by any fixed
     pixel distance from the grid container, so it stays correctly
     centered whether the sidebar is at its fluid 220-260px tablet
     width here or its Customizer-configurable desktop width
     (--rsd-sidebar-w) below — no JS, no extra grid track, no markup
     change. Height matches the sidebar column's own rendered height
     (top:0 to bottom:0 of the sidebar box), not an artificial stretch
     to the usually-taller main column — doing that would mean changing
     .rsd-layout's own align-items:start to stretch site-wide, which
     would alter how every sidebar/main pair vertically aligns, not
     just add a line between them. 768px, not 1024px: matches the exact
     breakpoint the two-column layout itself already begins at, two
     rules above — below it, .rsd-layout is a single stacked column and
     neither ::before rule below has a sidebar/main pair to sit between. */
  .rsd-layout--sidebar-right .rsd-layout__sidebar::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(var(--rsd-gap) / -2);
    width: 1px;
    background: var(--rsd-line);
  }
  .rsd-layout--sidebar-left .rsd-layout__sidebar::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    right: calc(var(--rsd-gap) / -2);
    width: 1px;
    background: var(--rsd-line);
  }
}

@media (min-width: 1024px) {
  .rsd-layout--sidebar-right { grid-template-columns: 1fr var(--rsd-sidebar-w, 300px); }
  .rsd-layout--sidebar-left { grid-template-columns: var(--rsd-sidebar-w, 300px) 1fr; }

  .rsd-layout__sidebar--sticky { position: sticky; top: calc(var(--rsd-sticky-top, 96px) + var(--rsd-tagline-space, 0px)); }
}

/* ---------------------------------------------------------- eyebrow + rule
   The red hairline under an eyebrow is the recurring structural device.
   It marks a measured claim — used only on sections that carry evidence.
   width:fit-content shrinks the box (and so the border-bottom hairline
   riding its bottom edge) to the text's own width, rather than the full
   block-level width the container would otherwise give it — every one of
   .rsd-eyebrow's host tags (p, h2, h3) is block-level by default, so
   without this the hairline always ran edge-to-edge regardless of how
   short the label was. The red tick (::after) is unaffected either way —
   it's already a fixed 2.5rem anchored to the box's own left edge, not
   sized relative to the box's width. */
/* .comment-reply-title (comments.php's own "Leave a response" heading,
   WordPress's own class — comment_form() has no 'class_title_reply' arg
   to set className directly) is added to THIS selector, not given a
   duplicate copy of these declarations elsewhere: the ask was "same
   style," and the only way that's genuinely guaranteed rather than a
   copy that can silently drift is one rule both share. */
.rsd-eyebrow,
.comment-reply-title {
  font-family: var(--rsd-display);
  font-weight: 600;
  font-size: var(--rsd-t-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--rsd-muted);
  width: fit-content;
  margin: 0 0 0.85rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rsd-line);
  position: relative;
}
.rsd-eyebrow::after,
.comment-reply-title::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 2.5rem; height: 2px; background: var(--rsd-eyebrow-accent, var(--rsd-red));
}

/* RedSprout Eyebrow Style (Customizer: RedSprout Typography → Eyebrow /
   Section Label, inc/typography.php) — Line, above, is the default and
   needs no rule here at all: the Customizer emits NO data-rsd-eyebrow-style
   attribute for "line", so these selectors simply never match and every
   .rsd-eyebrow renders exactly as it always has. Pill/Minimal only ever
   ADD to the base rule above (specificity 0,2,0/0,3,0 vs. the base rule's
   0,1,0/0,2,0, so they win regardless of source order) — neither touches
   font-family/weight/size/color/margin, so line-height and vertical rhythm
   stay identical across all three styles.

   .wp-block-heading.is-style-rsd-editorial (the Gutenberg "Editorial"
   heading style, further down this file) is included in every selector
   below: its own comment there says it's an exact restatement of
   .rsd-eyebrow's declarations for editor-inserted headings, so it's
   included as the same component, not a second design. .comment-reply-title
   is included for the same reason — it already deliberately shares
   .rsd-eyebrow's base rule above ("same style," one shared declaration).

   Neither variant sets `color` or `border-color` — .rsd-cta .rsd-eyebrow /
   .rsd-qualifier--no .rsd-eyebrow::after (this file, elsewhere) keep
   working completely unmodified: their color/border-color overrides
   simply have nothing to conflict with.

   :not(.rsd-footer *) on every .rsd-eyebrow/.wp-block-heading.is-style-
   rsd-editorial selector below (added for the footer-isolation task) —
   footer eyebrows ("LEARN", "RESOURCES", "COMPANY", etc., register_sidebar()'s
   before_title, inc/layout.php) must keep their existing, independent
   footer appearance regardless of the global Eyebrow Style/Pill Background/
   Accent Color Customizer settings, so these rules are written to never
   match one in the first place — no specificity fight, no !important. A
   footer eyebrow always falls through to the base .rsd-eyebrow rule above
   plus .rsd-footer .rsd-eyebrow's own color/border-color override and the
   dedicated .rsd-footer .rsd-eyebrow::after accent pin further down this
   file, unaffected by whatever Line/Pill/Minimal is currently selected.
   .comment-reply-title is NOT given this exclusion — it can never appear
   inside .rsd-footer (it's WordPress's own comment-reply-form class), so
   the extra selector would be dead weight.

   background: var(--rsd-eyebrow-pill-bg, color-mix(...)) — two distinct
   states, not one formula for both: with no custom color selected, the
   var() is never emitted (inc/typography.php's wp_head callback), so the
   fallback — color-mix(in srgb, currentColor 12%, transparent), the
   original default — applies, reading whatever color is already correct
   in context (muted gray on a light section, the light rgba .rsd-cta
   already set on a dark one) exactly as before. The moment an admin picks
   a color, --rsd-eyebrow-pill-bg is a real value and the background
   becomes THAT color directly and opaquely — a strong, premium fill
   rather than a 12% wash of it, per an earlier pass's own brief. No
   text-color logic changes: `color` is untouched here exactly as before,
   so an admin picking an unusually dark or light pill color can end up
   with poor text contrast — a known, accepted trade-off (keep the
   existing text-color contract rather than add JS-based contrast
   calculation), same as every other single-value Customizer color
   control already in this theme. */
html[data-rsd-eyebrow-style="pill"] .rsd-eyebrow:not(.rsd-footer *),
html[data-rsd-eyebrow-style="pill"] .comment-reply-title,
html[data-rsd-eyebrow-style="pill"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *) {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  border-bottom: 0;
  border-radius: var(--rsd-radius-pill);
  background: var(--rsd-eyebrow-pill-bg, color-mix(in srgb, currentColor 12%, transparent));
  /* Deterministic height, not inherited: the base .rsd-eyebrow rule sets
     no line-height of its own, so this box's height used to ride whatever
     line-height it happened to inherit from context — fine on desktop,
     but the reported "too thin on mobile" symptom traces to exactly that:
     a height nobody actually set on purpose. line-height:1 makes the
     box's height a pure function of font-size + padding below, in every
     context, at every width. */
  line-height: 1;
  padding: .35rem .9rem .4rem;
}
html[data-rsd-eyebrow-style="pill"] .rsd-eyebrow:not(.rsd-footer *)::after,
html[data-rsd-eyebrow-style="pill"] .comment-reply-title::after,
html[data-rsd-eyebrow-style="pill"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
  display: none;
}

/* Mobile only — desktop/tablet keep the compact padding above untouched.
   0.78rem font-size (--rsd-t-xs) + line-height:1 (12.48px) + 2 x 0.7rem
   padding-block (22.4px) = ~34.9px total height, inside the requested
   34-36px target; padding-inline 1rem (16px) is the top of the requested
   14-16px range. align-items:center (base rule, unchanged) keeps the text
   vertically centered regardless of which padding is active. */
@media (max-width: 767px) {
  html[data-rsd-eyebrow-style="pill"] .rsd-eyebrow:not(.rsd-footer *),
  html[data-rsd-eyebrow-style="pill"] .comment-reply-title,
  html[data-rsd-eyebrow-style="pill"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *) {
    padding-block: .7rem;
    padding-inline: 1rem;
  }
}

html[data-rsd-eyebrow-style="minimal"] .rsd-eyebrow:not(.rsd-footer *),
html[data-rsd-eyebrow-style="minimal"] .comment-reply-title,
html[data-rsd-eyebrow-style="minimal"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *) {
  border-bottom: 0;
  padding-bottom: 0;
  letter-spacing: 0.18em; /* wider than Line's 0.14em — the "refined" distinction the brief asked for, everything else unchanged */
}
html[data-rsd-eyebrow-style="minimal"] .rsd-eyebrow:not(.rsd-footer *)::after,
html[data-rsd-eyebrow-style="minimal"] .comment-reply-title::after,
html[data-rsd-eyebrow-style="minimal"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
  display: none;
}

/* Animated Line (Customizer "animated-line"). The base rule's accent
   ::after spans the whole label instead of a 2.5rem tick, with no grey
   hairline, and draws left → right once as the eyebrow enters view.
   transform only, so nothing reflows. Complete by default: it is hidden
   (scaleX 0) only once the inline head script in inc/typography.php has
   armed it (html.rsd-eyebrow-line-js — JS on, motion allowed), and each
   eyebrow draws when that script adds .is-line-drawn. ::after background
   is left to the base rule, so contextual accent overrides still apply. */
html[data-rsd-eyebrow-style="animated-line"] .rsd-eyebrow:not(.rsd-footer *),
html[data-rsd-eyebrow-style="animated-line"] .comment-reply-title,
html[data-rsd-eyebrow-style="animated-line"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *) {
  border-bottom-color: transparent;
}
html[data-rsd-eyebrow-style="animated-line"] .rsd-eyebrow:not(.rsd-footer *)::after,
html[data-rsd-eyebrow-style="animated-line"] .comment-reply-title::after,
html[data-rsd-eyebrow-style="animated-line"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
  left: 0; width: 100%;
  transform: scaleX(1); transform-origin: left center;
}
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .rsd-eyebrow:not(.rsd-footer *)::after,
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .comment-reply-title::after,
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
  transform: scaleX(0);
  transition: transform calc(var(--rsd-motion-slow) * 1.5) var(--rsd-ease-out) .1s;
}
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .rsd-eyebrow.is-line-drawn:not(.rsd-footer *)::after,
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .comment-reply-title.is-line-drawn::after,
html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .wp-block-heading.is-style-rsd-editorial.is-line-drawn:not(.rsd-footer *)::after {
  transform: scaleX(1);
}
@media (prefers-reduced-motion: reduce) {
  html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .rsd-eyebrow:not(.rsd-footer *)::after,
  html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .comment-reply-title::after,
  html.rsd-eyebrow-line-js[data-rsd-eyebrow-style="animated-line"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
    transform: scaleX(1); transition: none;
  }
}

/* Soft SaaS Pill (Customizer "saas"). Distinct from the Pill: a restrained
   6px radius instead of a full capsule, a hairline border, a fainter 5%
   tint, tighter padding and slightly smaller, less tracked type. Colour
   comes from the context's own text colour (currentColor), as the Pill's
   does, so it reads on light and dark sections alike. No accent tick. */
html[data-rsd-eyebrow-style="saas"] .rsd-eyebrow:not(.rsd-footer *),
html[data-rsd-eyebrow-style="saas"] .comment-reply-title,
html[data-rsd-eyebrow-style="saas"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *) {
  display: inline-flex; align-items: center; max-width: 100%;
  font-size: calc(var(--rsd-t-xs) * .92); letter-spacing: .08em; line-height: 1;
  padding: .4rem .65rem;
  border: 1px solid color-mix(in srgb, currentColor 20%, transparent);
  border-radius: calc(var(--rsd-radius) * 1.5);
  background: color-mix(in srgb, currentColor 5%, transparent);
}
html[data-rsd-eyebrow-style="saas"] .rsd-eyebrow:not(.rsd-footer *)::after,
html[data-rsd-eyebrow-style="saas"] .comment-reply-title::after,
html[data-rsd-eyebrow-style="saas"] .wp-block-heading.is-style-rsd-editorial:not(.rsd-footer *)::after {
  display: none;
}

/* Footer eyebrow isolation (this task) — .rsd-footer .rsd-eyebrow's tick
   is pinned back to the literal --rsd-red token, independent of the
   global Eyebrow Arrow / Accent Color control (--rsd-eyebrow-accent,
   inc/typography.php). Needed because the base rule above (.rsd-eyebrow::after,
   near the top of this component's CSS) reads --rsd-eyebrow-accent
   unconditionally — without this override, a
   footer eyebrow's tick, which was never given a dedicated color of its
   own before this control existed, would start tracking the global accent
   the moment an admin changed it, changing the one thing this task
   requires stay fixed. Specificity (0,2,1) beats the base rule's (0,1,1),
   so this wins regardless of source order — no !important needed. */
.rsd-footer .rsd-eyebrow::after { background: var(--rsd-red); }

/* ---------------------------------------------------------- header */
.rsd-header {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--rsd-paper) 88%, transparent);
  border-bottom: 1px solid var(--rsd-line);
}
.rsd-logo { display: inline-flex; align-items: center; gap: .55rem; text-decoration: none; font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold); letter-spacing: -0.02em; }
.rsd-logo__mark { width: 12px; height: 12px; background: var(--rsd-red); border-radius: 2px; transform: rotate(45deg); flex: none; }
.rsd-logo__text { font-size: 1.05rem; }

/* the_custom_logo() output — width driven by the Customizer's "Logo width"
   control (inc/logo-crop.php), not a fixed value, so it can be adjusted
   without re-uploading or re-cropping. */
.custom-logo { width: var(--rsd-logo-width, 180px); height: auto; }

/* min-height + inline-flex centering makes "consistent height" an explicit
   guarantee rather than an implicit consequence of padding/line-height
   math happening to land the same for every variant — solid and ghost
   already shared padding/radius/border-width via this one base rule, so
   there was no real divergence between them specifically, but nothing
   previously pinned the result to a real number either. 44px doubles as
   the accessible tap-target floor used elsewhere in this file
   (.rsd-hamburger, .rsd-call, the drawer's own button rule). */
.rsd-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--rsd-tap-target); font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-sm); padding: .6rem 1.1rem; border-radius: var(--rsd-radius);
  text-decoration: none; border: 1px solid transparent; cursor: pointer;
  transition: background var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out);
}
.rsd-btn--solid { background: var(--rsd-button-bg, var(--rsd-red)); color: var(--rsd-button-text, #fff); }
.rsd-btn--solid:hover { background: var(--rsd-button-hover-bg, var(--rsd-red-ink)); color: var(--rsd-button-hover-text, #fff); }
.rsd-btn--ghost { border-color: var(--rsd-charcoal); color: var(--rsd-charcoal); }
.rsd-btn--ghost:hover { background: var(--rsd-charcoal); color: var(--rsd-white); }

/* Client Login header button only — a quieter outline than .rsd-btn--ghost
   so it doesn't compete with the solid "Get a proposal" CTA. Scoped to this
   one button; .rsd-btn--ghost itself is unchanged everywhere else it's used. */
.rsd-btn--ghost.rsd-btn--muted {
  border-color: #6B6B6B; color: #4A4A4A;
  transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out);
}
.rsd-btn--ghost.rsd-btn--muted:hover { background: transparent; border-color: #2F2F2F; color: #2F2F2F; }

/* Compact size — overrides padding/font-size/min-height only, inherits
   everything else from .rsd-btn. Opts out of the 44px floor above on
   purpose: this variant exists specifically for dense contexts (the
   footer's own proposal button) where the full tap-target minimum isn't
   the point — deliberately smaller, not an oversight. */
.rsd-btn--sm { padding: .45rem .85rem; font-size: var(--rsd-t-xs); min-height: 0; }

/* Ghost variant for dark surfaces (footer brand column) — same rgba(247,246,244,…)
   opacity convention already used by .rsd-footer__line/__copy/__markets borders. */
.rsd-btn--ghost-invert { border-color: rgba(247, 246, 244, .35); color: var(--rsd-paper); }
.rsd-btn--ghost-invert:hover { background: var(--rsd-paper); color: var(--rsd-charcoal); }


/* ---------------------------------------------------------- page head */
.rsd-crumbs { margin: 1.25rem 0 1.75rem; font-size: var(--rsd-t-xs); color: var(--rsd-muted); }
.rsd-crumbs ol { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; margin: 0; padding: 0; }
.rsd-crumbs li + li::before { content: "/"; margin-right: .4rem; color: var(--rsd-line); }
.rsd-crumbs a { text-decoration: none; }

.rsd-pagehead { margin-bottom: var(--rsd-gap); }
/* max-width is in ch, which is relative to the element's OWN font-size —
   16ch of the H1's own (large, fluid) type size, so the column stays
   proportionate to the type at every viewport rather than being capped by
   a value computed at some other, smaller font-size (see the removed
   .rsd-hero__body cap below, which was exactly that bug: 34ch measured at
   the body's ~1.0625rem paragraph size constrained a heading rendered up
   to 3.6rem, capping it to a column far narrower than the type needed). */
/* -0.03em, tighter than the -0.02em every other heading level inherits —
   large display type reads loose at the base tracking; the biggest size
   on the page is the one that needs it pulled in further. */
.rsd-h1 { font-size: var(--rsd-t-h1); max-width: 16ch; letter-spacing: var(--rsd-t-h1-letter-spacing, -0.03em); color: var(--rsd-h1, var(--rsd-charcoal)); }
.rsd-h2 { font-size: var(--rsd-t-h2); color: var(--rsd-h2, var(--rsd-charcoal)); }
.rsd-h3 { font-size: var(--rsd-t-h3); color: var(--rsd-h3, var(--rsd-charcoal)); }
.rsd-lede { font-size: var(--rsd-t-lg); color: var(--rsd-muted); max-width: 58ch; }
.rsd-meta { font-size: var(--rsd-t-sm); color: var(--rsd-muted); display: flex; gap: .5rem; flex-wrap: wrap; }

/* ---------------------------------------------------------- hero (asymmetric)
   align-items:start keeps the body column reading from the top naturally;
   align-self:center on the aside (below) only re-centers the shorter right
   panel within that same row, rather than leaving it pinned to the top of
   a much taller row with all the slack dumped below it as visible empty
   space. Row height itself now comes only from real content height (the
   H1 fix above is what actually shrinks that height — a 2-3 line headline
   instead of 5 — this alignment change is the remaining polish once the
   row is a sane height, not a substitute for that fix). */
.rsd-hero { display: grid; grid-template-columns: 7fr 5fr; gap: var(--rsd-gap); align-items: start; padding-block: var(--rsd-gap) var(--rsd-block); }
.rsd-hero__body { min-width: 0; }
.rsd-hero__aside {
  align-self: center;
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius); padding: var(--rsd-gap);
}
.rsd-hero__aside h2 { font-size: var(--rsd-t-base); }

/* ---------------------------------------------------------- signature: sourced figure */
.rsd-figure {
  margin: 0 0 1.25rem; padding-left: 1rem;
  border-left: 2px solid var(--rsd-red);
}
.rsd-figure__value {
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold);
  font-size: clamp(2rem, 3.5vw, 3rem); line-height: 1; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.rsd-figure figcaption { display: block; margin-top: .5rem; }
.rsd-figure__label { display: block; font-size: var(--rsd-t-sm); }
.rsd-figure__source {
  display: block; margin-top: .25rem; font-style: normal;
  font-size: var(--rsd-t-xs); letter-spacing: .04em; text-transform: uppercase;
  color: var(--rsd-muted);
}

/* ---------------------------------------------------------- qualifier
   align-items:baseline lines up the two columns' own first line of text
   (each starts with an .rsd-eyebrow h2) exactly, so the pair reads as one
   deliberate grid rather than two independently-floating text blocks that
   happen to sit side by side. */
.rsd-qualifier { display: grid; width: 100%; box-sizing: border-box; gap: var(--rsd-gap); grid-template-columns: 1fr 1fr; align-items: baseline; margin-block: var(--rsd-block); }
.rsd-qualifier ul { margin: 0; padding-left: 1.1rem; }
.rsd-qualifier li { margin-bottom: .5rem; }
.rsd-qualifier--no .rsd-eyebrow::after { background: var(--rsd-charcoal); }

/* ---------------------------------------------------------- prose */
.rsd-prose { max-width: var(--rsd-read); }
/* scroll-margin-top: single-post.php's TOC links jump to these via #id —
   without this, .rsd-header's own position:sticky floats over the top of
   whatever the browser scrolls to, hiding the heading text underneath it.
   Same 96px offset as .rsd-article__aside's sticky top, for one consistent
   "space reserved for the floating header" value rather than two. */
.rsd-prose h2 { font-size: var(--rsd-t-h2); margin-top: 2.25em; scroll-margin-top: calc(96px + var(--rsd-tagline-space, 0px)); }
.rsd-prose h3 { font-size: var(--rsd-t-h3); margin-top: 1.75em; scroll-margin-top: calc(96px + var(--rsd-tagline-space, 0px)); }
.rsd-prose ul, .rsd-prose ol { padding-left: 1.25rem; }
.rsd-prose li { margin-bottom: .4rem; }
.rsd-prose blockquote {
  margin: 1.75rem 0; padding: .25rem 0 .25rem 1.25rem;
  border-left: 2px solid var(--rsd-red); font-size: var(--rsd-t-lg);
}
.rsd-prose table { width: 100%; border-collapse: collapse; margin: 1.75rem 0; font-size: var(--rsd-t-sm); }
.rsd-prose th, .rsd-prose td { text-align: left; padding: .7rem .8rem; border-bottom: 1px solid var(--rsd-line); vertical-align: top; }
.rsd-prose thead th { font-family: var(--rsd-display); font-size: var(--rsd-t-xs); letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-prose code { font-size: .9em; background: var(--rsd-white); border: 1px solid var(--rsd-line); padding: .1em .35em; border-radius: 3px; }
.rsd-prose figure { margin: 1.75rem 0; }
/* Reusable sections inside an article column. The 2.25em / 1.75em heading
   margins above are article rhythm — a heading opening a new passage of
   running text — and stay exactly as they are for that. A component's OWN
   head or column heading is different: the component already spaces itself
   (its shell / section padding), so the prose margin only pushed the
   heading away from its eyebrow (~90px), below the CTA form beside it, or
   down a column away from its image. Zeroed for exactly those positions:
   the heading inside a standard section head (.rsd-section-head — the
   RedSprout Section, Process, FAQ, Content Highlights, Insights,
   Industries, Client Feedback… — and the Services Showcase head), the
   first block in a core column and a column heading directly under its
   eyebrow (RS Content — Image + Content), the CTA capture heading and the
   Showcase panel title. Nothing else in prose changes. */
.rsd-prose :is(.rsd-section-head, .rsd-showcase__head) > :is(h2, h3, h4),
.rsd-prose .wp-block-column > :first-child,
.rsd-prose .wp-block-column > .rsd-eyebrow + :is(h2, h3, h4),
.rsd-prose .rsd-cta-capture :is(h2, h3),
.rsd-prose .rsd-showcase__title { margin-top: 0; }
/* The Showcase panel title is an h3 at the section scale; .rsd-prose h3
   would otherwise shrink it to the h3 step inside an article. */
.rsd-prose .rsd-showcase__title { font-size: var(--rsd-t-h2); }

/* ---------------------------------------------------------- lists / cards */
.rsd-postlist, .rsd-linklist { list-style: none; margin: 0; padding: 0; }
.rsd-postlist__item { padding-block: 1.5rem; border-top: 1px solid var(--rsd-line); }
.rsd-postlist__item h2 { margin: .35rem 0 .5rem; }
.rsd-postlist__item a { text-decoration: none; }
.rsd-postlist__item a:hover { text-decoration: underline; text-decoration-color: var(--rsd-red); }
.rsd-excerpt { color: var(--rsd-muted); margin: 0; max-width: 62ch; }

/* width:100% + box-sizing guard the grid against ever reading narrower
   than its container — belt-and-braces alongside auto-fit's own correct
   default behaviour (the actual number of tracks is already computed from
   the container's real width, so this is a safety net, not the primary
   mechanism). margin-top:var(--rsd-gap) is the medium heading→content
   tier. gap is the small tier — real spacing between cards now that each
   card is its own bordered box (see below), not the 1px shared-hairline
   mesh this used to be (grid gap:1px + a background colour showing
   through as dividers, every card sat flush against its neighbours with
   no room to lift independently on hover). overflow is no longer hidden
   here — a shared-mesh grid needed it to clip corners to one rounded
   boundary; individual cards carry their own radius now, and a hidden
   overflow on the parent would clip the hover-lift transform below. */
.rsd-cards {
  display: grid; width: 100%; box-sizing: border-box;
  gap: var(--rsd-gap-sm);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin-top: var(--rsd-gap);
}
/* Same padding value as .rsd-hero__aside — one padding for every card-like
   surface (was 1.4rem here vs 1.5rem there: two numbers for the same kind
   of surface, tightened to one, var(--rsd-gap), which also makes both
   fluid instead of fixed). The full-bleed .rsd-cta band keeps its own,
   deliberately more generous padding below — a section-width band reads
   differently from a grid card, not "the same kind of surface" this rule
   is about.
   border+border-radius replace the old shared-mesh trick with a real,
   individual hairline per card — needed so hover (below) can act on one
   card without disturbing its neighbours. Hover is restrained on purpose:
   the border tone deepens (color-mix, not a new token — the same
   "derived, not invented" approach .rsd-header already uses for its own
   translucency) and the card lifts 2px; no shadow, no scale, gated by
   prefers-reduced-motion like every other transition in this file. */
.rsd-cards > * {
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius); padding: var(--rsd-gap);
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-cards > * { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out), transform var(--rsd-motion-fast) var(--rsd-ease-out); }
}
.rsd-cards > *:hover {
  border-color: color-mix(in srgb, var(--rsd-line), var(--rsd-charcoal) 35%);
  transform: translateY(-2px);
}
.rsd-card__title { font-size: var(--rsd-t-base); margin-bottom: .4rem; }
.rsd-card__title a { text-decoration: none; }
.rsd-card p { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; }

.rsd-linklist li { border-top: 1px solid var(--rsd-line); }
.rsd-linklist a { display: block; padding: .9rem 0; text-decoration: none; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); }
.rsd-linklist a:hover { color: var(--rsd-red); }

/* ---------------------------------------------------------- FAQ */
.rsd-faq { margin-block: var(--rsd-block); max-width: var(--rsd-read); }
.rsd-faq details { border-top: 1px solid var(--rsd-line); padding: 1rem 0; }
.rsd-faq summary { cursor: pointer; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); list-style: none; display: flex; justify-content: space-between; gap: 1rem; }
.rsd-faq summary::-webkit-details-marker { display: none; }
.rsd-faq summary::after { content: "+"; color: var(--rsd-red); font-size: 1.25rem; line-height: 1; }
.rsd-faq details[open] summary::after { content: "–"; }
.rsd-faq details > p { margin: .75rem 0 0; color: var(--rsd-muted); }

/* ---------------------------------------------------------- market switcher */
.rsd-markets { margin-block: var(--rsd-block) 0; padding-top: 1.25rem; border-top: 1px solid var(--rsd-line); font-size: var(--rsd-t-sm); }
.rsd-markets__label { color: var(--rsd-muted); margin-right: .75rem; }
.rsd-markets ul { display: inline-flex; flex-wrap: wrap; gap: 1rem; list-style: none; margin: 0; padding: 0; }

/* ---------------------------------------------------------- CTA band */
.rsd-cta {
  margin-block: var(--rsd-block) 0; padding: clamp(1.75rem, 4vw, 3rem);
  background: var(--rsd-charcoal); color: var(--rsd-paper); border-radius: var(--rsd-radius);
}
.rsd-cta h2 { color: var(--rsd-white); max-width: 22ch; }
.rsd-cta p { color: rgba(247,246,244,.72); max-width: 52ch; }
.rsd-cta .rsd-eyebrow { color: rgba(247,246,244,.6); border-color: rgba(247,246,244,.18); }

/* Final CTA (redsprout-digital/final-cta, inc/final-cta-block.php): the
   same band, centred, roomier, with the heading as its focus and a
   primary + secondary button (.rsd-btn--solid / --ghost-invert, the global
   button system). Its section spacing comes from the block's own
   .rsd-shell, so the band's own top margin is dropped. Focus ring in
   paper here: the sitewide red ring is only ~2.8:1 on charcoal. */
.rsd-cta--final {
  margin-block: 0; padding: clamp(2.75rem, 6vw, 4.5rem) clamp(1.25rem, 5vw, 4rem);
  border-radius: calc(var(--rsd-radius) * 1.5); text-align: center;
}
.rsd-cta--final .rsd-eyebrow { margin-inline: auto; } /* a fit-content block */
.rsd-cta--final .rsd-h2 { max-width: 20ch; margin-inline: auto; font-size: calc(var(--rsd-t-h2) * 1.15); line-height: 1.1; }
.rsd-cta--final .rsd-cta__text { max-width: 46ch; margin: .9rem auto 0; font-size: var(--rsd-t-lg); line-height: 1.55; }
.rsd-cta--final .rsd-cta__actions {
  display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem;
  max-width: none; margin: 2rem 0 0;
}
.rsd-cta--final :focus-visible { outline-color: var(--rsd-paper); }
@media (max-width: 479px) {
  .rsd-cta--final .rsd-cta__actions .rsd-btn { flex: 1 1 100%; }
}

/* ---------------------------------------------------------- CTA capture band
   Distinct from .rsd-cta above: a light warm-tinted surface + hairline
   border rather than the dark charcoal band, and a real asymmetric
   two-column layout (~55/45, 11fr/9fr) rather than single-column centred
   content — copy left, the existing URL-capture field right. No
   margin-block of its own on purpose: .rsd-shell + .rsd-shell (this file,
   near the top) already gives the wrapping .rsd-shell correct large-tier
   spacing from whatever precedes it, and because this element has its own
   border, a margin set directly on it would NOT collapse through that
   border the way an unbordered child's margin does elsewhere in this file
   — adding one here would double the gap rather than share it.

   Background is a vertical gradient, plain paper → a color-mix() of
   paper and brand red, not a new hex value: the top stop is --rsd-paper
   outright (a definite colour, not "transparent" inheriting whatever sits
   behind it); the bottom stop is 5% --rsd-red mixed into --rsd-paper —
   deliberately red now, not the neutral --rsd-line this used before,
   because this band holds the form and the solid-red button: a neutral
   tint doesn't distinguish an action surface from any other section, a
   faint warm-red one says "something happens here."

   Computed before choosing, same discipline as the neutral version this
   replaced: paper is #F7F6F4 (lum≈246). At 5% red (#C40808 mixed in),
   the result is #F4EAE8 (lum≈236, an ≈10-point/≈4% delta) — R barely
   moves (247→244) while G and B both drop by roughly equal amounts
   (246→234, 244→232), which is what reads as WARM rather than pink: true
   pink needs R and B both elevated relative to G; here G actually sits
   slightly above B, if anything a warm-yellow lean, not a blue/magenta
   one. 5% sits in the middle of the requested 4-6% range — enough to
   read as intentional warmth, nowhere near "obviously red."

   The button stays the strongest red element on the band by a wide
   margin regardless: --rsd-red itself has a luminance of ≈48 (very dark,
   fully saturated) against this tint's ≈236 (very light, barely
   saturated) — a ≈188-point gap, before even accounting for the
   saturation difference between "5% mixed into near-white" and "100%
   pure." The background cannot credibly compete with the button at
   these values.

   This is the one deliberate, scoped exception to D-26's "no gradients"
   — everywhere else on the site still has none. Contrast is unaffected:
   even at the deepest point (≈236 luminance, still a near-white),
   --rsd-charcoal (heading) and --rsd-muted (lede) both keep effectively
   the same contrast they already have against plain --rsd-paper
   elsewhere in this file, and the input sits on its own explicit
   --rsd-white, independent of the band's gradient beneath it either way.

   Padding reuses .rsd-cta's own value (clamp(1.75rem,4vw,3rem)) rather
   than the card padding (var(--rsd-gap)) this used before — the same
   "a full-width band reads differently from a grid card" reasoning
   .rsd-cards' own comment already states, applied consistently here too.

   align-items:start, not baseline: the right column's first child is a
   <form> (label, input, button) rather than plain text, and true CSS
   baseline alignment against a form control is inconsistent across
   browsers/UA styles. start gives both columns a shared, deterministic
   top edge — the heading and the field visibly begin at the same height,
   which is the actual goal ("not floating at different heights"). */
.rsd-cta-capture {
  display: grid; grid-template-columns: 11fr 9fr; gap: var(--rsd-gap);
  align-items: start;
  background: linear-gradient(to bottom, var(--rsd-paper), color-mix(in srgb, var(--rsd-paper), var(--rsd-red) 5%));
  border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius); padding: clamp(1.75rem, 4vw, 3rem);
}
/* h2 scale explicitly — a bare <h2> carries no font-size of its own in
   this theme (only the .rsd-h2 class does; h1-h4's shared element rule
   sets weight/line-height/tracking but never size), so without this the
   heading rendered at the browser's plain UA default, which read as body
   text rather than "the second-biggest thing on the page." 18ch keeps it
   to two confident lines instead of one long one; -0.03em is the same
   tighter large-size tracking .rsd-h1 already uses, applied here because
   at --rsd-t-h2's now-widened size (previous pass) this counts as "large"
   too. */
.rsd-cta-capture h2 {
  font-size: var(--rsd-t-h2); max-width: 18ch; letter-spacing: -0.03em;
  margin-bottom: .5rem;
}
/* .rsd-lede already sets font-size:var(--rsd-t-lg) (restated explicitly
   below anyway, so this requirement is visibly satisfied here rather than
   only cross-referenced) — what it doesn't set is a line-height of its
   own (it inherits the sitewide 1.6, tuned for body copy, not a larger
   lede-scale line) or a width narrow enough to read as two lines rather
   than run the column's full ~58ch default. 1.5 is tighter than body's
   1.6 — larger type needs proportionally less line-height to still read
   as comfortable, the same reasoning .rsd-h1's own tighter tracking is
   built on. 42ch, not .rsd-lede's default 58ch: at this column's real
   width (~55% of the shell), 58ch was closer to the column's own edge
   than to a genuine two-line wrap. */
.rsd-cta-capture .rsd-lede {
  font-size: var(--rsd-t-lg); line-height: 1.5; max-width: 42ch;
}
/* rsd_url_capture()'s own markup/CSS (.rsd-capture) is an unchanged,
   reused field — everything below only overrides how it LAYS OUT and
   SIZES in this one context, scoped under .rsd-cta-capture so the
   default behaviour it keeps everywhere else (hero aside, services-hub
   closing CTA) is untouched.

   flex-direction:column flips the container's main axis from horizontal
   to vertical — .rsd-capture__input's own base rule sets
   flex: 1 1 14rem, written for the ROW layout it normally sits in, where
   14rem is a WIDTH. In a column-direction container that same flex-basis
   is read against the main axis, which is now HEIGHT — a 14rem-tall
   (224px) input was the actual bug, not a rendering fluke: this file's
   own scoped column override broke an assumption the shared rule never
   had to account for before. flex:none here removes that entirely, and
   height is set explicitly instead. */
.rsd-cta-capture .rsd-capture {
  flex-direction: column; max-width: none; gap: var(--rsd-gap-sm);
}
.rsd-cta-capture .rsd-capture__input {
  flex: none; width: 100%; height: 52px;
  padding-block: 0; padding-inline: 1rem;
}
/* height matches the input exactly, not just the sitewide 44px button
   floor — "so they read as a pair," per spec — and centres its own label
   the same way .rsd-btn already centres text everywhere else (inline-flex
   + align-items:center, inherited from the base rule; only height is
   added here). */
.rsd-cta-capture .rsd-capture .rsd-btn { width: 100%; height: 52px; }

/* ---------------------------------------------------------- footer */
.rsd-footer {
  position: relative; overflow: hidden;
  background: var(--rsd-footer-bg, var(--rsd-charcoal)); color: var(--rsd-paper); padding-block: var(--rsd-block) 2rem;
}
/* The one restrained "futuristic" signature for this footer, chosen
   deliberately singular rather than combined with other decorative
   effects (an ultra-subtle grid/dot pattern was the other candidate;
   not used, to keep this to one accent). A radial-gradient
   pseudo-element, not an image: zero network requests, no filter/
   blur cost (the soft edge is native to the gradient's own color
   stops), pointer-events:none so it can never intercept a click,
   position:absolute + z-index:0 so it paints strictly behind real
   content (.rsd-shell below gets z-index:1 for exactly this reason).
   Sized in % of .rsd-footer's own box with no negative offset, so it
   cannot push the footer wider than its container — overflow:hidden
   above is belt-and-braces, not load-bearing. Suppressed entirely on
   mobile (media query further down): the brief was explicit that
   mobile should read simpler, not merely "not stronger." */
.rsd-footer::before {
  content: "";
  position: absolute;
  top: 0; right: 0;
  width: 40%; height: 65%;
  background: radial-gradient(circle at top right, rgba(196,8,8,.06), transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.rsd-footer > .rsd-shell { position: relative; z-index: 1; }
.rsd-footer a { color: inherit; text-decoration: none; }
.rsd-footer .rsd-eyebrow { color: rgba(247,246,244,.55); border-color: rgba(247,246,244,.15); }
.rsd-footer__top { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--rsd-gap); align-items: start; }
.rsd-footer__line { color: rgba(247,246,244,.66); max-width: 30ch; font-size: var(--rsd-t-sm); }
.rsd-footer__list { list-style: none; margin: 0; padding: 0; font-size: var(--rsd-t-sm); }
.rsd-footer__list li { margin-bottom: .5rem; }
.rsd-footer__markets { margin-top: var(--rsd-gap); padding-top: 1.5rem; border-top: 1px solid rgba(247,246,244,.14); }
.rsd-footer__markets ul { display: flex; flex-wrap: wrap; gap: .75rem; list-style: none; margin: 0; padding: 0; font-size: var(--rsd-t-sm); }
/* Compact market "chips" rather than plain text links — reuses
   var(--rsd-radius) (the theme's existing 4px structural-container
   radius, D-7/design-system §7) so this doesn't invent a new corner
   value, and derives its border/background straight from the existing
   paper color at low opacity rather than a new token, matching how
   every other low-emphasis surface on this dark background already
   works. flex-wrap on the parent already prevents any overflow risk
   from the added padding. */
.rsd-footer__markets a {
  display: inline-flex; align-items: center; gap: .35rem;
  min-height: var(--rsd-tap-target);
  padding: .35rem .65rem;
  border: 1px solid rgba(247,246,244,.14);
  border-radius: var(--rsd-radius);
  background: rgba(247,246,244,.03);
  transition: border-color .18s ease, background-color .18s ease;
}
.rsd-footer__markets a:hover, .rsd-footer__markets a:focus-visible {
  border-color: rgba(196,8,8,.4);
  background: rgba(196,8,8,.05);
}
/* .rsd-footer__markets a is also matched by the sitewide underline rule
   (:is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li)
   a:not(.rsd-btn)::after, further down this file) — correct everywhere
   else links live in the footer, but these are chip-style selectors with
   their own border/background hover already, not text links, so the
   growing red underline read as a stray line cutting through the chip.
   content:none removes the pseudo-element's box entirely — the same
   technique this file already uses at .rsd-footer__col-summary::after —
   which cancels it in every state (normal, hover, focus-visible) with
   one declaration, since the sitewide rule's :hover/:focus-visible
   variants only ever redeclare transform, never content. Selector
   specificity here (.rsd-footer .rsd-footer__markets a:not(.rsd-btn), 3
   classes) deliberately exceeds the sitewide rule's own (:is() + :not() +
   a, 2 classes) so this wins outright, regardless of source order. */
.rsd-footer .rsd-footer__markets a:not(.rsd-btn)::after {
  content: none;
}
/* Muted default, brightens to full paper-white on hover/focus — footer
   links inherited full-white from .rsd-footer's own color before (no
   hierarchy between "resting" and "interacting" states). The red cue on
   hover/focus already exists sitewide via the shared underline rule
   above (:is(.rsd-crumbs, .rsd-footer, ...) a:not(.rsd-btn)::after) —
   this only adds the text-color half, deliberately not a second red
   treatment, so every link on the site still shares one hover language
   (underline goes red; text brightens) rather than the footer inventing
   its own. Transition is color-only — no layout-affecting property, so
   this has no reflow cost, only a paint-cheap recolor. */
.rsd-footer__col a,
.rsd-footer__markets a {
  color: rgba(247,246,244,.75);
  transition: color .18s ease;
}
/* Menu links additionally get a 2px hover/focus nudge — inline-block so
   transform reliably applies (a plain inline box's transform behavior is
   inconsistent across engines), transform only, so there is nothing for
   layout to recompute: no width/margin/position is touched, so this
   cannot shift surrounding text or trigger a reflow, only a
   compositor-level repaint. Not applied to the market chips, which
   already move via their own border/background hover below. */
.rsd-footer__col a {
  display: inline-block;
  transition: color .18s ease, transform .18s ease;
}
.rsd-footer__col a:hover, .rsd-footer__col a:focus-visible {
  transform: translateX(2px);
}
.rsd-footer__col a:hover, .rsd-footer__col a:focus-visible,
.rsd-footer__markets a:hover, .rsd-footer__markets a:focus-visible {
  color: var(--rsd-paper);
}
/* Copyright only now — no legal menu in this row (removed; a legal/
   policy link belongs in a footer column like any other link). Kept as
   flex/space-between rather than simplified to a plain block: the row
   still needs the top border + spacing treatment consistent with
   .rsd-footer__markets above it, and space-between with a single child
   is harmless (it just left-aligns). */
.rsd-footer__base { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; margin-top: var(--rsd-gap); padding-top: 1.25rem; border-top: 1px solid rgba(247,246,244,.14); font-size: var(--rsd-t-xs); }
.rsd-footer__copy { margin: 0; color: rgba(247,246,244,.6); max-width: 60ch; }

/* ---------------------------------------------------------- search / misc */
.rsd-search { margin-block: var(--rsd-gap); max-width: 480px; }
.rsd-search__row { display: flex; gap: .5rem; }
.rsd-search input {
  flex: 1; padding: .6rem .75rem; font: inherit; font-size: var(--rsd-t-sm);
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius); background: var(--rsd-white);
}
.rsd-empty { color: var(--rsd-muted); }
.rsd-related { margin-block: var(--rsd-block) 0; padding-top: 1.5rem; border-top: 1px solid var(--rsd-line); }
.rsd-related ul { list-style: none; margin: 0; padding: 0; }
.rsd-related li { border-bottom: 1px solid var(--rsd-line); }
.rsd-related a { display: block; padding: .75rem 0; text-decoration: none; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); }
.rsd-hero-img { margin: 0 0 var(--rsd-gap); }

/* ---------------------------------------------------------- article (blog post)
   single-post.php. Two-column: prose body + a sidebar carrying the table
   of contents and author credibility. Narrower split than .rsd-hero's 7/5
   (2fr/1fr ≈ 8/4) since this sidebar only ever holds two short cards, not
   a full hero panel — both cards reuse .rsd-hero__aside's existing surface
   (white, hairline border, no shadow) rather than a new component; D-26
   allows a shadow/gradient only on the two patterns that already carry
   one (the CTA capture band's gradient, nothing here), so this stays flat
   on purpose. */
.rsd-article { display: grid; grid-template-columns: 2fr 1fr; gap: var(--rsd-gap); align-items: start; }
.rsd-article__body { min-width: 0; }
/* position:sticky, not JS scroll-spy — the sidebar staying in view while
   the reader scrolls is the entire value; highlighting the active section
   would need an IntersectionObserver for a marginal gain, which is exactly
   the "nothing beyond what's strictly necessary" this was told to avoid.
   top is an approximate offset under the floating sticky pill header
   (.rsd-pill, ~68px min-height plus its own breathing room) — a few px of
   slack here is harmless, unlike overlap. Disabled below the 1024px
   (tablet) collapse (next rule block) since a stacked, full-width sidebar has
   nothing meaningful to stay pinned against. */
.rsd-article__aside { display: flex; flex-direction: column; gap: var(--rsd-gap-sm); position: sticky; top: calc(96px + var(--rsd-tagline-space, 0px)); }
/* .rsd-hero__aside's own align-self:center assumes a grid context sized
   for a full hero row; here it would shrink the card to its content width
   instead of filling this flex column, which is the opposite of what a
   sidebar card should do. */
.rsd-article__aside .rsd-hero__aside { align-self: stretch; }

/* Table of contents — one flat <ul>, no icon (nothing here needs one). No
   active-section highlighting — see the sticky comment above for why.
   H3 sub-items get an indent/rule via a modifier class on the <li> itself
   rather than an actual nested <ul> — a <ul> can only validly appear
   inside an <li> of its parent list, and building that correctly from a
   single linear heading sequence needs real tree logic for one cosmetic
   indent; flat li's with a class do the same visual job without it. */
.rsd-toc { margin: 0; padding: 0; list-style: none; }
.rsd-toc li + li { margin-top: .5rem; }
.rsd-toc a { display: block; font-size: var(--rsd-t-sm); text-decoration: none; }
.rsd-toc a:hover { text-decoration: underline; text-decoration-color: var(--rsd-red); }
.rsd-toc__sub { padding-left: .85rem; border-left: 1px solid var(--rsd-line); }
.rsd-toc__sub a { font-size: var(--rsd-t-xs); color: var(--rsd-muted); }

/* Author credibility — real WP author data (name, avatar, bio), never
   invented (D-21). */
.rsd-author { display: flex; gap: .85rem; align-items: flex-start; }
/* get_avatar() is requested at 88px (template) for a crisp image on 2x
   displays; constrained to 44px here so it actually displays at that
   size rather than the native 88px the <img> tag's own attributes carry. */
.rsd-author img { border-radius: 50%; flex: none; width: 44px; height: 44px; }
.rsd-author__name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-base); margin: 0 0 .25rem; }
.rsd-author__bio { font-size: var(--rsd-t-sm); color: var(--rsd-muted); margin: 0 0 .5rem; }
.rsd-author__link { font-size: var(--rsd-t-xs); }

/* Read Next — redsprout-digital/read-next pattern
   (inc/patterns-read-next.php) and single-post.php's automatic placement;
   one render function (rsd_read_next_content()) backs both, so this is
   the only markup shape to style. Reuses .rsd-cards/.rsd-cards > * exactly
   as every other card grid in this theme does — including that rule's own
   "no shadow, no scale" hover (border-color deepens, translateY(-2px)
   only); nothing here adds a second hover treatment. Same rhythm/divider
   convention as .rsd-related above (margin-block + border-top). */
.rsd-read-next { margin-block: var(--rsd-block) 0; padding-top: 1.5rem; border-top: 1px solid var(--rsd-line); }
/* Explicit 3/2/1 columns, not .rsd-cards' own auto-fit default — scoped to
   this context only. max-width:1023px/767px — the site-wide breakpoint
   system (Phase 1 foundation: desktop >= 1024px, tablet 768-1023px, mobile
   < 768px), so 1024 is desktop (3 columns) and 768 is tablet (2), the same
   tiers the header and every other component now use. (This used to be
   max-width:1024px/768px inclusive, "two columns AT 1024px", from before
   the breakpoints were unified; the same applies to .rsd-blog-grid below,
   which had the identical rule from the
   identical requirement wording. */
.rsd-read-next .rsd-cards { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1023px) { .rsd-read-next .rsd-cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 767px)  { .rsd-read-next .rsd-cards { grid-template-columns: 1fr; } }
/* overflow:hidden scoped to these cards only (not the shared .rsd-cards > *
   rule, which deliberately stays visible so the hover-lift on OTHER card
   grids isn't clipped by their own grid container) — here it's what makes
   the bled thumbnail respect the card's own rounded top corners. */
.rsd-read-next .rsd-cards > * { overflow: hidden; }
.rsd-read-next .rsd-card__thumb { display: block; margin: calc(var(--rsd-gap) * -1) calc(var(--rsd-gap) * -1) var(--rsd-gap-sm); }
.rsd-read-next .rsd-card__thumb img { display: block; width: 100%; height: auto; }
.rsd-read-next .rsd-badge { margin-bottom: .6rem; }
.rsd-read-next .rsd-card__meta { color: var(--rsd-muted); font-size: var(--rsd-t-xs); margin: .4rem 0 0; }
/* Inside an article column (the pattern inserted into post content): the
   label is an h2.rsd-eyebrow and the card titles are h3s, so .rsd-prose
   h2 / h3 would turn the label into a section heading and the titles into
   h3-scale type broken a word per line. Their own sizes and spacing win. */
.rsd-prose .rsd-read-next .rsd-eyebrow { margin-top: 0; font-size: var(--rsd-t-xs); }
.rsd-prose .rsd-read-next .rsd-card__title { margin-top: 0; font-size: var(--rsd-t-base); }
/* Phones: one compact row per post — a small square thumbnail beside the
   pill, title and reading time — instead of a full-width image card each
   (~500px per post). Same card surface; only cards that have a thumbnail
   take the two-column row. */
@media (max-width: 767px) {
  .rsd-read-next .rsd-cards > * { padding: var(--rsd-gap-sm); }
  .rsd-read-next .rsd-card:has(> .rsd-card__thumb) {
    display: grid; grid-template-columns: 5.5rem minmax(0, 1fr); column-gap: var(--rsd-gap-sm);
    align-items: start; align-content: start;
  }
  .rsd-read-next .rsd-card:has(> .rsd-card__thumb) > :not(.rsd-card__thumb) { grid-column: 2; justify-self: start; }
  .rsd-read-next .rsd-card__thumb { grid-row: 1 / span 3; margin: 0; border-radius: var(--rsd-radius); overflow: hidden; }
  .rsd-read-next .rsd-card__thumb img { aspect-ratio: 1; object-fit: cover; }
  .rsd-read-next .rsd-badge { margin-bottom: .35rem; }
}

/* ---------------------------------------------------------- comments
   comments.php. WordPress's default comment/form markup carries no theme
   styling at all until this block — 'comment-list'/'comment-form' html5
   support (inc/setup.php) puts it on the modern, predictable markup shape
   these selectors target (Walker_Comment's html5_comment(), and
   comment_form()'s own html5-mode field wrappers). */
.rsd-comments { margin-block: var(--rsd-block) 0; padding-top: 1.5rem; border-top: 1px solid var(--rsd-line); }
.rsd-comments__list, .rsd-comments__list .children { list-style: none; margin: 0; padding: 0; }
/* Hairline separator between each comment, not a bordered box — border-top
   only, no side/bottom borders, no background, no radius. First comment
   gets none (nothing above it to divide from); replies (.children) get a
   left rule + indent instead of their own top hairline, so a threaded
   reply reads as "part of" the comment above it, not a new hairline block. */
.rsd-comments__list > li { padding-top: var(--rsd-gap-sm); margin-top: var(--rsd-gap-sm); border-top: 1px solid var(--rsd-line); }
.rsd-comments__list > li:first-child { padding-top: 0; margin-top: 0; border-top: 0; }
.rsd-comments__list .children { margin-top: var(--rsd-gap-sm); padding-left: 1rem; border-left: 1px solid var(--rsd-line); }
.rsd-comments__list .children > li { border-top: 0; padding-top: var(--rsd-gap-sm); margin-top: var(--rsd-gap-sm); }
.rsd-comments__list .children > li:first-child { padding-top: 0; margin-top: 0; }
.comment-author { display: flex; align-items: center; gap: .6rem; margin-bottom: .3rem; }
.comment-author .avatar { border-radius: 50%; display: block; }
/* Commenter name in the display family (Inter Tight, weight 600) — the
   same "structural label" family every heading/eyebrow/card-title in
   this theme already uses, not the body font WP's default markup
   inherits with no styling at all. */
.comment-author .fn { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-style: normal; }
.comment-author .says { display: none; } /* "says:" — decorative WP boilerplate, no information */
/* Date in Plex Mono at small size, per D-24 (figures/eyebrows/source
   lines/table numerals are the mono family's job sitewide — a timestamp
   is exactly that kind of small, precise metadata). */
.comment-metadata { font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); color: var(--rsd-muted); margin-bottom: .6rem; }
.comment-metadata a { text-decoration: none; }
.comment-content p:last-child { margin-bottom: 0; }
.comment-awaiting-moderation { display: block; margin-top: .5rem; font-size: var(--rsd-t-xs); color: var(--rsd-muted); }
.comment-reply-link {
  display: inline-block; margin-top: .5rem; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-xs); text-decoration: none; color: var(--rsd-muted);
}
.comment-reply-link:hover { color: var(--rsd-red); }

/* Comment form — same field treatment as rsd_url_capture()'s own
   .rsd-capture__input (hairline border, --rsd-radius, --rsd-white
   background); the red focus ring comes free from the sitewide
   ::focus-visible rule (top of this file), same as that field — no
   second focus style invented here. */
#commentform p { margin-bottom: 1rem; }
#commentform label { display: block; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); margin-bottom: .4rem; }
/* Shared field surface — hairline border, --rsd-radius, white background,
   charcoal text, .875rem/inherit typography, uniform padding — identical,
   verbatim, to .rsd-capture__input's own contract (further down this
   file). Grouped here once rather than duplicated across both rules;
   layout-only properties (flex-row item vs. block-level width) stay on
   each selector's own separate rule below, since this is a normal
   block-flow form and .rsd-capture__input is a flex row item. */
.rsd-capture__input,
#commentform textarea,
#commentform input[type="text"],
#commentform input[type="email"],
#commentform input[type="url"] {
  font: inherit; font-size: var(--rsd-t-sm);
  padding: .65rem .85rem; border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
  background: var(--rsd-white); color: var(--rsd-charcoal);
}
#commentform textarea,
#commentform input[type="text"],
#commentform input[type="email"],
#commentform input[type="url"] {
  width: 100%; box-sizing: border-box;
}
/* Same native-:invalid neutralisation as .rsd-capture__input, and for the
   same reason — type="email"/"url" fields (html5 comment-form support
   turns these on) can carry the browser's own unrequested invalid-state
   decoration before the visitor has typed anything. */
#commentform input:invalid { border-color: var(--rsd-line); box-shadow: none; outline: none; }
#commentform textarea { min-height: 9rem; resize: vertical; }
.comment-notes, .comment-form-legend, .logged-in-as { color: var(--rsd-muted); font-size: var(--rsd-t-sm); }
.form-submit { margin-top: 1.25rem; margin-bottom: 0; }

.pagination { margin-top: var(--rsd-block); font-size: var(--rsd-t-sm); }
.pagination .nav-links { display: flex; gap: .75rem; flex-wrap: wrap; }
.pagination .page-numbers { padding: .35rem .7rem; border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius); text-decoration: none; }
.pagination .current { background: var(--rsd-charcoal); color: var(--rsd-white); border-color: var(--rsd-charcoal); }

/* ---------------------------------------------------------- blog index (home.php)
   Featured post — full width, larger than the grid cards below it: a
   bigger image size (rsd-wide, requested at asset-registration time in
   home.php, not scaled up here) and a bigger title (--rsd-t-h3, the grid
   cards use .rsd-card__title's --rsd-t-base). Asymmetric split, not a
   plain two-column 1fr/1fr — the image carries more visual weight than
   the text column here, same asymmetric instinct as .rsd-hero. */
.rsd-blog-featured {
  display: grid; grid-template-columns: 3fr 2fr; gap: var(--rsd-gap); align-items: center;
  margin-top: var(--rsd-block); padding-bottom: var(--rsd-block); border-bottom: 1px solid var(--rsd-line);
}
.rsd-blog-featured__thumb { display: block; overflow: hidden; border-radius: var(--rsd-radius); }
.rsd-blog-featured__thumb img { display: block; width: 100%; height: auto; }
.rsd-blog-featured__title { font-size: var(--rsd-t-h3); margin: .6rem 0 .5rem; }
.rsd-blog-featured__title a { text-decoration: none; }
/* One-line excerpt via actual truncation (overflow/ellipsis), not just a
   short wp_trim_words() word count — guarantees a single visual line
   regardless of how long an individual excerpt's words happen to run. */
.rsd-blog-featured__excerpt {
  color: var(--rsd-muted); font-size: var(--rsd-t-base); margin: 0 0 .75rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rsd-blog-featured__meta { margin: 0 0 .85rem; }
.rsd-blog-featured__more { display: inline-block; }

/* Featured-image placeholder (rsd_blog_thumb(), inc/blog-index.php) — a
   post with no featured image gets this instead of a broken <img> or
   empty space, per spec: plain paper surface, hairline border, and a
   small tick-on-a-hairline mark centred in it, the same red-tick-on-a-
   hairline motif .rsd-eyebrow::after already uses elsewhere (D-25's
   calibration language), not a new visual element invented for this one
   case. aspect-ratio reserves the same shape a real image would occupy —
   default matches rsd-card's own 640:400 (8:5); --wide matches rsd-wide's
   1200:675 (16:9) for the featured slot. Sits inside the same
   .rsd-card__thumb/.rsd-blog-featured__thumb wrapper a real <img> would,
   so it gets the identical bled, corner-clipped treatment automatically —
   nothing about the placeholder's own layout is a special case. */
.rsd-thumb-placeholder {
  display: flex; align-items: center; justify-content: center;
  width: 100%; aspect-ratio: 8 / 5; background: var(--rsd-paper); border: 1px solid var(--rsd-line);
}
.rsd-thumb-placeholder--wide { aspect-ratio: 16 / 9; }
.rsd-thumb-placeholder__mark { position: relative; width: 3rem; height: 1px; background: var(--rsd-line); }
.rsd-thumb-placeholder__mark::after {
  content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 2px; height: 14px; background: var(--rsd-red);
}

/* Category filter pills — reuses .rsd-badge exactly (design system §12),
   no new pill component. flex-wrap alone is what gives "wraps cleanly on
   mobile" — a row of inline-sized pills needs no breakpoint-specific
   rule to reflow correctly. */
.rsd-blog-filters { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: var(--rsd-gap); }

/* Post grid — same shape as redsprout-digital/read-next's own card grid
   (inc/patterns-read-next.php): explicit 3/2/1 columns scoped to this
   context rather than .rsd-cards' own auto-fit default, the same
   max-width:1023px/767px site-wide breakpoints (see the note on
   .rsd-read-next's own rule above), the same bled-thumbnail
   treatment. Kept as its own scoped rule set rather than sharing one
   class with .rsd-read-next — similar shape, different content (this
   grid also carries an excerpt and a full author/date/read-time line),
   so a forced shared abstraction would need as many overrides as it
   saved. */
.rsd-blog-grid { margin-top: var(--rsd-block); }
.rsd-blog-grid .rsd-cards { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1023px) { .rsd-blog-grid .rsd-cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 767px)  { .rsd-blog-grid .rsd-cards { grid-template-columns: 1fr; } }
.rsd-blog-grid .rsd-cards > * { overflow: hidden; }
/* Card surface restated directly on .rsd-card here, not left solely to
   the .rsd-cards > * inheritance path above (design system, this file) —
   a belt-and-braces fix: if a card was ever rendering as unstyled loose
   text rather than a bordered/padded box, the likely cause is that
   inheritance path not applying for some reason, and this more specific
   selector (two classes, beats a universal-child selector on specificity
   regardless of source order) guarantees the same result either way. */
.rsd-blog-grid .rsd-card {
  background: var(--rsd-white); border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius); padding: var(--rsd-gap);
}
.rsd-blog-grid .rsd-card__thumb { display: block; margin: calc(var(--rsd-gap) * -1) calc(var(--rsd-gap) * -1) var(--rsd-gap-sm); }
.rsd-blog-grid .rsd-card__thumb img { display: block; width: 100%; height: auto; }
.rsd-blog-grid .rsd-badge { display: inline-block; margin-bottom: .6rem; }
.rsd-blog-grid__excerpt {
  color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0 0 .6rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Author + date + read time in Plex Mono, per D-24 (figures/eyebrows/
   source lines/table numerals are the mono family's job sitewide) —
   scoped here only; redsprout-digital/read-next's own .rsd-card__meta
   (just a reading-time figure, no byline) is untouched. */
.rsd-blog-grid .rsd-card__meta { font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); color: var(--rsd-muted); margin: 0 0 .85rem; }
.rsd-blog-grid .rsd-card__more { display: inline-block; }

/* ---------------------------------------------------------- case studies hub
   tpl-case-studies-index.php only. Scoped to .rsd-case-studies-grid /
   .rsd-card--showcase so the shared .rsd-cards/.rsd-card base rules (used
   by services/team/locations/industries/blog grids, and by the plain
   redsprout-digital/case-studies-grid block wherever else it's inserted)
   are never touched — this is an additive layer, not a replacement. Every
   color/type/spacing/radius/shadow value below is an existing token. */

/* Explicit 3/2/1 columns, same pattern .rsd-blog-grid/.rsd-read-next
   already use, not .rsd-cards' own auto-fit default. */
.rsd-case-studies-grid .rsd-cards { grid-template-columns: repeat(3, 1fr); margin-top: var(--rsd-gap); }
@media (max-width: 1023px) { .rsd-case-studies-grid .rsd-cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 767px)  { .rsd-case-studies-grid .rsd-cards { grid-template-columns: 1fr; } }

/* padding:0 on the card itself (overriding .rsd-cards > *'s shared
   var(--rsd-gap) padding) so the image can bleed to the card's own edge;
   .rsd-card--showcase__body carries the padding instead, aspect-ratio
   (not a fixed height) keeps the image uncropped-by-guesswork at any
   image's real proportions. Base resting shadow is the "subtle" tier —
   a light lift, not the border itself, which stays the same 1px
   var(--rsd-line) hairline .rsd-cards > * already sets everywhere else;
   nothing here makes the border heavier. */
.rsd-card--showcase { display: flex; flex-direction: column; overflow: hidden; padding: 0; box-shadow: var(--rsd-shadow-subtle); }
.rsd-card--showcase .rsd-card__thumb { display: block; aspect-ratio: 16 / 10; background: var(--rsd-line); }
.rsd-card--showcase .rsd-card__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-card--showcase .rsd-card__thumb img { transition: transform .3s ease; }
  .rsd-card--showcase:hover .rsd-card__thumb img, .rsd-card--showcase:focus-within .rsd-card__thumb img { transform: scale(1.04); }
}
.rsd-card--showcase__body { padding: var(--rsd-gap); display: flex; flex-direction: column; gap: .6rem; flex: 1; }
/* Metadata row(s) — Industry (and Services Offered, on its own line) use
   the existing .rsd-badge pill; Location sits beside Industry as plain
   text, per the requested [Industry pill] [Location] / [Services] shape. */
.rsd-card--showcase__meta { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; margin: 0; }
.rsd-card--showcase__pill { font-size: var(--rsd-t-xs); padding: .2rem .6rem; }
.rsd-card--showcase__plain { font-size: var(--rsd-t-xs); color: var(--rsd-muted); }
.rsd-card--showcase__client { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-muted); margin: 0; }
/* Line-clamp is visual only — the full title/excerpt text and the
   title's <a href> are untouched in the DOM, so the complete text still
   reaches the accessibility tree and search engines; this only bounds
   how many lines render, so cards in the same grid row stay close in
   height without a fixed height clipping anything. */
.rsd-card--showcase .rsd-card__title { margin: 0; }
.rsd-card--showcase .rsd-card__title a {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
.rsd-card--showcase .rsd-excerpt {
  font-size: var(--rsd-t-sm); margin: 0;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}
.rsd-card--showcase__metric { margin-top: auto; padding-top: .75rem; border-top: 1px solid var(--rsd-line); }
.rsd-card--showcase__metric .rsd-figure { margin: 0; padding-left: 0; border-left: 0; }
.rsd-card--showcase__metric .rsd-figure__value { font-size: var(--rsd-t-h3); }
/* .rsd-btn/--ghost/--sm (existing button system, unchanged) — only the
   arrow reveal-on-hover/focus and top spacing are added here. Base state
   (no media query, and reduced-motion) leaves the arrow simply visible —
   the "hidden until interacted with" version is itself the motion
   enhancement, layered on only for visitors who don't mind it, not a
   fallback visitors would otherwise be denied the arrow for. */
.rsd-card--showcase__link { align-self: flex-start; margin-top: .5rem; }
/* Hidden at rest unconditionally — not just under no-preference — so the
   arrow never shows in the normal state for any visitor. The transition
   itself is the only part gated by prefers-reduced-motion: with no
   transition rule active, the opacity/transform flip on hover/focus
   still happens, just instantly instead of animated. */
.rsd-card--showcase__link span { display: inline-block; opacity: 0; transform: translateX(-4px); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-card--showcase__link span { transition: opacity .18s ease, transform .18s ease; }
}
.rsd-card--showcase__link:hover span,
.rsd-card--showcase__link:focus-visible span,
.rsd-card--showcase:hover .rsd-card--showcase__link span,
.rsd-card--showcase:focus-within .rsd-card--showcase__link span {
  opacity: 1; transform: translateX(0);
}
.rsd-card--showcase:hover, .rsd-card--showcase:focus-within {
  box-shadow: var(--rsd-shadow-medium);
  border-color: color-mix(in srgb, var(--rsd-line), var(--rsd-charcoal) 35%);
}
/* transform is deliberately NOT in this transition list, even though the
   hover lift below uses it. .rsd-card--showcase matches .rsd-cards > *,
   one of scroll-reveal.js's own reveal targets (assets/css/main.css's
   comment above the token block; the JS itself lives in
   assets/js/scroll-reveal.js) — GSAP's reveal tween sets this exact
   element's `transform` directly, every frame, for its one-shot
   fade/blur-in. A CSS `transition: transform` active on the same element
   at the same time fights that per-frame inline-style write (the browser
   tries to ease toward each GSAP-set value too), which is what silently
   broke the reveal on this card. box-shadow/border-color are never
   touched by GSAP, so they keep their smooth transition; the hover lift
   itself still happens via the plain rule below, just without an eased
   transition into it — an intentional, small trade to stop fighting
   GSAP rather than a redesign of the hover effect. */
@media (prefers-reduced-motion: no-preference) {
  .rsd-card--showcase { transition: box-shadow .18s ease, border-color .18s ease; }
  .rsd-card--showcase:hover, .rsd-card--showcase:focus-within { transform: translateY(-2px); }
}

/* ---------------------------------------------------------- Case Studies — editorial
   The case-studies-grid block's "Editorial showcase" layout
   (rsd_render_case_studies_editorial(), inc/case-studies.php). One item
   markup: image link, then body (lead = meta + title; detail =
   description, sourced result, link). The first item is the feature — a
   wide image with its copy below, split lead | detail from 1024px; every
   later item pairs image and copy side by side from 768px, alternating
   sides (--flip puts the copy first). Below 768px everything stacks in
   source order: image, meta, title, description, result, link.
   Images sit in fixed-ratio boxes (object-fit: cover), so nothing moves
   while they load. Hover is only the image easing to 1.02 and the arrow
   nudging — on the <img>, never on the item, which the reveal engine
   (data-rsd-reveal) owns the transform of. No borders, shadows or lifts. */
.rsd-csx {
  --rsd-csx-radius: calc(var(--rsd-radius) * 1.5);
  display: flex; flex-direction: column; gap: calc(var(--rsd-block) * .75);
  margin-top: var(--rsd-gap);
}
.rsd-csx__item { min-width: 0; }
.rsd-csx__media {
  display: block; overflow: hidden; aspect-ratio: 16 / 10;
  border-radius: var(--rsd-csx-radius); background: var(--rsd-line);
}
.rsd-csx__img { display: block; width: 100%; height: 100%; object-fit: cover; }
.rsd-csx__body { margin-top: 1.25rem; }
.rsd-csx__item--no-media .rsd-csx__body { margin-top: 0; }

.rsd-csx__meta {
  display: flex; flex-wrap: wrap; align-items: baseline; margin: 0 0 .6rem;
  font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); letter-spacing: .06em; text-transform: uppercase;
  color: var(--rsd-muted);
}
.rsd-csx__meta-item + .rsd-csx__meta-item::before { content: "/"; margin-inline: .55rem; color: var(--rsd-line); }
/* The client gets its own line (names can be long, e.g. an anonymized
   one), so a wrapped line never starts with a separator. */
.rsd-csx__client { flex-basis: 100%; margin-bottom: .3rem; color: var(--rsd-charcoal); font-weight: var(--rsd-weight-semibold); }
.rsd-csx__client + .rsd-csx__meta-item::before { content: none; }
.rsd-csx .rsd-csx__title {
  margin: 0; max-width: 26ch;
  font-family: var(--rsd-display); font-size: var(--rsd-t-h3); line-height: 1.15; letter-spacing: -0.01em;
}
.rsd-csx__item--feature .rsd-csx__title { font-size: calc((var(--rsd-t-h3) + var(--rsd-t-h2)) / 2); max-width: 22ch; }
.rsd-csx .rsd-csx__desc { margin: .75rem 0 0; max-width: 60ch; color: var(--rsd-muted); line-height: 1.6; }
.rsd-csx__result { margin-top: 1.25rem; }
.rsd-csx__result .rsd-figure { margin: 0; }
.rsd-csx__item--split .rsd-csx__result .rsd-figure__value { font-size: clamp(1.75rem, 2.6vw, 2.25rem); }
.rsd-csx__detail > .rsd-csx__link { margin-top: 1.25rem; }
.rsd-csx__link { gap: .45rem; }
.rsd-csx__arrow { display: inline-block; }
.rsd-csx__all { margin: 0; }

@media (prefers-reduced-motion: no-preference) {
  .rsd-csx__img { transition: transform .6s var(--rsd-ease-out); }
  .rsd-csx__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-csx__item:has(.rsd-csx__media:hover, .rsd-csx__link:hover, .rsd-csx__link:focus-visible) .rsd-csx__img { transform: scale(1.02); }
  .rsd-csx__item:has(.rsd-csx__media:hover) .rsd-csx__arrow,
  .rsd-csx__link:is(:hover, :focus-visible) .rsd-csx__arrow { transform: translateX(3px); }
}

/* Tablet up: the feature image gets wider, later items go side by side. */
@media (min-width: 768px) {
  .rsd-csx__item--feature .rsd-csx__media { aspect-ratio: 2 / 1; }
  .rsd-csx__item--split:not(.rsd-csx__item--no-media) {
    display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 4rem); align-items: center;
  }
  .rsd-csx__item--split .rsd-csx__body { margin-top: 0; }
  .rsd-csx__item--flip:not(.rsd-csx__item--no-media) { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
  .rsd-csx__item--flip .rsd-csx__media { grid-column: 2; }
  .rsd-csx__item--flip .rsd-csx__body { grid-column: 1; grid-row: 1; }
}
/* Desktop: a wider feature image, its copy split lead | detail. */
@media (min-width: 1024px) {
  .rsd-csx__item--feature .rsd-csx__media { aspect-ratio: 21 / 9; }
  .rsd-csx__item--feature .rsd-csx__body {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: 1rem clamp(2rem, 5vw, 4.5rem); align-items: start; margin-top: 2rem;
  }
  .rsd-csx__item--feature .rsd-csx__desc { margin-top: 0; }
}

/* Filter bar — SaaS toolbar. Plain server-side GET form, no JS: labelled
   native selects + a real submit button (.rsd-btn, existing button
   system), never a div styled to look like one. */
.rsd-case-filters {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--rsd-gap-sm);
  margin-top: var(--rsd-gap); padding: var(--rsd-gap-sm) var(--rsd-gap); box-sizing: border-box;
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-case-filters__label {
  flex: 0 0 auto; align-self: center;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-charcoal);
}
.rsd-case-filters__group { display: flex; flex-direction: column; gap: .3rem; min-width: 168px; flex: 1 1 168px; }
.rsd-case-filters__group label { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-xs); color: var(--rsd-muted); }
.rsd-case-filters__group select {
  -webkit-appearance: none; appearance: none;
  height: var(--rsd-tap-target); width: 100%; box-sizing: border-box;
  font: inherit; font-size: var(--rsd-t-sm); padding: 0 2rem 0 .75rem;
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
  background-color: var(--rsd-white); color: var(--rsd-charcoal);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2363636A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .75rem center;
  cursor: pointer;
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-case-filters__group select { transition: border-color .16s ease; }
}
.rsd-case-filters__group select:hover { border-color: var(--rsd-charcoal); }
/* Neutral keyboard-focus treatment, scoped to this toolbar only — the
   sitewide :focus-visible rule (top of this file) is untouched; every
   selector below wins locally through normal specificity (class+element
   +pseudo-class beats a bare pseudo-class), no !important anywhere.
   :focus (mouse/programmatic activation) is explicitly cleared first —
   native <select> focus rings are the one control most browsers still
   draw on plain :focus rather than gating on real keyboard use — then
   :focus-visible reinstates a single, deliberately muted (not red, not
   charcoal/black) ring for genuine keyboard navigation only. */
.rsd-case-filters__group select:focus,
.rsd-case-filters__apply:focus {
  outline: none;
}
.rsd-case-filters__group select:focus-visible,
.rsd-case-filters__apply:focus-visible {
  outline: 2px solid var(--rsd-muted);
  outline-offset: 2px;
}
/* min-height overrides .rsd-btn--sm's own min-height:0 opt-out (main.css,
   button system) so the submit button matches the selects' full
   --rsd-tap-target height instead of sitting shorter than them. */
.rsd-case-filters__apply { flex: 0 0 auto; min-height: var(--rsd-tap-target); }
.rsd-case-filters__clear { flex: 0 0 auto; align-self: center; font-size: var(--rsd-t-sm); color: var(--rsd-muted); }
/* Active-filter state — a genuine value selected, not just focused.
   Border only (no fill), same restraint .rsd-badge already uses for its
   own "notable" variant, so it reads as "on" without competing with the
   Filter Results button for attention. */
.rsd-case-filters__group--active label { color: var(--rsd-charcoal); }
.rsd-case-filters__group--active select { border-color: var(--rsd-red); }
.rsd-case-filters__count { margin-top: var(--rsd-gap-sm); font-size: var(--rsd-t-sm); color: var(--rsd-muted); }
@media (max-width: 1023px) {
  .rsd-case-filters { flex-direction: column; align-items: stretch; }
  .rsd-case-filters__label { align-self: flex-start; }
  /* Root cause of the huge gaps between groups: .rsd-case-filters__group's
     desktop rule is `flex: 1 1 168px` — a WIDTH basis in the desktop row
     layout, but flex-basis tracks the flex container's MAIN axis, which
     flex-direction:column (above) just rotated to vertical. The same
     "168px, grow:1" was then being read as "at least 168px tall, then
     grow to fill" for every group, inflating each one to roughly 168px+
     of mostly-empty height instead of its actual ~60-70px label+select
     content height. min-width:0 (already here) fixed the leftover
     cross-axis constraint; flex-basis on the now-vertical main axis was
     the real culprit and was untouched until this fix. auto/no-grow lets
     each group size to its own label+select content, so the existing
     gap: var(--rsd-gap-sm) on .rsd-case-filters (unchanged) now reads as
     the intended compact rhythm between groups instead of vanishing
     inside 100+px of inflated group height. */
  .rsd-case-filters__group { min-width: 0; flex: 0 0 auto; }
  .rsd-case-filters__apply, .rsd-case-filters__clear { width: 100%; text-align: center; }
}

/* Pagination — scoped override, not a change to the shared .pagination
   rule above (which archive.php's and index.php's own pagination still
   use unchanged). Base hairline border on .page-numbers already comes
   from that shared rule; this only adds the mono numerals and swaps
   current-page from charcoal to brand red. No arrow icons: home.php
   passes explicit prev_text/next_text strings (same values index.php/
   archive.php already use), so there's no default WordPress glyph to
   suppress here in the first place. */
.rsd-blog-pagination .page-numbers { font-family: var(--rsd-mono); }
.rsd-blog-pagination .page-numbers.current { background: var(--rsd-red); border-color: var(--rsd-red); color: var(--rsd-white); }

/* ---------------------------------------------------------- responsive */
@media (max-width: 1023px) {
  .rsd-hero, .rsd-qualifier, .rsd-cta-capture, .rsd-article, .rsd-blog-featured { grid-template-columns: 1fr; }
}
/* .rsd-article__aside: stacked full-width has nothing to stay pinned
   against (position:static), and order:-1 puts the TOC ahead of the full
   article body in the stacked reading order — useful for jumping to a
   section on a long article read on a phone; on desktop it's a sidebar,
   so source order there is irrelevant to what the reader sees first. */
@media (max-width: 1023px) {
  .rsd-article__aside { position: static; order: -1; }
}
/* ---------------------------------------------------------- footer
   responsive — four columns desktop (unconditional base rule, above),
   two on tablet, one on mobile. Own dedicated queries (not reusing the
   900/720 breakpoints above, which are unrelated legacy nav rules) at
   1199/767, chosen so the four widths this was tested at each land in
   the intended bucket: 1440 → base (4 cols), 1024 → ≤1199 (2 cols),
   768 → ≤1199 (2 cols, upper edge of "tablet"), 375 → ≤767 (1 col). */
@media (max-width: 1199px) {
  .rsd-footer__top { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 767px) {
  .rsd-footer__top { grid-template-columns: 1fr; }
  .rsd-footer { padding-block: var(--rsd-block) 1.5rem; }
  /* The ambient corner glow is desktop-only — the brief was explicit
     that mobile should read simpler than desktop, not just "no
     stronger," so this removes it rather than scaling it down. */
  .rsd-footer::before { display: none; }
  .rsd-footer__markets ul { gap: 1rem; }
  /* Copyright + legal menu: side-by-side (space-between) above this
     width relies on flex-wrap alone, which can look like an accidental
     line-break rather than a deliberate stack. Explicit column stack
     below 767px instead. */
  .rsd-footer__base { flex-direction: column; align-items: flex-start; gap: .75rem; }
  /* One step down the existing type scale — footer text doesn't need
     body-copy size on a narrow screen. */
  .rsd-footer__line { font-size: var(--rsd-t-xs); }
  .rsd-footer__col,
  .rsd-footer__col a,
  .rsd-footer__col li,
  .rsd-footer__col p,
  .rsd-footer__col .wp-block-navigation,
  .rsd-footer__col .wp-block-navigation-item,
  .rsd-footer__col .wp-block-navigation-item__content,
  .rsd-footer__col .wp-block-navigation__container {
    font-size: var(--rsd-t-xs) !important;
  }
}

/* ---------------------------------------------------------- motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* ============================================================
   Scroll reveal — RedSprout Animations (inc/animations.php,
   assets/js/scroll-reveal.js). Off site-wide by default.

   RETIRED as of the GSAP + ScrollTrigger migration: the CSS-transition
   reveal engine that used to live in this block (a
   html.rsd-reveal-ready + body.rsd-animations-on gated hidden state,
   animated via `transition:` and released via a JS-added .is-revealed
   class, driven by IntersectionObserver). GSAP now owns all of that —
   the hidden state, the tween, and the trigger — so a parallel CSS
   transition system controlling the same elements would just fight it
   for the same properties. Deliberately NOT replaced with an
   equivalent GSAP-flavoured CSS block: gsap.fromTo() sets its own
   "from" values via inline style at animation-setup time, only once
   GSAP + ScrollTrigger have actually loaded successfully — if either
   fails (CDN unreachable, blocked, JS error), fromTo() is simply never
   called, and nothing here or in scroll-reveal.js ever sets opacity/
   transform/filter on these elements, so they stay at their normal
   visible state by construction, not by a duration override. That's a
   stronger fail-safe than the old html.rsd-reveal-ready pre-paint gate
   could offer once the reveal engine depends on a network-loaded
   library — see assets/js/scroll-reveal.js for the actual mechanism.

   body.rsd-animations-on (inc/animations.php, body_class filter) is
   still the master toggle scroll-reveal.js checks before doing
   anything at all — unchanged.

   --rsd-reveal-offset is the one piece kept from the old system,
   repurposed rather than removed: scroll-reveal.js reads its computed
   value via getComputedStyle(document.documentElement) as the default
   translateY distance for GSAP's fromTo(), so the desktop/mobile
   difference below stays defined in exactly one place (here) instead
   of being duplicated as a second, JS-side breakpoint check. An
   element with its own data-rsd-offset attribute is read directly by
   JS and ignores this custom property entirely, at any width.
   16px / 24px (was an implicit 30px / 40px): a short, precise rise. */
:root { --rsd-reveal-offset: 16px; }
@media (min-width: 1024px) {
  :root { --rsd-reveal-offset: 24px; }
}

/* ============================================================
   Floating pill header — hand-written, no utility framework.
   ============================================================ */
.rsd-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.rsd-header { position: relative; z-index: 60; }

.rsd-pill {
  /* --rsd-st: 0 (top, normal) → 1 (fully compact/sticky). Driven by
     assets/js/main.js mapping scroll progress 3%→30% onto this one
     property; every property below is a pure calc() of it, so the
     transition is continuous and reverses for free on scroll-up. */
  --rsd-st: 0;
  position: fixed; top: calc(20px - 10px * var(--rsd-st)); left: 50%;
  transform: translateX(-50%) scale(calc(1 - 0.015 * var(--rsd-st)));
  transform-origin: top center;
  z-index: 60; width: calc(100% - 2.5rem); max-width: 1290px;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: calc(0.5rem - 0.15rem * var(--rsd-st)) calc(0.6rem - 0.1rem * var(--rsd-st))
           calc(0.5rem - 0.15rem * var(--rsd-st)) calc(1.25rem - 0.25rem * var(--rsd-st));
  background: color-mix(in srgb, var(--rsd-header-bg, var(--rsd-white)) calc(92% + 6% * var(--rsd-st)), transparent);
  backdrop-filter: blur(calc(14px + 4px * var(--rsd-st)));
  border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius-pill);
  box-shadow: 0 calc(8px + 4px * var(--rsd-st)) calc(30px + 10px * var(--rsd-st)) rgba(26, 26, 28, calc(0.06 + 0.06 * var(--rsd-st)));
}
@media (prefers-reduced-motion: no-preference) {
  /* 300ms (was 220ms): --rsd-st is now a two-state switch (assets/js/
     main.js) rather than a continuous scroll ramp, so these transitions
     are the whole full → compact animation, tagline collapse included
     (.rsd-pill__tagline, same duration and curve). */
  .rsd-pill {
    transition: top .3s var(--rsd-ease-out), transform .3s var(--rsd-ease-out),
                padding .3s var(--rsd-ease-out), background-color .3s ease,
                backdrop-filter .3s ease, box-shadow .3s ease;
  }
}
/* First paint on a mid-page landing: no contraction animation. Also used
   by the mega menu (assets/js/main.js) to hand the bar's paint back from
   the expanded surface in a single frame. */
.rsd-pill--instant, .rsd-pill--instant *,
.rsd-pill--instant::before, .rsd-pill--instant::after { transition: none !important; }
/* Brand lockup — the Site Identity tagline under the logo
   (rsd_site_tagline(), inc/template-tags.php). The logo is .rsd-pill's
   tallest flex item, so the tagline grows the pill by exactly its own
   margin + line box: --rsd-tagline-space. Every rule that assumed the old
   pill height adds it (0 when no tagline renders — body.rsd-has-tagline
   is only present when there is one): .rsd-main below, the mega-menu
   hover bridge, .rsd-article__aside's sticky top, .rsd-prose headings'
   scroll-margin-top, .rsd-layout__sidebar--sticky. Under 360px the
   tagline breaks onto a second line (between phrases — see
   rsd_site_tagline()), so the budget there is two lines.

   Size: --rsd-tagline-px is the Customizer's "Tagline font size" slider
   (12-22px, default 17px, inc/logo-crop.php), used as-is at 768-1279px
   (where the tagline has its own full-width row, below). Capped at 19px
   from 1440px and at 16px for 1280-1439px, where the tagline shares the
   row with the nav + CTA and the pill is narrowest; and on phones capped
   by a fluid 13px-at-375px → 22px-at-767px ceiling, which keeps it on one
   line beside nothing but the pill's own padding.

   --rsd-tagline-gap is negative on purpose: the logo <img> sits in a
   line box with strut space below it, and the uploaded logo PNG has its
   own blank rows under "digital", so -1px still leaves a clear ~7px
   between the artwork and the tagline — the tight lockup, not a
   collision. */
.rsd-has-tagline {
  --rsd-tagline-size: var(--rsd-tagline-px, 17px);
  --rsd-tagline-lh: 1.3;
  --rsd-tagline-gap: -0.0625rem;
  --rsd-tagline-lines: 1;
  --rsd-tagline-space: calc(var(--rsd-tagline-size) * var(--rsd-tagline-lh) * var(--rsd-tagline-lines) + var(--rsd-tagline-gap));
  --rsd-tagline-bridge: calc(var(--rsd-tagline-space) / 2);
}
@media (min-width: 1440px) { .rsd-has-tagline { --rsd-tagline-size: min(var(--rsd-tagline-px, 17px), 19px); } }
@media (min-width: 1280px) and (max-width: 1439px) { .rsd-has-tagline { --rsd-tagline-size: min(var(--rsd-tagline-px, 17px), 16px); } }
@media (max-width: 767px) { .rsd-has-tagline { --rsd-tagline-size: min(var(--rsd-tagline-px, 17px), clamp(13px, 13px + (100vw - 375px) * 0.023, 22px)); } }
@media (max-width: 359px) { .rsd-has-tagline { --rsd-tagline-lines: 2; } }

/* The taller pill's rounded (--rsd-radius-pill) left end curves in far
   enough to meet the tagline's bottom-left corner at the stock 1.25rem
   padding; the extra left padding keeps it clear of the curve. */
.rsd-has-tagline .rsd-pill { padding-left: calc(1.875rem - 0.125rem * var(--rsd-st)); }

.rsd-pill__tagline {
  margin: var(--rsd-tagline-gap) 0 0;
  font-family: var(--rsd-body);
  font-size: var(--rsd-tagline-size);
  font-weight: var(--rsd-weight-medium);
  line-height: var(--rsd-tagline-lh);
  letter-spacing: 0.01em;
  color: #000000; /* pure black by explicit brand decision — a step past --rsd-charcoal for the lockup */
  /* Compact sticky state (--rsd-st: 1, assets/js/main.js): the tagline
     collapses away — its line box to 0 (max-height starts at exactly the
     budgeted --rsd-tagline-space line height, so the collapse is linear
     from the first frame), its margin to 0, fading and rising 4px — and
     the pill contracts with it. The pill is position:fixed, so nothing on
     the page moves. */
  max-height: calc(var(--rsd-tagline-size) * var(--rsd-tagline-lh) * var(--rsd-tagline-lines) * (1 - var(--rsd-st, 0)));
  margin-top: calc(var(--rsd-tagline-gap) * (1 - var(--rsd-st, 0)));
  overflow: hidden;
  opacity: calc(1 - var(--rsd-st, 0));
  transform: translateY(calc(-4px * var(--rsd-st, 0)));
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-pill__tagline {
    transition: max-height .3s var(--rsd-ease-out), margin-top .3s var(--rsd-ease-out),
                opacity .22s ease, transform .3s var(--rsd-ease-out);
  }
}
.rsd-pill__tagline-phrase { display: inline-block; }

/* Visual left edge: the uploaded logo PNG (cropped-RedSprout_Digital_Logo,
   103x40) carries its own white margin — the artwork starts 12px in — so
   the tagline is indented by that same share of the rendered logo width
   (--rsd-logo-width, the Site Identity "Logo width" slider) to line up
   with the "r" of redsprout rather than the image's invisible edge.
   Re-measure --rsd-logo-ink-inset if the logo file is replaced; a logo
   trimmed to its artwork wants 0. Only after a custom logo — the text
   fallback (.rsd-logo) has no such margin. */
.rsd-has-tagline { --rsd-logo-ink-inset: calc(12 / 103); }
.custom-logo-link + .rsd-pill__tagline { padding-left: calc(var(--rsd-logo-width, 180px) * var(--rsd-logo-ink-inset)); }

/* 1280px+ (tagline in the logo's own column, beside nav + CTA): the caps
   above are sized for a typical menu. Should a longer menu plus a large
   slider value still run short of room, nav and CTA hold their width and
   the brand column gives way instead — the tagline wraps between phrases
   rather than anything overlapping or squeezing the nav/CTA labels. */
@media (min-width: 1280px) {
  .rsd-has-tagline .rsd-pill__nav, .rsd-has-tagline .rsd-pill__cta { flex-shrink: 0; }
}

/* Below 1280px the tagline can't sit in a column beside the rest of the
   row — nav + CTA (1024-1279px) or the call/hamburger cluster (below
   1024px) leave too little width, and it would squeeze their labels or
   wrap to several lines. display:contents lifts the logo and tagline into
   .rsd-pill's own flex row so the tagline takes a full-width second row
   instead — still directly below the logo, one line down to 360px, and
   the first row (logo / nav / CTA or logo / call / hamburger) is left
   exactly as it was. The logo link stays a block box with its image's
   line box intact, so row one keeps the stock pill height and the growth
   is still just --rsd-tagline-space (the tagline's own margin, as a flex
   item, doing what it does in the column layout; row-gap 0 because the
   gap is negative). Nav items now centre in row one rather than the
   whole pill, so the hover bridge has to span the full added height. */
@media (max-width: 1279px) {
  .rsd-has-tagline { --rsd-tagline-bridge: var(--rsd-tagline-space); }
  .rsd-has-tagline .rsd-pill { flex-wrap: wrap; row-gap: 0; }
  .rsd-has-tagline .rsd-pill__brand { display: contents; }
  .rsd-pill__tagline { order: 1; flex-basis: 100%; }
}

/* Offset the fixed bar so content never sits underneath it. */
.rsd-main { padding-top: calc(68px + var(--rsd-tagline-space, 0px) + var(--rsd-utility-pad, 0px) + clamp(1.5rem, 4vw, 2.75rem)); }

@media (min-width: 1280px) { .rsd-pill { max-width: 1290px; } }
@media (max-width: 1279px) { .rsd-pill { max-width: 1140px; } }
@media (max-width: 1023px) { .rsd-pill { max-width: 960px; } }
@media (max-width: 767px)  { .rsd-pill { max-width: 720px; } }

.rsd-pill__nav, .rsd-pill__cta { display: none; }
@media (min-width: 1024px) {
  .rsd-pill__nav, .rsd-pill__cta { display: flex; align-items: center; }
  .rsd-pill__cta { gap: .6rem; }
}

/* One-row fit for the real primary menu (five long pillar labels —
   "Performance Marketing", "Automation & AI", …, each with a chevron)
   beside the logo + tagline column and both buttons. Measured at the
   stock spacing, that row was ~40px (1440px) to ~160px (1024px) wider than
   the pill, so labels wrapped, the tagline got squeezed onto two lines or
   the CTA was pushed off the row. In priority order, with the proposal
   CTA never touched: Client Login and Support leave the row entirely (the
   utility links, below), header sections sit 1rem → .75rem apart, and nav
   labels never wrap mid-label. Nav items get 1.375rem (22px) between
   them — clear separation between one label's chevron and the next
   label — at 1084px+, where that fits beside the logo/tagline column and
   the CTA. Narrower than that (1024-1083px) the row has only ~12-23px
   per gap to give, so there the nav takes all the leftover width and
   spreads its items evenly (space-between, .5rem floor) instead of a
   fixed gap that would overflow the pill.

   The header's Get a proposal CTA is 140px wide (min-width; label stays
   centred, height/colour/radius/type untouched) at 1084px+, so the
   CTA-wide Support / Client Login row above it (below) sits a little in
   from the pill's right end and the right-side block reads balanced.
   Below 1084px it keeps its natural ~128px, where those 12px would
   otherwise come straight out of the nav's already-tight gaps. */
@media (min-width: 1024px) {
  .rsd-pill { gap: .75rem; }
  .rsd-pill__nav .rsd-menu { gap: 1.375rem; }
  .rsd-pill__nav .rsd-menu > li > a { white-space: nowrap; }
}
@media (min-width: 1084px) {
  .rsd-pill__cta .rsd-btn--solid { min-width: 8.75rem; }
}
@media (min-width: 1024px) and (max-width: 1083px) {
  .rsd-pill__nav { flex: 1 1 auto; min-width: 0; }
  .rsd-pill__nav .rsd-menu { flex: 1 1 auto; justify-content: space-between; gap: .5rem; }
}

/* Utility links — Support → Client Login, a small text-only group in the
   pill's upper-right corner above the Get a proposal CTA (header.php's
   nav.rsd-pill__utility), instead of buttons in the row, so they never
   compete with the main nav for width. Anchored to the CTA itself
   (.rsd-pill__cta is its containing block): a compact pair centred over
   the CTA, 9px above it, so links + CTA read as one action block. Desktop only:
   .rsd-pill__cta is display:none below 1024px, and the drawer carries its
   own Support and Client Login buttons.

   Room for it: the full state adds --rsd-utility-pad of top padding so
   the links have ~17-21px above them and a clear 9px (--rsd-utility-gap)
   to the CTA — quiet utility links visibly apart from, but still tied
   to, the CTA. 16px at 1280px+ with a tagline — enough that the links'
   space above roughly matches the tagline's space below, even where the
   pill's rounded right end curves the top border down (the logo + tagline column
   already makes the pill tall enough that the centred CTA sits ~26px
   down); 25px otherwise (1024-1279px, where the nav/CTA share the logo's
   own row, or with no tagline), where the CTA starts only ~15px down.
   Dropped again
   in the compact state along with the links, and added to .rsd-main's
   offset. Top padding moves the nav down with the pill's bottom edge, so
   the mega-menu hover bridge needs nothing extra.

   Compact state (.is-compact, set by assets/js/main.js alongside
   --rsd-st): the whole group fades and rises 4px — the same motion as
   the tagline — then goes visibility:hidden, so both links also leave the
   tab order rather than sitting there focusable but invisible. */
@media (min-width: 1024px) {
  :root { --rsd-utility-pad: 1.5625rem; --rsd-utility-gap: .5625rem; }
  /* Right inset 1.875rem — the same inset the tagline gives the left end
     (.rsd-has-tagline .rsd-pill, above), so the pill reads symmetrical:
     pulls the whole utility + CTA block in from the pill's rounded right
     end, far enough that the CTA-wide utility row clears the curve at the
     top. Same in the compact state, so the CTA doesn't slide sideways as
     the header contracts. */
  .rsd-pill {
    padding-top: calc(0.5rem - 0.15rem * var(--rsd-st) + var(--rsd-utility-pad) * (1 - var(--rsd-st)));
    padding-right: calc(1.875rem - 0.125rem * var(--rsd-st));
  }
  /* One right-side action block: the utility row is laid out over exactly
     the CTA's own width (.rsd-pill__cta shrink-wraps the button; the
     absolutely-positioned row doesn't count toward that), with Support
     and Client Login as one compact 16px-apart pair centred above it —
     not stretched edge to edge — --rsd-utility-gap (9px) above the CTA's
     top. */
  .rsd-pill__cta { position: relative; }
  .rsd-pill__utility {
    position: absolute; left: 0; right: 0; bottom: calc(100% + var(--rsd-utility-gap));
    display: flex; align-items: baseline; justify-content: center; gap: 1rem;
  }
  .rsd-pill__utility-link {
    font-family: var(--rsd-body); font-size: calc(var(--rsd-t-xs) - 1px); font-weight: var(--rsd-weight-regular);
    line-height: 1; letter-spacing: 0.01em; white-space: nowrap;
    color: var(--rsd-muted); text-decoration: none;
  }
  .rsd-pill__utility-link:hover, .rsd-pill__utility-link:focus-visible { color: var(--rsd-charcoal); }
  .rsd-pill.is-compact .rsd-pill__utility { opacity: 0; transform: translateY(-4px); visibility: hidden; }
}
@media (min-width: 1280px) {
  .rsd-has-tagline { --rsd-utility-pad: 1rem; }
}
@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
  .rsd-pill__utility-link { transition: color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-pill__utility { transition: opacity .2s ease, transform .3s var(--rsd-ease-out), visibility 0s linear 0s; }
  .rsd-pill.is-compact .rsd-pill__utility { transition: opacity .2s ease, transform .3s var(--rsd-ease-out), visibility 0s linear .2s; }
}

.rsd-menu { display: flex; align-items: center; gap: 1.5rem; list-style: none; margin: 0; padding: 0; }
.rsd-menu a {
  text-decoration: none;
  font-family: var(--rsd-t-menu-family, var(--rsd-body));
  font-size: var(--rsd-t-menu-size, var(--rsd-t-sm));
  font-weight: var(--rsd-t-menu-weight, 500);
  line-height: var(--rsd-t-menu-line-height, 1.6);
  letter-spacing: var(--rsd-t-menu-letter-spacing, normal);
  text-transform: var(--rsd-t-menu-text-transform, none);
  display: inline-block; padding-block: .35rem;
}
/* .rsd-menu > li is deliberately NOT position:relative (this task —
   horizontal clipping fix; see the full explanation on .rsd-menu > li >
   .sub-menu's own positioning rule, further down, for why). Mobile needs
   no equivalent here: .rsd-menu--stacked li.menu-item-has-children (this
   file, mobile accordion section) already sets its own position:relative,
   independently, scoped to items with a toggle button — that rule is
   untouched and was never the sitewide one removed here. */

/* Top-level trigger — desktop pill nav only (scoped via .rsd-pill__nav so
   this never competes with the drawer's own .rsd-menu--stacked padding/
   layout rules, which live in a completely separate .rsd-drawer__nav
   container). Same rounded pale-red hover language as the submenu links
   below (reusing the same --rsd-submenu-hover-bg token, not a second
   color), no underline. Padding grows slightly on hover/focus so the pill
   has room without the rest of the nav shifting — offset by a matching
   negative margin so neighbouring items don't move. */
.rsd-pill__nav .rsd-menu > li > a {
  border-radius: 9px; padding: .4rem .65rem; margin: 0 -.65rem;
  display: inline-flex; align-items: center; gap: .35rem;
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-pill__nav .rsd-menu > li > a { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
.rsd-pill__nav .rsd-menu > li:hover > a,
.rsd-pill__nav .rsd-menu > li:focus-within > a,
.rsd-pill__nav .rsd-menu > li.current-menu-item > a {
  background: var(--rsd-submenu-hover-bg);
}

/* Continuous hover region (this task) — root-level fix, not a bridge.
   Two prior attempts (a li::after bridge gated on li:hover, then an
   a::before bridge) both tried to PATCH the gap externally, with
   pointer-events logic that could still be timing-sensitive. This
   instead makes .rsd-menu > li.menu-item-has-children's OWN rendered
   box — the thing :hover/:focus-within below already keys off — cover
   the gap natively, so there is no separate element whose interactivity
   depends on any other element's state.

   .rsd-menu > li is still position:static (never restored to relative —
   the panel's containing block stays .rsd-pill, per the earlier
   horizontal-clipping fix, completely unrelated to this: padding/margin
   don't affect position/containing-block resolution at all). Normally,
   <li>'s own box is exactly as tall as its <a> content (~35px) — the
   gap down to where the panel starts (.rsd-pill's own bottom padding,
   calc(0.5rem - 0.15rem * var(--rsd-st)), plus flex-centering slack
   against .rsd-btn's 44px min-height, this file — roughly 10-12px
   combined, the same measurement the previous bridge attempts used) is
   OUTSIDE <li>'s own box entirely, so hovering it was never "hovering
   li" no matter what sat visually on top of it.

   padding-bottom:12px extends <li>'s own border box — the actual
   hit-tested area for :hover — down across that entire gap, natively,
   with no pointer-events logic and nothing else to fail. margin-bottom:
   -12px cancels the padding's contribution to the flex line's own
   cross-axis (height) calculation (.rsd-menu's align-items:center,
   above) — margin, unlike padding, is excluded from what a flex item
   contributes to a line's box height, so this pair nets to zero
   layout-height change: .rsd-menu / .rsd-pill__nav / .rsd-pill all
   render at the exact same height as before. <li> itself paints no
   background/border of its own (only .rsd-pill__nav .rsd-menu > li > a,
   above, does, on <a> specifically) — so this extra padding is
   completely invisible; nothing bleeds into it. Scoped to
   .rsd-pill__nav specifically (desktop nav only) so the mobile drawer's
   own .rsd-menu--stacked li.menu-item-has-children (different layout,
   different rule, untouched) can never be affected by this. */
.rsd-pill__nav .rsd-menu > li.menu-item-has-children {
  /* 15px, not 12px (this task) — corrected against real DevTools
     measurement at 1366px: trigger bottom 71.390625px, <li> bottom
     83.390625px (12px extension already applied), panel's open-state top
     (closed getBoundingClientRect().top 80px + the closed transform's
     translateY(-6px) reversed) ≈ 86px. Actual dead zone = 86 - 83.390625
     ≈ 2.61px still uncovered by the previous 12px value — this was an
     underestimate (the earlier calculation assumed .rsd-btn's 44px
     min-height was .rsd-pill's tallest flex sibling; the real gap
     confirms it needed roughly 2.6px more, most plausibly because
     .custom-logo's actual rendered height — unmeasurable from source,
     an admin-uploaded image — is the true tallest sibling instead).
     14.6px would cover the measured gap exactly; 15px is used as the
     nearest whole pixel with a hair of margin, not a new estimate.
     + --rsd-tagline-bridge: how much the Site Identity tagline grows the
     gap below this <li> — half the pill's added height at 1280px+, where
     the <li> stays centred in the taller pill; all of it below that,
     where the tagline takes its own row under the nav's row. Scaled by
     (1 - --rsd-st): the tagline is collapsed away in the compact sticky
     state, so there the bridge is back to the stock 15px. */
  padding-bottom: calc(15px + var(--rsd-tagline-bridge, 0px) * (1 - var(--rsd-st, 0)));
  margin-bottom: calc(-15px - var(--rsd-tagline-bridge, 0px) * (1 - var(--rsd-st, 0)));
}

/* Chevron — desktop pill nav only, same reasoning. Only on items that
   actually open something (RSD_Nav_Walker adds aria-haspopup="true" to
   exactly those), so it's never confused with the separate internal
   submenu-item icons. Pure CSS, no image/font; flips to point up while
   its mega-menu is open. */
.rsd-pill__nav .rsd-menu > li > a[aria-haspopup="true"]::after {
  content: ""; width: 7px; height: 7px; flex: none;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); margin-top: -3px;
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-pill__nav .rsd-menu > li > a[aria-haspopup="true"]::after { transition: transform .16s ease, margin .16s ease; }
}
.rsd-pill__nav .rsd-menu > li:hover > a[aria-haspopup="true"]::after,
.rsd-pill__nav .rsd-menu > li:focus-within > a[aria-haspopup="true"]::after {
  transform: rotate(225deg); margin-top: 3px;
}

/* ---- mega-menu text + icon (shared by the desktop panel and the mobile
   accordion — same markup, rendered twice by RSD_Nav_Walker) ----------
   All colors below are CSS custom properties generated from Customizer
   theme_mods (inc/customizer.php) — nothing here is a repeated literal.
   Defaults reuse the theme's own existing --rsd-charcoal/--rsd-muted
   tokens, so this looks exactly like it did before the Customizer
   controls existed until someone actually changes a setting. */
/* Heading polish (this task) — typography-only, two values changed:
   letter-spacing .06em -> .1em (a tracked-caps value read as "premium
   enterprise," noticeably more open than before but deliberately short
   of .rsd-eyebrow's own .14em — stays visually distinct from that
   component rather than becoming a second eyebrow, per this task's own
   "no eyebrow pill treatment" instruction) and font-weight 600 -> 700
   (matching the display family's strongest weight, so the heading reads
   more clearly heavier than .rsd-menu__label's own 500 default,
   reinforcing "strong enough to separate the category from its links").
   font-size, color, display, padding, and every other property are
   unchanged — still var(--rsd-t-xs)/var(--rsd-submenu-heading), the same
   Mega Menu Customizer color token as before. */
.rsd-menu__heading {
  display: block; font-family: var(--rsd-display); font-weight: 700;
  font-size: var(--rsd-t-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--rsd-submenu-heading); padding: .5rem .6rem .6rem;
}
/* Icon + text sit side by side; icon aligned to the flex-start (the label
   line), not centred on the whole two-line label+description block — see
   .rsd-menu__icon's own top nudge below for the fine adjustment. */
.rsd-menu__row { display: flex; align-items: flex-start; gap: .6rem; }
/* flex:1 (this task) — root cause of the 1-column right-side whitespace,
   traced past the panel/grid/track level entirely: every sizing rule
   from .sub-menu (width:100%, prior task) down through the grid track
   (1fr) down through <li> (stretches by default — no justify-items
   override anywhere in this file) down through <a> (.rsd-menu .sub-menu
   a{display:block}, further down, fills <li>) down through .rsd-menu__row
   (display:flex, a block-level box that fills <a>) was already correct.
   The ONE broken link: .rsd-menu__row's two flex children are
   .rsd-menu__icon (flex:none, fixed 18px, correct) and this element —
   which had no flex-grow of its own, so it defaulted to flex:0 1 auto
   and sat at its own intrinsic (label/description) content width,
   leaving whatever was left of .rsd-menu__row's already-full-width box
   empty. Invisible at 3 columns (a ~350-400px track leaves little to
   grow into); the entire visible gap at 1 column (a ~1180px track).
   flex:1 makes this the one child that actually claims the remaining
   space after the icon — min-width:0 (already present) is what lets it
   shrink safely on narrow tracks/viewports, unchanged. No effect on
   mobile: .rsd-menu--stacked's <a> is never given display:block (no
   override exists for it, unlike desktop's .rsd-menu .sub-menu a), so it
   stays content-sized (inline-block, the sitewide .rsd-menu a default)
   there — nothing upstream of this element ever has extra width to hand
   it on the mobile drawer, so flex:1 has nothing to do there. */
.rsd-menu__text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
/* Menu Typography Customizer fix — .rsd-menu__label is what actually
   wraps a menu item's title text at every depth (RSD_Nav_Walker,
   inc/setup.php), not the <a> itself, so .rsd-menu a's own
   --rsd-t-menu-family/-weight/-size (assets/css/main.css) never reached
   the visible text — this element's own declared values always win over
   whatever it would otherwise have inherited. Same three Customizer
   variables, same fallbacks, as .rsd-menu a — not a second typography
   source, just the one that was missing this variable wiring. color,
   display and every other property here are unchanged. */
/* overflow-wrap:anywhere (this task) — safety net only, not the primary
   fix (see .rsd-menu > li > .sub-menu > li below for that). Normal
   multi-word phrases ("Automate CRM and follow-up") still wrap at word
   boundaries first — overflow-wrap only breaks WITHIN a word, and only
   when a single word wouldn't otherwise fit, unlike word-break:break-all
   which breaks at any character regardless of need. Belt-and-braces for
   the rare single long word/label that could still exceed a shrunk
   column even after the real fix below. */
.rsd-menu__label {
  display: block;
  font-family: var(--rsd-t-menu-family, var(--rsd-body));
  font-weight: var(--rsd-t-menu-weight, 500);
  font-size: var(--rsd-t-menu-size, var(--rsd-t-sm));
  color: var(--rsd-submenu-text);
  overflow-wrap: anywhere;
}
.rsd-menu__desc { display: block; margin-top: .15rem; font-size: var(--rsd-t-xs); color: var(--rsd-submenu-desc); overflow-wrap: anywhere; }

/* Proof & Resources column content (this task — inc/mega-menu-settings.php
   + inc/services.php's rsd_render_pillar_proof_block()). Unscoped/universal
   like .rsd-menu__label/.rsd-menu__desc directly above, not inside the
   desktop-only @media block further down: the same swapped-in markup
   renders in both the desktop panel and the mobile drawer (one shared
   'wp_nav_menu' filter, both wp_nav_menu() calls), so it must read
   correctly at every width, not just ≥1024px. Every value below is an
   existing token — no new color, spacing, or type scale. */
.rsd-menu__proof { display: flex; flex-direction: column; gap: .3rem; }
/* .rsd-figure__value (above, existing "big proof number" component) is
   reused as-is via the second class on the element itself — font-weight,
   font-family and tabular-nums all still come from THAT base rule,
   completely unmodified (it is never edited here, so every other real
   usage of .rsd-figure__value on the site is unaffected). This rule only
   overrides font-size/line-height, and only inside the mega-menu's own
   Proof & Resources group — scoped with the .rsd-menu__group--proof
   ancestor (the RIGHT column's own group-heading <li>, a real ancestor of
   this element: RSD_Nav_Walker nests each group's <ul class="sub-menu">
   directly inside its own heading <li>) precisely so this can never reach
   any other .rsd-figure__value elsewhere on the site, exactly like
   .rsd-card--showcase__metric .rsd-figure__value already scopes its own
   "smaller reuse" override elsewhere in this file. No color override —
   plain ink, same as every other menu label, not a bright/decorative
   treatment.
   Mobile-first base below is the smaller ~28px size (this task's own
   26-30px mobile target) — the drawer never re-declares this, so this is
   what the mobile drawer actually shows; the ≥1024px override further
   down this file bumps it to ~36px for the desktop panel only.
   margin-top: 8px (this task) adds breathing room below the "PROOF &
   RESOURCES" group heading, which sits outside .rsd-menu__proof entirely
   (RSD_Nav_Walker renders it as its own .rsd-menu__heading span, a
   sibling of the nested <ul class="sub-menu"> this figure lives inside,
   not a flex-gap sibling of it) — so this is the only place that gap can
   be added without touching the heading markup or any other element.
   Scoped to this one selector, so it never touches font-size/line-height
   (unchanged above) or any other .rsd-menu__proof child's own spacing. */
.rsd-menu__group--proof .rsd-menu__proof-figure.rsd-figure__value { font-size: 1.75rem; line-height: 1.1; padding: 0 .6rem; margin-top: 8px; }
.rsd-menu__group--proof .rsd-menu__proof-headline {
  display: block; padding: 0 .6rem;
  font-family: var(--rsd-t-menu-family, var(--rsd-body));
  /* Existing semibold token (already used by .rsd-menu__explore's own
     label further down this file) — not a new weight value. */
  font-weight: var(--rsd-weight-semibold);
  font-size: 1.2rem; line-height: 1.3;
  color: var(--rsd-submenu-text);
  overflow-wrap: anywhere;
}
/* margin-bottom: 12px (this task) is ADDITIVE on top of the parent
   .rsd-menu__proof's own flex `gap: .3rem` (~4.8px, above) — margin and
   flex-gap are independent box-model properties, so this doesn't replace
   or double that gap, it sits on top of it: ~4.8px (gap) + 12px (this
   margin) = ~16.8px total between the description and the first CTA
   button, versus ~4.8px before. Scoped to this one element only — no
   other .rsd-menu__proof child gets a margin, so spacing between every
   OTHER pair (icon-free now/figure/headline/desc, and between the two
   buttons themselves) is unchanged, still the plain .3rem gap. */
.rsd-menu__proof-desc { display: block; padding: 0 .6rem; margin-bottom: 12px; font-size: var(--rsd-t-xs); color: var(--rsd-submenu-desc); overflow-wrap: anywhere; }
/* Secondary CTA — "Get a Free Proposal" (or the admin's own Secondary CTA
   text/URL, inc/mega-menu-settings.php) — the primary of the column's two
   stacked buttons, reads as a real compact button, not a plain text link
   (inc/services.php's rsd_render_pillar_proof_block(), rsd_link()'s
   $rsd_as_button branch). Reuses the exact same design tokens the
   sitewide .rsd-btn/--solid/--sm button system already uses
   (var(--rsd-button-bg)/var(--rsd-button-text)/var(--rsd-radius)/
   var(--rsd-weight-semibold)/var(--rsd-t-xs), the same compact-scale
   values .rsd-btn--sm's own "Compact size" rule already declares above)
   — restated here rather than applying the .rsd-btn classes directly,
   because .rsd-menu .sub-menu a's own generic rule (further down this
   file) carries an extra "a" tag in its selector and would otherwise be
   MORE specific than .rsd-btn/.rsd-btn--sm's bare single-class selectors,
   silently overriding this button's display/padding/border-radius/hover
   and requiring !important to fight. Restating the same values at a
   selector specific enough to win on its own gives the identical visual
   result without that fight. Deliberately smaller than the header's own
   "Get a proposal" button (.rsd-btn--solid, 44px tap-target floor) — this
   is .rsd-btn--sm's own compact scale, appropriate for a mega-menu
   column, not the full header CTA size.
   No margin-top here — the parent .rsd-menu__proof's own flex `gap: .3rem`
   (above) already gives every child in this column, buttons included, one
   uniform, consistent spacing value; a per-button margin would just stack
   on top of that gap inconsistently. */
.rsd-menu .sub-menu a.rsd-menu__proof-cta {
  display: inline-flex; align-items: center; justify-content: center;
  padding: .45rem .85rem; border-radius: var(--rsd-radius);
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-xs);
  background: var(--rsd-button-bg, var(--rsd-red)); color: var(--rsd-button-text, #fff);
  border: 1px solid transparent;
}
.rsd-menu .sub-menu a.rsd-menu__proof-cta:hover,
.rsd-menu .sub-menu a.rsd-menu__proof-cta:focus-visible {
  background: var(--rsd-button-hover-bg, var(--rsd-red-ink)); color: var(--rsd-button-hover-text, #fff);
}
/* Secondary/outline variant — "Read Our Case Study" (or the admin's own
   Optional secondary resource text/URL). Same base layout as the primary
   button above (both classes are present on the element — the compound
   selector below only needs to win on background/border-color/text-color,
   not redeclare display/padding/font-size), so both buttons share
   identical compact dimensions automatically. Colors reuse the existing
   .rsd-btn--ghost tokens verbatim (var(--rsd-charcoal) border/text,
   var(--rsd-white) hover text) — the sitewide "outline button" pattern,
   not a new one invented for this column. */
.rsd-menu .sub-menu a.rsd-menu__proof-cta.rsd-menu__proof-cta--outline {
  background: transparent; border-color: var(--rsd-charcoal); color: var(--rsd-charcoal);
}
.rsd-menu .sub-menu a.rsd-menu__proof-cta.rsd-menu__proof-cta--outline:hover,
.rsd-menu .sub-menu a.rsd-menu__proof-cta.rsd-menu__proof-cta--outline:focus-visible {
  background: var(--rsd-charcoal); color: var(--rsd-white);
}
/* Advanced Custom HTML (inc/mega-menu-settings.php) — a plain muted text
   baseline for whatever the small allowed tag set (p/br/strong/em/span/a/
   ul/ol/li) renders as; any real <a> inside it already picks up the
   existing .rsd-menu .sub-menu a link treatment automatically, being a
   real <a> nested inside .sub-menu — no separate link styling needed here. */
.rsd-menu__proof-custom { padding: 0 .6rem; font-size: var(--rsd-t-xs); color: var(--rsd-submenu-desc); }
.rsd-menu__proof-custom p { margin: 0 0 .3rem; }
.rsd-menu__proof-custom p:last-child { margin-bottom: 0; }

/* Icon — one small, consistent, hand-drawn inline SVG (no icon font or
   library exists in this project; this is the lightweight fallback),
   applied to every real link below the top level via RSD_Nav_Walker.
   Rendered on both desktop and mobile — only the hover-rectangle treatment
   below is desktop-only. Fixed 18px box regardless of an individual SVG's
   own viewBox, so every icon (the shared default arrow, or any per-service
   icon from inc/services.php's rsd_service_icons()) renders at the same
   size — sizing lives here, once, not on each icon's own markup. The
   margin-top nudge optically aligns the icon's visual centre with the
   label's cap-height, since align-items on .rsd-menu__row is flex-start
   (needed so the icon sits at the top of a two-line label+description
   block, not vertically centred across both lines). */
.rsd-menu__icon {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; width: 18px; height: 18px; margin-top: .1rem;
  color: var(--rsd-submenu-icon);
}
.rsd-menu__icon svg { display: block; width: 18px; height: 18px; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-menu__icon { transition: color .14s ease; }
}

/* ---- desktop mega-menu (≥1024px only — the same width the pill nav
   itself appears at) -----------------------------------------------------
   One panel shape, two layouts, chosen purely by structure (not by which
   item it is): a flat list of links (Services, Company) becomes a compact
   2-column grid; a panel whose children are themselves group headings
   with their own children (Resources) becomes a 3-column grouped panel.
   RSD_Nav_Walker (inc/setup.php) is what turns a childless-URL parent
   into the plain-text .rsd-menu__heading these :has() selectors key off.
   Scoping the whole panel mechanism to this breakpoint — rather than
   fighting :has()'s specificity with mobile overrides — is what keeps it
   from ever reaching the drawer's .rsd-menu--stacked rendering, since the
   drawer itself only ever shows below 1024px. */
/* Explicit layer order, declared once, up front: rsd-mega-auto (the
   existing structural rules below) is listed first = lowest priority;
   rsd-mega-override (the new global/per-item column system) is listed
   second = wins, regardless of either side's own selector specificity.
   Named here rather than relying only on first-use order so the priority
   is obvious on its own, independent of where each @layer block happens
   to sit further down this file. */
@layer rsd-mega-auto, rsd-mega-override;
@media (min-width: 1024px) {
  /* Zero positional gap between the trigger and the panel — on purpose.
     CSS applies pointer-events:none the instant :hover/:focus-within is
     lost, with no transition on that property, so ANY real gap (even a
     couple of px, even with a bridge pseudo-element sized to cover it)
     is a hard lock-out risk: one discrete mousemove event landing in the
     dead pixel row kills pointer-events on the panel before the pointer
     ever reaches it, and a non-interactive element can't be re-entered
     except by going back through the trigger. Removing the gap removes
     the dead zone entirely — no geometry to get wrong, no JS needed. The
     lost external gap is replaced by extra padding-top, so the visible
     panel still reads as "floating" with breathing room, it just has no
     literal unhoverable space between it and the trigger. */
  /* Scoped to ">li>.sub-menu" — the outer panel only — on purpose. A plain
     ".rsd-menu .sub-menu" descendant selector here would also match the
     nested (level-2) link list under a group heading, setting its
     opacity/visibility/pointer-events directly (not inherited — a rule
     that matches an element always wins over inheriting from a parent),
     and nothing un-hides it afterward since the reveal rule below is also
     ">li:hover>.sub-menu" and can't reach two levels deep. That was
     exactly why a grouped panel's real links (Services' pillars; this
     would equally have broken Resources, just never live-tested) never
     appeared: correct markup, permanently hidden third level. Leaving
     level 2 untouched here is what lets it inherit visibility/pointer-
     events from level 1's current state, per the comment further down. */
  /* Horizontal clipping fix (this task) — root cause, proven structurally:
     left:50%/transform:translateX(-50%) centers the panel on its
     POSITION:ABSOLUTE CONTAINING BLOCK, which used to be .rsd-menu > li
     itself (position:relative, removed above). A top-level trigger is
     wherever it naturally falls in the nav's left-to-right flex flow —
     not viewport-centered, and not even reliably centered within the
     pill — so a wide (up to var(--rsd-shell), 1180px) grouped panel
     centered on an off-center trigger can have its far edge pushed past
     the viewport, worse on a WIDE/maximized window specifically: .rsd-pill
     itself keeps widening (720/960/1140/1290px breakpoints, this file,
     above) as the viewport widens, so a later nav item's absolute X
     position keeps shifting further from viewport-center too, while the
     panel's own width also keeps growing to its 1180px cap — both effects
     compound in the same direction. A narrower window looked "better"
     only because both of those were smaller then, not because anything
     was actually correct.

     Fix: removing .rsd-menu > li's position:relative (above) means this
     position:absolute panel's containing block resolution now continues
     past li and .rsd-pill__nav (neither positioned) to .rsd-pill itself —
     already position:fixed, already perfectly viewport-centered via this
     exact left:50%/translateX(-50%) pattern on itself, and already capped
     at the same 720-1290px breakpoints every other viewport-safety rule
     in this file uses. Centering THIS panel on .rsd-pill's own box instead
     of on whichever trigger happens to be hovered means its edges are now
     bounded by a container that is provably always safely inside the
     viewport, at every width, for every trigger — not just the ones that
     happened to sit near center. top:100% is unaffected: .rsd-pill's own
     rendered height is the same single nav row .rsd-menu > li's height
     already was (brand/nav/cta all sit in that one row), so the panel
     still opens flush under the nav, unchanged vertically. One accepted,
     disclosed visual trade-off: every top-level item's panel now opens
     centered under the whole pill rather than precisely under its own
     trigger — necessary since nothing about an individual trigger's
     position is safe to center a wide panel on, and no panel width/column
     count/color/radius/shadow changed to get here. */
  .rsd-menu > li > .sub-menu {
    position: absolute; top: 100%; left: 50%;
    transform: translateX(-50%) translateY(-6px);
    list-style: none; margin: 0; padding: 1.5rem 1.5rem 1.25rem;
    background: var(--rsd-submenu-bg); border: 1px solid var(--rsd-submenu-border);
    border-radius: 14px; box-shadow: var(--rsd-shadow-medium); /* was the literal 0 12px 32px rgba(26,26,28,.10) — same value, now named. radius unchanged, not a pill. */
    /* width:100% (not max-content, this task) — see the alignment-fix
       comment on the grouped-panel rule below for the full root-cause
       explanation; the same fix applies here since the flat panel rule
       further down never overrides width/max-width and inherits both
       from this base rule. */
    width: 100%; max-width: min(620px, calc(100vw - 3rem));
    opacity: 0; visibility: hidden; pointer-events: none;
  }
  /* 3-column right-edge clipping fix (this task) — root cause, proven by
     calculation, not guessed: CSS Grid's "Implied Minimum Size of Grid
     Items" (spec) gives every grid item a default min-width:auto, which
     resolves to the LARGER of any explicit minimum (180px/220px here) or
     the item's OWN min-content size — computed from its full subtree
     (heading + nested link list, or the label/description text for a
     flat panel), not capped by minmax()'s stated floor. .rsd-menu__text
     already has flex:1 + min-width:0 (prior task), which lets it shrink
     WITHIN its own flex row — but that never reaches the GRID's own
     min-content calculation for the <li> itself, several levels up,
     which still defaults to min-width:auto. With enough label/description
     text, an <li>'s own implied minimum can exceed its 180px/220px floor;
     with 3 such tracks compounding, the grid's total required width can
     exceed the panel's actual available inner width, pushing the last
     (rightmost) track past the panel's right edge — read as "clipped"
     even though nothing is literally overflow:hidden anywhere.

     Calculated whether minmax(180px,1fr) itself is the problem, per this
     task's own instruction not to guess: at the tightest realistic
     desktop case (1024px viewport — .rsd-pill's own max-width:1140px
     tier), .rsd-pill's actual width is min(100% - 40px, 1140px) = 984px;
     the panel's width:100% of that, capped by max-width:min(1180px,
     100vw-48px=976px), resolves to 976px. Minus padding (1.5rem×2=48px)
     and this tier's own 3-column gap (1.5rem×2=48px, the 1024-1279px
     rule further down) leaves 880px of actual grid content width — 880 /
     3 = ~293px per column, comfortably above the 180px floor. The floor
     itself was never mathematically incompatible with the available
     width; the grid simply wasn't being allowed to use that available
     width, because of the implied-minimum issue above. Fixing that
     (not the floor value) is the correct, minimal, proven fix. */
  .rsd-menu > li > .sub-menu > li {
    min-width: 0;
  }
  /* Smooth open/close (this task): duration bumped from .16s to .22s
     (inside the 200-300ms range asked for) and the plain "ease" swapped
     for cubic-bezier(.2,.8,.2,1) — not a new curve, the exact same one
     .rsd-pill (above) already uses for its own scroll-driven transitions,
     reused here instead of inventing a second "polished" easing token.
     Still only opacity/transform/visibility — no height, no display
     toggle, so there is nothing here for prefers-reduced-motion to need
     to unwind beyond what the block below already does (this rule is
     itself inside that same no-preference query, unchanged). */
  @media (prefers-reduced-motion: no-preference) {
    .rsd-menu > li > .sub-menu {
      transition: opacity .22s cubic-bezier(.2,.8,.2,1), transform .22s cubic-bezier(.2,.8,.2,1), visibility 0s linear .22s;
    }
  }
  .rsd-menu > li:hover > .sub-menu,
  .rsd-menu > li:focus-within > .sub-menu {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translateX(-50%) translateY(0);
    transition-delay: 0s;
  }

  /* Mega menu: the header expands (reference: Capture.JPG). With
     assets/js/main.js running (.rsd-mega-ready on .rsd-pill), the open
     panel no longer floats as its own card: the header's own surface grows
     down by the active panel's measured height (--rsd-mega-h) and the
     panel is revealed inside it.
     Closed, the pill paints itself exactly as it always has and ::before
     is an empty, unpainted box over it. From the instant a menu opens
     until it has fully closed again (.is-mega-open / .is-mega-closing, set
     by main.js), the pill's own glass background, border and shadow move
     onto ::before — same values, same box — and ::before's bottom edge
     then grows and shrinks. The radius is the bar's own half-height
     (--rsd-mega-r, measured), which is exactly what the pill radius
     resolves to on the bar, so the top keeps its current curve and the
     bottom corners match it. ::after is the lower part of the same
     surface: the Mega Menu background colour under a hairline divider
     where the bar's bottom edge was. The pill is position:fixed, so
     nothing here can move the page. Which panel is open is JS state
     (li.is-mega-active), not :hover/:focus-within, so the whole expanded
     surface is one hover region and switching items keeps the surface
     open. Without JS none of this applies and the panels behave as before. */
  .rsd-mega-ready::before {
    content: ""; position: absolute; inset: -1px; z-index: -1;
  }
  .rsd-mega-ready:is(.is-mega-open, .is-mega-closing) {
    background: transparent; backdrop-filter: none; border-color: transparent; box-shadow: none;
  }
  .rsd-mega-ready:is(.is-mega-open, .is-mega-closing)::before {
    background: color-mix(in srgb, var(--rsd-header-bg, var(--rsd-white)) calc(92% + 6% * var(--rsd-st)), transparent);
    backdrop-filter: blur(calc(14px + 4px * var(--rsd-st)));
    border: 1px solid var(--rsd-line);
    border-radius: var(--rsd-mega-r, 2rem);
    box-shadow: 0 calc(8px + 4px * var(--rsd-st)) calc(30px + 10px * var(--rsd-st)) rgba(26, 26, 28, calc(0.06 + 0.06 * var(--rsd-st)));
  }
  .rsd-mega-ready.is-mega-open::before { bottom: calc(-1 * var(--rsd-mega-h, 0px)); }
  .rsd-mega-ready::after {
    content: ""; position: absolute; z-index: -1; left: 0; right: 0; top: 100%; bottom: 0;
    background: var(--rsd-submenu-bg); border-top: 1px solid var(--rsd-line);
    border-radius: 0 0 calc(var(--rsd-mega-r, 2rem) - 1px) calc(var(--rsd-mega-r, 2rem) - 1px);
    opacity: 0;
  }
  .rsd-mega-ready.is-mega-open::after { bottom: calc(1px - var(--rsd-mega-h, 0px)); opacity: 1; }
  /* Panel: the existing panel, minus its own card (background, border
     colour, shadow — the surface now provides them; border width, padding,
     columns and width are untouched). Revealed top-down with clip-path on
     the same duration and curve as the surface, so its content never shows
     past the surface's growing bottom edge — opening, closing, or when one
     panel replaces another of a different height. */
  .rsd-mega-ready .rsd-menu > li > .sub-menu {
    background: transparent; border-color: transparent; box-shadow: none;
    clip-path: inset(0 0 100% 0);
  }
  .rsd-mega-ready .rsd-menu > li:not(.is-mega-active) > .sub-menu {
    opacity: 0; visibility: hidden; pointer-events: none;
    transform: translateX(-50%) translateY(-6px);
  }
  .rsd-mega-ready .rsd-menu > li.is-mega-active > .sub-menu {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translateX(-50%) translateY(0);
    clip-path: inset(0 0 0 0);
  }
  @media (prefers-reduced-motion: no-preference) {
    /* The paint hand-over between the pill and ::before is instant (no
       background/border/shadow transitions in these states); only the
       surface's bottom edge animates. */
    .rsd-mega-ready:is(.is-mega-open, .is-mega-closing) {
      transition: top .3s var(--rsd-ease-out), transform .3s var(--rsd-ease-out), padding .3s var(--rsd-ease-out);
    }
    .rsd-mega-ready::before { transition: bottom var(--rsd-motion-base) var(--rsd-ease-out); }
    .rsd-mega-ready::after {
      transition: bottom var(--rsd-motion-base) var(--rsd-ease-out), opacity var(--rsd-motion-fast) ease;
    }
    .rsd-mega-ready.is-mega-open::after { transition-delay: 0s; }
    .rsd-mega-ready .rsd-menu > li > .sub-menu {
      transition: opacity var(--rsd-motion-base) var(--rsd-ease-out), transform var(--rsd-motion-base) var(--rsd-ease-out),
                  clip-path var(--rsd-motion-base) var(--rsd-ease-out), visibility 0s linear var(--rsd-motion-base);
    }
    .rsd-mega-ready .rsd-menu > li.is-mega-active > .sub-menu { transition-delay: 0s; }
  }
  /* The open item's trigger keeps its hover look while the pointer is
     elsewhere in the expanded header (the existing hover/focus state). */
  .rsd-mega-ready .rsd-menu > li.is-mega-active > a { background: var(--rsd-submenu-hover-bg); }
  .rsd-mega-ready .rsd-menu > li.is-mega-active > a[aria-haspopup="true"]::after { transform: rotate(225deg); margin-top: 3px; }
  /* Chevron follows the open state, not bare hover/focus, in this mode. */
  .rsd-mega-ready .rsd-menu > li:not(.is-mega-active):hover > a[aria-haspopup="true"]::after,
  .rsd-mega-ready .rsd-menu > li:not(.is-mega-active):focus-within > a[aria-haspopup="true"]::after { transform: rotate(45deg); margin-top: -3px; }

  /* Content width inside the expanded header. The panel caps above
     (620px flat, 760/920px Two/Three, the shell for Auto) were sized for
     a floating card; inside the full-width surface they left empty bands
     either side. Here every panel spans the surface minus an
     --rsd-gap-sm gutter each side, capped so its content box (inside the
     unchanged 1.5rem padding + 1px border) is at most the page's own
     --rsd-shell — at 1440px the first column lines up exactly with the
     page content below. Columns keep their existing templates and simply
     get wider (3 → thirds, 4 → quarters, the proof card stays one column
     of them). Single keeps its 480px list: one column stretched to
     ~1180px would only make every row a very long line. */
  .rsd-mega-ready {
    --rsd-mega-content: min(calc(var(--rsd-shell) + 3rem + 2px), calc(100% - 2 * var(--rsd-gap-sm)));
  }
  .rsd-mega-ready .rsd-menu > li > .sub-menu:not(:has(> li.menu-item-has-children)),
  html:not([data-rsd-mega-layout="single"]) .rsd-mega-ready .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
    max-width: var(--rsd-mega-content);
  }
  /* Flat link lists (Company, …) have no column structure of their own —
     the fixed 2 columns just wrapped the list. In the wider panel they
     flow into as many ~15rem columns as fit (4 at 1440px, 3 at 1024px),
     left-aligned on the same grid, instead of two ~580px-wide columns.
     Kept in the auto layer, so a per-item rsd-mega-N class still wins. */
  @layer rsd-mega-auto {
    .rsd-mega-ready .rsd-menu > li > .sub-menu:not(:has(> li.menu-item-has-children)) {
      grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    }
  }

  /* No hover-gap bridge pseudo-element here anymore (this task). Two prior
     attempts lived at this spot and then at .rsd-pill__nav .rsd-menu > li >
     a[aria-haspopup="true"]::before — both patched the gap with a
     separate, conditionally-interactive element. The current fix is
     .rsd-pill__nav .rsd-menu > li.menu-item-has-children's own
     padding-bottom/margin-bottom (that selector's own comment, above in
     this file) — <li>'s OWN rendered box now natively covers the gap, so
     there is nothing separate here to gate, bridge, or fail. Panel
     transform checked: the closed state is translateY(-6px), which moves
     the panel toward the trigger, not away — the panel's own opening
     animation doesn't widen the gap this fix covers. */

  /* Mega Menu Layout (Customizer: RedSprout Colors → Header/Navigation →
     Mega Menu → Mega Menu Layout, inc/customizer.php) — two cascade
     layers, declared once here, so the new global/per-item override
     system can beat these existing structural rules without rewriting
     them, fighting their specificity with duplicated selectors, or
     resorting to !important. Layer priority in CSS is resolved BEFORE
     specificity: any rule in a later-declared layer always wins over any
     rule in an earlier one, regardless of how specific either selector
     is — the one guarantee plain selector specificity can't give here,
     since the most specific existing rule below (the 4-group :nth-child()
     variant) would otherwise require an increasingly fragile, ever-
     growing specificity arms race to reliably override as this system
     evolves. rsd-mega-auto (declared first = lowest priority) holds the
     existing rules completely unmodified; rsd-mega-override (declared
     second = wins) holds the new global-default and per-item-class rules
     below. Every OTHER rule in this file (panel positioning, opacity/
     hover reveal, colors, spacing, hover states) stays outside any layer
     on purpose — unlayered styles always outrank layered ones by spec,
     and none of those properties are contested here anyway, so leaving
     them unlayered is both correct and the smaller diff. */
  @layer rsd-mega-auto {
    /* Flat panel (Services, Company): direct child links only — compact
       2-column grid, generous but controlled, not an oversized card. */
    .rsd-menu > li > .sub-menu:not(:has(> li.menu-item-has-children)) {
      display: grid; grid-template-columns: repeat(2, minmax(220px, 1fr)); gap: .1rem 1.5rem;
    }
    /* Grouped panel (Resources, and Services since it became dynamic):
       children are group headings with their own lists. Width ceiling
       reuses the sitewide shell token rather than a one-off number, and
       never forces the panel wider than the content actually needs. Base
       rule here is the tablet-and-up default (2 columns, 1024-1279px);
       1280px+ ("true" desktop, the same tier this design already treats as
       the wide breakpoint — see .rsd-pill's own min-width:1280px rule
       earlier in this file) is where column count follows however many
       group-heading children actually exist, capped at 4 — see
       rsd_service_pillars_with_leftovers() in inc/services.php for where
       that count comes from for Services. A 5th+ group wraps to a second
       row inside the same 4-column template rather than forcing a 5th
       column. Below 1024px this selector doesn't apply at all — the mobile
       accordion (.rsd-menu--stacked) takes over instead. */
    /* Column-alignment fix (this task) — root cause, proven structurally:
       width:max-content sizes the panel to its OWN CONTENT's intrinsic
       width, not to max-width — max-width only ever acted as a ceiling,
       never a floor. A 3-column panel's content naturally runs close to
       that ceiling (~1180px), so it looked "right"; the SAME panel forced
       to 2 or 1 columns has far less intrinsic content width (2 or 1
       tracks instead of 3), so it rendered visibly narrower — with the
       SAME 1.5rem padding, above, now looking proportionally larger on
       the narrower states. That's the entire reported inconsistency: one
       property (width), not padding, not gap, not the grid tracks
       themselves (minmax(180px,1fr) already distributes whatever width
       the container actually has correctly). width:100% (of the
       containing block — .rsd-pill, per the earlier positioning fix,
       already capped at up to 1290px, always ≥ this max-width) means
       max-width is now always the binding constraint: the panel renders
       at its full intended width (min(var(--rsd-shell), viewport-safe
       value)) EVERY time, regardless of whether Auto, Global, or a
       per-item rsd-mega-N class puts 1, 2, 3, or 4 columns inside it. Left
       untouched on purpose: padding (already a single, unconditional
       1.5rem/1.5rem/1.25rem contract — it only ever LOOKED inconsistent
       because of this width bug), gap (already tier-scoped, not
       column-count-scoped, so it was never actually inconsistent), and
       the minmax(180px,1fr) column tracks (already correct once the
       container width is fixed — no need for minmax(0,1fr) here). */
    .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
      display: grid; grid-template-columns: repeat(2, minmax(180px, 1fr)); gap: 0 1.5rem;
      width: 100%; max-width: min(var(--rsd-shell), calc(100vw - 3rem));
    }
    @media (min-width: 1280px) {
      .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
        grid-template-columns: repeat(3, minmax(180px, 1fr)); gap: 0 2rem;
      }
      .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children):not(:has(> li.menu-item-has-children:nth-child(2))) {
        grid-template-columns: minmax(180px, 1fr);
      }
      .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children:nth-child(2)):not(:has(> li.menu-item-has-children:nth-child(3))) {
        grid-template-columns: repeat(2, minmax(180px, 1fr));
      }
      .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children:nth-child(4)) {
        grid-template-columns: repeat(4, minmax(180px, 1fr));
      }
    }
  }

  @layer rsd-mega-override {
    /* Per-item override — native WordPress "CSS Classes" field (Appearance
       → Menus → edit item → CSS Classes), same mechanism already used for
       rsd-icon-* (inc/setup.php) and rsd-menu__group--boxed above. Applied
       to the TOP-LEVEL <li>. A separate, numeric, independent mechanism
       from the named single/two/three system below (unlayered, further
       down this file) — untouched by this task, which only asked for the
       global Customizer setting's choices to change. .rsd-menu is
       deliberately doubled (.rsd-menu.rsd-menu) — a plain, well-known
       specificity nudge, not a hack that changes what's matched (it's the
       same single element, just counted twice) — kept from an earlier
       pass, when it needed to beat a global override rule that lived in
       this same layer; that rule is gone now (retired below, superseded
       by the unlayered single/two/three system), so the doubling is
       harmless-but-no-longer-load-bearing here. Left in place rather than
       stripped, since removing it isn't necessary and re-verifying its
       specificity math against nothing is pure churn. */
    .rsd-menu.rsd-menu > li.rsd-mega-1 > .sub-menu { grid-template-columns: minmax(180px, 1fr); }
    .rsd-menu.rsd-menu > li.rsd-mega-2 > .sub-menu { grid-template-columns: repeat(2, minmax(180px, 1fr)); }
    .rsd-menu.rsd-menu > li.rsd-mega-3 > .sub-menu { grid-template-columns: repeat(3, minmax(180px, 1fr)); }
  }

  /* Retired (this task): the old global override rule that used to live
     here — html[data-rsd-mega-layout] .rsd-menu > li > .sub-menu {
     grid-template-columns: repeat(var(--rsd-mega-columns), minmax(180px,
     1fr)) } — is superseded by the named single/two/three system below.
     That old rule only ever changed track COUNT; the new named layouts
     also change grouping structure (single/two flatten pillar headings
     entirely) and per-layout panel width, which a bare grid-template-
     columns swap can't express. --rsd-mega-columns is no longer emitted
     by inc/customizer.php's wp_head callback (removed alongside this). */

  /* Named Mega Menu layouts — Single / Two / Three (this task). Gated on
     html[data-rsd-mega-layout="single|two|three"] (inc/customizer.php's
     language_attributes filter — "auto" emits no attribute, so these
     never match and rsd-mega-auto above stays fully authoritative,
     exactly as before). Unlayered on purpose: unlayered rules always
     outrank anything in @layer rsd-mega-auto regardless of specificity,
     which is what lets these apply uniformly without needing to fight
     the :has()/:nth-child() selectors' own specificity. Scoped to
     :has(> li.menu-item-has-children) throughout — flat panels (Company,
     or any future ungrouped item) are untouched by this system entirely,
     same as the old numeric override was.

     Single and Two both start from the same structural move: the real
     content this theme already generates is pillar-grouped (a heading
     <li> containing its own nested <ul class="sub-menu"> of real links —
     RSD_Nav_Walker + inc/services.php's synthetic Services injection, or
     an admin-managed group like Resources — neither touched by this
     task). Single/Two intentionally show a flat list of the real links
     with no group headings (matching the requested reference layouts);
     Three keeps the existing grouped/headed shape. Rather than duplicating
     PHP to emit two different DOM shapes for the same content, this uses
     display:contents to dissolve the pillar <li> wrapper and its own
     nested <ul> out of the box tree — their CHILDREN (the real, unchanged
     <li><a>...</a></li> items) become the grid/column-flow's direct
     participants instead. display:contents keeps every child, including
     the real <a> links, fully in the accessibility tree and fully
     interactive — only the wrapper's own box (which had no visible
     styling of its own to begin with beyond spacing) stops rendering.
     The now-orphaned .rsd-menu__heading (Acquisition/Technology/
     Intelligence) is explicitly hidden for these two layouts only —
     Three still shows it normally, unaffected. */
  html[data-rsd-mega-layout="single"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children,
  html[data-rsd-mega-layout="single"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children > .sub-menu,
  html[data-rsd-mega-layout="two"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children,
  html[data-rsd-mega-layout="two"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children > .sub-menu {
    display: contents;
  }
  html[data-rsd-mega-layout="single"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) .rsd-menu__heading,
  html[data-rsd-mega-layout="two"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) .rsd-menu__heading {
    display: none;
  }

  /* Single — one flexible column, every real link stacked, matching the
     first reference's flat icon+title+description list. Width: this
     task's own suggested 420-500px range (480px), responsively capped
     the same way every other panel width in this file already is —
     min(intended px, viewport-safe value), never a bare fixed width. */
  html[data-rsd-mega-layout="single"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
    grid-template-columns: minmax(0, 1fr);
    max-width: min(480px, calc(100vw - 3rem));
  }

  /* Two — CSS multi-column, not grid. Grid was deliberately not used
     here: a grid needs grid-template-rows declared up front to know when
     to wrap from column 1 to column 2, but the real item count (6 today
     across 3 pillars, more as inc/services.php's pillar lists grow) has
     no fixed row count this CSS could hardcode without silently going
     stale the next time a service is added. column-count:2 auto-balances
     any number of real items into exactly 2 equal-width columns, filling
     top-to-bottom then wrapping, with zero knowledge of how many items
     exist — future services inherit correct 2-column placement with no
     CSS change needed. break-inside:avoid keeps one link's icon+title+
     description from being split across the column break. Width: this
     task's own suggested 680-800px range (760px), same responsive cap
     pattern as Single above. */
  html[data-rsd-mega-layout="two"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
    display: block;
    column-count: 2;
    column-gap: 1.5rem;
    max-width: min(760px, calc(100vw - 3rem));
  }
  html[data-rsd-mega-layout="two"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li {
    break-inside: avoid;
  }

  /* Three — the existing grouped/headed shape, structurally untouched
     (no display:contents here; .rsd-menu__heading stays visible). Only
     two values change from what rsd-mega-auto's own 1280px+ 3-group rule
     already sets: minmax(0,1fr) instead of minmax(180px,1fr) — this
     task's own explicit target contract for the three explicit layouts —
     and an explicit width (this task's own suggested 850-950px, 920px)
     replacing the legacy var(--rsd-shell) (1180px) that Auto still uses
     unchanged. Since Three is layer-unlayered and Auto's own rule lives
     inside @layer rsd-mega-auto, this wins regardless of viewport tier —
     one rule covers both the 1024-1279px and 1280px+ cases Auto needs
     two separate rules for. */
  html[data-rsd-mega-layout="three"] .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    max-width: min(920px, calc(100vw - 3rem));
  }

  /* Nested (group) link list — just a plain static column, positioning-wise.
     Deliberately NOT setting opacity/visibility/pointer-events here: those
     must inherit from the outer panel's own current open/closed state.
     An earlier version forced pointer-events:auto (and visibility:visible)
     unconditionally, which — because a descendant CAN override an
     ancestor's pointer-events:none/visibility:hidden — left every real
     link in this nested list permanently interactive, invisible but
     hoverable, everywhere the panel's laid-out footprint existed, whether
     the panel was actually open or not. That was the exact cause of the
     mega-menu appearing to open from empty space. */
  .rsd-menu .sub-menu .sub-menu {
    position: static; display: block; list-style: none;
    background: none; border: 0; box-shadow: none; padding: 0; margin: 0;
    transform: none; width: auto; max-width: none;
  }
  /* Right-side featured group — Trust & Policies ONLY. Previously
     ":last-child" of any grouped panel, which was wrong: once the Services
     panel became dynamic and grouped too, its last column ("Intelligence")
     matched the same rule and got boxed for no reason. Scoped to an
     explicit class instead — add "rsd-menu__group--boxed" to the Trust &
     Policies item itself via Appearance → Menus → (edit item) → CSS
     Classes (a native WordPress field). Nothing else should carry this
     class; individual links stay clean/lightweight everywhere else. */
  .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children.rsd-menu__group--boxed {
    background: var(--rsd-paper); border: 1px solid var(--rsd-submenu-border);
    border-radius: 10px; padding: .5rem .75rem .75rem;
  }
  /* Contextual "proof & resources" column (this task) — each pillar's own
     top-level flyout's third (rightmost) column (inc/services.php's
     rsd_inject_dynamic_services_into_menu(), part 2) — text-only Case
     Study/Tutorial/CTA links, carrying this class on its own group
     heading. Same visually-distinct-but-subtle box treatment as
     rsd-menu__group--boxed directly above, same tokens reused
     (var(--rsd-paper)/var(--rsd-submenu-border)/10px radius) — a separate
     class rather than reusing that one directly, since its own comment
     scopes it to Trust & Policies only. */
  .rsd-menu > li > .sub-menu:has(> li.menu-item-has-children) > li.menu-item-has-children.rsd-menu__group--proof {
    background: var(--rsd-paper); border: 1px solid var(--rsd-submenu-border);
    border-radius: 10px; padding: .5rem .75rem .75rem;
  }
  /* Proof Number, desktop panel only (this task) — the mobile-first ~28px
     base is declared once, unscoped, near .rsd-menu__proof-figure's own
     rule further up this file (so the drawer keeps using it unchanged);
     this ≥1024px-only override is the ONLY place the desktop size lives,
     matching this task's own 32-38px target. Still the same
     .rsd-menu__group--proof-scoped selector, still never touching the
     bare .rsd-figure__value component other pages use. */
  .rsd-menu__group--proof .rsd-menu__proof-figure.rsd-figure__value {
    font-size: 2.25rem;
  }
  /* "Explore {pillar} →" trailing link (this task) — the last <li> in a
     pillar's own LEFT group and in a related pillar's RIGHT group
     (inc/services.php, rsd-menu__explore class). A plain top border in
     the existing submenu-border token separates it from the real service
     links above it; no new color, no new spacing scale, link itself keeps
     every existing .rsd-menu .sub-menu a rule (padding, hover, radius)
     unchanged. */
  .rsd-menu > li > .sub-menu li.rsd-menu__explore {
    margin-top: .35rem; padding-top: .35rem;
    border-top: 1px solid var(--rsd-submenu-border);
  }
  .rsd-menu__explore .rsd-menu__label { font-weight: var(--rsd-weight-semibold); }

  /* Icon box (this task) — desktop-only override of the shared, mobile-
     inclusive base .rsd-menu__icon rule (above): the base rule stays
     untouched at a plain 18px glyph with no border, so mobile (which
     never re-declares this) is completely unaffected — only this
     @media(min-width:1024px)-scoped rule grows the box to a "small
     refined bordered box" (this task's own 32-38px range, 34px) around
     the still-18px SVG (unchanged, .rsd-menu__icon svg's own rule),
     centered via the base rule's already-existing align-items/
     justify-content:center. border reuses the existing Mega Menu
     Customizer border token (--rsd-submenu-border) and border-radius
     reuses the sitewide --rsd-radius token — no new color or spacing
     value introduced. Applies to every layout (Single/Two/Three/Auto/
     flat) uniformly, matching "all icon boxes must align vertically"
     as one shared treatment, not a per-layout variant. */
  .rsd-menu__icon {
    width: 34px; height: 34px;
    border: 1px solid var(--rsd-submenu-border);
    border-radius: var(--rsd-radius);
  }

  /* Hover/focus — a soft red-tinted rounded rectangle, not an underline.
     Same treatment for every link in every panel, including inside the
     tinted Trust & Policies box. Duration bumped from .13s to .2s (this
     task's 180-220ms range) and transform added (this task's "optional
     1px movement") — background-color and transform transition together. */
  .rsd-menu .sub-menu a {
    display: block; padding: .4rem .6rem; border-radius: 9px;
  }
  @media (prefers-reduced-motion: no-preference) {
    .rsd-menu .sub-menu a { transition: background-color .2s ease, transform .2s ease; }
  }
  .rsd-menu .sub-menu a:hover,
  .rsd-menu .sub-menu a:focus-visible {
    background: var(--rsd-submenu-hover-bg);
    transform: translateY(-1px);
  }
  .rsd-menu .sub-menu a:hover .rsd-menu__label,
  .rsd-menu .sub-menu a:focus-visible .rsd-menu__label { color: var(--rsd-submenu-hover-text); }
  /* Icon + icon-box border deliberately do NOT change on hover/focus
     (this task) — removed the .rsd-menu .sub-menu a:hover/:focus-visible
     .rsd-menu__icon { color; border-color: var(--rsd-submenu-hover-icon) }
     rule that used to sit here, along with .rsd-menu__icon's own now-
     purposeless transition:color/border-color entry (above) — nothing
     left to animate once neither property ever changes. .rsd-menu__icon's
     base rule (this file, "Icon box" comment) keeps setting its normal
     color (var(--rsd-submenu-icon)) and border (var(--rsd-submenu-border))
     unconditionally, so both stay exactly as-is in every state, including
     hover/focus — label color and background still change exactly as
     before; only the icon and its box border were detached from the
     hover-icon token. */
}

.rsd-btn--block { display: block; text-align: center; margin-top: 1.25rem; }
.rsd-pill .rsd-btn--solid, .rsd-pill .rsd-btn--ghost { border-radius: var(--rsd-radius-pill); }

/* Mobile-only cluster: call icon + hamburger, grouped together so the two
   sit at a fixed small gap from each other regardless of how much space
   .rsd-pill's own space-between gives the row — the call icon otherwise
   would land mid-pill instead of hugging the hamburger. Hidden ≥1024px,
   same breakpoint .rsd-pill__nav/.rsd-pill__cta swap in at. */
.rsd-pill__mobile { display: flex; align-items: center; gap: .5rem; }
@media (min-width: 1024px) { .rsd-pill__mobile { display: none; } }

/* Icon only — no button chrome, no visible number. 44px hit area via
   padding around the fixed 18px SVG so the tap target still clears D-39-
   style accessibility minimums without looking like a filled button next
   to the circular hamburger. */
.rsd-call {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;
  color: var(--rsd-charcoal); text-decoration: none;
}
.rsd-call svg { display: block; width: 18px; height: 18px; }
@media (prefers-reduced-motion: no-preference) { .rsd-call { transition: color .16s ease; } }
.rsd-call:hover, .rsd-call:focus-visible { color: var(--rsd-red); }

/* hamburger — plain lines only, no circle/background/border. 44px hit area
   (matches .rsd-call's own tap-target treatment) even though the visible
   mark (three 22px lines) is smaller than that box. */
.rsd-hamburger {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  width: 44px; height: 44px; flex: none; padding: 0; cursor: pointer;
  background: none; border: 0;
}
.rsd-hamburger span[aria-hidden] { display: block; width: 22px; height: 2px; background: var(--rsd-charcoal); }
@media (min-width: 1024px) { .rsd-hamburger { display: none; } }

/* left-side drawer — anchored to the left edge (right/left auto swapped vs.
   a right drawer), off-screen at translateX(-100%) when closed. 320ms,
   cubic-bezier(0.22, 1, 0.36, 1) is the same curve the link-underline
   transition uses further down this file — one motion signature, reused. */
.rsd-drawer {
  position: fixed; inset: 0 auto 0 0; width: min(100%, 420px); height: 100dvh;
  background: var(--rsd-white); z-index: 70; padding: 1.25rem;
  transform: translateX(-100%);
  overflow-y: auto; overscroll-behavior: contain;
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-drawer { transition: transform .32s cubic-bezier(0.22, 1, 0.36, 1); }
}
.rsd-drawer.is-open { transform: translateX(0); }
.rsd-drawer__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem; }
/* Plain X, no circle/background/border — same treatment as .rsd-hamburger.
   44px hit area though the visible mark (two 16px lines) is smaller. */
.rsd-drawer__close {
  position: relative; width: 44px; height: 44px; flex: none; padding: 0; cursor: pointer;
  background: none; border: 0;
}
.rsd-drawer__close span[aria-hidden] {
  position: absolute; top: 50%; left: 50%; width: 16px; height: 2px; background: var(--rsd-charcoal);
}
.rsd-drawer__close span[aria-hidden]:first-of-type { transform: translate(-50%, -50%) rotate(45deg); }
.rsd-drawer__close span[aria-hidden]:last-of-type  { transform: translate(-50%, -50%) rotate(-45deg); }

.rsd-menu--stacked { flex-direction: column; align-items: stretch; gap: 0; }
.rsd-menu--stacked > li { border-bottom: 1px solid var(--rsd-line); }
.rsd-menu--stacked a, .rsd-menu--stacked .rsd-menu__heading { padding-block: .8rem; }
.rsd-menu--stacked > li > a::after { display: none; }
.rsd-menu--stacked .sub-menu {
  position: static; display: block; list-style: none; border: 0; box-shadow: none; padding: 0 0 .6rem .9rem; background: none;
  opacity: 1; visibility: visible; pointer-events: auto; transform: none; width: auto; max-width: none;
}
/* Same --rsd-t-menu-weight variable as desktop's .rsd-menu__label above,
   not a hardcoded 500 — the mobile drawer restates this property (its own
   fallback happens to match desktop's default) rather than deleting the
   rule outright, so a future divergence between drawer and desktop weight
   still has an explicit place to live if one is ever genuinely needed. */
.rsd-menu--stacked .rsd-menu__label { font-weight: var(--rsd-t-menu-weight, 500); }
.rsd-menu--stacked .rsd-menu__desc { display: none; } /* keep the drawer list scannable; the tagline is a desktop-panel nicety */
/* Related pillar (MIDDLE) and Proof & Resources (RIGHT) — desktop-only
   mega-menu columns (inc/services.php's rsd_inject_dynamic_services_into_menu()
   part 2, and rsd-menu__group--proof from an earlier task). Only LEFT (a
   pillar's own real services) belongs in the mobile drawer's single-column
   accordion. Hidden, not removed: the exact same server-rendered markup
   still exists in the DOM (progressive enhancement, same reasoning as the
   "Mobile accordion" comment below), simply never shown or reachable on a
   touch device. main.js's initMobileAccordion() still inserts a toggle
   for each of these (they're still real 'menu-item-has-children' groups,
   for desktop's sake) — that toggle is just never visible or reachable,
   since its own parent <li> is display:none here. Desktop is untouched:
   .rsd-menu--stacked only ever exists in the drawer's own markup (never
   in .rsd-pill__nav's desktop <ul>), and none of the desktop 3-column
   @media(min-width:1024px) rules elsewhere in this file reference
   .rsd-menu--stacked at all, so this selector cannot reach the desktop
   panel regardless of viewport width. */
.rsd-menu--stacked .rsd-menu__group--related,
.rsd-menu--stacked .rsd-menu__group--proof {
  display: none;
}
/* LEFT's own heading — hidden, not the group itself: LEFT's heading text
   is always just the top-level pillar's own name repeated (rsd_own['label'],
   inc/services.php), which the mobile drawer already shows as the visible
   accordion trigger one level up — showing it again here would read as a
   duplicate heading. Only the heading <span> is hidden; the real service
   links inside this same <li> stay fully visible (assets/js/main.js's
   initMobileAccordion() is told to skip inserting a toggle for this
   specific group — see its own comment — so there's no separate collapsed
   state to reveal here; the services are simply always shown once the
   top-level pillar's own accordion is open). */
.rsd-menu--stacked .rsd-menu__group--own > .rsd-menu__heading { display: none; }

/* Mobile accordion — main.js inserts .rsd-menu__toggle only inside the
   drawer, only for items with children. Without JS these submenus simply
   stay visible (today's behaviour) — a safe no-JS fallback, never a dead
   link: the real <a>/<span> is always server-rendered regardless. */
.rsd-menu--stacked li.menu-item-has-children { position: relative; }
.rsd-menu--stacked li.menu-item-has-children > a,
.rsd-menu--stacked li.menu-item-has-children > .rsd-menu__heading { padding-right: 2.75rem; }
.rsd-menu__toggle {
  position: absolute; top: 0; right: 0; width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer; color: var(--rsd-charcoal);
}
.rsd-menu__toggle span[aria-hidden] { position: relative; width: 12px; height: 12px; display: block; }
.rsd-menu__toggle span[aria-hidden]::before,
.rsd-menu__toggle span[aria-hidden]::after {
  content: ""; position: absolute; top: 50%; left: 50%; background: currentColor;
  transform: translate(-50%, -50%);
}
.rsd-menu__toggle span[aria-hidden]::before { width: 12px; height: 2px; }
.rsd-menu__toggle span[aria-hidden]::after { width: 2px; height: 12px; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-menu__toggle span[aria-hidden]::after { transition: transform .16s ease; }
}
.rsd-menu__toggle[aria-expanded="true"] span[aria-hidden]::after { transform: translate(-50%, -50%) scaleY(0); }

/* ARIA state is the single source of truth for both semantics and visibility. */
.rsd-menu__toggle + .sub-menu { display: none; }
.rsd-menu__toggle[aria-expanded="true"] + .sub-menu { display: block; }

/* Blurred, dimmed backdrop — fades in step with the drawer via the same
   .32s cubic-bezier(0.22, 1, 0.36, 1) curve. opacity/visibility (not the
   `hidden` attribute) so it can transition instead of snapping; the
   visibility delay keeps it out of the tab order and unclickable while
   closed without a hard display:none cutting the fade short. */
.rsd-scrim {
  position: fixed; inset: 0; z-index: 65;
  background: var(--rsd-overlay);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  opacity: 0; visibility: hidden; pointer-events: none;
}
.rsd-scrim.is-open { opacity: 1; visibility: visible; pointer-events: auto; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-scrim { transition: opacity .32s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear .32s; }
  .rsd-scrim.is-open { transition: opacity .32s cubic-bezier(0.22, 1, 0.36, 1); }
}
@media (min-width: 1024px) { .rsd-drawer, .rsd-scrim { display: none; } }

/* Bottom of the drawer: Client Login (outline) then the proposal button
   (solid), matching the desktop pill's own two-button treatment. Separated
   from the nav by margin alone (the last stacked menu item already ends on
   its own hairline — see .rsd-menu--stacked > li — so a second border here
   would double up the rule right above these buttons). min-height rather
   than trusting .rsd-btn's own padding: at this font-size .rsd-btn's
   padding alone lands a hair under the 44px tap-target floor. */
.rsd-drawer__actions { display: flex; flex-direction: column; gap: .65rem; margin-top: 1.75rem; }
.rsd-drawer__actions .rsd-btn--block {
  margin-top: 0; min-height: 44px;
  display: flex; align-items: center; justify-content: center;
}

/* ============================================================
   Homepage components — reuse existing tokens only, per
   REDSPROUT_DESIGN_SYSTEM.md §12 (badges) and the homepage build.
   ============================================================ */

/* Shared vertical rhythm between homepage sections. */
.rsd-home-section { margin-block: var(--rsd-block) 0; }
.rsd-home-section:first-child { margin-top: 0; }

/* [rsd_reach] and [rsd_services] (inc/shortcodes.php) both echo their own
   <section class="rsd-home-section"> directly — the homepage pattern
   places them as bare top-level shortcode blocks, never wrapped in
   .rsd-shell the way every other section on the page is (verified against
   the live rendered homepage: this section is a direct child of
   .rsd-main, siblings with .rsd-shell, not nested inside one). Un-shelled,
   it inherits no width constraint at all and runs edge to edge while
   .rsd-shell content on the same page sits in a centred 1180px column —
   the pill rows' left edge then can't line up with any heading above them
   either, since there's no shared reference box to align to.
   Scoped to ".rsd-main >" specifically so this only ever engages for that
   genuinely un-shelled case: a .rsd-home-section already nested inside a
   real .rsd-shell (the normal case everywhere else this class is used,
   including the rest of this same homepage pattern) doesn't match this
   selector at all, so it isn't touched or re-constrained a second time.
   The width formula is copied verbatim from .rsd-shell itself, not
   re-derived, so a self-constrained instance computes the exact same left
   offset as a real .rsd-shell and lines up with it pixel for pixel. */
.rsd-main > .rsd-home-section {
  width: min(100% - var(--rsd-shell-gutter), var(--rsd-shell));
  margin-inline: auto;
}

/* Badges (§12 of the design system) — neutral by default; the red variant
   is reserved for genuinely notable flags, not used on this page. */
.rsd-badge {
  display: inline-flex; align-items: center; text-decoration: none;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-xs); letter-spacing: .04em; text-transform: uppercase;
  padding: .3rem .75rem; border-radius: var(--rsd-radius-pill);
  border: 1px solid var(--rsd-line); background: var(--rsd-white); color: var(--rsd-muted);
  transition: border-color .16s ease, color .16s ease;
}
.rsd-badge:hover { border-color: var(--rsd-red); color: var(--rsd-red); }
.rsd-badge--red { background: var(--rsd-red); color: var(--rsd-white); border-color: transparent; }
/* Row-gap AND column-gap explicitly, not a single value relying on the
   shorthand's "applies to both" behaviour reading as an accident — small
   tier (related items in one row), same token .rsd-points/.rsd-steps use
   for the same relationship. Was a flat .6rem before: smaller than the
   established small tier and, being a single unlabelled value, easy to
   misread as governing only the horizontal axis. */
.rsd-badge-list { display: flex; flex-wrap: wrap; row-gap: var(--rsd-gap-sm); column-gap: var(--rsd-gap-sm); list-style: none; margin: 0 0 1rem; padding: 0; }
.rsd-badge-list:last-child { margin-bottom: 0; }

/* Markets/Industries pill-row rhythm ([rsd_reach], inc/shortcodes.php) —
   scoped to the two adjacent-sibling relationships that actually exist in
   that shortcode's own markup: an .rsd-eyebrow immediately followed by the
   pill row it labels (medium tier — heading to its content), and a pill
   row immediately followed by the NEXT block's own .rsd-eyebrow (large
   tier — Markets to Industries is a section boundary, not a related-item
   gap, so it gets the same rhythm as any other major section transition,
   not the medium heading-to-content spacing). .rsd-eyebrow's own
   margin-bottom (0.85rem, unchanged, used everywhere else eyebrows appear)
   is what read as "the rule sits directly on the pills" — too tight for
   this specific pairing specifically, not for eyebrows in general, hence
   scoping the fix to these two adjacent-sibling combinators rather than
   changing .rsd-eyebrow itself. */
.rsd-eyebrow + .rsd-badge-list { margin-top: var(--rsd-gap); }
.rsd-badge-list + .rsd-eyebrow { margin-top: var(--rsd-block); }

/* Positioning strip — three sourced statements, not a client-logo bar.
   Reuses the same red-left-border "evidenced claim" motif as .rsd-figure. */
.rsd-strip {
  list-style: none; margin: var(--rsd-block) 0 0; padding: 1.5rem 0;
  border-top: 1px solid var(--rsd-line); border-bottom: 1px solid var(--rsd-line);
  display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem;
  font-size: var(--rsd-t-sm); color: var(--rsd-muted);
}
.rsd-strip li { flex: 1 1 220px; padding-left: 1rem; border-left: 2px solid var(--rsd-red); }

/* Outcome cards — reuse .rsd-cards/.rsd-card, add a problem/outcome pairing. */
.rsd-card--outcome { display: flex; flex-direction: column; gap: var(--rsd-gap-sm); }
.rsd-card__problem { color: var(--rsd-charcoal); font-weight: var(--rsd-weight-semibold); margin: 0; }
.rsd-card__outcome { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; padding-left: 1rem; border-left: 2px solid var(--rsd-red); }

/* "How we operate" — a two-column point grid of four peer items. gap
   (both axes — every item here is a peer of every other, not "sections
   vs. items within a section") is the small tier (related items);
   margin-top stays the medium tier (this group as a whole, under its own
   heading). Previously gap used var(--rsd-gap), conflating the two tiers
   the spacing scale now separates. */
.rsd-points { display: grid; width: 100%; box-sizing: border-box; grid-template-columns: 1fr 1fr; align-items: baseline; gap: var(--rsd-gap-sm); margin-top: var(--rsd-gap); }
.rsd-points__item h3 { font-size: var(--rsd-t-base); margin-bottom: .35rem; }
.rsd-points__item p { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; }

/* Process steps — numbered with CSS counters, tabular-nums in the brand red,
   echoing the sourced-figure numeral treatment for a related but distinct use.
   Children are plain Group-block divs, not <li> — Gutenberg's core blocks
   can't cleanly nest a heading + paragraph inside a single List Item, so
   this trades strict list semantics for a heading-per-step structure that's
   just as navigable by assistive tech via the heading outline itself. */
.rsd-steps {
  margin: var(--rsd-gap) 0 0; counter-reset: rsd-step;
  display: grid; width: 100%; box-sizing: border-box;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--rsd-gap-sm);
}
/* Each step keeps its own top hairline as the default/mobile-stacked
   state (a horizontal connecting line makes no sense once steps are in
   one vertical column) — overridden below at ≥1024px, where the steps
   are realistically all in one row and a single line spanning the whole
   .rsd-steps container reads as one continuous sequence instead of a
   dashed one (one border-top per grid cell is visually broken by the
   gap between cells; that's what made it read as separate cards rather
   than a sequence). */
.rsd-steps > div { counter-increment: rsd-step; padding-top: 1.25rem; border-top: 2px solid var(--rsd-line); }
@media (min-width: 1024px) {
  .rsd-steps { position: relative; }
  .rsd-steps::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0;
    height: 1px; background: var(--rsd-line);
  }
  .rsd-steps > div { border-top: 0; }
}
/* mono + brand red + reusing .rsd-figure__value's own large-numeral scale
   (the theme's other "big red number" component, D-25) is what actually
   separates the step number from its title visually — the number was
   already the first block-level child (structurally above the title, not
   inline with it), but at the old display-font/lede-sized treatment it
   read close enough in weight to the title beneath it that the two
   blurred into what looked like one line. Mono is also what visually
   marks it as a measured/counted value elsewhere on the site (figures,
   table numerals, D-24) — the same signal, reused. */
.rsd-steps > div::before {
  content: counter(rsd-step, decimal-leading-zero); display: block;
  font-family: var(--rsd-mono); font-weight: var(--rsd-weight-bold); font-size: clamp(1.75rem, 2.5vw, 2.25rem);
  color: var(--rsd-red); font-variant-numeric: tabular-nums; line-height: 1; margin-bottom: .6rem;
}
.rsd-steps h3 { font-size: var(--rsd-t-base); margin-bottom: .35rem; }
.rsd-steps p { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; }

/* ---------------------------------------------------------- Learn article
   single-tutorials.php's optional structured sections. Same eyebrow
   headings, prose and step numerals as the rest of the site; only the
   pieces with no existing equivalent are added here. */
.rsd-learn-section { margin-block: var(--rsd-block); }
.rsd-learn-section .rsd-lede + .rsd-learn-list { margin-top: var(--rsd-gap-sm); }

/* Steps in an article carry full prose, so they always stack — one per
   row, each with its own hairline, at every width (the base .rsd-steps
   row/line treatment is for short process blurbs). */
.rsd-steps--stack { grid-template-columns: minmax(0, 1fr); gap: var(--rsd-gap); margin-top: 0; }
.rsd-steps--stack::before { content: none; }
.rsd-steps.rsd-steps--stack > div { border-top: 2px solid var(--rsd-line); }
.rsd-steps--stack h3 { font-size: var(--rsd-t-h3); margin-bottom: .6rem; }
.rsd-steps--stack p { color: inherit; font-size: inherit; margin: 0 0 1em; }
.rsd-steps--stack .rsd-prose > :last-child { margin-bottom: 0; }
.rsd-steps--stack img { display: block; max-width: 100%; height: auto; margin-top: var(--rsd-gap-sm); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius); }

/* Outcome lists — a red tick per point; --watch (common mistakes) uses a
   charcoal marker and a bold lead line with an optional note under it. */
.rsd-learn-list { list-style: none; margin: 0; padding: 0; max-width: var(--rsd-read); }
.rsd-learn-list > li { position: relative; padding: .7rem 0 .7rem 1.75rem; border-bottom: 1px solid var(--rsd-line); overflow-wrap: anywhere; }
.rsd-learn-list > li:first-child { border-top: 1px solid var(--rsd-line); }
.rsd-learn-list > li::before {
  content: ""; position: absolute; left: .15rem; top: 1.05rem;
  width: .7rem; height: .38rem; border-left: 2px solid var(--rsd-red); border-bottom: 2px solid var(--rsd-red);
  transform: rotate(-45deg);
}
.rsd-learn-list--watch > li::before { top: 1.3rem; width: .7rem; height: 0; border-left: 0; border-bottom-color: var(--rsd-charcoal); transform: none; }
.rsd-learn-list--watch strong { display: block; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); }
.rsd-learn-list--watch p { margin: .25rem 0 0; color: var(--rsd-muted); font-size: var(--rsd-t-sm); }

/* Ebook card — cover beside the copy from 600px, stacked above it below. */
.rsd-learn-ebook {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rsd-gap); align-items: center;
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line);
  border-radius: var(--rsd-radius); padding: var(--rsd-gap);
}
@media (min-width: 600px) {
  .rsd-learn-ebook--cover { grid-template-columns: minmax(120px, 180px) minmax(0, 1fr); }
}
.rsd-learn-ebook__cover { max-width: 180px; }
.rsd-learn-ebook__cover img {
  display: block; width: 100%; height: auto; border-radius: calc(var(--rsd-radius) * .75);
  box-shadow: 0 12px 28px rgba(26, 26, 28, .14), 0 2px 6px rgba(26, 26, 28, .08);
}
.rsd-learn-ebook__body { min-width: 0; }
.rsd-learn-ebook__title { font-size: var(--rsd-t-h3); margin: 0 0 .5rem; overflow-wrap: anywhere; }
.rsd-learn-ebook__text { color: var(--rsd-muted); margin: 0 0 1.25rem; max-width: 52ch; }

/* ---------------------------------------------------------- Process
   redsprout-digital/process (inc/process-block.php; editor:
   assets/js/process-editor.js, same classes). An <ol> of steps — number,
   a marker on a thin connecting line, title, description — never cards.
   Phones: a vertical line down the left joining the markers. Tablet
   (768–1023px): an editorial index, one hairline-ruled row per step
   (number | title | description). Desktop: the steps side by side
   (--rsd-process-cols, from the step count), the line running from
   marker to marker across the row. Numbers use the same mono + red
   instrument voice as .rsd-steps / .rsd-figure. Hover only fills the
   step's marker — colour, never size or position. Separate from
   .rsd-steps (tutorials, M05), which stays as it is. */
.rsd-process {
  --rsd-process-gap: clamp(1.25rem, 2.5vw, 2.25rem);
  --rsd-process-dot: 9px;
  list-style: none; margin: var(--rsd-gap) 0 0; padding: 0;
}
.rsd-process__step { position: relative; margin: 0; padding: 0 0 1.75rem 2.25rem; }
.rsd-process__step:last-child { padding-bottom: 0; }
.rsd-process__num {
  display: block; font-family: var(--rsd-mono); font-weight: var(--rsd-weight-bold);
  font-size: clamp(1.4rem, 2vw, 1.75rem); line-height: 1; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--rsd-red);
}
/* Marker + line. Phones: the marker beside the number, the line running
   down to the next step's marker. */
.rsd-process__mark { position: absolute; top: .45rem; bottom: 0; left: 0; width: var(--rsd-process-dot); }
.rsd-process__mark::after {
  content: ""; position: absolute; top: 0; left: 0; box-sizing: border-box;
  width: var(--rsd-process-dot); height: var(--rsd-process-dot); border-radius: 50%;
  border: 1.5px solid currentColor; background: transparent;
}
.rsd-process__mark::before {
  content: ""; position: absolute; left: calc(var(--rsd-process-dot) / 2 - .5px);
  top: calc(var(--rsd-process-dot) + .4rem); bottom: .05rem; width: 1px; background: var(--rsd-line);
}
.rsd-process__step:last-child .rsd-process__mark::before { content: none; }
.rsd-process .rsd-process__title {
  margin: .55rem 0 0; font-family: var(--rsd-display); font-size: var(--rsd-t-lg);
  font-weight: var(--rsd-weight-semibold); line-height: 1.25; letter-spacing: -0.01em;
}
.rsd-process .rsd-process__desc {
  margin: .4rem 0 0; max-width: 46ch; font-size: var(--rsd-t-sm); line-height: 1.6; color: var(--rsd-muted);
}
.rsd-process__step:hover .rsd-process__mark::after { background: var(--rsd-red); border-color: var(--rsd-red); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-process__mark::after { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out), border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* On a Charcoal section the muted grey would lose contrast. */
.rsd-section--bg-charcoal .rsd-process .rsd-process__desc { color: rgba(247, 246, 244, .72); }

/* Tablet: an editorial index — one ruled row per step. */
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-process__step {
    display: grid; grid-template-columns: 4rem minmax(9rem, 15rem) minmax(0, 1fr);
    column-gap: var(--rsd-process-gap); align-items: baseline;
    padding: 1.25rem 0; border-top: 1px solid var(--rsd-line);
  }
  .rsd-process__step:last-child { padding-bottom: 1.25rem; border-bottom: 1px solid var(--rsd-line); }
  .rsd-process__mark { display: none; }
  .rsd-process .rsd-process__title, .rsd-process .rsd-process__desc { margin: 0; }
  .rsd-process .rsd-process__desc { grid-column: 3; }
}

/* Desktop: the steps side by side, one line from marker to marker. */
@media (min-width: 1024px) {
  .rsd-process {
    display: grid; grid-template-columns: repeat(var(--rsd-process-cols, 5), minmax(0, 1fr));
    column-gap: var(--rsd-process-gap); row-gap: 2.5rem;
  }
  .rsd-process__step, .rsd-process__step:last-child { padding: 0; }
  .rsd-process__mark { position: relative; top: auto; bottom: auto; display: block; width: auto; height: var(--rsd-process-dot); margin: 1.1rem 0 1.15rem; }
  .rsd-process__mark::before {
    left: calc(var(--rsd-process-dot) + .5rem); right: calc(.5rem - var(--rsd-process-gap));
    top: calc(var(--rsd-process-dot) / 2 - .5px); bottom: auto; width: auto; height: 1px;
  }
  .rsd-process .rsd-process__title { margin: 0; }
  .rsd-process .rsd-process__desc { max-width: 30ch; }
}

/* ---------------------------------------------------------- Industries — editorial index
   The industries-grid block's "Editorial index" layout
   (rsd_render_industries_index(), inc/industries.php). An <ol>, one
   hairline-ruled row per industry: number | name (+ its excerpt) | arrow.
   The name's link stretches over the whole row (::after), so the row is
   the target while the link's accessible name stays just the industry;
   keyboard focus outlines that whole row. Hover: a faint tint mixed from
   the current text colour (so it suits paper, white and charcoal
   sections alike) and the arrow nudging — no movement, borders or
   shadows. From 1024px the section head sits beside the list. */
.rsd-ind { margin-top: var(--rsd-gap); }
.rsd-ind__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rsd-line); }
.rsd-ind__item {
  position: relative; display: grid; grid-template-columns: 2.25rem minmax(0, 1fr) 1.25rem;
  column-gap: .9rem; align-items: baseline;
  margin: 0; padding: 1.05rem .5rem; border-bottom: 1px solid var(--rsd-line);
}
.rsd-ind__num {
  font-family: var(--rsd-mono); font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold);
  font-variant-numeric: tabular-nums; color: var(--rsd-red);
}
.rsd-ind .rsd-ind__name {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-lg);
  font-weight: var(--rsd-weight-semibold); line-height: 1.3; letter-spacing: -0.01em;
}
/* The sitewide text-link underline (":is(… .rsd-shell li) a:not(.rsd-btn)",
   "text-link" below) also matches these links: it makes the link the
   positioned box and turns ::after into a scaled-out 1px underline. Here
   ::after is the row overlay instead, so both are undone — one class more
   specific than that rule. */
.rsd-ind .rsd-ind__item .rsd-ind__link { position: static; color: inherit; text-decoration: none; }
.rsd-ind .rsd-ind__item .rsd-ind__link::after {
  content: ""; position: absolute; inset: 0; height: auto;
  background: none; transform: none; transition: none;
}
.rsd-ind .rsd-ind__item .rsd-ind__link:focus-visible { outline: none; }
.rsd-ind .rsd-ind__item .rsd-ind__link:focus-visible::after { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
.rsd-ind .rsd-ind__desc { margin: .3rem 0 0; max-width: 60ch; font-size: var(--rsd-t-sm); line-height: 1.55; color: var(--rsd-muted); }
/* pointer-events: its hover transform would otherwise lift it above the
   row's link overlay and swallow clicks that land on it. */
.rsd-ind__arrow { justify-self: end; display: inline-block; color: var(--rsd-muted); pointer-events: none; }
.rsd-ind__item:hover { background: color-mix(in srgb, currentColor 4%, transparent); }
.rsd-ind__item:is(:hover, :focus-within) .rsd-ind__arrow { color: currentColor; transform: translateX(4px); }
.rsd-ind__all { margin: 1.5rem 0 0; }
.rsd-ind__all .rsd-btn { gap: .45rem; }
.rsd-ind__all-arrow { display: inline-block; }
.rsd-ind__all a:is(:hover, :focus-visible) .rsd-ind__all-arrow { transform: translateX(3px); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-ind__item { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ind__arrow, .rsd-ind__all-arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* On a Charcoal section the muted grey — and the small red number, ~3.3:1
   there — would lose contrast. */
.rsd-section--bg-charcoal .rsd-ind :is(.rsd-ind__desc, .rsd-ind__arrow, .rsd-ind__num) { color: rgba(247, 246, 244, .72); }

@media (min-width: 768px) {
  .rsd-ind__item { grid-template-columns: 3rem minmax(0, 1fr) 1.5rem; padding: 1.2rem .75rem; }
}
/* Desktop: the section head beside the list (only when there is a head). */
@media (min-width: 1024px) {
  .rsd-block-section:has(> .rsd-section-head + .rsd-ind) {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem); align-items: start;
  }
  .rsd-block-section:has(> .rsd-section-head + .rsd-ind) > .rsd-section-head { margin-bottom: 0; }
  .rsd-section-head + .rsd-ind { margin-top: 0; }
}

/* ---------------------------------------------------------- Industries — carousel
   The industries-grid block's "Mosaic" layout, now a carousel
   (rsd_render_industries_mosaic(), inc/industries.php; behaviour:
   assets/js/industries-carousel.js). The section head is the editorial
   intro — beside the carousel from 1024px (5 : 7, the editorial index's
   own proportion), above it below that. The track is a native horizontal
   scroller with scroll-snap, so without JS it is still a usable swipe /
   trackpad / Tab list with a thin scrollbar; with JS (.is-enhanced) the
   scrollbar goes and the previous / next / pause controls show (their row
   is reserved either way, so nothing shifts). Visible cards: about 2.3
   beside the head on desktop, 1.8–2.2 on tablets, 1.15–1.25 on phones —
   always a sliver of the next card. Tiles are the theme's card surface —
   hairline border, 6px radius, a short red rule — and each is one link:
   the name's link stretches over the tile, so the tile is the target and
   the industry name its accessible name. Hover: the border warms toward
   red and the arrow nudges 3px; nothing else moves. */
.rsd-ind-mosaic { display: grid; gap: var(--rsd-gap); }
.rsd-ind-mosaic__intro .rsd-section-head { margin: 0; }
.rsd-ind-mosaic__carousel { min-width: 0; }
.rsd-ind-mosaic__track {
  --rsd-ind-gap: .75rem; --rsd-ind-per: 1.15; --rsd-ind-whole: 1;
  position: relative; display: flex; gap: var(--rsd-ind-gap); margin: 0; padding: 0 0 .5rem; list-style: none;
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-behavior: auto;
  scrollbar-width: thin; scrollbar-color: var(--rsd-line) transparent;
}
.rsd-ind-mosaic__carousel.is-enhanced .rsd-ind-mosaic__track { scrollbar-width: none; }
.rsd-ind-mosaic__carousel.is-enhanced .rsd-ind-mosaic__track::-webkit-scrollbar { display: none; }
/* While the script glides the track, snapping would fight each frame. */
.rsd-ind-mosaic__carousel.is-moving .rsd-ind-mosaic__track { scroll-snap-type: none; }
.rsd-ind-mosaic__slide {
  display: flex; flex: 0 0 calc((100% - var(--rsd-ind-gap) * var(--rsd-ind-whole)) / var(--rsd-ind-per));
  min-width: 0; margin: 0; scroll-snap-align: start;
}
.rsd-ind-mosaic__tile {
  position: relative; display: flex; flex: 1; flex-direction: column; min-width: 0;
  padding: .95rem 2.75rem 1rem 1.1rem;
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-ind-mosaic__tile::before { content: ""; width: 1.25rem; height: 2px; margin-bottom: .5rem; background: var(--rsd-red); }
/* The industry's line icon (rsd_industry_icon(), decorative) between the
   red rule (8px above) and the name (15px below): 24px, charcoal. Fixed
   size, so it never shifts the card while anything loads. The card's
   vertical padding is kept tight (about 1rem) so the card stays compact. */
.rsd-ind-mosaic__icon { display: block; flex: none; width: 24px; height: 24px; margin: 0 0 .95rem; color: var(--rsd-charcoal); line-height: 0; }
.rsd-ind-mosaic__icon svg { display: block; width: 100%; height: 100%; }
.rsd-section--bg-charcoal .rsd-ind-mosaic__icon { color: rgba(247, 246, 244, .85); }
.rsd-ind-mosaic .rsd-ind-mosaic__name {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-lg);
  font-weight: var(--rsd-weight-semibold); line-height: 1.25; letter-spacing: -0.01em; overflow-wrap: break-word;
}
.rsd-ind-mosaic .rsd-ind-mosaic__link { position: static; color: inherit; text-decoration: none; }
.rsd-ind-mosaic .rsd-ind-mosaic__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.rsd-ind-mosaic .rsd-ind-mosaic__link:focus-visible { outline: none; }
/* Inset, so the track's horizontal clipping never cuts the focus ring. */
.rsd-ind-mosaic .rsd-ind-mosaic__link:focus-visible::after { outline: 2px solid var(--rsd-red); outline-offset: -2px; border-radius: 6px; }
/* Three lines at most, so every card in the row stays compact and equal. */
.rsd-ind-mosaic .rsd-ind-mosaic__desc {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
  margin: .4rem 0 0; max-width: 52ch; font-size: var(--rsd-t-sm); line-height: 1.55; color: var(--rsd-muted);
}
/* pointer-events: so a nudged arrow never sits above the tile's link overlay. */
.rsd-ind-mosaic__arrow {
  position: absolute; top: .9rem; right: 1.1rem; display: inline-block;
  color: var(--rsd-muted); pointer-events: none;
}
.rsd-ind-mosaic__tile:hover { border-color: color-mix(in srgb, var(--rsd-red) 40%, var(--rsd-line)); }
.rsd-ind-mosaic__tile:is(:hover, :focus-within) .rsd-ind-mosaic__arrow { color: var(--rsd-red); transform: translateX(3px); }
/* Under the track: the "Explore" link, the controls at the end. */
.rsd-ind-mosaic__foot { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.5rem; margin-top: 1rem; }
.rsd-ind-mosaic__controls { display: flex; gap: .5rem; margin-left: auto; }
.rsd-ind-mosaic__carousel:not(.is-enhanced) .rsd-ind-mosaic__controls { visibility: hidden; }
.rsd-ind-mosaic__nav {
  display: inline-flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; margin: 0; padding: 0;
  font: inherit; font-size: 1rem; line-height: 1; color: var(--rsd-charcoal); cursor: pointer;
  background: transparent; border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-ind-mosaic__nav:hover { color: var(--rsd-red); border-color: color-mix(in srgb, var(--rsd-red) 40%, var(--rsd-line)); }
.rsd-ind-mosaic__nav:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
/* Pause / play: two hairline bars, or a small play triangle when paused. */
.rsd-ind-mosaic__nav--pause span { display: inline-flex; gap: 3px; }
.rsd-ind-mosaic__nav--pause span::before, .rsd-ind-mosaic__nav--pause span::after { content: ""; width: 2px; height: 10px; background: currentColor; }
.rsd-ind-mosaic__nav--pause[aria-pressed="true"] span { gap: 0; }
.rsd-ind-mosaic__nav--pause[aria-pressed="true"] span::before { width: 0; height: 0; background: none; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent currentColor; }
.rsd-ind-mosaic__nav--pause[aria-pressed="true"] span::after { display: none; }
.rsd-section--bg-charcoal .rsd-ind-mosaic__nav { color: var(--rsd-paper); border-color: rgba(247, 246, 244, .24); }
.rsd-ind-mosaic__all { margin: 0; font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold); }
.rsd-ind-mosaic__all a { color: inherit; }
.rsd-ind-mosaic__all-arrow { display: inline-block; }
.rsd-ind-mosaic__all a:is(:hover, :focus-visible) .rsd-ind-mosaic__all-arrow { transform: translateX(3px); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-ind-mosaic__tile { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ind-mosaic__arrow, .rsd-ind-mosaic__all-arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ind-mosaic__nav { transition: color var(--rsd-motion-fast) var(--rsd-ease-out), border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* Charcoal section: a faint light surface instead of white. */
.rsd-section--bg-charcoal .rsd-ind-mosaic__tile { background: rgba(247, 246, 244, .04); border-color: rgba(247, 246, 244, .14); }
.rsd-section--bg-charcoal .rsd-ind-mosaic :is(.rsd-ind-mosaic__desc, .rsd-ind-mosaic__arrow) { color: rgba(247, 246, 244, .72); }

/* Larger phones: one card and a quarter. */
@media (min-width: 600px) and (max-width: 767px) {
  .rsd-ind-mosaic__track { --rsd-ind-per: 1.25; }
}
/* Tablet: the head above, 1.8 → 2.2 cards with more room between. */
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-ind-mosaic__track { --rsd-ind-gap: 1rem; --rsd-ind-per: 1.8; }
  .rsd-ind-mosaic__tile { padding: 1rem 3.25rem .95rem 1.4rem; }
  .rsd-ind-mosaic__arrow { top: .95rem; right: 1.4rem; }
  .rsd-ind-mosaic__nav { width: 2.5rem; height: 2.5rem; }
}
@media (min-width: 900px) and (max-width: 1023px) {
  .rsd-ind-mosaic__track { --rsd-ind-per: 2.2; --rsd-ind-whole: 2; }
}
/* Desktop: the head beside the carousel (5 : 7); about 2.3 cards in view,
   or 3.3 across the full width when there is no head. */
@media (min-width: 1024px) {
  .rsd-ind-mosaic--has-head {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem); align-items: center;
  }
  .rsd-ind-mosaic__track { --rsd-ind-gap: 1rem; --rsd-ind-per: 2.3; --rsd-ind-whole: 2; }
  .rsd-ind-mosaic:not(.rsd-ind-mosaic--has-head) .rsd-ind-mosaic__track { --rsd-ind-per: 3.3; --rsd-ind-whole: 3; }
  .rsd-ind-mosaic__tile { padding: .95rem 3.5rem .85rem 1.6rem; }
  .rsd-ind-mosaic__arrow { top: .9rem; right: 1.6rem; }
  .rsd-ind-mosaic__nav { width: 2.5rem; height: 2.5rem; }
}

/* ---------------------------------------------------------- Client Feedback
   redsprout-digital/client-feedback (inc/client-feedback-block.php). Real
   case-study feedback only. The first testimonial is set large — a quote
   in display type under one red opening mark (decorative; "/ ''" keeps it
   out of the accessibility tree), the real attribution beneath — and any
   others sit in a hairline-ruled grid below it. No cards, shadows,
   ratings or placeholder portraits: a portrait appears only when a real
   client image exists. A long featured quote is set smaller, never cut. */
.rsd-fb { margin-top: var(--rsd-gap); }
.rsd-fb__figure { margin: 0; }
.rsd-fb__quote { margin: 0; padding: 0; border: 0; }
.rsd-fb .rsd-fb__quote p { margin: 0; }
.rsd-fb__item--featured .rsd-fb__quote::before {
  content: "\201C"; content: "\201C" / "";
  display: block; height: .55em; margin-bottom: .1em;
  font-family: var(--rsd-display); font-size: clamp(3.5rem, 6vw, 5rem); line-height: 1; color: var(--rsd-red);
}
.rsd-fb__item--featured .rsd-fb__quote p {
  max-width: 36ch; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: clamp(1.4rem, 1rem + 1.7vw, 2.3rem); line-height: 1.28; letter-spacing: -0.015em;
}
.rsd-fb__item--long .rsd-fb__quote p { max-width: 62ch; font-weight: var(--rsd-weight-medium); font-size: clamp(1.15rem, .95rem + .8vw, 1.5rem); line-height: 1.45; }

.rsd-fb__by { display: flex; align-items: center; gap: .9rem; margin-top: 1.5rem; }
.rsd-fb__item--featured .rsd-fb__by { margin-top: 2rem; }
.rsd-fb__portrait { flex: none; width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; background: var(--rsd-line); }
.rsd-fb__who { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.rsd-fb__name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-base); line-height: 1.3; }
.rsd-fb__role { font-size: var(--rsd-t-sm); line-height: 1.4; color: var(--rsd-muted); }
.rsd-fb .rsd-fb__meta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem 1.5rem;
  margin: 1rem 0 0; font-size: var(--rsd-t-sm);
}
.rsd-fb__case { font-weight: var(--rsd-weight-semibold); }
.rsd-fb__case span[aria-hidden] { display: inline-block; }
.rsd-fb__source { font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); letter-spacing: .04em; text-transform: uppercase; color: var(--rsd-muted); }

.rsd-fb__more {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: 2.25rem clamp(1.5rem, 4vw, 3.5rem); margin-top: calc(var(--rsd-block) * .7);
}
.rsd-fb__more .rsd-fb__item { padding-top: 1.5rem; border-top: 1px solid var(--rsd-line); }
.rsd-fb__more .rsd-fb__quote p { max-width: 60ch; font-size: var(--rsd-t-base); line-height: 1.6; }
.rsd-fb__all { margin: calc(var(--rsd-block) * .6) 0 0; }
.rsd-fb__all .rsd-btn { gap: .45rem; }

@media (prefers-reduced-motion: no-preference) {
  .rsd-fb__case span[aria-hidden] { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
}
.rsd-fb__case:is(:hover, :focus-visible) span[aria-hidden] { transform: translateX(3px); }
/* On a Charcoal section the muted grey would lose contrast. */
.rsd-section--bg-charcoal .rsd-fb :is(.rsd-fb__role, .rsd-fb__source) { color: rgba(247, 246, 244, .72); }

/* ---------------------------------------------------------- Client Feedback — carousel
   The block's Carousel layout (rsd_render_client_feedback_carousel(),
   inc/client-feedback-block.php; behaviour assets/js/client-feedback-
   carousel.js). Everything is scoped to .rsd-fbc — the Editorial rules
   above are untouched. Square cards (aspect-ratio 1 / 1) on a native
   horizontal track with scroll-snap: without JS a usable swipe / trackpad
   / keyboard scroller with a thin scrollbar; with JS (.is-enhanced) the
   scrollbar goes and the counter + previous / next row shows (reserved
   either way, so nothing shifts). Cards in view follow the carousel's OWN
   width (container query): ~1.08 on phones, 1.35 on large phones, 1.8 → 2
   on tablets, 2.2 → 2.4 on desktop — always a sliver of the next card.
   Card: the theme's surface — white, hairline border, 6px radius, a short
   red rule on the top edge — a small "Client perspective" label, the quote
   in display type sized by its length and the card's width (a long quote
   is set smaller, never cut), the real attribution anchored to the bottom,
   and the source / case study link under a hairline. */
.rsd-fbc { container-type: inline-size; min-width: 0; }
.rsd-fbc__track {
  --rsd-fbc-gap: .75rem; --rsd-fbc-per: 1.08; --rsd-fbc-whole: 1;
  display: flex; gap: var(--rsd-fbc-gap); margin: 0; padding: 0 0 .5rem;
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-behavior: auto;
  scrollbar-width: thin; scrollbar-color: var(--rsd-line) transparent;
}
.rsd-fbc.is-enhanced .rsd-fbc__track { scrollbar-width: none; }
.rsd-fbc.is-enhanced .rsd-fbc__track::-webkit-scrollbar { display: none; }
/* Scripted: the track is one strip inside a clipping viewport, moved as a
   unit by a transform transition (no scrolling, no card ever reordered);
   .is-jumping drops the transition for the silent reset after a loop step
   and while a finger drags. Vertical page scrolling stays with the browser. */
.rsd-fbc__viewport { overflow: hidden; touch-action: pan-y; }
.rsd-fbc.is-enhanced .rsd-fbc__track { overflow: visible; scroll-snap-type: none; transition: transform .6s cubic-bezier(.65, 0, .35, 1); }
.rsd-fbc.is-enhanced .rsd-fbc__track.is-jumping { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .rsd-fbc.is-enhanced .rsd-fbc__track { transition: none; }
}
.rsd-fbc__track:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
.rsd-fbc__slide {
  display: flex; flex: 0 0 calc((100% - var(--rsd-fbc-gap) * var(--rsd-fbc-whole)) / var(--rsd-fbc-per));
  min-width: 0; scroll-snap-align: start; container-type: inline-size;
}
@container (min-width: 32rem) { .rsd-fbc__track { --rsd-fbc-per: 1.35; } }
@container (min-width: 44rem) { .rsd-fbc__track { --rsd-fbc-gap: 1rem; --rsd-fbc-per: 1.8; } }
@container (min-width: 52rem) { .rsd-fbc__track { --rsd-fbc-per: 2.05; --rsd-fbc-whole: 2; } }
@container (min-width: 60rem) { .rsd-fbc__track { --rsd-fbc-per: 2.2; --rsd-fbc-whole: 2; } }
@container (min-width: 72rem) { .rsd-fbc__track { --rsd-fbc-per: 2.4; --rsd-fbc-whole: 2; } }

/* The square card. Its type and spacing scale with its own width (cqi),
   so every card size keeps the same proportions. */
.rsd-fbc__card {
  --rsd-fbc-pad: clamp(1.25rem, 7cqi, 2.25rem);
  position: relative; display: flex; flex-direction: column; width: 100%; min-width: 0; aspect-ratio: 1 / 1;
  padding: var(--rsd-fbc-pad); color: var(--rsd-charcoal);
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-fbc__card::before { content: ""; position: absolute; top: -1px; left: var(--rsd-fbc-pad); width: 2.25rem; height: 2px; background: var(--rsd-red); }
.rsd-fbc__card:is(:hover, :focus-within) { border-color: color-mix(in srgb, var(--rsd-red) 30%, var(--rsd-line)); }
.rsd-fbc__label {
  display: block; margin-bottom: clamp(.75rem, 4.5cqi, 1.4rem);
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .68rem; line-height: 1.2;
  letter-spacing: .14em; text-transform: uppercase; color: var(--rsd-muted);
}
/* Without JS a card whose quote does not fit grows rather than clip; with
   JS (.is-enhanced) it stays square and the script fits the quote (one or
   two smaller steps, then — last resort — a whole-line clamp; the full
   quote stays in the DOM for screen readers and on its case study). */
.rsd-fbc__figure { display: flex; flex: 1; flex-direction: column; margin: 0; }
.rsd-fbc.is-enhanced .rsd-fbc__figure { min-height: 0; }
.rsd-fbc .rsd-fbc__quote p.is-clamped { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
.rsd-fbc .rsd-fbc__quote { margin: 0; padding: 0; border: 0; font-size: inherit; }
.rsd-fbc .rsd-fbc__quote p {
  margin: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); letter-spacing: -0.01em;
  color: inherit; overflow-wrap: break-word; text-wrap: pretty;
}
/* Quote tiers by length (rsd_client_feedback_tier()). */
.rsd-fbc .rsd-fbc__quote--short p { font-size: calc(clamp(1.1rem, 6.2cqi, 1.75rem) * var(--rsd-fbc-fit, 1)); line-height: 1.28; }
.rsd-fbc .rsd-fbc__quote--medium p { font-size: calc(clamp(.95rem, 4.8cqi, 1.35rem) * var(--rsd-fbc-fit, 1)); line-height: 1.38; }
.rsd-fbc .rsd-fbc__quote--long p { font-weight: var(--rsd-weight-medium); font-size: calc(clamp(.85rem, 4cqi, 1.12rem) * var(--rsd-fbc-fit, 1)); line-height: 1.45; letter-spacing: 0; }
.rsd-fbc .rsd-fbc__quote--xlong p { font-weight: 400; font-size: calc(clamp(.8rem, 3.5cqi, 1rem) * var(--rsd-fbc-fit, 1)); line-height: 1.45; letter-spacing: 0; }
/* The attribution, anchored to the bottom of the card. */
.rsd-fbc__by { display: flex; align-items: center; gap: .7rem; margin-top: auto; padding-top: clamp(.75rem, 4cqi, 1.25rem); }
.rsd-fbc__portrait { flex: none; width: 2.25rem; height: 2.25rem; border-radius: 50%; object-fit: cover; background: var(--rsd-line); }
.rsd-fbc__who { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.rsd-fbc__name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: clamp(.875rem, 3.6cqi, 1rem); line-height: 1.3; overflow-wrap: break-word; }
.rsd-fbc__role { font-size: clamp(.75rem, 3cqi, .82rem); line-height: 1.35; color: var(--rsd-muted); overflow-wrap: break-word; }
.rsd-fbc .rsd-fbc__foot {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem 1rem;
  margin: clamp(.6rem, 3cqi, .9rem) 0 0; padding-top: clamp(.6rem, 3cqi, .9rem); border-top: 1px solid var(--rsd-line);
  font-size: .75rem; line-height: 1.3;
}
.rsd-fbc__source { font-family: var(--rsd-mono); font-size: .66rem; letter-spacing: .04em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-fbc .rsd-fbc__foot a.rsd-fbc__case { margin-left: auto; font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); text-decoration: none; }
.rsd-fbc__arrow { display: inline-block; }
.rsd-fbc__case:is(:hover, :focus-visible) .rsd-fbc__arrow { color: var(--rsd-red); transform: translateX(3px); }
/* Small cards (phones): the label, attribution and foot sit a little
   tighter, leaving the quote more of the square. */
@container (max-width: 20rem) {
  .rsd-fbc__label { margin-bottom: .6rem; }
  .rsd-fbc__by { padding-top: .6rem; }
  .rsd-fbc .rsd-fbc__foot { margin-top: .5rem; padding-top: .5rem; }
}

/* Position + previous / next, under the track. Hidden (space kept) until
   the script runs; hidden outright when every card already fits. */
.rsd-fbc__controls { display: flex; align-items: center; gap: .5rem; margin-top: 1rem; }
.rsd-fbc__controls[hidden] { display: none; }
.rsd-fbc:not(.is-enhanced) .rsd-fbc__controls { visibility: hidden; }
.rsd-fbc__count { margin-right: auto; font-family: var(--rsd-mono); font-size: .72rem; letter-spacing: .06em; color: var(--rsd-muted); }
.rsd-fbc__current { font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); }
.rsd-fbc__nav {
  display: inline-flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; margin: 0; padding: 0;
  font: inherit; font-size: 1rem; line-height: 1; color: var(--rsd-charcoal); cursor: pointer;
  background: transparent; border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-fbc__nav:hover { color: var(--rsd-red); border-color: color-mix(in srgb, var(--rsd-red) 40%, var(--rsd-line)); }
.rsd-fbc__nav:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
@media (min-width: 768px) { .rsd-fbc__nav { width: 2.5rem; height: 2.5rem; } }
/* Autoplay Pause / Play (added by the script): two hairline bars, or a small
   play triangle when paused — the Industries carousel's pause control. */
/* Same 40px look as Previous / Next from 768px, with a 44px hit area. */
.rsd-fbc__nav--pause { position: relative; }
.rsd-fbc__nav--pause::after { content: ""; position: absolute; inset: min(0px, calc((100% - 2.75rem) / 2)); }
.rsd-fbc__nav--pause span { display: inline-flex; gap: 3px; }
.rsd-fbc__nav--pause span::before, .rsd-fbc__nav--pause span::after { content: ""; width: 2px; height: 10px; background: currentColor; }
.rsd-fbc__nav--pause.is-paused span { gap: 0; }
.rsd-fbc__nav--pause.is-paused span::before { width: 0; height: 0; background: none; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent currentColor; }
.rsd-fbc__nav--pause.is-paused span::after { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-fbc__card { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-fbc__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-fbc__nav { transition: color var(--rsd-motion-fast) var(--rsd-ease-out), border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* Charcoal section: a faint light surface instead of white. */
.rsd-section--bg-charcoal .rsd-fbc__card { color: var(--rsd-paper); background: rgba(247, 246, 244, .04); border-color: rgba(247, 246, 244, .14); }
.rsd-section--bg-charcoal .rsd-fbc :is(.rsd-fbc__label, .rsd-fbc__role, .rsd-fbc__source, .rsd-fbc__count) { color: rgba(247, 246, 244, .72); }
.rsd-section--bg-charcoal .rsd-fbc .rsd-fbc__foot { border-top-color: rgba(247, 246, 244, .14); }
.rsd-section--bg-charcoal .rsd-fbc .rsd-fbc__foot a.rsd-fbc__case, .rsd-section--bg-charcoal .rsd-fbc__current { color: var(--rsd-paper); }
.rsd-section--bg-charcoal .rsd-fbc__nav { color: var(--rsd-paper); border-color: rgba(247, 246, 244, .24); }

/* ---------------------------------------------------------- Insights
   redsprout-digital/insights (inc/insights-block.php). Real posts only: the
   first featured (16:10 image box when it has a featured image, set
   text-first when it has none), the rest as compact, hairline-ruled text
   entries — beside it from 1024px, a two-column list on tablets, stacked
   on phones. Each article is one link: the title's link stretches over the
   article (::after), keyboard focus outlines the article. Hover: the image
   eases to 1.02 and the arrow nudges — on the <img>/arrow, never the
   article, whose transform the reveal engine owns. */
.rsd-ins { display: grid; gap: 2rem; margin-top: var(--rsd-gap); }
.rsd-ins__item { position: relative; min-width: 0; }
.rsd-ins__media {
  overflow: hidden; aspect-ratio: 16 / 10;
  border-radius: calc(var(--rsd-radius) * 1.5); background: var(--rsd-line);
}
.rsd-ins__img { display: block; width: 100%; height: 100%; object-fit: cover; }
.rsd-ins__media + .rsd-ins__body { margin-top: 1.25rem; }
.rsd-ins .rsd-ins__meta {
  display: flex; flex-wrap: wrap; align-items: baseline; margin: 0 0 .6rem;
  font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); letter-spacing: .05em; text-transform: uppercase;
  color: var(--rsd-muted);
}
.rsd-ins__meta > * + *::before { content: "·"; margin-inline: .5rem; }
.rsd-ins__cat { color: var(--rsd-red); font-weight: var(--rsd-weight-semibold); }
.rsd-ins .rsd-ins__title {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-lg);
  font-weight: var(--rsd-weight-semibold); line-height: 1.25; letter-spacing: -0.01em;
}
.rsd-ins__item--featured .rsd-ins__title { font-size: calc((var(--rsd-t-h3) + var(--rsd-t-h2)) / 2); line-height: 1.15; max-width: 26ch; }
.rsd-ins .rsd-ins__link { position: static; color: inherit; text-decoration: none; }
.rsd-ins .rsd-ins__link::after { content: ""; position: absolute; inset: 0; }
.rsd-ins .rsd-ins__link:focus-visible { outline: none; }
.rsd-ins .rsd-ins__link:focus-visible::after { outline: 2px solid var(--rsd-red); outline-offset: 4px; border-radius: 2px; }
.rsd-ins .rsd-ins__excerpt { margin: .6rem 0 0; max-width: 60ch; font-size: var(--rsd-t-sm); line-height: 1.6; color: var(--rsd-muted); }
.rsd-ins__item--featured .rsd-ins__excerpt { font-size: var(--rsd-t-base); }
.rsd-ins__more {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: .9rem;
  font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold);
}
.rsd-ins__arrow { display: inline-block; }
.rsd-ins__item:is(:hover, :focus-within) .rsd-ins__arrow { transform: translateX(3px); }
.rsd-ins__item:hover .rsd-ins__img { transform: scale(1.02); }
.rsd-ins__item:hover .rsd-ins__title { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .2em; }
/* A featured post without an image: text-first, under a rule. */
.rsd-ins__item--text { padding-top: 1.5rem; border-top: 2px solid currentColor; }
.rsd-ins__list > .rsd-ins__item { padding-top: 1.25rem; border-top: 1px solid var(--rsd-line); }
.rsd-ins__all { margin: 0; }
.rsd-ins__all .rsd-btn { gap: .45rem; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-ins__img { transition: transform .6s var(--rsd-ease-out); }
  .rsd-ins__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* On a Charcoal section the muted grey would lose contrast. */
.rsd-section--bg-charcoal .rsd-ins :is(.rsd-ins__meta, .rsd-ins__excerpt) { color: rgba(247, 246, 244, .72); }

/* Latest insights: under the feature and its "View all", a hairline, a
   compact head and the four newest posts as cards — the same meta, title,
   excerpt and "Read article" as above, over a 16:10 image box (the
   rsd-card crop; the blog's placeholder when a post has no image). The
   body is a column so "Read article" lines up along the row's bottom. */
.rsd-ins__latest { padding-top: clamp(2rem, 4vw, 3rem); border-top: 1px solid var(--rsd-line); }
.rsd-ins__latest-head { margin-bottom: clamp(1.5rem, 3vw, 2rem); }
.rsd-ins__latest-head .rsd-eyebrow { margin: 0 0 .6rem; }
.rsd-ins .rsd-ins__latest-title {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-h3);
  font-weight: var(--rsd-weight-semibold); line-height: 1.2; letter-spacing: -0.01em;
}
.rsd-ins__grid { display: grid; gap: 2.25rem var(--rsd-gap); }
.rsd-ins__item--card { display: flex; flex-direction: column; }
.rsd-ins .rsd-ins__item--card .rsd-ins__media + .rsd-ins__body { margin-top: 1rem; }
.rsd-ins__item--card .rsd-ins__body { display: flex; flex: 1; flex-direction: column; }
.rsd-ins .rsd-ins__item--card .rsd-ins__title { overflow-wrap: break-word; }
.rsd-ins .rsd-ins__item--card .rsd-ins__excerpt {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.rsd-ins__item--card .rsd-ins__more { margin-top: auto; padding-top: .9rem; }
.rsd-ins__media > .rsd-thumb-placeholder { height: 100%; aspect-ratio: auto; border-radius: inherit; }
@media (min-width: 768px) {
  .rsd-ins__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .rsd-ins__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem clamp(1.25rem, 2vw, 2rem); }
}

/* Tablet: the compact entries as a two-column list under the feature. */
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-ins__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem var(--rsd-gap); }
  .rsd-ins__item--featured .rsd-ins__media { aspect-ratio: 21 / 9; }
}
@media (max-width: 767px) {
  .rsd-ins__list { display: grid; gap: 1.5rem; }
}
/* Desktop: feature | compact entries. A lone post sets image | copy. */
@media (min-width: 1024px) {
  .rsd-ins:not(.rsd-ins--solo) { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
  .rsd-ins__list { display: grid; gap: 1.5rem; }
  .rsd-ins__list > .rsd-ins__item:first-child { padding-top: 0; border-top: 0; }
  .rsd-ins__all { grid-column: 1 / -1; }
  .rsd-ins--solo .rsd-ins__item--featured:not(.rsd-ins__item--text) {
    display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
  }
  .rsd-ins--solo .rsd-ins__media + .rsd-ins__body { margin-top: 0; }
}

/* ---------------------------------------------------------- FAQ
   redsprout-digital/faq (inc/faq-block.php; behaviour assets/js/faq.js;
   editor assets/js/faq-editor.js, same classes). Hairline-ruled rows:
   number | question | a thin plus that becomes a minus. The answer opens
   with the grid-template-rows 0fr → 1fr technique the footer accordion
   already uses; while closed it is visibility:hidden, so it is out of the
   tab order and the accessibility tree too. Hover only tints the row. From
   1024px the section head sits beside the list. Deliberately not `.rsd-faq`
   (M12 / content FAQs keep those rules). */
.rsd-qa { margin-top: var(--rsd-gap); }
.rsd-qa__list { border-top: 1px solid var(--rsd-line); }
.rsd-qa__item { border-bottom: 1px solid var(--rsd-line); }
.rsd-qa .rsd-qa__q { margin: 0; font: inherit; letter-spacing: inherit; color: inherit; }
.rsd-qa__btn {
  appearance: none; display: grid; grid-template-columns: 2.25rem minmax(0, 1fr) 1rem;
  column-gap: .9rem; align-items: baseline; width: 100%; min-height: 3.5rem;
  margin: 0; padding: 1.15rem .5rem; background: none; border: 0; border-radius: 0;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.rsd-qa .rsd-qa__btn:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
.rsd-qa__btn:hover { background: color-mix(in srgb, currentColor 4%, transparent); }
.rsd-qa__num { font-family: var(--rsd-mono); font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold); font-variant-numeric: tabular-nums; color: var(--rsd-red); }
.rsd-qa__text { font-family: var(--rsd-display); font-size: var(--rsd-t-lg); font-weight: var(--rsd-weight-semibold); line-height: 1.3; letter-spacing: -0.01em; }
.rsd-qa__icon { position: relative; align-self: center; width: 1rem; height: 1rem; }
.rsd-qa__icon::before, .rsd-qa__icon::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1.5px; margin-top: -.75px; background: currentColor;
}
.rsd-qa__icon::after { transform: rotate(90deg); }
.rsd-qa__item.is-open .rsd-qa__icon::after { transform: rotate(0deg); }
.rsd-qa__panel { display: grid; grid-template-rows: 0fr; visibility: hidden; }
.rsd-qa__item.is-open .rsd-qa__panel { grid-template-rows: 1fr; visibility: visible; }
.rsd-qa__clip { min-height: 0; overflow: hidden; }
.rsd-qa .rsd-qa__answer {
  margin: 0; max-width: 64ch; padding: 0 .5rem 1.4rem calc(.5rem + 2.25rem + .9rem);
  font-size: var(--rsd-t-base); line-height: 1.65; color: var(--rsd-muted);
}
.rsd-qa__more { margin: 1.5rem 0 0; }
.rsd-qa__more .rsd-btn { gap: .45rem; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-qa__btn { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-qa__icon::after { transition: transform var(--rsd-motion-base) var(--rsd-ease-out); }
  /* Closing: rows shrink, then visibility drops once they have. Opening:
     visibility returns at once, then rows grow. */
  .rsd-qa__panel { transition: grid-template-rows var(--rsd-motion-base) var(--rsd-ease-out), visibility 0s linear var(--rsd-motion-base); }
  .rsd-qa__item.is-open .rsd-qa__panel { transition-delay: 0s; }
}
/* On a Charcoal section the muted grey would lose contrast. */
.rsd-section--bg-charcoal .rsd-qa .rsd-qa__answer { color: rgba(247, 246, 244, .78); }
.rsd-section--bg-charcoal .rsd-qa__num { color: rgba(247, 246, 244, .72); }

@media (max-width: 767px) {
  .rsd-qa__btn { grid-template-columns: 1.75rem minmax(0, 1fr) 1rem; column-gap: .75rem; padding-block: 1rem; }
  .rsd-qa .rsd-qa__answer { padding-left: calc(.5rem + 1.75rem + .75rem); }
}
/* Desktop: the section head beside the questions (only when there is a head). */
@media (min-width: 1024px) {
  .rsd-block-section:has(> .rsd-section-head + .rsd-qa) {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem); align-items: start;
  }
  .rsd-block-section:has(> .rsd-section-head + .rsd-qa) > .rsd-section-head { margin-bottom: 0; }
  .rsd-section-head + .rsd-qa { margin-top: 0; }
}

/* ---------------------------------------------------------- Glossary
   redsprout-digital/glossary (inc/glossary-block.php; behaviour
   assets/js/glossary.js; editor assets/js/glossary-editor.js). An
   editorial list, not cards: tools (search, category, letters, count +
   clear) over letter groups of hairline-ruled terms. A closed term shows a
   two-line preview of its definition (the full text is in the HTML; the
   clamp is visual only); open, the definition shows in full, the related
   link eases in (the FAQ's 0fr → 1fr technique — out of the tab order
   while closed) and a thin red rule marks the row; the chevron turns (a
   shape cue, with aria-expanded). Every control is at least 44px. The
   section head sits above the glossary and everything uses the full
   container width. Phones: the letters scroll sideways inside their row.
   Motion only under no-preference; the one-time scroll reveal is the
   global engine's (assets/js/scroll-reveal.js, "Glossary"). */
.rsd-gl { margin-top: var(--rsd-gap); }
.rsd-gl__tools { display: grid; gap: .75rem; margin-bottom: 1.25rem; }
.rsd-gl__fields { display: flex; flex-wrap: wrap; gap: .5rem; }
.rsd-gl__search { position: relative; flex: 1 1 14rem; min-width: 0; }
.rsd-gl__search::before, .rsd-gl__search::after { content: ""; position: absolute; pointer-events: none; }
.rsd-gl__search::before { top: 50%; left: .9rem; width: .7rem; height: .7rem; margin-top: -.45rem; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
.rsd-gl__search::after { top: 50%; left: 1.52rem; width: 1.5px; height: .4rem; margin-top: .1rem; background: var(--rsd-muted); transform: rotate(-45deg); }
.rsd-gl__cat { position: relative; flex: 0 1 13rem; min-width: 0; }
.rsd-gl__cat::after {
  content: ""; position: absolute; top: 50%; right: .95rem; width: .4rem; height: .4rem; margin-top: -.3rem; pointer-events: none;
  border-right: 1.5px solid var(--rsd-charcoal); border-bottom: 1.5px solid var(--rsd-charcoal); transform: rotate(45deg);
}
.rsd-gl__input, .rsd-gl__select {
  -webkit-appearance: none; appearance: none; display: block; width: 100%; min-height: var(--rsd-tap-target); margin: 0; padding: .55rem .85rem;
  font: inherit; font-size: var(--rsd-t-sm); line-height: 1.4; color: var(--rsd-charcoal);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-gl__input { padding-left: 2.35rem; }
.rsd-gl__input::placeholder { color: var(--rsd-muted); opacity: 1; }
.rsd-gl__input::-webkit-search-cancel-button { cursor: pointer; }
.rsd-gl__select { padding-right: 2.25rem; cursor: pointer; }
.rsd-gl__input:hover, .rsd-gl__select:hover { border-color: var(--rsd-muted); }
.rsd-gl__letters { display: flex; flex-wrap: wrap; gap: .25rem; }
.rsd-gl__letter-btn {
  -webkit-appearance: none; appearance: none; flex: none; min-width: var(--rsd-tap-target); min-height: var(--rsd-tap-target); margin: 0; padding: 0 .6rem;
  font-family: var(--rsd-mono); font-size: .8rem; font-weight: var(--rsd-weight-semibold); line-height: 1; color: var(--rsd-charcoal);
  background: transparent; border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius); cursor: pointer;
}
.rsd-gl__letter-btn:hover { border-color: var(--rsd-charcoal); }
.rsd-gl__letter-btn[aria-pressed="true"] { color: var(--rsd-white); background: var(--rsd-charcoal); border-color: var(--rsd-charcoal); }
.rsd-gl__bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 1rem; }
.rsd-gl .rsd-gl__status { margin: 0; font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); letter-spacing: .04em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-gl__reset {
  -webkit-appearance: none; appearance: none; min-height: var(--rsd-tap-target); margin: 0; padding: 0 .25rem; background: none; border: 0;
  font: inherit; font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--rsd-red); text-underline-offset: 3px;
}
.rsd-gl__reset:disabled { visibility: hidden; } /* keeps its space: nothing shifts */
.rsd-gl__group + .rsd-gl__group { margin-top: 1.75rem; }
.rsd-gl .rsd-gl__letter {
  margin: 0; padding-bottom: .5rem; border-bottom: 1px solid var(--rsd-line);
  font-family: var(--rsd-display); font-size: var(--rsd-t-h3); font-weight: var(--rsd-weight-semibold); line-height: 1; letter-spacing: -.01em; color: var(--rsd-red);
}
.rsd-gl .rsd-gl__terms { margin: 0; padding: 0; }
.rsd-gl__item { border-bottom: 1px solid var(--rsd-line); }
.rsd-gl .rsd-gl__dt { margin: 0; font: inherit; }
.rsd-gl__btn {
  -webkit-appearance: none; appearance: none; display: grid; grid-template-columns: minmax(0, 1fr) auto 1rem; align-items: center; column-gap: .75rem;
  width: 100%; min-height: var(--rsd-tap-target); margin: 0; padding: .95rem .6rem .3rem; background: none; border: 0; border-radius: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.rsd-gl .rsd-gl__btn:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
.rsd-gl__btn:hover { background: color-mix(in srgb, currentColor 4%, transparent); }
.rsd-gl__term { min-width: 0; font-family: var(--rsd-display); font-size: 1.125rem; font-weight: var(--rsd-weight-semibold); line-height: 1.3; letter-spacing: -.01em; overflow-wrap: anywhere; }
.rsd-gl__tag {
  max-width: 12rem; overflow: hidden; padding: .1rem .45rem; font-family: var(--rsd-mono); font-size: .68rem; line-height: 1.4; letter-spacing: .05em;
  text-transform: uppercase; text-overflow: ellipsis; white-space: nowrap; color: var(--rsd-muted); border: 1px solid var(--rsd-line); border-radius: 3px;
}
.rsd-gl__icon { grid-column: 3; justify-self: center; width: .5rem; height: .5rem; margin-top: -.25rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); }
.rsd-gl__item.is-open .rsd-gl__icon { margin-top: .25rem; transform: rotate(-135deg); }
.rsd-gl .rsd-gl__dd { margin: 0; padding: 0 .6rem 1rem; }
.rsd-gl .rsd-gl__def {
  display: -webkit-box; margin: 0; max-width: 64ch; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  font-size: var(--rsd-t-sm); line-height: 1.6; color: var(--rsd-muted); cursor: pointer;
}
.rsd-gl__item.is-open { box-shadow: inset 2px 0 0 var(--rsd-red); }
.rsd-gl__item.is-open .rsd-gl__def { display: block; -webkit-line-clamp: none; color: var(--rsd-charcoal); cursor: auto; }
.rsd-gl__panel { display: grid; grid-template-rows: 0fr; visibility: hidden; }
.rsd-gl__item.is-open .rsd-gl__panel { grid-template-rows: 1fr; visibility: visible; }
.rsd-gl__clip { min-height: 0; overflow: hidden; }
.rsd-gl .rsd-gl__more { margin: .75rem 0 0; font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold); }
.rsd-gl .rsd-gl__empty { margin: 0; padding: 1.5rem .6rem; font-size: var(--rsd-t-sm); color: var(--rsd-muted); border-top: 1px solid var(--rsd-line); border-bottom: 1px solid var(--rsd-line); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-gl__btn, .rsd-gl__letter-btn, .rsd-gl__input, .rsd-gl__select { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out), border-color var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-gl__icon { transition: transform var(--rsd-motion-base) var(--rsd-ease-out), margin var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-gl__item { transition: box-shadow var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-gl__item.is-open .rsd-gl__def { animation: rsd-gl-in var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-gl__panel { transition: grid-template-rows var(--rsd-motion-base) var(--rsd-ease-out), visibility 0s linear var(--rsd-motion-base); }
  .rsd-gl__item.is-open .rsd-gl__panel { transition-delay: 0s; }
}
@keyframes rsd-gl-in { from { opacity: .55; } to { opacity: 1; } }
/* On a Charcoal section: paper text, the pressed letter inverted. */
.rsd-section--bg-charcoal .rsd-gl :is(.rsd-gl__def, .rsd-gl__status, .rsd-gl__tag) { color: rgba(247, 246, 244, .78); }
.rsd-section--bg-charcoal .rsd-gl__item.is-open .rsd-gl__def { color: var(--rsd-paper); }
.rsd-section--bg-charcoal .rsd-gl__letter-btn { color: var(--rsd-paper); border-color: rgba(247, 246, 244, .35); }
.rsd-section--bg-charcoal .rsd-gl__letter-btn[aria-pressed="true"] { color: var(--rsd-charcoal); background: var(--rsd-paper); border-color: var(--rsd-paper); }
.rsd-section--bg-charcoal .rsd-gl__reset { color: var(--rsd-paper); }
@media (max-width: 767px) {
  /* The letters stay one row and scroll inside it. */
  .rsd-gl__letters { flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; padding-bottom: .25rem; }
  .rsd-gl__cat { flex: 1 1 100%; }
}
@media (max-width: 599px) {
  .rsd-gl__btn { grid-template-columns: minmax(0, 1fr) 1rem; padding-inline: .4rem; }
  .rsd-gl__tag { grid-row: 2; justify-self: start; margin-top: .3rem; }
  .rsd-gl__icon { grid-row: 1; grid-column: 2; }
  .rsd-gl .rsd-gl__dd { padding-inline: .4rem; }
}
/* Full width at every size: the head above, the tools and the terms across
   the whole container (no side column). The search keeps a comfortable
   width rather than stretching edge to edge; definitions keep their 64ch
   reading measure inside full-width rows. */
@media (min-width: 768px) {
  .rsd-gl__search { flex: 0 1 36rem; }
}

/* ---------------------------------------------------------- Why RedSprout
   redsprout-digital/why-redsprout (inc/why-redsprout-block.php; behaviour
   assets/js/why-redsprout.js). One window in the Hero visuals' language
   (white surface, hairline border, 8px radius, a quiet shadow) holding
   the system: five equal capability nodes as one progression row, joined
   by a bus to the RedSprout core beneath, Improve returning along the base;
   a detail area under it repeats the active capability. Geometry follows
   the window's own width: below 30rem it becomes a vertical spine (core,
   01 ↓ … 05, Improve), with full-width rows — never a shrunken diagram.
   States: the active node gets a red top rule, red number and a filled
   marker (shape, not colour alone), its connector turns red; the others go
   paper with muted titles. Motion only under no-preference: 300ms state
   easing and the one-time signal. From 1024px the section head sits beside
   it (as the FAQ / Glossary heads do). */
.rsd-why {
  --why-cycle: 6s; --why-link: rgba(99, 99, 106, .45);
  container: rsd-why / inline-size;
  position: relative; max-width: 52rem; margin-top: var(--rsd-gap); overflow: hidden;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-shadow-subtle);
}
.rsd-why__top { display: flex; align-items: center; justify-content: space-between; gap: .75rem; padding: .55rem 1.1rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-why__brand { display: inline-flex; align-items: center; gap: .5rem; font-family: var(--rsd-display); font-size: .82rem; font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); }
.rsd-why__brand i { width: 10px; height: 10px; border-radius: 2px; background: var(--rsd-red); }
.rsd-why__tag { padding: 0 .4rem; font-family: var(--rsd-mono); font-size: .66rem; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap; color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px; }
.rsd-why__map { display: flex; flex-direction: column; padding: 1.4rem 1.25rem 1.1rem; }
.rsd-why__list { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .5rem; margin: 0; padding: 0; list-style: none; }
.rsd-why__item { position: relative; min-width: 0; margin: 0; }
.rsd-why__node {
  -webkit-appearance: none; appearance: none; position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: .4rem;
  width: 100%; height: 100%; min-height: 5rem; margin: 0; padding: .7rem .65rem .75rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.rsd-why__node:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
.rsd-why__num { font-family: var(--rsd-mono); font-size: .68rem; font-weight: var(--rsd-weight-semibold); line-height: 1; color: var(--rsd-muted); }
.rsd-why__title { font-family: var(--rsd-display); font-size: .9rem; font-weight: var(--rsd-weight-semibold); line-height: 1.2; color: var(--rsd-charcoal); overflow-wrap: break-word; }
.rsd-why__mark { position: absolute; top: .7rem; right: .65rem; width: 8px; height: 8px; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
/* Descriptions: each node's accessible description; shown inline only without JavaScript (<noscript>). */
.rsd-why__desc { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; font-size: var(--rsd-t-sm); line-height: 1.5; color: var(--rsd-muted); }
.rsd-why__node:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-why__node.is-on { box-shadow: inset 0 2px 0 var(--rsd-red); }
.rsd-why__node:is(.is-on, .is-sweep) .rsd-why__num { color: var(--rsd-red); }
.rsd-why__node:is(.is-on, [aria-pressed="true"]) .rsd-why__mark { background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-why.has-cur .rsd-why__node:not(.is-on) { background: var(--rsd-paper); }
.rsd-why.has-cur .rsd-why__node:not(.is-on) .rsd-why__title { color: var(--rsd-muted); }
/* The bus: the progression line under the nodes (the signal's track) and a
   connector from every node down to the core. */
.rsd-why__bus { position: relative; height: 2.6rem; }
.rsd-why__links { display: block; width: 100%; height: 100%; }
.rsd-why__link { stroke: var(--why-link); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rsd-why__link:is(.is-on, .is-sweep) { stroke: var(--rsd-red); stroke-width: 1.5; }
.rsd-why__track { position: absolute; top: 38%; left: 10%; right: 10%; height: 1px; background: var(--why-link); }
/* The progression: a small chevron in each gap, 01 → 02 → … → 05. */
.rsd-why__item:not(:last-child)::after {
  content: ""; position: absolute; z-index: 2; top: 50%; right: -.42rem; width: .32rem; height: .32rem; margin-top: -.16rem;
  border-top: 1.5px solid var(--rsd-muted); border-right: 1.5px solid var(--rsd-muted); transform: rotate(45deg);
}
.rsd-why__sig { position: absolute; top: 0; left: 0; width: 100%; height: 0; opacity: 0; pointer-events: none; }
.rsd-why__sig::before { content: ""; position: absolute; top: -3px; left: -3.5px; width: 7px; height: 7px; border-radius: 50%; background: var(--rsd-red); }
.rsd-why__core {
  position: relative; z-index: 1; display: inline-flex; align-self: center; align-items: center; gap: .55rem; padding: .55rem 1rem;
  color: var(--rsd-paper); background: var(--rsd-charcoal); border-top: 2px solid var(--rsd-red); border-radius: 6px;
}
.rsd-why__core i { width: 8px; height: 8px; border-radius: 2px; background: var(--rsd-red); }
.rsd-why__core b { font-family: var(--rsd-display); font-size: .74rem; font-weight: var(--rsd-weight-semibold); letter-spacing: .12em; text-transform: uppercase; }
.rsd-why__core small { font-family: var(--rsd-mono); font-size: .62rem; letter-spacing: .04em; color: rgba(247, 246, 244, .72); }
/* Improve: the return from Intelligence back to Strategy, under the core. */
.rsd-why .rsd-why__improve { position: relative; display: flex; justify-content: center; margin: -.9rem 0 0; padding-top: 1.55rem; font-family: var(--rsd-mono); font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-why__return { position: absolute; top: 0; left: 10%; right: 10%; height: 1.95rem; border: 1px dashed var(--why-link); border-top: 0; border-radius: 0 0 8px 8px; }
.rsd-why__return::before { content: ""; position: absolute; top: -1px; left: -4px; border-style: solid; border-width: 0 3.5px 5px; border-color: transparent transparent var(--why-link); }
.rsd-why__improve b { position: relative; z-index: 1; margin-top: .55rem; padding: 0 .5rem; font-weight: var(--rsd-weight-semibold); background: var(--rsd-white); }
.rsd-why__improve:is(.is-on, .is-sweep) { color: var(--rsd-red); }
.rsd-why__improve:is(.is-on, .is-sweep) .rsd-why__return { border-color: var(--rsd-red); }
.rsd-why__improve:is(.is-on, .is-sweep) .rsd-why__return::before { border-bottom-color: var(--rsd-red); }
/* Detail: every entry stacked in one cell; only the current one shows. */
.rsd-why__detail { display: grid; padding: .85rem 1.25rem 1rem; border-top: 1px solid var(--rsd-line); }
.rsd-why .rsd-why__dt { grid-area: 1 / 1; display: grid; align-content: start; gap: .25rem; margin: 0; visibility: hidden; opacity: 0; }
.rsd-why .rsd-why__dt.is-shown { visibility: visible; opacity: 1; }
.rsd-why__dl { font-family: var(--rsd-mono); font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-red); }
.rsd-why__dd { font-size: var(--rsd-t-sm); line-height: 1.55; color: var(--rsd-charcoal); }
/* Under the description (secondary): the capability's three items as small
   bordered labels; they fade with their entry. Then (tertiary) one quiet
   system line below every entry. */
.rsd-why .rsd-why__caps { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0 0; padding: 0; list-style: none; }
.rsd-why .rsd-why__caps li {
  display: inline-flex; align-items: center; gap: .4rem; margin: 0; padding: .2rem .55rem;
  font-size: .74rem; line-height: 1.35; color: var(--rsd-charcoal); background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 4px;
}
.rsd-why .rsd-why__caps li::before { content: ""; flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-red); }
.rsd-why .rsd-why__outcome { grid-row: 2; margin: .85rem 0 0; padding-top: .65rem; border-top: 1px dashed var(--rsd-line); font-family: var(--rsd-mono); font-size: .68rem; line-height: 1.5; letter-spacing: .04em; color: var(--rsd-muted); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-why__node, .rsd-why__node *, .rsd-why__link, .rsd-why__improve, .rsd-why__return { transition: background-color var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-base) var(--rsd-ease-out), color var(--rsd-motion-base) var(--rsd-ease-out), box-shadow var(--rsd-motion-base) var(--rsd-ease-out), stroke var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-why .rsd-why__dt { transition: opacity var(--rsd-motion-base) var(--rsd-ease-out), visibility var(--rsd-motion-base); }
  /* Node i lights at i/6 of the cycle (why-redsprout.js), Improve at 5/6:
     the dot reaches node i (i/4 of the track) at the same moment. */
  .rsd-why.is-playing .rsd-why__sig { animation: rsd-why-x calc(var(--why-cycle) * 4 / 6) linear 1 both; }
}
@keyframes rsd-why-x { 0% { transform: translateX(0); opacity: 0; } 6% { opacity: 1; } 94% { opacity: 1; } 100% { transform: translateX(100%); opacity: 0; } }
/* Narrow windows (phones): a vertical spine — the core, then 01 ↓ … 05,
   then Improve; rows full width (≥ 48px). */
@container rsd-why (max-width: 30rem) {
  .rsd-why__top, .rsd-why__detail { padding-inline: .9rem; }
  .rsd-why__map { padding: 1rem .9rem .9rem; }
  .rsd-why__core { order: -1; align-self: flex-start; margin-bottom: 1rem; }
  .rsd-why__bus { display: none; }
  .rsd-why__list { grid-template-columns: minmax(0, 1fr); gap: .75rem; }
  .rsd-why__item:not(:last-child)::after { display: none; }
  .rsd-why__item + .rsd-why__item::before { content: ""; position: absolute; top: -.75rem; left: 1.4rem; width: 1px; height: .75rem; background: var(--why-link); }
  .rsd-why__core::after { content: ""; position: absolute; top: 100%; left: 1.4rem; width: 1px; height: 1rem; background: var(--why-link); }
  .rsd-why__node { flex-direction: row; align-items: center; gap: .75rem; min-height: 3rem; padding: .6rem .8rem; }
  .rsd-why__num { flex: none; width: 1.25rem; }
  .rsd-why__title { flex: 1 1 auto; font-size: .95rem; }
  .rsd-why__mark { position: static; flex: none; }
  .rsd-why .rsd-why__improve { justify-content: flex-start; margin: .75rem 0 0; padding: 0 0 0 .55rem; }
  .rsd-why__return { display: none; }
  .rsd-why__improve b { margin: 0; padding: 0; }
  .rsd-why .rsd-why__improve::before { content: ""; position: absolute; top: -.75rem; left: 1.4rem; width: 1px; height: .75rem; background: var(--why-link); }
  /* Capability items as compact inline labels (dot-separated), not pills, so the detail stays short. */
  .rsd-why .rsd-why__caps { gap: .2rem .9rem; margin-top: .4rem; }
  .rsd-why .rsd-why__caps li { gap: .35rem; padding: 0; background: none; border: 0; }
  .rsd-why .rsd-why__outcome { margin-top: .7rem; padding-top: .55rem; }
}
@media (max-width: 1023px) {
  .rsd-block-section:has(> .rsd-section-head + .rsd-why) .rsd-why { margin-inline: 0; }
}
@media (min-width: 1024px) {
  .rsd-block-section:has(> .rsd-section-head + .rsd-why) {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem); align-items: center;
  }
  .rsd-block-section:has(> .rsd-section-head + .rsd-why) > .rsd-section-head { margin-bottom: 0; }
  .rsd-section-head + .rsd-why { margin-top: 0; }
}

/* ---------------------------------------------------------- FAQ — Digital System
   rsd_faq_system_visual() (inc/faq-block.php; exploration assets/js/faq.js).
   Three stages top to bottom — 01 Build / 02 Grow / 03 Understand — on
   white with hairline borders and 6px radius, joined by short connectors,
   and a thin red "Improve" rail looping from the last stage back to the
   first. Modules are small bordered buttons. Exploring (hover / focus /
   tap): the active stage's border and connectors warm to red, the other
   stages fade back, the caption line names the module. Transitions use
   the motion tokens (300ms; ~0 under reduced motion). After the questions
   below 1024px; from 1024px it sits under the head in the left column,
   the questions spanning both rows on the right. */
.rsd-sysmap { position: relative; max-width: 34rem; margin: var(--rsd-gap) 0 0; padding-right: 2.6rem; }
.rsd-sysmap__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .25rem 1rem; margin-bottom: .85rem; }
.rsd-sysmap__title { font-family: var(--rsd-mono); font-size: .75rem; font-weight: var(--rsd-weight-semibold); letter-spacing: .12em; text-transform: uppercase; color: var(--rsd-charcoal); }
.rsd-sysmap__flow { font-family: var(--rsd-mono); font-size: .7rem; letter-spacing: .04em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-sysmap__flow i { font-style: normal; color: var(--rsd-red); }
.rsd-sysmap__body { position: relative; }
.rsd-sysmap__stages { display: grid; gap: 1rem; margin: 0; padding: 0; list-style: none; }
.rsd-sysmap__stage {
  position: relative; display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); align-items: center; column-gap: 1rem;
  margin: 0; padding: .75rem .9rem; background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: 6px;
}
/* Connector to the next stage: a short line and a small arrowhead. */
.rsd-sysmap__stage:not(:last-child)::after {
  content: ""; position: absolute; left: 1.6rem; top: 100%; width: 1px; height: 1rem; background: var(--rsd-line);
}
.rsd-sysmap__stage:not(:last-child)::before {
  content: ""; position: absolute; left: calc(1.6rem - 3px); top: calc(100% + 1rem - 5px); z-index: 1;
  border-style: solid; border-width: 5px 3.5px 0; border-color: var(--rsd-line) transparent transparent;
}
.rsd-sysmap__label { grid-column: 1; margin: 0; font-family: var(--rsd-mono); font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-sysmap__num { font-weight: var(--rsd-weight-semibold); color: var(--rsd-red); }
.rsd-sysmap__name { grid-column: 1; margin: .15rem 0 0; font-family: var(--rsd-display); font-size: .95rem; font-weight: var(--rsd-weight-semibold); line-height: 1.25; color: var(--rsd-charcoal); }
.rsd-sysmap__mods { grid-column: 2; grid-row: 1 / span 2; display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.rsd-sysmap__mods li { margin: 0; }
.rsd-sysmap__mod {
  appearance: none; display: inline-flex; align-items: center; gap: .35rem; min-height: 2rem; margin: 0; padding: .3rem .6rem;
  font: inherit; font-size: .78rem; line-height: 1.2; color: var(--rsd-charcoal); cursor: pointer;
  background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 4px;
}
.rsd-sysmap__mod::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-line); }
.rsd-sysmap__mod:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
.rsd-sysmap__mod.is-active, .rsd-sysmap__mod[aria-pressed="true"] { border-color: var(--rsd-red); background: var(--rsd-white); }
.rsd-sysmap__mod.is-active::before, .rsd-sysmap__mod[aria-pressed="true"]::before { background: var(--rsd-red); }
/* The Improve loop: a red rail on the right from the last stage back up
   into the first, its arrowhead pointing into Build. */
.rsd-sysmap__loop {
  position: absolute; right: -1.5rem; top: 1.5rem; bottom: 1.5rem; width: 1.15rem;
  border: 1px solid var(--rsd-red); border-left: 0; border-radius: 0 6px 6px 0; opacity: .55;
}
.rsd-sysmap__loop::before {
  content: ""; position: absolute; top: -4px; left: -2px;
  border-style: solid; border-width: 3.5px 5px 3.5px 0; border-color: transparent var(--rsd-red) transparent transparent;
}
.rsd-sysmap__loop span {
  position: absolute; top: 50%; right: -1.05rem; transform: translateY(-50%) rotate(180deg); writing-mode: vertical-rl;
  font-family: var(--rsd-mono); font-size: .68rem; line-height: 1; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap;
  color: var(--rsd-red);
}
.rsd-sysmap__detail { display: flex; flex-wrap: wrap; gap: .15rem .5rem; min-height: 2.6rem; margin: .9rem 0 0; padding-top: .7rem; border-top: 1px solid var(--rsd-line); font-size: var(--rsd-t-sm); line-height: 1.45; }
.rsd-sysmap__detail-k { font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); }
.rsd-sysmap__detail-v { color: var(--rsd-muted); }
/* Exploring: the active stage leads, the others step back. */
.rsd-sysmap.is-exploring .rsd-sysmap__stage:not(.is-active) { opacity: .5; }
.rsd-sysmap__stage.is-active { border-color: color-mix(in srgb, var(--rsd-red) 55%, var(--rsd-line)); }
.rsd-sysmap__stage.is-active::after, .rsd-sysmap__stage:has(+ .is-active)::after { background: var(--rsd-red); }
.rsd-sysmap__stage.is-active::before, .rsd-sysmap__stage:has(+ .is-active)::before { border-top-color: var(--rsd-red); }
.rsd-sysmap[data-active="understand"] .rsd-sysmap__loop, .rsd-sysmap[data-active="build"] .rsd-sysmap__loop { opacity: 1; }
.rsd-sysmap.is-exploring:not([data-active="understand"]):not([data-active="build"]) .rsd-sysmap__loop { opacity: .25; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-sysmap__stage, .rsd-sysmap__loop { transition: opacity var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-sysmap__mod { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out), background-color var(--rsd-motion-fast) var(--rsd-ease-out); }
}
.rsd-section--bg-charcoal .rsd-sysmap :is(.rsd-sysmap__title, .rsd-sysmap__detail-k) { color: var(--rsd-paper); }
.rsd-section--bg-charcoal .rsd-sysmap :is(.rsd-sysmap__flow, .rsd-sysmap__detail-v) { color: rgba(247, 246, 244, .72); }
/* Narrow: the stage label above its modules. */
@media (max-width: 479px) {
  .rsd-sysmap__head { margin-bottom: .7rem; }
  .rsd-sysmap__stage { grid-template-columns: auto minmax(0, 1fr); align-items: baseline; column-gap: .6rem; row-gap: .5rem; padding: .65rem .7rem; }
  .rsd-sysmap__name { grid-column: 2; grid-row: 1; margin: 0; font-size: .9rem; }
  .rsd-sysmap__mods { grid-column: 1 / -1; grid-row: 2; gap: .35rem; }
  .rsd-sysmap__mod { min-height: 1.75rem; padding: .25rem .5rem; font-size: .74rem; }
  .rsd-sysmap__stage:not(:last-child)::after { left: 1.3rem; }
  .rsd-sysmap__stage:not(:last-child)::before { left: calc(1.3rem - 3px); }
  .rsd-sysmap__detail { margin-top: .75rem; }
}
/* Narrow desktop column (1024–1279px): a slimmer label column. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .rsd-sysmap__stage { grid-template-columns: 7rem minmax(0, 1fr); column-gap: .75rem; padding: .7rem .75rem; }
  .rsd-sysmap__mod { padding: .28rem .5rem; font-size: .74rem; }
}
/* From 1024px: under the head in the left column; the questions span both rows. */
@media (min-width: 1024px) {
  .rsd-block-section:has(> .rsd-section-head + .rsd-qa) > .rsd-sysmap { grid-column: 1; grid-row: 2; align-self: start; margin-top: clamp(1.75rem, 3vw, 2.5rem); }
  .rsd-block-section:has(> .rsd-section-head + .rsd-qa):has(> .rsd-sysmap) { grid-template-rows: auto 1fr; }
  .rsd-block-section:has(> .rsd-section-head + .rsd-qa):has(> .rsd-sysmap) > .rsd-qa { grid-column: 2; grid-row: 1 / span 2; }
}

/* ---------------------------------------------------------- Digital Growth System
   redsprout-digital/growth-system (inc/growth-system-block.php; editor
   assets/js/growth-system-editor.js). A reusable four-stage editorial
   diagram for articles and pages. Laid out by the block's OWN width (a
   container query), since an article column is narrower than the screen:
   a vertical stack with ↓ arrows, the stage name beside its line once
   there is room (≥ 420px); four across with → arrows from 620px. White
   cards, hairline border, 6px radius, a short red rule. Selectors are two
   classes deep so the article's own list / paragraph rules never reach in. */
.rsd-gsys { container-type: inline-size; margin-block: var(--rsd-gap); }
.rsd-gsys .rsd-gsys__figure { margin: 0; }
.rsd-gsys .rsd-gsys__head { display: flex; flex-direction: column; gap: .35rem; margin: 0 0 1.25rem; }
.rsd-gsys .rsd-gsys__eyebrow { font-family: var(--rsd-mono); font-size: .72rem; font-weight: var(--rsd-weight-semibold); letter-spacing: .12em; text-transform: uppercase; color: var(--rsd-red); }
.rsd-gsys .rsd-gsys__title { font-family: var(--rsd-display); font-size: var(--rsd-t-lg); font-weight: var(--rsd-weight-semibold); line-height: 1.3; letter-spacing: -0.01em; color: var(--rsd-charcoal); }
.rsd-gsys .rsd-gsys__intro { max-width: 60ch; font-size: var(--rsd-t-sm); line-height: 1.55; color: var(--rsd-muted); }
.rsd-gsys .rsd-gsys__stages { display: grid; gap: 1.6rem; margin: 0; padding: 0; list-style: none; }
.rsd-gsys .rsd-gsys__stage {
  position: relative; display: grid; grid-template-columns: 1.75rem minmax(0, 1fr); column-gap: .4rem; row-gap: .2rem; align-items: baseline; align-content: start;
  margin: 0; padding: .8rem 1rem .9rem; list-style: none;
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-gsys .rsd-gsys__stage::marker { content: none; }
.rsd-gsys .rsd-gsys__stage::before { content: ""; grid-column: 1 / -1; width: 1.25rem; height: 2px; margin-bottom: .45rem; background: var(--rsd-red); }
/* Arrow to the next stage — down in the stack, right in the row. */
.rsd-gsys .rsd-gsys__stage:not(:last-child)::after {
  content: "\2193"; position: absolute; left: 1rem; top: 100%; height: 1.6rem;
  display: flex; align-items: center; font-size: .95rem; line-height: 1; color: var(--rsd-red);
}
.rsd-gsys .rsd-gsys__num { font-family: var(--rsd-mono); font-size: .7rem; font-weight: var(--rsd-weight-semibold); color: var(--rsd-muted); }
.rsd-gsys .rsd-gsys__name { font-family: var(--rsd-mono); font-size: .78rem; font-weight: var(--rsd-weight-semibold); line-height: 1.35; letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-charcoal); }
.rsd-gsys .rsd-gsys__text { grid-column: 2; font-size: var(--rsd-t-sm); line-height: 1.5; color: var(--rsd-muted); }
.rsd-gsys .rsd-gsys__cta { margin: 1.25rem 0 0; }
.rsd-gsys .rsd-gsys__cta .rsd-btn { gap: .45rem; }
@container (min-width: 420px) {
  .rsd-gsys .rsd-gsys__stage { grid-template-columns: 2rem 10rem minmax(0, 1fr); column-gap: .75rem; align-items: baseline; padding: .85rem 1rem; }
  .rsd-gsys .rsd-gsys__text { grid-column: 3; }
}
@container (min-width: 620px) {
  .rsd-gsys .rsd-gsys__stages { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.5rem; }
  .rsd-gsys .rsd-gsys__stage { grid-template-columns: minmax(0, 1fr); align-items: start; padding: .95rem .9rem 1rem; }
  .rsd-gsys .rsd-gsys__text { grid-column: 1; margin-top: .25rem; }
  /* Two lines reserved for every name, so the descriptions line up across the row. */
  .rsd-gsys .rsd-gsys__name { min-height: calc(2em * 1.35); }
  .rsd-gsys .rsd-gsys__stage:not(:last-child)::after {
    content: "\2192"; left: 100%; top: 50%; width: 1.5rem; height: auto; justify-content: center; transform: translateY(-50%);
  }
}

/* ---------------------------------------------------------- Ebook Promotion
   redsprout-digital/ebook-promotion (inc/ebook-promotion-block.php; editor
   assets/js/ebook-promotion-editor.js). An editorial resource
   recommendation, not an advert: a hairline-framed panel, the cover on a
   white "drawing board" (a faint 24px hairline grid and a small "Digital
   Guide" tag) at about 40%, the text at about 60%; stacked, cover first,
   below 640px. The cover keeps a fixed 3:4 frame (so nothing shifts while
   it loads, whatever the image's shape) and the image sits whole inside
   it. Selectors are two classes deep so an article's heading / paragraph
   rules never reach in. Backgrounds: paper (default), soft neutral,
   charcoal. */
.rsd-ebook {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem;
  margin-block: var(--rsd-gap); padding: clamp(1rem, 2.5vw, 1.75rem);
  background: var(--rsd-paper); color: var(--rsd-charcoal); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-ebook--neutral { background: color-mix(in srgb, var(--rsd-charcoal) 4%, var(--rsd-paper)); border-color: transparent; }
.rsd-ebook--charcoal { background: var(--rsd-charcoal); color: var(--rsd-paper); border-color: var(--rsd-charcoal); }
.rsd-ebook .rsd-ebook__media {
  position: relative; display: flex; align-items: center; justify-content: center; min-width: 0;
  padding: 2.25rem 1.25rem 1.5rem; border-radius: 4px;
  background-color: var(--rsd-white);
  background-image: linear-gradient(color-mix(in srgb, var(--rsd-line) 55%, transparent) 1px, transparent 1px),
                    linear-gradient(90deg, color-mix(in srgb, var(--rsd-line) 55%, transparent) 1px, transparent 1px);
  background-size: 24px 24px; background-position: -1px -1px;
}
.rsd-ebook--charcoal .rsd-ebook__media {
  background-color: rgba(247, 246, 244, .04);
  background-image: linear-gradient(rgba(247, 246, 244, .07) 1px, transparent 1px), linear-gradient(90deg, rgba(247, 246, 244, .07) 1px, transparent 1px);
}
.rsd-ebook .rsd-ebook__tag {
  position: absolute; top: .75rem; left: .85rem; display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--rsd-mono); font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; color: var(--rsd-muted);
}
.rsd-ebook .rsd-ebook__tag::before { content: ""; width: .9rem; height: 2px; background: var(--rsd-red); }
.rsd-ebook--charcoal .rsd-ebook__tag { color: rgba(247, 246, 244, .6); }
.rsd-ebook--no-image .rsd-ebook__tag { display: none; }
.rsd-ebook .rsd-ebook__frame { display: flex; align-items: center; justify-content: center; width: min(100%, 13.75rem); aspect-ratio: 3 / 4; }
@media (min-width: 480px) { .rsd-ebook .rsd-ebook__frame { width: min(100%, 15rem); } }
.rsd-ebook .rsd-ebook__img {
  display: block; width: auto; height: auto; max-width: 100%; max-height: 100%; margin: 0;
  border: 1px solid var(--rsd-line); border-radius: 3px;
  box-shadow: 0 12px 24px -16px rgba(26, 26, 28, .38), 0 1px 3px rgba(26, 26, 28, .08);
}
/* No cover chosen: an original placeholder — charcoal, a red top edge, the
   "Digital Guide" label and three hairlines. Decorative (aria-hidden). */
.rsd-ebook .rsd-ebook__placeholder {
  display: flex; flex-direction: column; width: 100%; height: 100%; padding: 1rem 1rem 1.1rem;
  color: var(--rsd-paper); background: var(--rsd-charcoal); border-top: 4px solid var(--rsd-red); border-radius: 3px;
  box-shadow: 0 12px 24px -16px rgba(26, 26, 28, .45);
}
.rsd-ebook--charcoal .rsd-ebook__placeholder { box-shadow: inset 0 0 0 1px rgba(247, 246, 244, .16); }
.rsd-ebook .rsd-ebook__ph-brand { font-family: var(--rsd-mono); font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; color: rgba(247, 246, 244, .72); }
.rsd-ebook .rsd-ebook__ph-label { margin-top: auto; font-family: var(--rsd-display); font-size: 1.35rem; font-weight: var(--rsd-weight-semibold); line-height: 1.15; letter-spacing: -0.01em; }
.rsd-ebook .rsd-ebook__ph-lines { display: grid; gap: .4rem; margin-top: .9rem; }
.rsd-ebook .rsd-ebook__ph-lines i { display: block; height: 1px; background: rgba(247, 246, 244, .28); }
.rsd-ebook .rsd-ebook__ph-lines i:last-child { width: 60%; }
.rsd-ebook .rsd-ebook__body { min-width: 0; align-self: center; }
.rsd-ebook .rsd-ebook__eyebrow { margin: 0; font-family: var(--rsd-mono); font-size: .75rem; font-weight: var(--rsd-weight-semibold); letter-spacing: .12em; text-transform: uppercase; color: inherit; }
.rsd-ebook .rsd-ebook__eyebrow::before { content: ""; display: block; width: 1.5rem; height: 2px; margin-bottom: .75rem; background: var(--rsd-red); }
.rsd-ebook .rsd-ebook__title {
  margin: .6rem 0 0; font-family: var(--rsd-display); font-size: var(--rsd-t-h3); font-weight: var(--rsd-weight-semibold);
  line-height: 1.2; letter-spacing: -0.015em; color: inherit; overflow-wrap: break-word; text-wrap: balance;
}
.rsd-ebook .rsd-ebook__desc { margin: .8rem 0 0; max-width: 52ch; font-size: var(--rsd-t-base); line-height: 1.6; color: var(--rsd-muted); }
.rsd-ebook--charcoal .rsd-ebook__desc { color: rgba(247, 246, 244, .78); }
.rsd-ebook .rsd-ebook__actions { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.1rem; margin: 1.35rem 0 0; }
.rsd-ebook .rsd-ebook__cta { gap: .5rem; }
.rsd-ebook .rsd-ebook__cta:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 3px; }
.rsd-ebook--charcoal .rsd-ebook__cta:focus-visible { outline-color: var(--rsd-paper); }
.rsd-ebook .rsd-ebook__meta { font-family: var(--rsd-mono); font-size: .75rem; letter-spacing: .04em; color: var(--rsd-muted); }
.rsd-ebook--charcoal .rsd-ebook__meta { color: rgba(247, 246, 244, .72); }
/* Two columns — cover about 40%, text about 60% — once there is room. */
@media (min-width: 640px) {
  .rsd-ebook { grid-template-columns: minmax(0, 9fr) minmax(0, 11fr); gap: clamp(1.5rem, 3.5vw, 2.5rem); }
  .rsd-ebook .rsd-ebook__media { align-self: stretch; padding: 2.5rem 1.25rem 1.75rem; }
}

/* ---------------------------------------------------------- Content Highlights
   redsprout-digital/content-highlights (inc/content-highlights-block.php;
   editor assets/js/content-highlights-editor.js). A reusable editorial
   section: the standard head, then 2–6 highlight rows — a small line icon
   in a hairline square, a title, an optional description — under a
   hairline rule with a short red tick (the eyebrow's own motif). Not cards.
   The wrapper is the RedSprout Section's (.rsd-section + its --bg / --space
   modifiers, below in this file), so background, spacing and placement
   behave exactly like a section; Soft neutral sets that same
   --rsd-section-bg variable here (two classes, so source order never
   matters). Highlights go two-up by the content's OWN width (a container
   query): full width from ~640px of content, beside an image only once the
   content column itself is that wide. Media split: image about 42%,
   content about 58% once the block is 45rem wide (768px pages and up);
   stacked, image first, below that. */
.rsd-section.rsd-chl--neutral { --rsd-section-bg: color-mix(in srgb, var(--rsd-charcoal) 4%, var(--rsd-paper)); }
.rsd-chl--neutral + .rsd-chl--neutral { padding-top: 0; }
.rsd-chl .rsd-chl__layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(1.75rem, 4vw, 2.5rem); }
.rsd-chl .rsd-chl__body { min-width: 0; container-type: inline-size; }
.rsd-chl .rsd-chl__head { margin: 0; }
.rsd-chl .rsd-chl__heading { overflow-wrap: break-word; text-wrap: balance; }
/* H3 / H4: one step quieter, so it reads as part of the section around it. */
.rsd-chl:is(.rsd-chl--h3, .rsd-chl--h4) .rsd-chl__heading { font-size: var(--rsd-t-h3); }
.rsd-chl .rsd-chl__list {
  display: grid; grid-template-columns: minmax(0, 1fr); column-gap: clamp(1.5rem, 4vw, 3.5rem);
  margin: clamp(1.5rem, 3.5vw, 2.5rem) 0 0; padding: 0; list-style: none;
}
.rsd-chl .rsd-chl__head:empty + .rsd-chl__list { margin-top: 0; }
.rsd-chl .rsd-chl__item {
  position: relative; display: grid; grid-template-columns: 2.25rem minmax(0, 1fr); column-gap: 1rem; align-items: start;
  margin: 0; padding: 1.25rem 0 1.4rem; list-style: none; border-top: 1px solid var(--rsd-line);
}
.rsd-chl .rsd-chl__item::marker { content: none; }
.rsd-chl .rsd-chl__item::before { content: ""; position: absolute; top: -1px; left: 0; width: 2.25rem; height: 2px; background: var(--rsd-red); }
.rsd-chl .rsd-chl__icon {
  display: flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-chl .rsd-chl__icon svg { display: block; width: 1.125rem; height: 1.125rem; }
.rsd-chl .rsd-chl__text { min-width: 0; padding-top: .3rem; }
.rsd-chl .rsd-chl__title {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-intro); font-weight: var(--rsd-weight-semibold);
  line-height: 1.35; letter-spacing: -0.01em; color: inherit; overflow-wrap: break-word;
}
.rsd-chl .rsd-chl__desc { margin: .35rem 0 0; max-width: 48ch; font-size: var(--rsd-t-sm); line-height: 1.6; color: var(--rsd-muted); overflow-wrap: break-word; }
@container (min-width: 40rem) {
  .rsd-chl .rsd-chl__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Media split. The frame reserves its space before the image loads; the
   picture fills it from its focal point (object-position, inline). 3:2
   stacked, 4:5 beside the content — never a thin slice. */
.rsd-chl .rsd-chl__media { min-width: 0; }
.rsd-chl .rsd-chl__frame {
  aspect-ratio: 3 / 2; overflow: hidden; border: 1px solid var(--rsd-line); border-radius: 6px;
  background: color-mix(in srgb, var(--rsd-charcoal) 4%, var(--rsd-paper));
}
.rsd-chl .rsd-chl__img { display: block; width: 100%; height: 100%; margin: 0; object-fit: cover; }
/* Side by side once the block itself is at least 45rem wide (a page at
   768px and up) — by its own width, so inside a narrow article column it
   stays stacked instead of squeezing the image. */
.rsd-chl--split .rsd-section__inner { container-type: inline-size; }
@container (min-width: 45rem) {
  .rsd-chl--split .rsd-chl__layout { grid-template-columns: minmax(0, 42fr) minmax(0, 58fr); align-items: center; column-gap: clamp(2rem, 5vw, 4.5rem); }
  .rsd-chl--split .rsd-chl__frame { aspect-ratio: 4 / 5; }
  .rsd-chl--image-right .rsd-chl__layout { grid-template-columns: minmax(0, 58fr) minmax(0, 42fr); }
  .rsd-chl--image-right .rsd-chl__media { order: 2; }
}
/* Charcoal: the same quiet structure in paper tints. Head colours and the
   focus ring come from the existing dark-surface rules. */
.rsd-chl--charcoal .rsd-chl__item { border-top-color: rgba(247, 246, 244, .14); }
.rsd-chl--charcoal .rsd-chl__icon { color: var(--rsd-paper); background: rgba(247, 246, 244, .04); border-color: rgba(247, 246, 244, .18); }
.rsd-chl--charcoal .rsd-chl__desc { color: rgba(247, 246, 244, .72); }
.rsd-chl--charcoal .rsd-chl__frame { border-color: rgba(247, 246, 244, .14); background: rgba(247, 246, 244, .04); }

/* ---------------------------------------------------------- Editorial Card
   redsprout-digital/editorial-card (inc/editorial-card-block.php; editor
   assets/js/editorial-card-editor.js). One standalone card: a 24px line
   icon, title, description, optional link →. Hairline border, 6px radius,
   no shadow; the optional red accent is the short tick on the top edge
   (the eyebrow / Content Highlights motif), aligned with the content.
   Laid out by the card's OWN width (the wrapper is the container):
   Standard is a single column capped at a comfortable 38rem; Compact is a
   row — icon | text | link — from 34rem of container and stacks below.
   Light and Dark share every size and space; only colours change. Links
   cover the whole card (stretched ::after) — hover deepens the border and
   nudges the arrow, focus rings the card. Selectors are three classes deep
   where they meet article-prose link / heading rules. */
.rsd-ecard { container-type: inline-size; margin-block: var(--rsd-gap); }
.rsd-ecard .rsd-ecard__card {
  --rsd-ecard-pad: clamp(1.25rem, 6cqi, 2rem);
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start;
  max-width: 38rem; padding: var(--rsd-ecard-pad);
  background: var(--rsd-white); color: var(--rsd-charcoal);
  border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-ecard--accent .rsd-ecard__card::before {
  content: ""; position: absolute; top: -1px; left: var(--rsd-ecard-pad);
  width: 2.25rem; height: 2px; background: var(--rsd-red);
}
.rsd-ecard .rsd-ecard__icon { display: flex; width: 1.5rem; height: 1.5rem; margin-bottom: 1.25rem; color: currentColor; }
/* The theme's 16px line icons drawn at 24px with a 1.5px line — the same
   weight they have at 16px, rather than scaled up thicker. */
.rsd-ecard .rsd-ecard__icon svg { display: block; width: 100%; height: 100%; }
.rsd-ecard .rsd-ecard__icon svg * { vector-effect: non-scaling-stroke; stroke-width: 1.5; }
.rsd-ecard .rsd-ecard__body { min-width: 0; }
.rsd-ecard .rsd-ecard__title {
  margin: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-lg); font-weight: var(--rsd-weight-semibold);
  line-height: 1.25; letter-spacing: -0.01em; color: inherit; overflow-wrap: break-word; text-wrap: balance;
}
.rsd-ecard .rsd-ecard__desc { margin: .6rem 0 0; max-width: 52ch; font-size: var(--rsd-t-sm); line-height: 1.6; color: var(--rsd-muted); overflow-wrap: break-word; }
.rsd-ecard .rsd-ecard__card .rsd-ecard__link {
  display: inline-flex; align-items: center; gap: .45rem; margin-top: 1.5rem;
  font-family: var(--rsd-display); font-size: var(--rsd-t-sm); font-weight: var(--rsd-weight-semibold); line-height: 1.3;
  color: inherit; text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px;
}
.rsd-ecard .rsd-ecard__card a.rsd-ecard__link::after { content: ""; position: absolute; inset: -1px; border-radius: 6px; } /* the whole card is the link */
.rsd-ecard .rsd-ecard__arrow { display: inline-block; }
.rsd-ecard--linked .rsd-ecard__card:hover { border-color: color-mix(in srgb, var(--rsd-line), var(--rsd-charcoal) 35%); }
.rsd-ecard--linked .rsd-ecard__card:hover .rsd-ecard__link { text-decoration-color: var(--rsd-red); }
.rsd-ecard--linked .rsd-ecard__card:hover .rsd-ecard__arrow { transform: translateX(3px); }
/* Keyboard focus rings the whole card (its clickable area), not just the label. */
@supports selector(:has(*)) {
  .rsd-ecard .rsd-ecard__card:has(.rsd-ecard__link:focus-visible) { outline: 2px solid var(--rsd-red); outline-offset: 3px; }
  .rsd-ecard .rsd-ecard__card a.rsd-ecard__link:focus-visible { outline: none; }
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-ecard--linked .rsd-ecard__card { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ecard .rsd-ecard__link { transition: text-decoration-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ecard .rsd-ecard__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
}

/* Dark — the charcoal surface with a light hairline; the same red accent. */
.rsd-ecard--dark .rsd-ecard__card { background: var(--rsd-charcoal); color: var(--rsd-paper); border-color: rgba(247, 246, 244, .14); }
.rsd-ecard--dark .rsd-ecard__title { color: var(--rsd-white); }
.rsd-ecard--dark .rsd-ecard__desc { color: rgba(247, 246, 244, .72); }
.rsd-ecard--dark.rsd-ecard--linked .rsd-ecard__card:hover { border-color: rgba(247, 246, 244, .34); }
/* The red ring is under 3:1 on charcoal — paper instead, as on every dark surface. */
@supports selector(:has(*)) {
  .rsd-ecard--dark .rsd-ecard__card:has(.rsd-ecard__link:focus-visible) { outline-color: var(--rsd-paper); }
}
.rsd-ecard--dark .rsd-ecard__card a.rsd-ecard__link:focus-visible { outline-color: var(--rsd-paper); }

/* Compact — a horizontal row once the card has the room, stacked below. */
.rsd-ecard--compact .rsd-ecard__card { --rsd-ecard-pad: clamp(1rem, 4cqi, 1.5rem); max-width: none; column-gap: 1.25rem; padding-block: 1.1rem; }
.rsd-ecard--compact .rsd-ecard__icon { margin-bottom: .85rem; }
.rsd-ecard--compact .rsd-ecard__title { font-size: var(--rsd-t-base); line-height: 1.3; }
.rsd-ecard--compact .rsd-ecard__desc { margin-top: .3rem; }
.rsd-ecard--compact .rsd-ecard__card .rsd-ecard__link { margin-top: .85rem; }
@container (min-width: 34rem) {
  .rsd-ecard--compact .rsd-ecard__card { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; }
  .rsd-ecard--compact .rsd-ecard__icon { margin: 0; }
  /* A long label wraps within ~28% of the card instead of squeezing the text. */
  .rsd-ecard--compact .rsd-ecard__card .rsd-ecard__link { margin: 0 0 0 .5rem; justify-self: end; max-width: max(8rem, 28cqi); text-align: right; }
}

/* Hero button row — the core Buttons block ships no layout CSS of its own
   once wp-block-library is dequeued, so this supplies the flex/gap. */
.rsd-hero__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.5rem; }

/* Bridge for core Button blocks carrying an .rsd-btn* className.
   The block's real DOM is <div class="wp-block-button rsd-btn rsd-btn--solid">
   <a class="wp-block-button__link">…</a></div> — className lands on the
   outer div, not the link .rsd-btn itself was written for, so the button
   look is re-anchored onto .wp-block-button__link here. This is the one
   deliberate exception to "apply existing classes with no new CSS": the
   classes are reused as-is, only the selector that paints them differs,
   because Gutenberg's Button block has a wrapper .rsd-btn never assumed. */
.wp-block-button.rsd-btn { background: none; padding: 0; border: 0; border-radius: 0; }
/* Same min-height/centering guarantee as the plain .rsd-btn rule above —
   a Button-block-wrapped .rsd-btn and a plain <a class="rsd-btn"> should
   never be the one place height quietly diverges between the two ways
   this theme renders "the same button." */
.wp-block-button.rsd-btn .wp-block-button__link {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--rsd-tap-target); font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-sm); padding: .6rem 1.1rem; border-radius: var(--rsd-radius);
  text-decoration: none; border: 1px solid transparent; cursor: pointer;
  transition: background var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out);
}
.wp-block-button.rsd-btn--solid .wp-block-button__link { background: var(--rsd-red); color: var(--rsd-white); }
.wp-block-button.rsd-btn--solid .wp-block-button__link:hover { background: var(--rsd-red-ink); }
/* theme.json's styles.elements.button sets background:red + color:white
   globally on every .wp-element-button (WordPress's own "global styles"
   inline <style>, printed in wp_footer — see wp-includes/block-supports/
   elements.php). That rule targets the SAME .wp-block-button__link element
   this bridge does, and its selector is :root :where(.wp-element-button),
   which is a real selector — a `:root` pseudo-class carries specificity —
   not the zero-specificity most devs assume from seeing :where(). This
   bridge's higher specificity (two classes + a class, vs :root's one)
   already beat it for color, which is why the ghost button's text was
   never actually red-on-red — but nothing here ever set its OWN
   background, so WordPress's background:red went uncontested and painted
   straight through underneath the (correctly) charcoal text: a charcoal-
   on-red button that was supposed to be an outline, unreadable at a
   glance. background:transparent below is the fix — same header/Client
   Login language: transparent fill, charcoal border and text, inverting
   solid-charcoal-with-white-text on hover. */
.wp-block-button.rsd-btn--ghost .wp-block-button__link { background: transparent; border-color: var(--rsd-charcoal); color: var(--rsd-charcoal); }
.wp-block-button.rsd-btn--ghost .wp-block-button__link:hover { background: var(--rsd-charcoal); color: var(--rsd-white); }

/* .rsd-sr (visually-hidden) already defined above — reused as-is for the
   accessible <section> heading in [rsd_reach]'s combined output. */

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

/* ---------------------------------------------------------- services hub
   Added for the /services/ commercial hub (inc/patterns-services-hub.php,
   inc/services.php). None of this touches the nav/mega-menu rules above —
   .rsd-pillars is the services-grid block's own layout, unrelated to
   .rsd-menu's pillar-grouped submenu, which reuses that existing markup/CSS
   unchanged. */

.rsd-pillars {
  display: grid;
  grid-template-columns: repeat(var(--rsd-pillar-cols, 3), 1fr);
  gap: var(--rsd-gap);
  margin-top: var(--rsd-gap);
}
.rsd-pillar__title { font-size: var(--rsd-t-base); margin-bottom: .25rem; }
.rsd-pillar__blurb { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0 0 1rem; }
.rsd-pillar .rsd-cards { grid-template-columns: 1fr; }

/* Services Index (tpl-services-index.php) showcase card — additive only,
   scoped to .rsd-card--service, same discipline as .rsd-card--showcase
   (Case Studies): the shared .rsd-cards/.rsd-card base rules, and the
   plain rsd_render_service_grid() card used everywhere else this
   function/block is called, are untouched. No transition on `transform`
   anywhere below — .rsd-cards > * (this card included) is one of
   scroll-reveal.js's own GSAP reveal targets, and a CSS transition
   fighting GSAP's own per-frame transform writes is exactly the
   regression already root-caused and fixed once on the Case Studies
   card; not reintroduced here. */
.rsd-card--service { display: flex; flex-direction: column; overflow: hidden; padding: 0; box-shadow: var(--rsd-shadow-subtle); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-card--service { transition: box-shadow .18s ease, border-color .18s ease; }
}
.rsd-card--service:hover, .rsd-card--service:focus-within {
  box-shadow: var(--rsd-shadow-medium);
  border-color: color-mix(in srgb, var(--rsd-line), var(--rsd-charcoal) 35%);
}
.rsd-card--service .rsd-card__thumb { display: block; aspect-ratio: 16 / 10; background: var(--rsd-line); }
.rsd-card--service .rsd-card__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.rsd-card--service__body { padding: var(--rsd-gap); display: flex; flex-direction: column; gap: .5rem; flex: 1; }
.rsd-card--service .rsd-card__title { margin: 0; }
.rsd-card--service__body p { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; }
.rsd-card--service__link { align-self: flex-start; margin-top: auto; padding-top: .5rem; }
.rsd-card--service__link span { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-card--service__link span { transition: transform .18s ease; }
  .rsd-card--service:hover .rsd-card--service__link span, .rsd-card--service:focus-within .rsd-card--service__link span { transform: translateX(3px); }
}

/* ---------------------------------------------------------- Services Grid
   The redsprout-digital/services-grid block (rsd_render_services_grid_
   component(), inc/services.php; switching: assets/js/main.js). A set of
   service panels of which exactly one is expanded — whichever the visitor
   chose last, wherever it sits in the row — and the rest are narrow
   selectors. Below 1024px it is a stacked accordion (the base rules
   here); from 1024px a horizontal row of panels whose widths animate.
   Collapsed content is visibility:hidden, so it is out of the tab order
   and the accessibility tree. Scoped under .rsd-sgrid where page-content
   rules (.rsd-shell links, headings) are more specific than one class. */
.rsd-sgrid {
  --rsd-sgrid-gap: .5rem;
  --rsd-sgrid-rail: 2.75rem;
  --rsd-sgrid-pad: var(--rsd-gap);
  --rsd-sgrid-radius: calc(var(--rsd-radius) * 1.5);
  display: flex; flex-direction: column; gap: var(--rsd-sgrid-gap);
  margin-top: var(--rsd-gap);
}
.rsd-sgrid__item {
  position: relative; overflow: hidden; min-width: 0;
  background: var(--rsd-white); color: var(--rsd-charcoal);
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-sgrid-radius);
}
.rsd-sgrid__item.is-active { background: var(--rsd-charcoal); color: var(--rsd-paper); border-color: var(--rsd-charcoal); }
/* Hover is only a faint tint — the border stays the same neutral line, so
   a hovered panel never reads as the open one. */
.rsd-sgrid__item:not(.is-active):hover { background: color-mix(in srgb, var(--rsd-white), var(--rsd-paper) 70%); }

/* Featured image — the expanded panel's backdrop, under a restrained
   charcoal gradient so the text stays readable on any image. */
.rsd-sgrid__media { display: none; position: relative; aspect-ratio: 16 / 10; background: var(--rsd-charcoal); }
.rsd-sgrid__item.is-active .rsd-sgrid__media { display: block; }
.rsd-sgrid__img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
.rsd-sgrid__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(26, 26, 28, .9) 0%, rgba(26, 26, 28, .55) 45%, rgba(26, 26, 28, .12) 100%);
}
.rsd-sgrid__icon {
  display: none; position: absolute; z-index: 1; top: .75rem; left: .75rem;
  width: 2.25rem; height: 2.25rem; align-items: center; justify-content: center;
  color: var(--rsd-paper); background: rgba(26, 26, 28, .45);
  border: 1px solid rgba(247, 246, 244, .35); border-radius: var(--rsd-radius);
}
.rsd-sgrid__icon svg { width: 1.1rem; height: 1.1rem; }
.rsd-sgrid__item.is-active .rsd-sgrid__icon { display: inline-flex; }

/* The selector: the heading's button (number + title). */
/* Neutral wrapper at either level (h3 in the block, h4 on the Services
   page): the global h3/h4 colour, size, weight and tracking must not
   reach the button — it takes its look from the panel. */
.rsd-sgrid .rsd-sgrid__heading { margin: 0; font: inherit; letter-spacing: inherit; color: inherit; }
.rsd-sgrid__toggle {
  appearance: none; display: flex; align-items: center; gap: .9rem;
  width: 100%; min-height: 3.5rem; margin: 0; padding: .9rem 1rem;
  background: none; border: 0; border-radius: 0; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
}
.rsd-sgrid__item.is-active .rsd-sgrid__toggle { cursor: default; }
.rsd-sgrid .rsd-sgrid__toggle:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: -4px; }
.rsd-sgrid .rsd-sgrid__item.is-active .rsd-sgrid__toggle:focus-visible { outline-color: var(--rsd-paper); }
.rsd-sgrid__num {
  flex: none; font-family: var(--rsd-display); font-size: var(--rsd-t-xs); font-weight: var(--rsd-weight-semibold);
  letter-spacing: .08em; font-variant-numeric: tabular-nums; color: var(--rsd-red);
}
.rsd-sgrid__item.is-active .rsd-sgrid__num { color: rgba(247, 246, 244, .72); }
.rsd-sgrid__rail, .rsd-sgrid__teaser { display: none; }
.rsd-sgrid__name {
  flex: 1; min-width: 0; font-family: var(--rsd-display); font-size: var(--rsd-t-base);
  font-weight: var(--rsd-weight-semibold); line-height: 1.3; overflow-wrap: break-word;
}
/* Collapsed rows show where they open: a small chevron. */
.rsd-sgrid__item:not(.is-active) .rsd-sgrid__toggle::after {
  content: ""; flex: none; width: 7px; height: 7px; margin: -4px .25rem 0 0;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
}

/* The open content: description + Read more. */
.rsd-sgrid__panel { display: none; }
.rsd-sgrid__item.is-active .rsd-sgrid__panel { display: block; padding: 0 1rem 1.25rem; }
.rsd-sgrid .rsd-sgrid__desc {
  margin: 0; max-width: 48ch; font-size: var(--rsd-t-sm); line-height: 1.6; color: rgba(247, 246, 244, .78);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden;
}
.rsd-sgrid .rsd-sgrid__more {
  display: inline-flex; align-items: center; gap: .4rem; min-height: 2.75rem; margin-top: .35rem;
  font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-paper); text-decoration: none;
}
.rsd-sgrid .rsd-sgrid__more:hover { text-decoration: underline; text-underline-offset: .25em; }
.rsd-sgrid .rsd-sgrid__more:focus-visible { outline: 2px solid var(--rsd-paper); outline-offset: 2px; }
.rsd-sgrid__more span[aria-hidden] { display: inline-block; }

@media (prefers-reduced-motion: no-preference) {
  .rsd-sgrid__item { transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-sgrid__item.is-active :is(.rsd-sgrid__media, .rsd-sgrid__panel) { animation: rsd-sgrid-in var(--rsd-motion-base) var(--rsd-ease-out) both; }
  .rsd-sgrid__more span[aria-hidden] { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-sgrid__more:hover span[aria-hidden] { transform: translateX(3px); }
}
@keyframes rsd-sgrid-in { from { opacity: 0; } to { opacity: 1; } }

/* Services page (tpl-services-index.php): one Services Grid per pillar,
   each under the pillar's existing heading + blurb (.rsd-pillar__title /
   __blurb), stacked full width with a section-sized gap between pillars. */
.rsd-sgrid-groups { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rsd-block); margin-top: var(--rsd-gap); }
.rsd-sgrid-group .rsd-sgrid { margin-top: var(--rsd-gap-sm); }

/* ≥1024px: one horizontal row, fixed height (switching never changes the
   section's height). Widths come from the number of services
   (--rsd-sgrid-n, set by the markup): each collapsed panel gets its share
   of ~30% of the row, kept between 2.75rem and 12rem; the open one gets the
   rest (≈62–70% for 3–8 services from 1024px up). The bases add up to
   exactly the row, which clips (overflow) rather than ever widening the
   page. Only flex-basis animates — the panel visibly grows and
   shrinks — while the open panel's text is laid out at its final width
   from the first frame (never reflowing mid-animation) and clipped by the
   panel until it has room. */
@media (min-width: 1024px) {
  .rsd-sgrid {
    --rsd-sgrid-pad: clamp(1.5rem, 2.6vw, 2.5rem);
    flex-direction: row; height: clamp(25rem, 29.2vw, 27.5rem); overflow: hidden;
    container-type: inline-size;
  }
  .rsd-sgrid__item {
    --rsd-sgrid-in: clamp(var(--rsd-sgrid-rail), (100cqw - (var(--rsd-sgrid-n) - 1) * var(--rsd-sgrid-gap)) * .3 / max(var(--rsd-sgrid-n) - 1, 1), 12rem);
    --rsd-sgrid-open: calc(100cqw - (var(--rsd-sgrid-n) - 1) * (var(--rsd-sgrid-gap) + var(--rsd-sgrid-in)));
    flex: 0 0 var(--rsd-sgrid-in);
  }
  .rsd-sgrid__item.is-active { flex-basis: var(--rsd-sgrid-open); }
  .rsd-sgrid--one .rsd-sgrid__item { flex: 1 1 auto; --rsd-sgrid-open: 100cqw; }

  /* Open: the photograph fills the panel under a charcoal gradient that is
     densest at the lower left, where the copy sits. */
  .rsd-sgrid__media { display: block; position: absolute; inset: 0; aspect-ratio: auto; opacity: 0; }
  .rsd-sgrid__item.is-active .rsd-sgrid__media { opacity: 1; }
  .rsd-sgrid__media::after {
    background:
      linear-gradient(to top, rgba(26, 26, 28, .92) 0%, rgba(26, 26, 28, .55) 38%, rgba(26, 26, 28, 0) 72%),
      linear-gradient(to right, rgba(26, 26, 28, .55) 0%, rgba(26, 26, 28, 0) 65%);
  }
  .rsd-sgrid__icon { display: inline-flex; top: var(--rsd-sgrid-pad); left: var(--rsd-sgrid-pad); opacity: 0; visibility: hidden; }
  .rsd-sgrid__item.is-active .rsd-sgrid__icon { opacity: 1; visibility: visible; }

  /* Collapsed: a light selector, and the whole panel is its button. Its
     layout follows its own width (a query container): narrow panels show
     the number over a title written top-to-bottom; once a panel is wide
     enough (few services) the title runs horizontally under the number
     with a short line below it. Both start at the top. */
  .rsd-sgrid__toggle {
    position: absolute; inset: 0; z-index: 1; min-height: 0;
    flex-direction: column; align-items: center; justify-content: flex-start; gap: 1rem;
    padding: var(--rsd-sgrid-pad) 0;
    container: rsd-sgrid-sel / inline-size;
  }
  .rsd-sgrid__item:not(.is-active) .rsd-sgrid__toggle::after { content: none; }
  .rsd-sgrid__item:not(.is-active) .rsd-sgrid__rail {
    display: block; flex: 0 1 auto; min-height: 0; max-width: 100%; padding-inline: .5rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    /* Reads top to bottom: vertical-rl runs the line downward, and mixed
       turns the Latin glyphs a quarter clockwise. No rotate() — rotating
       it 180° is what made it read bottom to top. */
    writing-mode: vertical-rl; text-orientation: mixed;
    font-family: var(--rsd-display); font-size: var(--rsd-t-base); font-weight: var(--rsd-weight-semibold); line-height: 1.2;
  }
  .rsd-sgrid__item:not(.is-active) .rsd-sgrid__name {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  @container rsd-sgrid-sel (min-width: 8.5rem) {
    .rsd-sgrid__item:not(.is-active) :is(.rsd-sgrid__num, .rsd-sgrid__name, .rsd-sgrid__teaser) {
      align-self: stretch; margin-inline: clamp(1rem, 12cqw, 1.5rem);
    }
    .rsd-sgrid__item:not(.is-active) .rsd-sgrid__rail { display: none; }
    .rsd-sgrid__item:not(.is-active) .rsd-sgrid__name {
      position: static; width: auto; height: auto; overflow: visible; clip: auto; white-space: normal;
      flex: none; font-size: var(--rsd-t-base); line-height: 1.25;
    }
    .rsd-sgrid__item:not(.is-active) .rsd-sgrid__teaser {
      display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden;
      margin-top: -.5rem; font-size: var(--rsd-t-sm); line-height: 1.5; color: var(--rsd-muted);
    }
  }

  /* Open: number, title, description and link stacked at the bottom-left,
     at the open panel's final width. */
  .rsd-sgrid__item.is-active .rsd-sgrid__body {
    position: absolute; z-index: 1; left: var(--rsd-sgrid-pad); bottom: var(--rsd-sgrid-pad);
    width: calc(var(--rsd-sgrid-open) - 2 * var(--rsd-sgrid-pad) - 2px);
  }
  .rsd-sgrid__item.is-active .rsd-sgrid__toggle { position: static; display: block; padding: 0; }
  .rsd-sgrid__item.is-active .rsd-sgrid__num { display: block; margin-bottom: .75rem; }
  .rsd-sgrid__item.is-active .rsd-sgrid__name { display: block; max-width: 20ch; font-size: var(--rsd-t-h2); line-height: 1.1; color: var(--rsd-white); }
  .rsd-sgrid__item.is-active .rsd-sgrid__panel { padding: 0; margin-top: 1rem; }
  .rsd-sgrid .rsd-sgrid__item.is-active .rsd-sgrid__desc { max-width: 52ch; font-size: var(--rsd-t-base); -webkit-line-clamp: 3; line-clamp: 3; }
  .rsd-sgrid .rsd-sgrid__item.is-active .rsd-sgrid__more { margin-top: .75rem; }

  /* One timing for the whole switch (~400ms, a symmetric ease-in-out so
     the growing and the shrinking panel meet smoothly): widths, surface
     colour and the image cross-fade run together; the text of whichever
     state a panel is entering fades in over the second half, once the
     panel has room for it, so nothing reflows or flickers mid-move.
     Reduced motion: none of this applies (and --rsd-motion-base drops to
     .01s site-wide). */
  @media (prefers-reduced-motion: no-preference) {
    .rsd-sgrid {
      --rsd-sgrid-dur: calc(var(--rsd-motion-base) * 1.35);
      --rsd-sgrid-ease: cubic-bezier(.45, 0, .2, 1);
    }
    .rsd-sgrid__item {
      transition: flex-basis var(--rsd-sgrid-dur) var(--rsd-sgrid-ease),
                  background-color var(--rsd-sgrid-dur) var(--rsd-sgrid-ease),
                  border-color var(--rsd-sgrid-dur) var(--rsd-sgrid-ease);
    }
    .rsd-sgrid__item.is-active :is(.rsd-sgrid__media, .rsd-sgrid__panel) { animation: none; }
    .rsd-sgrid__media { transition: opacity var(--rsd-sgrid-dur) var(--rsd-sgrid-ease); }
    .rsd-sgrid__item.is-active .rsd-sgrid__body,
    .rsd-sgrid__item.is-active .rsd-sgrid__icon,
    .rsd-sgrid__item:not(.is-active) .rsd-sgrid__toggle {
      animation: rsd-sgrid-in calc(var(--rsd-sgrid-dur) * .55) var(--rsd-ease-out) calc(var(--rsd-sgrid-dur) * .45) both;
    }
  }
}

/* URL capture (D-40) — one input, one button, zero JS. */
.rsd-capture {
  display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.25rem; max-width: 32rem;
}
/* Shared surface properties (border, radius, background, color, type)
   live once, grouped with #commentform's own text fields, above — this
   rule keeps only what's specific to the flex-row capture-form context. */
.rsd-capture__input {
  flex: 1 1 14rem; min-width: 0;
}
/* type="url" — browsers apply their own native :invalid styling (often a
   red ring or border) to email/url inputs on their own UA stylesheet,
   independent of anything authored here, and it can show before a visitor
   has typed anything at all: there's no `required` or `pattern` on this
   field, an empty value is not actually invalid, but several engines
   apply the styling anyway. The theme's own border is already the
   standard hairline at rest (above) and the standard 2px red 3px-offset
   ring on focus (the global :focus-visible rule, top of this file) — this
   only neutralizes the browser's own extra, unrequested invalid-state
   decoration so red means "focused," never "empty." */
.rsd-capture__input:invalid { border-color: var(--rsd-line); box-shadow: none; outline: none; }
.rsd-capture__input::placeholder { color: var(--rsd-muted); }

/* Data tables (core/table, "RedSprout — Data table" style) — the system,
   engagement-variables and measurement tables. Numerals in mono per D-24. */
.is-style-rsd-data table { border-collapse: collapse; width: 100%; margin: 1.5rem 0; }
.is-style-rsd-data th,
.is-style-rsd-data td {
  border-bottom: 1px solid var(--rsd-line); padding: .65rem .9rem .65rem 0;
  text-align: left; vertical-align: top; font-size: var(--rsd-t-sm);
}
/* Shared uppercase-label typography (family/weight/size/transform/
   tracking) — identical, verbatim, across this table header, the
   comparison table's caption, and its own thead th below (further down
   this file). Grouped once rather than duplicated three times; each
   selector keeps only what's actually different about it (color,
   border, or layout) on its own rule. Selector-disjoint (a data-table
   th, a comparison-table caption, a comparison-table's own thead th —
   never the same element), so grouping doesn't change cascade order for
   any of them. */
.is-style-rsd-data th,
.rsd-comparison__caption,
.rsd-comparison__table thead th {
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold); font-size: var(--rsd-t-xs);
  text-transform: uppercase; letter-spacing: .04em;
}
.is-style-rsd-data th {
  color: var(--rsd-muted);
  border-bottom: 1px solid var(--rsd-charcoal);
}
.is-style-rsd-data td:first-child,
.is-style-rsd-data th:first-child { font-family: var(--rsd-mono); }

/* ---------------------------------------------------------- comparison table
   group_rsd_comparison (inc/acf-fields.php) — Commercial Service, Market
   Service, Industry (page.php / tpl-market-service.php / single-industries.php).
   Reuses two existing recipes rather than inventing a third table language:
   .is-style-rsd-data's own typographic treatment just above (uppercase
   tracked header row, charcoal divider under it) and .rsd-cards' own surface
   (white, hairline border, --rsd-radius, no shadow — this design system
   reserves shadow for a handful of specific elevated elements, not plain
   cards/tables). :has() for the "flagged column" tint mirrors the exact
   technique the mega-menu's own grouping logic already uses further up this
   file, not a new technique introduced here. */
.rsd-comparison {
  margin-top: var(--rsd-gap);
  overflow-x: auto; overflow-y: hidden; /* independent axes: horizontal scroll on narrow screens, vertical clip so the rounded corners below actually round. */
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-comparison__table {
  width: 100%; min-width: 520px; border-collapse: collapse;
  font-size: var(--rsd-t-sm); font-variant-numeric: tabular-nums;
}
.rsd-comparison__caption {
  caption-side: top; text-align: left; padding: var(--rsd-gap-sm) var(--rsd-gap-sm) 0;
  color: var(--rsd-muted);
}
.rsd-comparison__table th,
.rsd-comparison__table td {
  padding: .85rem var(--rsd-gap-sm); text-align: center; vertical-align: middle;
  border-bottom: 1px solid var(--rsd-line);
}
.rsd-comparison__table thead th {
  color: var(--rsd-charcoal);
  border-bottom: 1px solid var(--rsd-charcoal);
}
/* The one column comparison_note flags — a restrained header-cell tint only,
   not a floating "Most popular" badge/ribbon: :has() has no way to reach the
   body cells below it too (row_cells carries no per-column class to select
   on), and a quieter, header-only signal reads as considered rather than as
   the generic pricing-page cliché a floating badge would be anyway. */
.rsd-comparison__table thead th:has(.rsd-comparison__note) {
  background: color-mix(in srgb, var(--rsd-paper), var(--rsd-red) 6%);
}
.rsd-comparison__note {
  display: block; margin-top: .3rem;
  font-family: var(--rsd-mono); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-xs);
  letter-spacing: .03em; color: var(--rsd-red);
}
.rsd-comparison__rowhead {
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal);
  text-align: left; white-space: nowrap;
}
.rsd-comparison__table tbody tr:last-child th,
.rsd-comparison__table tbody tr:last-child td { border-bottom: 0; }
/* Check/cross glyphs — a neutral, legible treatment, not colour-coded red vs
   grey: both use the identical two-span aria-hidden+.rsd-sr markup shape
   (template-parts/modules/comparison.php), and CSS has no selector that can
   read the glyph's own text content to tell the two apart. The glyph itself
   (✓ vs –) plus the .rsd-sr text already carry the distinction without
   relying on colour alone to do it. */
.rsd-comparison__table td span[aria-hidden] { font-size: 1.15em; font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal); }

@media (prefers-reduced-motion: no-preference) {
  .rsd-comparison__table tbody tr { transition: background-color .15s ease; }
}
.rsd-comparison__table tbody tr:hover { background: var(--rsd-paper); }

@media (max-width: 1023px) {
  .rsd-comparison__table th,
  .rsd-comparison__table td { padding: .65rem var(--rsd-gap-sm); }
}
@media (max-width: 767px) {
  .rsd-comparison__table { font-size: var(--rsd-t-xs); }
  /* Sticky label column — mobile only; at desktop widths the table already
     fits without scrolling, so there is nothing for this to do there. */
  .rsd-comparison__rowhead {
    position: sticky; left: 0; z-index: 1;
    background: var(--rsd-white); border-right: 1px solid var(--rsd-line);
  }
}

/* Proof — section-level spacing only; .rsd-figure/.rsd-excerpt (both
   already styled above) cover a real unit's own contents once one exists.
   Deliberately empty today (D-21) — inc/block-guards.php suppresses the
   whole block while it has zero .rsd-proof-unit children, so none of this
   paints anything yet. */
.rsd-proof { margin-block: var(--rsd-block); }
.rsd-proof-unit { margin-bottom: var(--rsd-gap); }
.rsd-proof-unit__limitation { color: var(--rsd-muted); max-width: 62ch; }

/* ---------------------------------------------------------- case study results
   Reuses .rsd-comparison/.rsd-comparison__table wholesale (single-case_studies.php)
   for the table shell, scroll container, sticky first column and tabular
   numerals — none of that is redeclared here. This only adds the two
   things the Results table needs that Comparison's own cells don't: a
   left-aligned, top-aligned last column for the stacked period/source/
   limitation text (Comparison's cells are short and centred by design),
   and a wrapping row header (Comparison's row labels are deliberately
   short and nowrap; a Results metric name can run longer). Both are
   scoped under .rsd-proof — the only section wrapper Results renders
   inside — so neither rule can ever reach the real comparison.php module,
   which never renders inside .rsd-proof (confirmed: only m08-proof.php and
   this Results section use that class, and m08-proof.php has no table).
   metric_direction (the data-direction attribute on each row) is
   deliberately left unstyled here: any colour-only treatment risks
   implying a positive number is automatically an improvement, which isn't
   true for every metric (e.g. average position, cost per acquisition) —
   that judgement needs a real text label, which is template work, not
   CSS, so it stays an inert hook for now. */
.rsd-proof .rsd-comparison__rowhead { white-space: normal; }
.rsd-proof .rsd-comparison__table thead th:last-child { text-align: left; }
.rsd-proof .rsd-comparison__table tbody td:last-child {
  text-align: left; vertical-align: top; max-width: 32ch;
}

/* ---------------------------------------------------------- case study feedback
   The quote reuses .rsd-prose blockquote's existing red-left-border
   "evidenced claim" treatment (the same motif .rsd-figure and .rsd-strip
   already use) — only the size is raised here, from --rsd-t-lg to
   --rsd-t-h3, to give the quote real editorial presence without inventing
   a new border/colour/spacing language for it. Attribution deliberately
   gets no card surface (no background, no border, no shadow) — a hairline
   top rule is enough to separate it from the quote, keeping it visually
   subordinate rather than a competing box. No decorative quotation-mark
   glyph is added: the red-left-border already carries the "this is a
   sourced claim" signal this design system uses everywhere else, and a
   second decorative device would compete with it rather than reinforce it. */
.rsd-feedback blockquote { font-size: var(--rsd-t-h3); }
.rsd-feedback blockquote p:last-child { margin-bottom: 0; }
.rsd-feedback__attribution {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--rsd-gap-sm);
  margin-top: var(--rsd-gap); padding-top: var(--rsd-gap-sm);
  border-top: 1px solid var(--rsd-line);
}
.rsd-feedback__attribution figcaption { display: flex; flex-direction: column; gap: .15rem; }
/* Deliberately square-cornered, not circular like .rsd-cta-modal__avatar
   elsewhere in this file — a round avatar reads as a chat/social widget,
   exactly the tone this section is meant to avoid. Same white-surface +
   hairline-border + --rsd-radius language as .rsd-cards/.rsd-hero__aside,
   so the photo reads as attached evidence rather than a decorative image. */
.rsd-feedback__avatar {
  width: 56px; height: 56px; object-fit: cover; flex: none;
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-feedback__name { display: block; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-charcoal); }
.rsd-feedback__role { display: block; font-size: var(--rsd-t-xs); color: var(--rsd-muted); }

/* ---------------------------------------------------------- case study evidence
   Scoped to .rsd-case-evidence (single-case_studies.php's Evidence &
   limitations section only) — the shared .rsd-proof-unit__limitation base
   rule (used elsewhere by hand-authored .rsd-proof-unit content on
   Commercial/Market Service pages, per inc/block-guards.php) is not
   touched. In Case Study's stripped-down Evidence block there is no big
   .rsd-figure__value numeral above it to justify full body-size text
   sitting beside --rsd-t-sm/--rsd-t-xs metadata siblings — this brings it
   down to --rsd-t-sm to match .rsd-meta, an existing token, no new size
   introduced. */
.rsd-case-evidence .rsd-proof-unit__limitation { font-size: var(--rsd-t-sm); }

@media (max-width: 1023px) {
  .rsd-pillars { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 767px) {
  .rsd-pillars { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------- text-link
   hover: a thin underline that draws in left-to-right on hover/focus and
   retracts back to the left on mouse-out — not the instant native
   text-decoration:underline toggle this replaces (which is what read as
   abrupt), and not a fade (opacity is never touched here).
   Scope is deliberately narrow: breadcrumbs, footer links, and general
   in-content prose links (a plain <a> inside a <p> or <li> somewhere in
   .rsd-shell — how post/page content and most lists render in this
   theme). Explicitly excludes .rsd-btn (buttons keep their own solid/
   ghost hover) and never touches .rsd-menu (the primary/mega nav keeps
   its separate pale-red rounded hover, per D-38) — neither selector is
   part of the :is() list below, so this rule never reaches them. */
:is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn) {
  position: relative;
  text-decoration: none;
}
:is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn)::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: var(--rsd-red);
  transform: scaleX(0);
  transform-origin: left;
}
@media (prefers-reduced-motion: no-preference) {
  /* Duration/easing only exist under no-preference — see the reduced-
     motion block below for what happens instead. */
  :is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn)::after {
    transition: transform .32s cubic-bezier(0.22, 1, 0.36, 1);
  }
}
:is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn):hover::after,
:is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn):focus-visible::after {
  transform: scaleX(1);
}
/* prefers-reduced-motion: reduce — no draw-in, no retraction. The
   transition above simply doesn't exist in this mode, so the scaleX(0)
   to scaleX(1) flip on :hover/:focus-visible happens instantly: the
   underline is just present while hovering/focused, gone otherwise. */
@media (prefers-reduced-motion: reduce) {
  :is(.rsd-crumbs, .rsd-footer, .rsd-shell p, .rsd-shell li) a:not(.rsd-btn)::after {
    transition: none;
  }
}

/* ---------------------------------------------------------- footer
   widget areas — all four columns (inc/widgets.php), uniformly. Column
   1's structural logo and Column-1-only CTA button (footer.php) are the
   only things in a column that aren't widget content; both are direct
   children of .rsd-footer__col alongside the widget wrapper, so they get
   their own spacing rules below rather than through .rsd-footer__widget.
   Links/headings inside reuse .rsd-footer a (this file, and the
   text-link underline treatment near the end of this file) and
   .rsd-eyebrow (register_sidebar()'s before_title/after_title) as-is —
   nothing new is defined for either here. */
.rsd-footer__widget { margin-bottom: 1.25rem; }
.rsd-footer__widget:last-child { margin-bottom: 0; }
/* Breathing room between independent accordion groups within one column —
   Learn/Services, Resources/Industries, Company/Legal — a hairline, not a
   card border, so the groups read as related-but-distinct sections rather
   than one crowded list. rsd_footer_col_accordion_wrap() (inc/widgets.php)
   now produces one details+panel PAIR per heading-carrying widget, so the
   boundary between groups is "a .rsd-footer__col-details that immediately
   follows a previous group's .rsd-footer__col-panel" — the second, third,
   etc. group in a column, never the first. (Superseded selector: this used
   to target .rsd-footer__widget + .rsd-footer__widget inside one shared
   .rsd-footer__col-panel-inner, back when a column bundled multiple
   widgets under a single accordion — no longer applicable now that each
   panel-inner holds exactly one widget.) Scoped to .rsd-footer__col-panel
   + .rsd-footer__col-details specifically so Column 1 — logo/tagline/CTA,
   never accordion-wrapped since none of its widgets have a heading — has
   no matching pair and is untouched. Same value at every width (24px sits
   inside the mobile 20-28px section-spacing range this footer targets),
   so no separate mobile override is needed. */
.rsd-footer__col-panel + .rsd-footer__col-details {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(247,246,244,.08);
}
.rsd-footer__widget p {
  margin: 0 0 .75rem; font-size: var(--rsd-t-sm); color: rgba(247,246,244,.85);
}
.rsd-footer__widget p:last-child { margin-bottom: 0; }
.rsd-footer__widget img { max-width: 100%; height: auto; display: block; }

/* Column-1-only "Get a proposal" button (footer.php, gated by
   rsd_footer_cta_enabled) — reuses .rsd-btn--ghost-invert (already the
   dark-surface ghost variant, defined above) rather than a new visual
   style. inline-flex so an optional avatar image sits beside the label
   instead of stacking under it. */
/* margin-top nudged up slightly (.9rem → 1.1rem) purely for a touch more
   separation from Column 1's text above it — spacing only, per brief.
   Hover treatment is additive on top of the shared .rsd-btn--ghost-invert
   fill/color hover (untouched, unchanged) rather than replacing it: a
   soft red-tinted glow (a standard box-shadow, not filter/backdrop-
   filter — cheap, already used elsewhere in this design system's own
   shadow scale) plus a 1px lift. Both are transform/box-shadow only, so
   neither triggers layout. */
.rsd-footer__cta {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: 1.1rem;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.rsd-footer__cta:hover, .rsd-footer__cta:focus-visible {
  transform: translateY(-1px);
  /* Brand-red glow, not part of the neutral --rsd-shadow-* scale above
     (those are all charcoal-based) — left as its own literal rather than
     forced onto the nearest neutral tier, which would shift its color. */
  box-shadow: 0 6px 20px rgba(196,8,8,.16);
  border-color: rgba(196,8,8,.45);
}
/* .rsd-btn--ghost-invert:hover (line 254) sets background: var(--rsd-paper)
   and color: var(--rsd-charcoal) — correct everywhere else that class is
   used, but wrong for this specific button, which needs a red fill, not
   a paper one. Both properties are overridden here, together: fixing
   only color (an earlier pass) left this button's own paper background
   in place, producing white-on-white — this now replaces both halves of
   the shared hover for this instance. border-color in the sibling rule
   below (.rsd-footer__cta:hover) already uses rgba(196,8,8,.45) — the
   same RGB triple as --rsd-red itself, just translucent — so it already
   reads correctly against this red fill and needs no change. Compound
   class selector (.rsd-btn--ghost-invert.rsd-footer__cta:hover) rather
   than relying on source order to win the tie, so this stays correct
   even if the shared rule is ever reordered. Scoped to this one button
   instance only — .rsd-btn--ghost-invert's own hover is unchanged for
   every other button that uses it. */
.rsd-btn--ghost-invert.rsd-footer__cta:hover,
.rsd-btn--ghost-invert.rsd-footer__cta:focus-visible {
  background: var(--rsd-red);
  color: var(--rsd-paper);
}
.rsd-footer__cta-avatar { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex: none; }

/* Footer widget-area normalization — whatever block gets dropped into a
   footer column (Navigation, List, Latest Posts, Page List, the live
   Services Grid, anything) renders with the same footer-density look, not
   that block's own default styling. Scoped to .rsd-footer__col only —
   .rsd-footer__markets and .rsd-footer__base (copyright) are separate
   classes and untouched by any rule here, and nothing here reaches
   outside .rsd-footer at all, so the mega menu and every other list on
   the site are equally untouched. */

/* No bullets, no default WP list spacing, at any depth — a plain
   descendant selector (no ">") reaches a Navigation block's own nested
   submenu <ul>s just as much as a top-level list. */
.rsd-footer__col ul,
.rsd-footer__col ol {
  list-style: none; margin: 0; padding: 0;
}
.rsd-footer__col li { margin: 0 0 .5rem; }
.rsd-footer__col li:last-child { margin-bottom: 0; }

/* Footer size everywhere in a footer column — the same size the Markets
   row and legal line use (--rsd-t-sm, see .rsd-footer__list/.rsd-footer__
   markets ul above). !important is deliberate and narrow here: WordPress
   core blocks (core/navigation in particular) can apply their own font
   size as an INLINE style attribute when a size is picked in the editor's
   typography controls, and an inline style beats any class-based rule
   regardless of specificity — normal specificity has no way to win that.
   Setting it on the container too (not just a, li, p) means anything not
   explicitly listed here still inherits the right size by default. */
.rsd-footer__col,
.rsd-footer__col a,
.rsd-footer__col li,
.rsd-footer__col p,
.rsd-footer__col .wp-block-navigation,
.rsd-footer__col .wp-block-navigation-item,
.rsd-footer__col .wp-block-navigation-item__content,
.rsd-footer__col .wp-block-navigation__container {
  font-size: var(--rsd-t-sm) !important;
}

/* Any heading dropped in — a bare Heading block, or a widget's own title
   (register_sidebar()'s before_title/after_title in inc/widgets.php
   already wraps that one in .rsd-eyebrow) — gets the same eyebrow +
   calibration-rule treatment as every other section heading on the site.
   Targets the element, not a class, so it applies whether or not
   rsd-eyebrow is actually present on it. Colors match the existing
   ".rsd-footer .rsd-eyebrow" override for this dark background exactly. */
.rsd-footer__col h1,
.rsd-footer__col h2,
.rsd-footer__col h3,
.rsd-footer__col h4 {
  font-family: var(--rsd-display); font-weight: 600; font-size: var(--rsd-t-xs);
  letter-spacing: .14em; text-transform: uppercase;
  color: rgba(247,246,244,.55);
  width: fit-content; /* same fix as .rsd-eyebrow above — this is that exact pattern's dark-surface reimplementation, not a shared rule, so it needed the same edit separately. */
  margin: 0 0 .85rem; padding-bottom: .5rem;
  border-bottom: 1px solid rgba(247,246,244,.15);
  position: relative;
}
.rsd-footer__col h1::after,
.rsd-footer__col h2::after,
.rsd-footer__col h3::after,
.rsd-footer__col h4::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 2.5rem; height: 2px; background: var(--rsd-red);
}

/* Tight, even vertical rhythm — footer density, not article density. */
.rsd-footer__col p { margin: 0 0 .5rem; font-size: var(--rsd-t-sm); }
.rsd-footer__col p:last-child { margin-bottom: 0; }

/* Force vertical stacking + full column width regardless of a block's
   own default layout — core/navigation in particular defaults to a
   horizontal flex row, which on its own would break column width/
   alignment consistency with the other columns. */
.rsd-footer__col .wp-block-navigation,
.rsd-footer__col .wp-block-navigation__container,
.rsd-footer__col ul.wp-block-latest-posts,
.rsd-footer__col ul.wp-block-page-list {
  display: flex; flex-direction: column; align-items: flex-start;
  width: 100%; gap: 0;
}
.rsd-footer__col .wp-block-navigation-item,
.rsd-footer__col .wp-block-latest-posts__post {
  width: 100%; margin: 0 0 .5rem;
}
.rsd-footer__col .wp-block-navigation-item:last-child,
.rsd-footer__col .wp-block-latest-posts__post:last-child { margin-bottom: 0; }
.rsd-footer__col .wp-block-navigation-item__content { padding: 0; font-size: var(--rsd-t-sm); }

/* Links: color and the left-to-right underline hover already come from
   .rsd-footer a (this file, above) and the shared text-link underline
   rule (:is(.rsd-crumbs, .rsd-footer, ...) a:not(.rsd-btn), further down
   this file) — .rsd-footer is in both selector lists already, so
   anything inside .rsd-footer__col inherits both with no new rule
   needed here. */

/* ------------------------------------------------ footer mobile accordion
   The <details>/<summary> shell is built once, server-side, for every
   column that has a leading heading (rsd_footer_col_accordion_wrap(),
   inc/widgets.php) — same markup at every width, from 375px to 1440px.
   This CSS is the only thing that decides whether that shell behaves
   like an accordion or like a plain, always-open column; nothing here
   duplicates or replaces the .rsd-footer__col rules above, which still
   apply unchanged to whatever ends up inside .rsd-footer__col-panel.

   Desktop/tablet default — everything below outside the max-width:767px
   query further down — .rsd-footer__col-panel simply renders as normal
   block content, always: it is a SIBLING of .rsd-footer__col-details in
   the markup (inc/widgets.php's rsd_footer_col_accordion_wrap()), not a
   child of it, so the browser's native closed-<details> child-hiding
   behavior never applies to it in the first place — nothing is being
   overridden here, there is simply nothing to hide. (An earlier version
   of this shell put the panel INSIDE <details> and fought the UA
   stylesheet with display:block; that was found to be unreliable —
   a closed <details>'s own generated box does not reliably contribute a
   forced-visible child's content to a parent's layout sizing, confirmed
   by direct measurement — hence the sibling structure instead.) The four
   columns render open, side by side, exactly as before. The native
   marker and the custom chevron are both suppressed on the summary here
   too, so there is no stray hint of interactivity where none is meant to
   exist. */
/* .rsd-footer__col-panel is a SIBLING of .rsd-footer__col-details in the
   markup (inc/widgets.php's rsd_footer_col_accordion_wrap()), not a child
   of it — <details> now contains only <summary>. This is what makes the
   desktop rule below trivially correct: the panel is a plain <div>, sized
   by ordinary content flow, and was never inside <details> for the
   browser's native closed-<details> sizing behavior to affect in the
   first place. No override of <details> itself is needed any more. */
.rsd-footer__col-summary {
  cursor: default;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}
.rsd-footer__col-summary::-webkit-details-marker { display: none; }
/* display:none, not content:"" — an empty content value can still leave
   a marker BOX in place in some engines (WebKit in particular), which
   renders at the native marker's conventional position: the START of
   the summary, i.e. the left, ahead of the heading text. That leftover
   box is what was actually showing up on the left; the custom ::after
   chevron below was already correctly on the right the whole time.
   display:none removes the box itself, not just its content, so there
   is nothing left to render on either side. */
.rsd-footer__col-summary::marker { display: none; }
.rsd-footer__col-summary::after { content: none; }
.rsd-footer__col-panel { display: block; }
/* The heading's own margin-bottom (.rsd-footer__col h1-h4 above, .85rem)
   was what separated it from the content that used to follow it directly
   in the same flow. Now that the heading lives inside .col-summary — a
   flex container — that margin still takes up room but stops doing that
   job: a flex item's margin doesn't collapse into space after its
   container the way a normal block child's would, so left alone the
   panel content would start flush under the heading row instead. Zeroing
   it here and giving .col-panel-inner the exact same .85rem as top
   padding instead moves the gap to where it now actually needs to be,
   at every width — this is a structural fix, not a spacing change: the
   visible gap above the content is exactly what it was before. */
.rsd-footer__col-summary h1,
.rsd-footer__col-summary h2,
.rsd-footer__col-summary h3,
.rsd-footer__col-summary h4 {
  margin-bottom: 0;
}
.rsd-footer__col-panel-inner { padding-top: .85rem; }

@media (max-width: 767px) {
  /* Same "hide the native triangle, draw a custom indicator on ::after"
     convention .rsd-faq's own accordion already established above
     (.rsd-faq summary) — a chevron here instead of a +/-, rotated
     rather than swapped, but the identical underlying pattern: a
     couple of borders, no icon font, no image request. */
  /* Chevron sits immediately beside the heading text (~8-12px away, via
     the base rule's own gap:.75rem = 12px), not at the row's far right
     edge. Two things push it right by default and both are overridden
     here: the base rule's justify-content:space-between (pins the last
     flex item to the row's own end) and the chevron's own margin-left:auto
     (an independent "pin to the end" mechanism — belt-and-braces in the
     base rule, so both had to be neutralized, not just one). Deliberate
     choice: this means chevron x-position now varies with heading length
     (Industries We Serve's chevron sits further right than Legal's) —
     traded consistent right-edge alignment for "close to the heading",
     per explicit direction. */
  .rsd-footer__col-summary { cursor: pointer; padding-block: .35rem; justify-content: flex-start; }
  .rsd-footer__col-summary::after {
    content: "";
    display: block;
    width: 8px; height: 8px;
    flex: none;
    margin-left: 0;
    border-right: 2px solid rgba(247,246,244,.55);
    border-bottom: 2px solid rgba(247,246,244,.55);
    transform: rotate(45deg);
    transition: transform .2s ease;
  }
  /* A 45deg→225deg swing is a 180deg turn either direction — closed
     points down, open points up. */
  .rsd-footer__col-details[open] > .rsd-footer__col-summary::after {
    transform: rotate(225deg);
  }

  /* Mobile: no divider line between accordion groups — the desktop hairline
     (.rsd-footer__col-panel + .rsd-footer__col-details, base rule above,
     unchanged) reads correctly next to four columns side by side, but
     stacked full-width on a single mobile column a horizontal rule reads
     as a stronger, heavier separator than intended. Groups are separated
     by clean vertical spacing alone here instead: a single margin-top,
     no border, no padding-top (nothing to hold space open for a border
     that no longer exists). 1.25rem (20px) sits at the lower edge of the
     20-24px target — deliberately not the desktop's doubled margin+padding
     (48px total), which reads as excessive gap without a line to justify
     that much separation. */
  .rsd-footer__col-panel + .rsd-footer__col-details {
    margin-top: 1.25rem;
    padding-top: 0;
    border-top: 0;
  }

  /* The animated-height trick: a grid container with a single track
     sized in fr units can transition between two fr values smoothly —
     unlike height or max-height, this needs no JS measurement of the
     content's real height and no arbitrary cap to guess at; 0fr and 1fr
     are exact regardless of how tall the content actually is.
     .col-panel is the transitioning grid; .col-panel-inner is what
     actually gets clipped, because a grid track mid-transition has no
     length of its own for overflow to hang off directly — its child
     does. display:grid here still wins over the UA's own
     details:not([open]) hiding for the same cascade-origin reason as
     the desktop default above; only the grid-template-rows value (not
     the display) now differs between the two states, and that value is
     what actually does the showing/hiding.

     .rsd-footer__col-panel is a SIBLING of .rsd-footer__col-details, not
     its child (inc/widgets.php), so a plain [open] > .panel child-combinator
     can't reach it — the adjacent-sibling combinator does instead:
     .rsd-footer__col-details[open] + .rsd-footer__col-panel matches only
     the ONE panel immediately following a specific open <details>, not any
     panel anywhere in the column. This matters now that a column can hold
     several independent details+panel pairs (Learn, then Services, each
     with its own <details>) — an earlier version of this rule used
     :has(> .rsd-footer__col-details[open]) scoped to .rsd-footer__col,
     which asked "does this COLUMN have any open details" and then matched
     EVERY .rsd-footer__col-panel child of it; with more than one pair per
     column that would incorrectly expand every group's panel whenever any
     one of them opened. The adjacent-sibling form has no such ambiguity —
     it can only ever match the specific pair whose own <details> is open. */
  .rsd-footer__col-panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .28s ease;
  }
  .rsd-footer__col-details[open] + .rsd-footer__col-panel {
    grid-template-rows: 1fr;
  }
  /* padding-bottom: measured directly against real browser output — at
     430px with Learn genuinely open, the panel's own 1fr-resolved height
     (447.844px) fell ~0.006px short of the actual combined content height
     of both widgets (padding-top + widget 1 + widget 2's own margin-top +
     widget 2, measured via getBoundingClientRect() on each). That's
     floating-point rounding in the fr-track calculation, not a missing
     widget or a structural gap — but paired with overflow:hidden below,
     even a sub-pixel shortfall hard-clips whatever sits on that boundary.
     A small, deliberate content-side buffer here becomes part of what 1fr
     itself measures as .col-panel-inner's max-content height — this adds
     real headroom rather than relying on rounding to cooperate. Not a
     fixed panel height: nothing here declares how tall the panel is, only
     how much extra room its own content asks for. Mobile-only — desktop
     never uses this grid/overflow mechanism at all.

     min-height:0 overrides the grid item's own implicit min-height:auto
     (CSS Grid spec, "Implied Minimum Size of Grid Items") — the default
     floor that stops a grid item shrinking below its own intrinsic
     min-content size. That fixed the CONTENT half of the leak (the top of
     the first link no longer peeks through), but not the padding half:
     padding is not "content" and is not covered by min-height at all — an
     element with zero content height still renders its own padding-top +
     padding-bottom as unconditional, always-visible box space, exactly
     like an empty <div style="padding:20px"> still visibly occupies 40px.
     Measured directly: the base rule's padding-top (.85rem = 13.6px) plus
     this rule's own padding-bottom (.5rem = 8px) summed to the exact
     residual height browser measurement showed on a closed panel
     (21.5938px ≈ 13.6 + 8). min-height:0 could never have removed that,
     because padding isn't part of what min-height governs.

     Fix: padding-top/padding-bottom are zeroed here UNCONDITIONALLY
     (closed is the default state), and restored in a separate rule below,
     scoped to only fire when this panel-inner's own panel immediately
     follows an open <details> — i.e. only while genuinely open. The base
     .rsd-footer__col-panel-inner { padding-top: .85rem; } rule above
     (outside this media query) still governs desktop unchanged, where
     there is no collapse mechanism to leak through in the first place. */
  .rsd-footer__col-panel-inner {
    overflow: hidden;
    padding-top: 0;
    padding-bottom: 0;
    min-height: 0;
  }
  .rsd-footer__col-details[open] + .rsd-footer__col-panel .rsd-footer__col-panel-inner {
    padding-top: .85rem;
    padding-bottom: .5rem;
  }
}

/* ---------------------------------------------------------- proposal CTA
   Deliberately no entrance/exit animation on the <dialog> itself: doing
   that correctly needs @starting-style + transition-behavior:allow-
   discrete (dialog toggles display:none -> block, which a plain
   transition can't animate across without them), and this was built
   without the ability to visually verify it renders correctly in a real
   browser — an instant, fully-functional, on-brand modal beats a
   fancier one that might silently fail to show at all. The button's own
   hover still transitions, gated by prefers-reduced-motion as required. */
/* This is the desktop shape and it is the ONLY shape declared unconditionally
   — avatar + label side by side in a rectangular pill, same construction as
   the header's solid "Get a proposal" button (.rsd-btn--solid). The
   avatar-only circle is exclusively a max-width:1024px override, further
   down — there is no min-width rule re-asserting the rectangle at desktop,
   because none is needed: with the circle quarantined behind a max-width
   query, nothing can make this round above 1024px. */
.rsd-cta-btn {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 70;
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  background: var(--rsd-red); color: var(--rsd-white); border: 0; cursor: pointer;
  padding: .75rem 1.15rem; border-radius: var(--rsd-radius-pill); /* pill — explicitly allowed for this button, like the header CTA */
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm);
  /* Doesn't match any --rsd-shadow-* tier's exact blur/spread/alpha —
     left as its own literal rather than nudged onto the nearest one,
     which would visibly change it. */
  box-shadow: 0 4px 14px rgba(26,26,28,.18); /* small, not the "large shadow" this is meant to avoid */
}
.rsd-cta-btn:hover, .rsd-cta-btn:focus-visible { background: var(--rsd-red-ink); transform: translateY(-2px); }
.rsd-cta-btn__avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: none; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-cta-btn { transition: background-color .15s ease, transform .18s ease; }
}

/* Attention pulse — a single thin ring, ::after, pure CSS. inset:0 +
   border-radius:inherit starts the ring flush with the button's own edge
   (rectangle on desktop, circle at <=1024px — inherit means it's never a
   second shape to keep in sync with the max-width override further down);
   transform:scale() carries it outward while opacity fades to 0, so
   nothing here touches layout or paints a scrollbar (transformed overflow
   is paint-only, not layout). z-index:-1 keeps it behind the avatar/label
   within the button's own stacking context (position:fixed + z-index:70
   above already establishes that context, so -1 here can't drop below
   anything on the page outside it). One ::after, one animation instance —
   structurally there is only ever one ring, never a stack, and nothing in
   main.js touches this element or class on scroll/interaction (the only
   scroll listener in the theme writes --rsd-st onto the header pill, a
   different element entirely) — so this never retriggers on scroll, only
   on the hover/focus rule just below. Base state is opacity:0 outside the
   no-preference block below, so prefers-reduced-motion: reduce shows no
   ring at all, exactly D-28. */
.rsd-cta-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 1px solid var(--rsd-red);
  pointer-events: none;
  opacity: 0;
  z-index: -1;
}
@media (prefers-reduced-motion: no-preference) {
  /* 6.5s total = 2.5s visible pulse + 4s pause, so it reads as an
     occasional draw of the eye rather than constant motion. 38% is
     2.5s/6.5s — the ring finishes expanding/fading there and simply
     holds at scale(1.55)/opacity:0 (the explicit 100% keyframe repeats
     the 38% values rather than leaving the hold implicit, so the "pause"
     is a real, readable segment of the timeline, not an accident of an
     unfinished keyframe list) until the next cycle snaps back to 0%.
     cubic-bezier(.16,1,.3,1) ("ease-out-expo") replaces the plain
     ease-out keyword: ease-out's own curve front-loads most of the scale
     change into roughly the first third of the segment, which is what
     read as an abrupt "jump then crawl" rather than one continuous,
     considered expansion — this curve decelerates more gradually across
     the whole 2.5s instead. */
  .rsd-cta-btn::after { animation: rsd-cta-pulse 6.5s cubic-bezier(.16,1,.3,1) infinite; }
}
/* The pulse exists to attract attention; once attention has actually
   arrived (hover/focus) it stops immediately rather than continuing
   to compete with itself. */
.rsd-cta-btn:hover::after, .rsd-cta-btn:focus-visible::after {
  animation: none;
  opacity: 0;
}
@keyframes rsd-cta-pulse {
  0%   { transform: scale(1);    opacity: .55; }
  38%  { transform: scale(1.55); opacity: 0; }
  100% { transform: scale(1.55); opacity: 0; }
}

/* Tablet and mobile, <=1023px — the site-wide breakpoint system (Phase 1
   foundation: desktop >= 1024px, tablet 768-1023px, mobile < 768px), so
   1024 itself now gets the desktop rectangle, matching the header, which
   shows its full desktop nav from 1024px. (This used to be <=1024px
   inclusive, when 1024 was treated as the tablet test width.) This is the
   ONLY place the round, avatar-only shape is declared — the rectangle
   above has no min-width query re-asserting itself, so there is exactly
   one rule in the cascade that can make this button round.
   Label is hidden outright rather than truncated: the round shape has no
   room for text at all, avatar-only per spec. width==height + the
   already-inherited border-radius:999px is what turns the pill into a
   true circle (999px on equal box dimensions is a circle, same trick the
   ring's border-radius:inherit above relies on). Shadow is the header
   pill's own resting (unscrolled, --rsd-st:0) shadow value, copied
   literally rather than re-derived, so the two are the same shadow, not
   merely a similar one. */
@media (max-width: 1023px) {
  .rsd-cta-btn {
    width: 56px;
    height: 56px;
    padding: 0;
    gap: 0;
    box-shadow: var(--rsd-shadow-subtle); /* was the literal 0 8px 30px rgba(26,26,28,.06), copied from .rsd-pill's own resting shadow — same value, now named */
  }
  .rsd-cta-btn__label {
    display: none;
  }
}

.rsd-cta-modal {
  position: fixed; margin: auto; border: 0; border-radius: 3px; padding: 2rem;
  max-width: min(480px, calc(100vw - 2rem)); width: 100%; max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--rsd-white); color: var(--rsd-charcoal);
  box-shadow: var(--rsd-shadow-prominent); /* was the literal 0 12px 32px rgba(26,26,28,.16) — same value, now named */
}
.rsd-cta-modal::backdrop { background: var(--rsd-overlay); }
.rsd-cta-modal__close {
  position: absolute; top: .75rem; right: .75rem;
  width: 32px; height: 32px; border-radius: 3px; border: 1px solid var(--rsd-line);
  background: var(--rsd-paper); color: var(--rsd-charcoal); cursor: pointer;
  font-size: 1.25rem; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.rsd-cta-modal__head { margin-bottom: 1.25rem; }
.rsd-cta-modal__avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; margin-bottom: .75rem; }
/* Same eyebrow-adjacent calibration-rule language as every other section
   heading on the site (.rsd-eyebrow, near the top of this file), sized
   up for a modal heading rather than a small-caps label. */
.rsd-cta-modal__heading {
  font-family: var(--rsd-display); font-size: var(--rsd-t-h3); font-weight: var(--rsd-weight-bold);
  margin: 0 0 .6rem; padding-bottom: .5rem; border-bottom: 1px solid var(--rsd-line);
  position: relative;
}
.rsd-cta-modal__heading::after {
  content: ""; position: absolute; left: 0; bottom: -1px; width: 2.5rem; height: 2px; background: var(--rsd-red);
}
.rsd-cta-modal__subheading { color: var(--rsd-muted); font-size: var(--rsd-t-sm); margin: 0; }

.rsd-cta-form__row { margin: 0 0 .85rem; }
.rsd-cta-form__row label { display: block; font-size: var(--rsd-t-xs); font-weight: var(--rsd-weight-semibold); margin-bottom: .3rem; color: var(--rsd-muted); }
.rsd-cta-form__row input, .rsd-cta-form__row textarea {
  width: 100%; font: inherit; font-size: var(--rsd-t-sm); padding: .55rem .7rem;
  border: 1px solid var(--rsd-line); border-radius: 3px; background: var(--rsd-white); color: var(--rsd-charcoal);
  box-sizing: border-box;
}
/* Honeypot — off-screen, not display:none (some bots specifically check
   for and skip display:none fields), aria-hidden on the wrapper and
   tabindex="-1" on the field itself (inc/proposal-cta.php) so it's
   invisible and unreachable for real/keyboard visitors either way. */
.rsd-cta-form__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.rsd-cta-form__submit { width: 100%; text-align: center; margin-top: .25rem; }
.rsd-cta-form__submit:disabled { opacity: .6; cursor: default; }
.rsd-cta-form__status { font-size: var(--rsd-t-xs); color: var(--rsd-muted); margin: .6rem 0 0; min-height: 1em; }

.rsd-cta-modal__phone { margin: 1.25rem 0 0; font-size: var(--rsd-t-sm); }
.rsd-cta-modal__phone a { color: var(--rsd-red); font-weight: var(--rsd-weight-semibold); }
.rsd-cta-modal__consent { margin: .5rem 0 0; font-size: var(--rsd-t-xs); color: var(--rsd-muted); }

@media (max-width: 480px) {
  .rsd-cta-modal { padding: 1.5rem; }
}

/* ---------------------------------------------------------- RS Block Library
   inc/case-study-blocks.php. RS Results / RS Evidence / RS Client Feedback
   need nothing here — they render the exact existing .rsd-proof/
   .rsd-comparison/.rsd-case-evidence/.rsd-feedback markup, already fully
   styled above. This section covers only the two pieces that genuinely
   need new selectors: RS Heading / RS Button (core block STYLES need a
   class to hang the existing look off — is-style-* is that class, added
   here rather than editing .rsd-h1/.rsd-eyebrow/.rsd-btn* themselves) and
   RS Two Column (core/columns ships no layout of its own once
   wp-block-library is dequeued, so it needs one small base rule to be
   theme-owned rather than left unstyled — same "this theme styles blocks
   itself" reasoning as the .wp-block-button.rsd-btn* bridge above). */

/* RS Heading — exact .rsd-h1 / .rsd-h2 / .rsd-eyebrow declarations, restated
   under the block-style class Gutenberg adds rather than duplicating a new
   scale. Hero = page-level title. Section = the real, dominant section-
   heading scale — the default choice for an ordinary section heading, and
   what single-case_studies.php's own primary sections ("Challenge",
   "Strategy", "Results", "Client feedback", etc.) now use themselves.
   Editorial = the small tracked-caps kicker/label treatment this theme
   already uses for quieter, secondary headings (e.g. "Evidence &
   limitations") — deliberately the non-default option. */
.wp-block-heading.is-style-rsd-hero { font-size: var(--rsd-t-h1); max-width: 16ch; letter-spacing: var(--rsd-t-h1-letter-spacing, -0.03em); }
.wp-block-heading.is-style-rsd-section { font-size: var(--rsd-t-h2); }
.wp-block-heading.is-style-rsd-editorial {
  font-family: var(--rsd-display); font-weight: 600; font-size: var(--rsd-t-xs);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--rsd-muted);
  width: fit-content; margin: 0 0 0.85rem; padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rsd-line); position: relative;
}
.wp-block-heading.is-style-rsd-editorial::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 2.5rem; height: 2px; background: var(--rsd-eyebrow-accent, var(--rsd-red));
}

/* RS Button — same wrapper-div/inner-link bridge the existing
   .wp-block-button.rsd-btn* rules use (main.css, above), restated under the
   is-style-* class a block STYLE adds rather than the className an editor
   would otherwise have to type by hand. Primary/Secondary reuse
   .rsd-btn--solid/.rsd-btn--ghost's exact declarations; Text strips all
   button chrome to a plain link using the theme's ordinary anchor colours. */
.wp-block-button.is-style-rsd-primary,
.wp-block-button.is-style-rsd-secondary,
.wp-block-button.is-style-rsd-dark,
.wp-block-button.is-style-rsd-text {
  background: none; padding: 0; border: 0; border-radius: 0;
}
.wp-block-button.is-style-rsd-primary .wp-block-button__link,
.wp-block-button.is-style-rsd-secondary .wp-block-button__link,
.wp-block-button.is-style-rsd-dark .wp-block-button__link,
.wp-block-button.is-style-rsd-text .wp-block-button__link {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--rsd-tap-target); font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-sm); padding: .6rem 1.1rem; border-radius: var(--rsd-radius);
  text-decoration: none; border: 1px solid transparent; cursor: pointer;
  transition: background var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out);
}
.wp-block-button.is-style-rsd-primary .wp-block-button__link { background: var(--rsd-red); color: var(--rsd-white); }
.wp-block-button.is-style-rsd-primary .wp-block-button__link:hover { background: var(--rsd-red-ink); }
.wp-block-button.is-style-rsd-secondary .wp-block-button__link { background: transparent; border-color: var(--rsd-charcoal); color: var(--rsd-charcoal); }
.wp-block-button.is-style-rsd-secondary .wp-block-button__link:hover { background: var(--rsd-charcoal); color: var(--rsd-white); }
.wp-block-button.is-style-rsd-text .wp-block-button__link {
  min-height: 0; padding: 0; font-weight: var(--rsd-weight-semibold); color: var(--rsd-charcoal);
  text-decoration: underline; text-decoration-color: transparent;
}
.wp-block-button.is-style-rsd-text .wp-block-button__link:hover { color: var(--rsd-red); text-decoration-color: var(--rsd-red); }

/* RedSprout Button (redsprout-digital/redsprout-button, inc/redsprout-
   button-block.php) — Primary and Secondary are the two RS Button styles
   above, unchanged (the Hero's own CTAs); Dark joins their base rule and
   adds only colours: charcoal, its hover one step lighter, mixed from the
   same charcoal and white tokens (no new colour). On a dark surface it
   takes the ghost-invert hairline so its edge stays visible. Everything
   here is scoped to .rsd-button, so the Hero's buttons are untouched. */
.wp-block-button.is-style-rsd-dark .wp-block-button__link { background: var(--rsd-charcoal); color: var(--rsd-white); }
.wp-block-button.is-style-rsd-dark .wp-block-button__link:hover { background: color-mix(in srgb, var(--rsd-charcoal) 84%, var(--rsd-white)); color: var(--rsd-white); }
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .rsd-section--bg-charcoal) .wp-block-button.is-style-rsd-dark .wp-block-button__link { border-color: rgba(247, 246, 244, .35); }
/* Long labels wrap inside the button instead of pushing past a narrow
   column; the button stays content-width. */
.rsd-button .wp-block-button__link { max-width: 100%; text-align: center; overflow-wrap: anywhere; }
/* Optional arrow — decorative (aria-hidden), after the label; nudges 3px on
   hover / keyboard focus by transform (no reflow), the theme's existing
   arrow-nudge (.rsd-ind__all-arrow, .rsd-fbc__arrow). Under reduced
   motion the arrow stays put. */
.rsd-button__arrow { display: inline-block; flex: none; margin-left: .5rem; line-height: 1; }
@media (prefers-reduced-motion: no-preference) {
  .rsd-button__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-button .wp-block-button__link:is(:hover, :focus-visible) .rsd-button__arrow { transform: translateX(3px); }
}

/* RS Two Column — core/columns has no layout without wp-block-library CSS
   (dequeued, inc/cleanup.php); this is the one base rule that makes it
   theme-owned. Reuses --rsd-gap and the existing 768px stacking breakpoint
   (matches .rsd-blog-grid/.rsd-read-next's own mobile collapse). */
.wp-block-columns { display: flex; flex-wrap: wrap; gap: var(--rsd-gap); align-items: flex-start; }
.wp-block-column { flex: 1 1 0; min-width: 0; }
@media (max-width: 767px) {
  .wp-block-columns { flex-direction: column; }
}

/* RS Content — Standard (redsprout-digital/rs-rich-content): matched to the
   RedSprout Section Wrapper. The pattern is a .rsd-shell group holding a
   RedSprout — Section heading and a .rsd-prose group; it is identified by
   that structure (so pages that already use it are covered too). Challenge,
   Objectives, Strategy, Execution and Key Takeaways share the shape but
   carry an rsd-section-* marker class and are excluded.
   - Width: the text fills the container like Section content, instead of
     .rsd-prose's 68ch article measure.
   - Spacing: the title → text gap is the Section Wrapper's own head →
     content gap (--rsd-gap); headings inside the text drop .rsd-prose's
     article margins (2.25em / 1.75em) for the rhythm tokens.
   - Type: unchanged — it already uses the Section Wrapper's tokens.
   - Motion: the Section Wrapper's soft section-head reveal. On the front
     end the heading is rendered inside the Section Wrapper's own
     <header class="rsd-section-head"> as a .rsd-h2 (and the group marked
     .rsd-standard-content) — rsd_standard_content_section_head(),
     inc/shared-blocks.php, for saved and new instances alike. The editor
     keeps the plain structure, hence both selectors below; :is() keeps
     each rule's specificity as it was. The last three rules keep that head
     from changing the layout: no 62ch cap on the title, the title's colour
     as before, and inside an article the title keeps the article margin
     the head would otherwise remove. */
:is(.rsd-standard-content, .rsd-shell:not([class*="rsd-section-"]):has(> .wp-block-heading.is-style-rsd-section + .rsd-prose)) > .wp-block-heading.is-style-rsd-section { margin-bottom: 0; }
:is(.rsd-standard-content, .rsd-shell:not([class*="rsd-section-"]):has(> .wp-block-heading.is-style-rsd-section + .rsd-prose)) > .rsd-prose { max-width: none; margin-top: var(--rsd-gap); }
:is(.rsd-standard-content, .rsd-shell:not([class*="rsd-section-"]):has(> .wp-block-heading.is-style-rsd-section + .rsd-prose)) > .rsd-prose h2 { margin-top: var(--rsd-gap); }
:is(.rsd-standard-content, .rsd-shell:not([class*="rsd-section-"]):has(> .wp-block-heading.is-style-rsd-section + .rsd-prose)) > .rsd-prose :is(h3, h4) { margin-top: var(--rsd-gap-sm); }
:is(.rsd-standard-content, .rsd-shell:not([class*="rsd-section-"]):has(> .wp-block-heading.is-style-rsd-section + .rsd-prose)) > .rsd-prose > :first-child { margin-top: 0; }
.rsd-standard-content > .rsd-section-head { max-width: none; }
.rsd-standard-content > .rsd-section-head > .rsd-h2 { color: inherit; }
.rsd-prose .rsd-standard-content > .rsd-section-head > h2 { margin-top: 2.25em; }
.rsd-prose .rsd-standard-content > .rsd-section-head > h3 { margin-top: 1.75em; }

/* RS Content — Two Column (.rsd-two-col, inc/shared-blocks.php). Each
   column opens on the editorial hairline with the short red tick (the
   eyebrow / Content Highlights motif) — a deliberate pair, not two loose
   paragraphs. No card surface. */
.rsd-two-col .wp-block-column { position: relative; padding-top: 1.25rem; border-top: 1px solid var(--rsd-line); }
.rsd-two-col .wp-block-column::before { content: ""; position: absolute; top: -1px; left: 0; width: 2.25rem; height: 2px; background: var(--rsd-red); }
.rsd-two-col .wp-block-column > :first-child { margin-top: 0; }
.rsd-two-col .wp-block-column > :last-child { margin-bottom: 0; }

/* RS Content — Image + Content (.rsd-media-split). Columns ~42/58 and the
   4:5 cover crop come from the core blocks' own settings in the pattern;
   this adds the existing hairline frame, the 6px radius, a calmer 3:2
   crop once core stacks the columns (below 782px — its inline 4:5 would
   make a phone-height image), and the section-head intro size for the
   lede. "Image right" (core/columns block style) swaps the sides only
   while they sit side by side. */
.rsd-media-split .wp-block-columns { column-gap: clamp(2rem, 5vw, 4.5rem); }
.rsd-media-split .wp-block-image { margin: 0; }
.rsd-media-split .wp-block-image img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--rsd-line); border-radius: 6px;
  background: color-mix(in srgb, var(--rsd-charcoal) 4%, var(--rsd-paper));
}
.rsd-media-split .wp-block-column > :first-child { margin-top: 0; }
.rsd-media-split .wp-block-column > :last-child { margin-bottom: 0; }
.rsd-media-split .rsd-lede { font-size: var(--rsd-t-intro); }
@media (max-width: 781px) {
  .rsd-media-split .wp-block-image img { aspect-ratio: 3 / 2 !important; } /* beats core's inline 4/5 */
}
@media (min-width: 782px) {
  .wp-block-columns.is-style-rsd-image-right { flex-direction: row-reverse; }
}

/* RS Section — Objectives (.rsd-section-objectives). An editorial list:
   hairline-separated rows, a short red marker in place of the browser
   bullet. Scoped to the section's own marker class, so every Objectives
   section already published picks it up and no other list changes. */
.rsd-section-objectives .wp-block-list { margin: var(--rsd-gap-sm) 0 0; padding: 0; list-style: none; border-bottom: 1px solid var(--rsd-line); }
.rsd-section-objectives .wp-block-list > li {
  position: relative; margin: 0; padding: .85rem 0 .85rem 1.75rem;
  border-top: 1px solid var(--rsd-line); line-height: 1.6;
}
.rsd-section-objectives .wp-block-list > li::before {
  content: ""; position: absolute; left: 0; top: calc(.85rem + .8em - 1px);
  width: .85rem; height: 2px; background: var(--rsd-red);
}

/* RedSprout Image (redsprout-digital/redsprout-image, inc/shared-blocks.php):
   one core/image block in two block styles — only these two classes are
   styled, so no other image changes. Both take the parent's width (the
   pattern's .rsd-shell: the page container, an article column, a Section),
   a hairline and the 6px radius on all four corners, and an optional
   caption with the short red tick.
   - Full width (default): the image's natural proportions across the full
     content width; only a square, portrait or very tall image is capped
     (the larger of 85% of the viewport height and 3:4 of its width) and
     covered from its centre, so nothing towers.
   - Cropped / framed: a tighter editorial crop — 16:9 (3:2 on phones) —
     covered from the centre, inside a white hairline mat. */
.wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) { margin-block: var(--rsd-gap); margin-inline: 0; }
.wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) img {
  display: block; width: 100%; height: auto; box-sizing: border-box;
  border: 1px solid var(--rsd-line); border-radius: 6px;
  background: color-mix(in srgb, var(--rsd-charcoal) 4%, var(--rsd-paper));
}
/* The cap is never below 3:4 of the image's width (75cqi of the figure), so
   any landscape image of 4:3 or wider is never cropped — only square,
   portrait and very tall images are, from the centre. */
.wp-block-image.is-style-rsd-image-full { container-type: inline-size; }
.wp-block-image.is-style-rsd-image-full img { max-height: max(85vh, 75cqi); max-height: max(85svh, 75cqi); object-fit: cover; }
.wp-block-image.is-style-rsd-image-framed {
  padding: clamp(.5rem, 1.2vw, .75rem);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.wp-block-image.is-style-rsd-image-framed img { aspect-ratio: 16 / 9; object-fit: cover; object-position: 50% 50%; border-radius: var(--rsd-radius); }
@media (max-width: 599px) {
  .wp-block-image.is-style-rsd-image-framed img { aspect-ratio: 3 / 2; }
}
.wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) figcaption {
  display: flex; align-items: flex-start; gap: .6rem; margin: .7rem 0 0; text-align: left;
  font-size: var(--rsd-t-sm); line-height: 1.5; color: var(--rsd-muted);
}
.wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) figcaption::before {
  content: ""; flex: none; width: 1rem; height: 2px; margin-top: .7em; background: var(--rsd-red);
}
.wp-block-image.is-style-rsd-image-framed figcaption { margin: .6rem .15rem .1rem; }
.rsd-section--bg-charcoal .wp-block-image.is-style-rsd-image-framed { background: rgba(247, 246, 244, .04); border-color: rgba(247, 246, 244, .14); }
.rsd-section--bg-charcoal .wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) img { border-color: rgba(247, 246, 244, .14); }
.rsd-section--bg-charcoal .wp-block-image:is(.is-style-rsd-image-full, .is-style-rsd-image-framed) figcaption { color: rgba(247, 246, 244, .72); }

/* ---------------------------------------------------------- case study visual refinement (RB Industries pass)
   single-case_studies.php. Two changes, both scoped to that one template:
   1) every primary narrative/Results/Feedback section heading now uses the
      real .rsd-h2 scale (already defined above) instead of the tiny
      .rsd-eyebrow label every section heading used before — this is the
      one missing rung between the H1 and body text that made the page read
      flat. Evidence & limitations deliberately keeps .rsd-eyebrow (stays
      visually secondary, per its own design intent) and so do the
      "Related …" asides further down the template — neither was changed.
   2) .rsd-feedback__layout — the editorial two-column quote block. Grid
      columns only appear when a real client photo exists (:has(), same
      technique .rsd-comparison__table's flagged-column tint already uses);
      with no photo it stays the same single-column block it was before.
      .rsd-feedback__portrait reuses the exact card-surface language
      (--rsd-radius, --rsd-line border) as .rsd-feedback__avatar/.rsd-cards,
      just larger — a left-column editorial portrait, not an inline avatar,
      so it gets its own class rather than resizing the existing one. */
.rsd-feedback__layout { display: block; }
.rsd-feedback__layout:has(.rsd-feedback__media) {
  display: grid; grid-template-columns: 140px 1fr; gap: var(--rsd-gap); align-items: start;
}
.rsd-feedback__media { min-width: 0; }
.rsd-feedback__portrait {
  display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover;
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
}
.rsd-feedback__body { min-width: 0; }
@media (max-width: 767px) {
  .rsd-feedback__layout:has(.rsd-feedback__media) { grid-template-columns: 1fr; }
  .rsd-feedback__portrait { width: 96px; }
}

/* ---------------------------------------------------------- RS Block Design System, phase 2
   inc/case-study-blocks.php. Everything below is additive — no existing
   rule above this point is changed. Four things: RS Image's native
   alignwide/alignfull, RS Results' two new styles (Metric Cards, Before /
   After — Detailed Table needed no new CSS, it already had all of it),
   RS Client Feedback's two new styles (Editorial Quote, Compact — both
   CSS-only, no PHP branching), and RS Callout (core/quote block styles). */

/* RS Image — native core/image alignment (align-wide theme support,
   inc/setup.php), not a custom block. Standard needs no rule at all — no
   align class, core/image's own default sizing applies. Wide reuses
   --rsd-shell directly, the exact width every other section on the site
   already uses, rather than a second width value — it expands up to that
   width and no further; inside a narrower ancestor it simply fills that
   ancestor's own width instead of overflowing it. A true edge-to-viewport
   breakout for Wide would need a known-width ancestor this file doesn't
   control while the Case Study template itself stays untouched, so Wide is
   deliberately bounded, not a breakout. Full-width is a genuine viewport
   breakout via the standard calc(50% - 50vw) technique — the one place
   this rule set does escape its container, because "full-width" has no
   other honest meaning. */
.wp-block-image.alignwide { width: 100%; max-width: var(--rsd-shell); margin-left: auto; margin-right: auto; }
.wp-block-image.alignfull {
  width: 100vw; max-width: 100vw;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
}
.wp-block-image.alignwide img,
.wp-block-image.alignfull img { width: 100%; height: auto; display: block; }

/* RS Results — Metric Cards. Reuses .rsd-cards wholesale (grid + card
   surface, already defined above) for the layout; only the two small label
   classes below are new. metric_direction is deliberately not colour-coded
   here either, same restraint .rsd-proof's own comment already states for
   the Detailed Table — a bigger number is not automatically "better" for
   every metric. */
.rsd-results-card__metric { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-charcoal); margin: 0 0 .35rem; }
.rsd-results-card__change { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); color: var(--rsd-muted); margin: .15rem 0 .75rem; }
.rsd-results-card .rsd-figure__value { margin: 0 0 .15rem; }
.rsd-results-card .rsd-excerpt,
.rsd-results-card .rsd-figure__source,
.rsd-results-card .rsd-proof-unit__limitation { font-size: var(--rsd-t-xs); }

/* RS Results — Before / After. A plain list of rows, not a table — each
   metric's own Before/After pair reuses .rsd-figure__value's exact number
   treatment (the same class Metric Cards and the Evidence/Feedback figures
   already use), muted only on the Before side so After reads as the
   current, headline figure. */
.rsd-results-beforeafter { list-style: none; margin: var(--rsd-gap) 0 0; padding: 0; }
.rsd-results-beforeafter__row { padding-block: var(--rsd-gap-sm); border-bottom: 1px solid var(--rsd-line); }
.rsd-results-beforeafter__row:last-child { border-bottom: 0; }
.rsd-results-beforeafter__metric { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-sm); margin: 0 0 .5rem; }
.rsd-results-beforeafter__values { display: flex; align-items: baseline; gap: .75rem; margin: 0 0 .35rem; flex-wrap: wrap; }
.rsd-results-beforeafter__before { color: var(--rsd-muted); }
.rsd-results-beforeafter__arrow { color: var(--rsd-muted); font-size: var(--rsd-t-lg); }

/* RS Client Feedback — Editorial Quote / Compact. Both are pure CSS,
   descended from the is-style-* class ACF adds to the block's own wrapper
   (not the same element .rsd-feedback__layout is on), reusing the exact
   same markup every style shares (rsd_render_block_rs_client_feedback()).
   Editorial Quote drops the two-column grid entirely and lets any real
   photo re-flow small, after the quote, rather than deleting it — flex
   order does the repositioning without touching PHP. Compact keeps the
   existing square-cornered portrait language (never circular — see
   .rsd-feedback__avatar's own comment above on why) and only tightens
   scale/spacing for denser placements. */
.is-style-rsd-editorial-quote .rsd-feedback__layout { display: flex; flex-direction: column; }
.is-style-rsd-editorial-quote .rsd-feedback__body { order: 1; }
.is-style-rsd-editorial-quote .rsd-feedback__media { order: 2; width: 44px; margin-top: var(--rsd-gap-sm); }
.is-style-rsd-editorial-quote blockquote { font-size: var(--rsd-t-h2); }

.is-style-rsd-compact .rsd-feedback__layout:has(.rsd-feedback__media) { grid-template-columns: 56px 1fr; gap: var(--rsd-gap-sm); align-items: center; }
.is-style-rsd-compact blockquote { font-size: var(--rsd-t-base); }
.is-style-rsd-compact .rsd-feedback__attribution { margin-top: var(--rsd-gap-sm); padding-top: var(--rsd-gap-sm); }
.is-style-rsd-compact .rsd-feedback__name { font-size: var(--rsd-t-sm); }

/* RS Callout — core/quote block styles. None of the three touches
   .rsd-prose blockquote's own rule (still the default for any ordinary
   quote inside prose) — these only apply once an editor deliberately picks
   one from the block's own Style panel. Insight reuses the exact red-
   left-border "evidenced claim" motif .rsd-figure/.rsd-prose blockquote
   already use. Key Takeaway reuses the same card-surface language as
   .rsd-cards (white, hairline border, --rsd-radius, no shadow). Highlight
   reuses the exact color-mix() paper/red tint .rsd-comparison__table's own
   flagged-column treatment already uses — no new colour anywhere. */
.wp-block-quote.is-style-rsd-insight {
  border-left: 2px solid var(--rsd-red); padding: .25rem 0 .25rem 1.25rem;
  margin: 1.75rem 0; font-size: var(--rsd-t-lg);
}
.wp-block-quote.is-style-rsd-key-takeaway {
  background: var(--rsd-surface, var(--rsd-white)); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
  border-left: 2px solid var(--rsd-red); padding: var(--rsd-gap); margin: 1.75rem 0;
}
.wp-block-quote.is-style-rsd-highlight {
  background: color-mix(in srgb, var(--rsd-paper), var(--rsd-red) 6%);
  border-radius: var(--rsd-radius); padding: var(--rsd-gap); margin: 1.75rem 0;
}
.wp-block-quote.is-style-rsd-insight p:last-child,
.wp-block-quote.is-style-rsd-key-takeaway p:last-child,
.wp-block-quote.is-style-rsd-highlight p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------- Services Showcase
   inc/services-showcase.php (markup), assets/js/main.js (selection).
   One large featured panel + a service selector. Everything reuses the
   existing system: .rsd-shell width/rhythm, .rsd-eyebrow/.rsd-h2/.rsd-lede
   for the head, the .rsd-cards card surface (white, hairline, --rsd-radius)
   for selector items, the red accent + mono "instrument voice" for the
   index numbers, .rsd-btn--ghost-invert for the CTA on the dark panel.

   Layout: a two-area grid. Below 1024px the selector row sits above the
   panel (DOM order: tablist, then panels); from 1024px the panel takes the
   left ~2/3 and the selector becomes a vertical list on the right whose
   items stretch to the panel's height.

   No layout jump: every panel sits in the same grid cell
   (.rsd-showcase__panels is a one-cell grid), so the stage is always as
   tall as its TALLEST panel, whichever is showing. Inactive panels are
   opacity:0 + visibility:hidden (out of the accessibility tree and the
   tab order); the panels' own charcoal base means a cross-fade never
   flashes the page background through. */
.rsd-showcase__head { max-width: 62ch; margin-bottom: var(--rsd-gap); }
.rsd-showcase__head .rsd-h2 { margin-bottom: .35em; }
.rsd-showcase__head .rsd-lede { margin: 0; }

.rsd-showcase__stage {
  display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "tabs" "panels"; gap: var(--rsd-gap-sm);
}

/* Selector — horizontal, scrollable row by default (phones/tablets). */
.rsd-showcase__tabs {
  grid-area: tabs; position: relative; min-width: 0;
  display: flex; gap: .5rem;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.rsd-showcase__tabs::-webkit-scrollbar { display: none; }
.rsd-showcase__tab {
  flex: 0 0 min(80%, 17rem); scroll-snap-align: start;
  display: flex; align-items: flex-start; gap: .85rem;
  min-height: var(--rsd-tap-target); margin: 0; padding: .9rem 1rem;
  background: var(--rsd-surface, var(--rsd-white)); color: var(--rsd-charcoal);
  border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius);
  font: inherit; text-align: left; cursor: pointer;
}
/* Inset outline: the row scrolls (overflow clips anything outside it), so
   the global offset-outward focus ring would be cut off at its edges. */
.rsd-showcase__tab:focus-visible { outline-offset: -3px; }
.rsd-showcase__tab:hover { border-color: color-mix(in srgb, var(--rsd-line), var(--rsd-charcoal) 35%); }
.rsd-showcase__tab.is-active { border-color: var(--rsd-charcoal); box-shadow: inset 0 -2px 0 var(--rsd-red); }
.rsd-showcase__num {
  flex: none; padding-top: .15em;
  font-family: var(--rsd-mono); font-size: var(--rsd-t-xs); color: var(--rsd-muted);
}
.rsd-showcase__tab.is-active .rsd-showcase__num { color: var(--rsd-red); }
.rsd-showcase__tab-text { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.rsd-showcase__tab-title {
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: var(--rsd-t-base); line-height: 1.25; overflow-wrap: anywhere;
}
.rsd-showcase__tab-tagline { font-size: var(--rsd-t-sm); line-height: 1.4; color: var(--rsd-muted); overflow-wrap: anywhere; }

/* Featured panel. */
.rsd-showcase__panels {
  grid-area: panels; min-width: 0; display: grid;
  background: var(--rsd-charcoal); border-radius: var(--rsd-radius); overflow: hidden;
}
.rsd-showcase__panel {
  grid-area: 1 / 1; position: relative; isolation: isolate; min-width: 0;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(21rem, 95vw, 26rem);
  color: var(--rsd-paper);
  opacity: 0; visibility: hidden;
}
.rsd-showcase__panel.is-active { opacity: 1; visibility: visible; }
.rsd-showcase__media { position: absolute; inset: 0; z-index: -1; }
.rsd-showcase__img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
/* Charcoal only, in two layers. The image gets a light overall tint (so it
   still reads as an image); the copy carries its own backing — clear at
   its top edge, ~88% charcoal from a few rem down — so contrast holds
   however far a long description climbs up the panel, not just when the
   copy happens to sit low. The body spans the full panel width (no visible
   edge to its backing); its children keep the reading measure. */
.rsd-showcase__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--rsd-charcoal) 45%, transparent),
    color-mix(in srgb, var(--rsd-charcoal) 10%, transparent));
}
.rsd-showcase__body {
  position: relative; padding: clamp(3rem, 7vw, 5rem) clamp(1.5rem, 4vw, 2.75rem) clamp(1.5rem, 4vw, 2.75rem);
  background: linear-gradient(to top,
    color-mix(in srgb, var(--rsd-charcoal) 88%, transparent) calc(100% - clamp(3rem, 7vw, 5rem)),
    transparent);
}
.rsd-showcase__body > * { max-width: 40rem; }
/* No image: the plain charcoal surface, with the same red rule the
   sourced-figure signature uses marking the copy. */
.rsd-showcase__panel--no-media .rsd-showcase__body { background: none; padding-top: clamp(1.5rem, 4vw, 2.75rem); border-left: 2px solid var(--rsd-red); }
.rsd-showcase__title {
  margin: 0 0 .3em; color: var(--rsd-white);
  font-size: var(--rsd-t-h2); overflow-wrap: anywhere;
}
.rsd-showcase__tagline {
  margin: 0 0 .75rem; color: var(--rsd-paper);
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-medium); font-size: var(--rsd-t-lg); line-height: 1.35;
}
.rsd-showcase__desc {
  margin: 0 0 1.5rem; max-width: 52ch;
  color: color-mix(in srgb, var(--rsd-paper) 82%, transparent);
}
.rsd-showcase__desc:last-child, .rsd-showcase__tagline:last-child { margin-bottom: 0; }
.rsd-showcase__cta { gap: .5rem; }
/* The site's red focus ring is too low-contrast on charcoal (< 3:1) — on
   the dark panel, focus shows in paper instead. */
.rsd-showcase__panel:focus-visible,
.rsd-showcase__panel :focus-visible { outline-color: var(--rsd-paper); }
.rsd-showcase__panel:focus-visible { outline-offset: -4px; } /* inside: .rsd-showcase__panels clips for its radius */
.rsd-showcase__arrow { display: inline-block; }

/* Layout tiers follow the showcase's OWN width (a container query), not
   the viewport: full width on a page they match the old 768px / 1024px
   screen breakpoints (40rem / 60rem of shell), and inside a ~670px article
   column the showcase keeps the tablet layout instead of squeezing the
   desktop split into it. assets/js/main.js reads the same 60rem for the
   selector's aria-orientation. */
.rsd-showcase { container-type: inline-size; }

/* Tablet: the row fits three items without scrolling; more than that
   scrolls, never squeezes. */
@container (min-width: 40rem) {
  .rsd-showcase__tab { flex: 1 0 13rem; }
  .rsd-showcase__panel { min-height: clamp(24rem, 50vw, 28rem); }
}

/* Desktop: panel left, selector as a vertical list on the right, its items
   stretching to share the panel's full height. */
@container (min-width: 60rem) {
  .rsd-showcase__stage {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    grid-template-areas: "panels tabs"; align-items: stretch;
  }
  .rsd-showcase__tabs { flex-direction: column; overflow: visible; scroll-snap-type: none; }
  .rsd-showcase__tab { flex: 1 1 0; align-items: center; padding: 1.1rem 1.25rem; }
  .rsd-showcase__tab.is-active { box-shadow: inset 3px 0 0 var(--rsd-red); }
  .rsd-showcase__panel { min-height: clamp(26rem, 36vw, 32rem); }
}

/* A panel with no image has nothing to reserve image height for: it takes
   its copy's height (the stage still matches its tallest panel, and on
   desktop the selector column beside it). */
.rsd-showcase__panel.rsd-showcase__panel--no-media { min-height: 0; }

/* Motion — a restrained cross-fade; the incoming copy settles 8px and the
   image eases from a 2% zoom. Nothing moves the layout. Not present at all
   under prefers-reduced-motion (the site-wide reduce rule above also
   neutralises any transition). */
@media (prefers-reduced-motion: no-preference) {
  .rsd-showcase__tab { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out), box-shadow var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-showcase__num { transition: color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-showcase__panel { transition: opacity .35s var(--rsd-ease-out), visibility 0s linear .35s; }
  .rsd-showcase__panel.is-active { transition: opacity .35s var(--rsd-ease-out), visibility 0s linear 0s; }
  .rsd-showcase__body { transition: transform .45s var(--rsd-ease-out); }
  .rsd-showcase__panel:not(.is-active) .rsd-showcase__body { transform: translateY(8px); }
  .rsd-showcase__img { transition: transform .6s var(--rsd-ease-out); }
  .rsd-showcase__panel:not(.is-active) .rsd-showcase__img { transform: scale(1.02); }
  .rsd-showcase__arrow { transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-showcase__cta:hover .rsd-showcase__arrow,
  .rsd-showcase__cta:focus-visible .rsd-showcase__arrow { transform: translateX(3px); }
}

/* ============================================================
   Gutenberg / design-system foundation (Phase 1)
   ============================================================
   Since WP 6.9, classic themes load block assets on demand: WordPress's
   global styles (theme.json presets, layout rules, element styles) and
   each rendered block's own stylesheet reach the front end regardless of
   inc/cleanup.php. The one core sheet cleanup.php still removes is the
   small "common" block stylesheet (wp-block-library) — and with it the
   classes a few everyday editor controls depend on. Those rules are
   restated here with core's own values (so the editor, which loads
   common.css itself, and the front end match exactly); nothing else in
   the dequeued sheet is needed. */

/* Text alignment toolbar (Heading, Paragraph, List…). */
:root .has-text-align-center { text-align: center; }
:root .has-text-align-left { text-align: left; }
:root .has-text-align-right { text-align: right; }
.aligncenter { clear: both; }
/* core common.css's figure reset (":where(figure) { margin: 0 0 1em }"),
   scoped to BLOCK figures only (Image, Table, Embed, Video, Gallery…):
   without it every block figure outside .rsd-prose kept the browser's
   40px side margins on the front end while the editor showed it flush.
   The theme's own template figures (.rsd-figure, .rsd-hero-img,
   .rsd-feedback__attribution…) are deliberately not matched — they keep
   exactly what they render today. Zero specificity, so any theme rule wins. */
:where(figure[class*="wp-block-"]) { margin: 0 0 1em; }
/* Legacy justification classes some core blocks still print. */
.items-justified-left { justify-content: flex-start; }
.items-justified-center { justify-content: center; }
.items-justified-right { justify-content: flex-end; }
.items-justified-space-between { justify-content: space-between; }
/* WordPress's own visually-hidden class (printed by core blocks/widgets,
   e.g. search labels) — the theme's .rsd-sr is the same idea for theme
   markup. */
.screen-reader-text {
  border: 0; clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden;
  padding: 0; position: absolute; width: 1px; word-wrap: normal !important;
}
.screen-reader-text:focus {
  background-color: var(--rsd-paper); clip-path: none; color: var(--rsd-charcoal); display: block;
  font-size: 1em; height: auto; left: 5px; line-height: normal; padding: 15px 23px 14px;
  text-decoration: none; top: 5px; width: auto; z-index: 100000;
}

/* Standard section head — rsd_section_head() (inc/template-tags.php):
   optional eyebrow (a label), a real .rsd-h2, optional .rsd-lede intro.
   Only spacing here; the three classes keep their own type. No bottom
   margin — the content that follows (.rsd-cards, .rsd-pillars, …) already
   opens with its own var(--rsd-gap) top margin. */
.rsd-section-head { max-width: 62ch; }
.rsd-section-head .rsd-h2 { margin-bottom: .35em; }
.rsd-section-head .rsd-lede { margin: 0; }
/* Every section intro, shared: the standard head and the Services showcase's
   own head. text-wrap: pretty keeps a lone word off the last line. */
:is(.rsd-section-head, .rsd-showcase__head) .rsd-lede { font-size: var(--rsd-t-intro); text-wrap: pretty; }
.rsd-section-head > :last-child { margin-bottom: 0; }

/* Editor-chosen card-grid columns — rsd_cards_cols_class(), added only by
   the dynamic grid blocks (Industries / Locations / Team / Case Studies).
   The "Columns" value is the desktop count; tablets show at most two,
   phones one, and minmax(0, 1fr) means a long word can never push a track
   wider than the grid (no horizontal overflow). Template callers never get
   this class and keep .rsd-cards' own auto-fit grid. */
@media (min-width: 1024px) {
  .rsd-cards--cols-1 { grid-template-columns: minmax(0, 1fr); }
  .rsd-cards--cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rsd-cards--cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rsd-cards--cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-cards--cols-1 { grid-template-columns: minmax(0, 1fr); }
  .rsd-cards--cols-2, .rsd-cards--cols-3, .rsd-cards--cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .rsd-cards--cols { grid-template-columns: minmax(0, 1fr); }
}

/* Dark surfaces — focus and default text. The site's red focus ring is
   below 3:1 against charcoal (and invisible on red); on every dark surface
   the ring switches to paper. Covers the CTA band, the footer, and any
   Group/Paragraph an editor gives a dark palette background. (Header and
   Services Showcase are not touched: the header has no dark surface, the
   Showcase already handles its own panel.) */
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :focus-visible,
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal):focus-visible {
  outline-color: var(--rsd-paper);
}
/* An editor-made dark section with no text colour picked would otherwise
   keep charcoal text on a charcoal/red ground. Paper by default, headings
   follow it (overriding the Customizer's light-surface heading colours),
   and the muted supporting styles use the same translucent paper the .rsd-cta
   band already uses. An explicit text colour choice (.has-text-color) still
   wins. */
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal):not(.has-text-color) { color: var(--rsd-paper); }
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal):not(.has-text-color) :is(h1, h2, h3, h4, h5, h6) { color: inherit; }
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal):not(.has-text-color) :is(.rsd-lede, .rsd-eyebrow, .rsd-excerpt) { color: rgba(247, 246, 244, .72); }
/* ---------------------------------------------------------- RedSprout Section
   inc/section-block.php (markup) / assets/js/section-editor.js (editor).
   Structure only — background, width, spacing, the standard section head
   and ordinary inner blocks. Every value below is an existing token.

   Background: Paper is transparent (the page is already paper, and a Paper
   section nested inside a dark one simply takes on that dark surface);
   White and Charcoal paint --rsd-white / --rsd-charcoal. */
.rsd-section {
  --rsd-section-bg: transparent;
  --rsd-section-space: var(--rsd-block);
  background: var(--rsd-section-bg);
  padding-block: var(--rsd-section-space);
}
.rsd-section--bg-white { --rsd-section-bg: var(--rsd-white); }
.rsd-section--bg-charcoal { --rsd-section-bg: var(--rsd-charcoal); }

/* Spacing — the existing fluid tiers, so every option already shrinks on
   smaller screens (--rsd-block: 3rem → 5.5rem, --rsd-gap: 1.25rem →
   2.5rem). Spacious is the standard tier × 1.5, not a new value. */
.rsd-section--space-compact { --rsd-section-space: var(--rsd-gap); }
.rsd-section--space-spacious { --rsd-section-space: calc(var(--rsd-block) * 1.5); }
/* Two consecutive sections on the same background read as one band: the
   second drops its top padding so the gap between them is one spacing
   step, not two stacked together. */
.rsd-section--bg-paper + .rsd-section--bg-paper,
.rsd-section--bg-white + .rsd-section--bg-white,
.rsd-section--bg-charcoal + .rsd-section--bg-charcoal { padding-top: 0; }

/* Head → content. The head is the Phase 1 .rsd-section-head (eyebrow
   label, real .rsd-h2, .rsd-lede intro); content margins at the edges are
   zeroed so the section's own padding alone sets the spacing. */
.rsd-section-head + .rsd-section__content { margin-top: var(--rsd-gap); }
.rsd-section__content > :first-child { margin-top: 0; }
.rsd-section__content > :last-child { margin-bottom: 0; }
/* Block-level components stacked inside one section (a grid, the Services
   Showcase, a nested section…) sit one medium step apart — the same
   --rsd-gap tier the head → content gap uses; within a section the large
   --rsd-block step between whole sections would be too much. */
.rsd-section__content > :is(.rsd-shell, .rsd-section) + *,
.rsd-section__content > * + :is(.rsd-shell, .rsd-section) { margin-top: var(--rsd-gap); }

/* Container — how the content stays aligned with the rest of the page in
   each place a section can sit:
   1) Top level of the page (front-page.php prints the_content() straight
      into .rsd-main): the section spans the page, and its inner .rsd-shell
      centres the content at the standard width — exactly like every other
      top-level section. Wide / Full use .rsd-shell--wide / --full.
   2) Inside a page container (page.php wraps the_content() in .rsd-shell):
      the section keeps that container's exact width, so its content lines
      up with the page title and everything else on the page — the inner
      .rsd-shell fills it (the Phase 1 nested-shell rule), no second inset.
      The background is painted edge to edge with a spread box-shadow,
      clipped to the section's own height; it adds no scrollable overflow,
      and unlike a 100vw breakout it never shifts the content by the width
      of a classic scrollbar. Wide / Full content steps out symmetrically
      from the page container to the wider width. */
.rsd-shell > .rsd-section:not(.rsd-section--bg-paper) {
  box-shadow: 0 0 0 100vmax var(--rsd-section-bg);
  clip-path: inset(0 -100vmax);
}
.rsd-shell > .rsd-section > .rsd-section__inner.rsd-shell--wide {
  width: min(100vw - var(--rsd-shell-gutter), var(--rsd-shell-wide));
  margin-inline: calc((100% - min(100vw - var(--rsd-shell-gutter), var(--rsd-shell-wide))) / 2);
}
.rsd-shell > .rsd-section > .rsd-section__inner.rsd-shell--full {
  width: calc(100vw - var(--rsd-shell-gutter));
  margin-inline: calc((100% - (100vw - var(--rsd-shell-gutter))) / 2);
}
/* 3) Inside a narrower column — an article/service body (.rsd-prose), a
      sidebar layout's main column, or another section: painting edge to
      edge would run under the sidebar, so here the section is a contained
      band instead. Content fills the column; a White or Charcoal band gets
      inner padding and the standard radius so its content never touches
      the coloured edge. */
:is(.rsd-prose, .rsd-layout__main, .rsd-section__content) .rsd-section { box-shadow: none; clip-path: none; }
:is(.rsd-prose, .rsd-layout__main, .rsd-section__content) .rsd-section > .rsd-section__inner.rsd-shell { width: 100%; margin-inline: 0; }
:is(.rsd-prose, .rsd-layout__main, .rsd-section__content) .rsd-section:not(.rsd-section--bg-paper) {
  padding-inline: var(--rsd-gap); border-radius: var(--rsd-radius);
}

/* Content on dark surfaces (Charcoal section, the CTA band, the footer,
   editor-coloured dark groups) — completes the Phase 1 dark rules for
   what can sit inside: Secondary / ghost buttons take the existing
   .rsd-btn--ghost-invert treatment and Text buttons go paper; light
   surfaces placed on the dark ground (cards, hero asides, the light quote
   styles, the capture band) keep their own dark text and red focus ring,
   since they're still light surfaces — a White RedSprout Section nested in a dark one included. */
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.wp-block-button.is-style-rsd-secondary, .wp-block-button.rsd-btn--ghost) .wp-block-button__link,
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) a.rsd-btn--ghost:not(.rsd-btn--ghost-invert) {
  background: transparent; border-color: rgba(247, 246, 244, .35); color: var(--rsd-paper);
}
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.wp-block-button.is-style-rsd-secondary, .wp-block-button.rsd-btn--ghost) .wp-block-button__link:hover,
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) a.rsd-btn--ghost:not(.rsd-btn--ghost-invert):hover {
  background: var(--rsd-paper); color: var(--rsd-charcoal);
}
:is(.rsd-cta, .rsd-footer, .has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) .wp-block-button.is-style-rsd-text .wp-block-button__link { color: var(--rsd-paper); }
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) { color: var(--rsd-charcoal); }
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) :is(.rsd-lede, .rsd-eyebrow, .rsd-excerpt) { color: var(--rsd-muted); }
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) :focus-visible { outline-color: var(--rsd-red); }/* …and the buttons inside those light surfaces revert to the standard
   light-ground look (the dark-surface inversion above would otherwise
   leave them paper-on-white). */
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) :is(.wp-block-button.is-style-rsd-secondary, .wp-block-button.rsd-btn--ghost) .wp-block-button__link,
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) a.rsd-btn--ghost:not(.rsd-btn--ghost-invert) {
  background: transparent; border-color: var(--rsd-charcoal); color: var(--rsd-charcoal);
}
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) :is(.wp-block-button.is-style-rsd-secondary, .wp-block-button.rsd-btn--ghost) .wp-block-button__link:hover,
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) a.rsd-btn--ghost:not(.rsd-btn--ghost-invert):hover {
  background: var(--rsd-charcoal); color: var(--rsd-white);
}
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) :is(.rsd-cards > *, .rsd-hero__aside, .wp-block-quote.is-style-rsd-key-takeaway, .wp-block-quote.is-style-rsd-highlight, .rsd-cta-capture, .rsd-section--bg-white) .wp-block-button.is-style-rsd-text .wp-block-button__link { color: var(--rsd-charcoal); }
/* ---------------------------------------------------------- RedSprout Hero
   inc/hero-block.php (markup) / assets/js/hero-editor.js (editor). A
   separate component from the template hero (.rsd-hero, the page
   templates) — that one is untouched. Type is the existing .rsd-eyebrow /
   .rsd-h1 / .rsd-lede; CTAs are the existing RS Button styles; spacing and
   radius are existing tokens. The block carries .rsd-shell itself, so it
   is contained at the top of the homepage and fills a RedSprout Section or
   page container exactly (Phase 1 nested-shell rule).

   Mobile first: one column, text then visual. Standalone it opens with the
   same padding the template hero uses; inside a RedSprout Section the
   section's own spacing applies instead. */
.rsd-hero-block {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--rsd-gap);
  align-items: center;
  padding-block: var(--rsd-gap) var(--rsd-block);
}
.rsd-section__content .rsd-hero-block { padding-block: 0; }
.rsd-hero-block__body { min-width: 0; }
.rsd-hero-block__body > :last-child { margin-bottom: 0; }
.rsd-hero-block__title { margin-bottom: .45em; overflow-wrap: break-word; }
/* The lead one step quieter than the shared .rsd-lede, so the H1 leads
   clearly: 90% of the same fluid --rsd-t-lg token (21.6px → 19.4px at
   desktop), scaling down with it at smaller widths. Hero-scoped only. */
.rsd-hero-block__lead { margin: 0; font-size: calc(var(--rsd-t-lg) * .9); }
.rsd-hero-block__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem;
  margin-top: var(--rsd-gap);
}
.rsd-hero-block__actions .wp-block-button { margin: 0; }
/* Proof line — small and quiet, with the red left rule of the sourced
   figure (.rsd-figure), the theme's existing "evidenced claim" motif. */
.rsd-hero-block__proof {
  margin: var(--rsd-gap) 0 0; max-width: 58ch;
  padding-left: .75rem; border-left: 2px solid var(--rsd-red);
  font-size: var(--rsd-t-sm); line-height: 1.5; color: var(--rsd-muted);
}

/* Visual — its box is sized by aspect-ratio before the image arrives, so
   nothing shifts; the image covers it from the editor's focal point
   (object-position, set inline). 4:3 on phones, 16:9 on tablets (a wide
   band under the text), square beside the text on desktop. */
.rsd-hero-block__visual {
  margin: 0; min-width: 0; aspect-ratio: 4 / 3;
  border-radius: var(--rsd-radius); overflow: hidden; background: var(--rsd-line);
}
.rsd-hero-block__img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-hero-block__visual { aspect-ratio: 16 / 9; }
}
/* Desktop: text and visual side by side — the template hero's own 7:5
   proportion, the gap one step wider than the stacked gap. */
@media (min-width: 1024px) {
  .rsd-hero-block--has-visual {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: calc(var(--rsd-gap) * 1.5);
  }
  .rsd-hero-block__visual { aspect-ratio: 1 / 1; }
}

/* Centred (Text-only layout). */
.rsd-hero-block--align-center .rsd-hero-block__body { text-align: center; }
.rsd-hero-block--align-center :is(.rsd-eyebrow, .rsd-hero-block__title, .rsd-hero-block__lead, .rsd-hero-block__proof) { margin-inline: auto; }
.rsd-hero-block--align-center .rsd-hero-block__actions { justify-content: center; }
.rsd-hero-block--align-center .rsd-hero-block__proof { padding-left: 0; border-left: 0; }

/* On a dark surface (a Charcoal RedSprout Section, a dark group) the proof
   line takes the same translucent paper as the other supporting text. */
:is(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal):not(.has-text-color) .rsd-hero-block__proof { color: rgba(247, 246, 244, .72); }

/* ---------------------------------------------------------- RedSprout Hero — collage
   The Hero's HTML/CSS visual (rsd_hero_collage(), inc/hero-block.php),
   selected by the block's Visual control; the section carries
   .rsd-hero--collage-growth or .rsd-hero--collage-system. It takes the
   image's slot (and the same desktop 7:5 split) but sizes itself: a stage
   with a fixed aspect ratio (growth) or a compact grid (system), capped
   so it never outgrows the text. White surfaces, hairline borders, one
   red accent, 6–8px radius, quiet shadows; nothing moves except the
   existing reveal. Phones: the centre piece plus two cards, no
   connectors. Every piece stays inside its stage — no overflow. */
.rsd-hero-collage {
  --rsd-hc-shadow: 0 14px 32px -16px rgba(26, 26, 28, .24), 0 2px 6px rgba(26, 26, 28, .05);
  aspect-ratio: auto; overflow: visible; background: none; border-radius: 0;
}
.rsd-hero-collage :is(b, i) { font-style: normal; font-weight: inherit; }

/* Growth: one compact "Digital Growth" app window — traffic by channel
   (a restrained four-line chart beside the channel list) over a strip of
   the four growth modules with neutral status dots. No figures, a
   visible "Demo interface" tag. About 464 × 320px on desktop (≈1.45:1),
   its height the content's own — it never stretches to the hero's
   height and sits vertically centred beside the text (the hero grid's
   align-items: center). No floating cards, nothing outside the window. */
.rsd-gd {
  width: 100%; max-width: 29rem; margin-inline: auto; overflow: hidden;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-hc-shadow);
}
.rsd-gd__top { display: flex; align-items: center; justify-content: space-between; gap: .6rem; padding: .55rem .85rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-gd__brand { display: inline-flex; align-items: center; gap: .45rem; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .8rem; color: var(--rsd-charcoal); }
.rsd-gd__brand i { width: 12px; height: 12px; border-radius: 3px; background: var(--rsd-red); }
.rsd-gd__tag {
  padding: .05rem .4rem; font-family: var(--rsd-mono); font-size: .7rem; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap;
  color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-gd__label { font-family: var(--rsd-mono); font-size: .7rem; line-height: 1.25; letter-spacing: .04em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-gd__range { font-size: .7rem; color: var(--rsd-muted); white-space: nowrap; }
.rsd-gd__traffic { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 1rem; padding: 1.1rem .95rem 1rem; }
.rsd-gd__chart-wrap { display: grid; gap: .45rem; min-width: 0; }
.rsd-gd__head { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
.rsd-gd__chart { display: block; width: 100%; height: 8.25rem; }
.rsd-gd__grid { fill: none; stroke: var(--rsd-line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rsd-gd__line { fill: none; stroke-width: 1.6; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.rsd-gd__line--organic { stroke: var(--rsd-red); }
.rsd-gd__line--paid { stroke: var(--rsd-charcoal); }
.rsd-gd__line--direct, .rsd-gd__line--referral { stroke: var(--rsd-muted); opacity: .55; }
.rsd-gd__line--referral { stroke-dasharray: 3 3; }
.rsd-gd__axis { display: flex; justify-content: space-between; font-size: .7rem; color: var(--rsd-muted); }
.rsd-gd__channels { display: grid; gap: .55rem; margin: 0; padding: 0 0 0 1rem; border-left: 1px solid var(--rsd-line); list-style: none; }
.rsd-gd__channels li { display: flex; align-items: center; gap: .45rem; font-size: .72rem; line-height: 1.2; color: var(--rsd-charcoal); white-space: nowrap; }
.rsd-gd__key { flex: none; width: 12px; height: 2px; border-radius: 1px; }
.rsd-gd__key--organic { background: var(--rsd-red); }
.rsd-gd__key--paid { background: var(--rsd-charcoal); }
.rsd-gd__key--direct { background: var(--rsd-muted); opacity: .55; }
.rsd-gd__key--referral { background: repeating-linear-gradient(90deg, var(--rsd-muted) 0 3px, transparent 3px 6px); opacity: .55; }
.rsd-gd__modules { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rsd-line); }
.rsd-gd__modules li { display: flex; flex-direction: column; gap: .3rem; min-width: 0; padding: .8rem .95rem .9rem; }
.rsd-gd__modules li + li { border-left: 1px solid var(--rsd-line); }
.rsd-gd__module { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .75rem; line-height: 1.25; color: var(--rsd-charcoal); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rsd-gd__status { display: inline-flex; align-items: center; gap: .35rem; font-size: .7rem; line-height: 1.2; color: var(--rsd-muted); white-space: nowrap; }
.rsd-gd__status::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--rsd-charcoal); opacity: .55; }

/* HubSpot visual (a pasted HubSpot embed, or a form shortcode): a clean,
   contained surface; its height is the form's own. The form's markup
   is kept inside the column. From 1024px the hero aligns to the top so
   the text never re-centres while an embedded form loads. A min-height
   reserves most of a typical embedded form's space (forms load async) so
   the content below barely moves; taller forms simply grow. */
.rsd-hero-form {
  aspect-ratio: auto; overflow: visible; min-width: 0; padding: clamp(1.25rem, 3vw, 2rem);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-hc-shadow, none);
}
.rsd-hero-form :where(iframe, form, input, select, textarea, img, fieldset) { max-width: 100%; }
.rsd-hero-form iframe { width: 100%; border: 0; }
/* HubSpot's container (rsd_hero_hubspot_form()): full column width; the
   iframe HubSpot puts in it sizes its own height. */
.rsd-hero-form :is(.hs-form-frame, .rsd-hero-form__target) { width: 100%; min-width: 0; }
/* Editor-only preview of the configured shortcode (hero-editor.js). */
.rsd-hero-form--editor { display: flex; flex-direction: column; justify-content: center; gap: .5rem; min-height: 12rem; border-style: dashed; box-shadow: none; }
.rsd-hero-form__editor-title { margin: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: var(--rsd-t-lg); }
.rsd-hero-form__editor-code { font-family: var(--rsd-mono); font-size: .8rem; overflow-wrap: anywhere; }
.rsd-hero-form__editor-note { margin: 0; font-size: var(--rsd-t-sm); color: var(--rsd-muted); }
.rsd-hero-form:not(.rsd-hero-form--editor) { min-height: 26rem; }
@media (min-width: 1024px) {
  .rsd-hero--shortcode { align-items: start; }
}

/* System: "Digital System" at the centre, four capability cards around it
   in a clockwise flow (products → growth → intelligence → automation),
   joined to it by hairlines that run under the cards. */
.rsd-hs { position: relative; width: 100%; max-width: 30rem; margin-inline: auto; }
.rsd-hs__lines { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; }
.rsd-hs__lines line { stroke: var(--rsd-line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rsd-hs__list {
  position: relative; z-index: 1; display: grid; grid-template-columns: 1fr 1fr;
  /* Equal outer rows, so the core (centred on the whole collage) sits
     exactly in the middle row even when one row's text wraps further. */
  grid-template-rows: 1fr 5.5rem 1fr; grid-template-areas: "a b" ". ." "d c";
  column-gap: 1.25rem; margin: 0; padding: 0; list-style: none;
}
.rsd-hs__card {
  display: flex; flex-direction: column; gap: .2rem; min-width: 0; margin: 0; padding: .85rem .95rem;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; box-shadow: var(--rsd-hc-shadow);
}
.rsd-hs__card--products { grid-area: a; }
.rsd-hs__card--growth { grid-area: b; }
.rsd-hs__card--intelligence { grid-area: c; }
.rsd-hs__card--automation { grid-area: d; }
.rsd-hs__num { font-family: var(--rsd-mono); font-size: .7rem; font-weight: var(--rsd-weight-semibold); color: var(--rsd-red); }
.rsd-hs__title { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .8rem; line-height: 1.25; letter-spacing: .09em; text-transform: uppercase; color: var(--rsd-charcoal); }
.rsd-hs__desc { font-size: .78rem; line-height: 1.45; color: var(--rsd-muted); }
.rsd-hs__core {
  position: absolute; z-index: 2; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: .2rem; padding: .75rem 1.1rem; white-space: nowrap;
  background: var(--rsd-charcoal); color: var(--rsd-paper); border-top: 2px solid var(--rsd-red); border-radius: 6px; box-shadow: var(--rsd-hc-shadow);
}
.rsd-hs__core-title { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .82rem; letter-spacing: .14em; text-transform: uppercase; }
.rsd-hs__core-note { font-size: .72rem; color: rgba(247, 246, 244, .72); }
/* The centre as an image (the hero's own image, chosen in the block): a
   16:10 window, covered from the focal point, with the cards' own border,
   radius and quiet shadow — none of the core card's charcoal or red rule.
   The middle row grows to fit it, so it never touches the cards. */
.rsd-hero-collage--core-image .rsd-hs__list { grid-template-rows: 1fr 7.5rem 1fr; }
.rsd-hs__core--image {
  height: 6.5rem; aspect-ratio: 16 / 10; padding: 0; overflow: hidden;
  background: var(--rsd-white); border: 1px solid var(--rsd-line);
}
.rsd-hs__img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Tablet: the collage sits under the text, a little smaller; the Digital
   Growth window lines up with the text's left edge. */
@media (min-width: 768px) and (max-width: 1023px) {
  .rsd-hs { max-width: 30rem; }
  .rsd-gd { max-width: 27rem; }
}
@media (max-width: 1023px) {
  .rsd-hero-block--align-left .rsd-gd { margin-inline: 0; }
}
/* Phones: the centre piece plus two cards; no connectors. */
@media (max-width: 767px) {
  .rsd-hs__lines, .rsd-hs__card--intelligence, .rsd-hs__card--automation { display: none; }
  .rsd-hs__list { grid-template-rows: auto; grid-template-areas: "a b"; column-gap: .75rem; }
  .rsd-hs__core { position: static; transform: none; width: fit-content; margin: 1rem auto 0; }
  .rsd-hero-collage--core-image .rsd-hs__list { grid-template-rows: auto; }
  .rsd-hs__core--image { width: min(100%, 16rem); height: auto; }
}
/* Small phones: Digital Growth stacks — a shorter chart, the channels as
   a two-column key under it, the modules two by two. */
@media (max-width: 599px) {
  .rsd-gd__traffic { grid-template-columns: minmax(0, 1fr); gap: .65rem; padding: .75rem .75rem .7rem; }
  .rsd-gd__chart { height: 4rem; }
  .rsd-gd__channels { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .4rem 1rem; padding: 0; border-left: 0; }
  .rsd-gd__modules { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rsd-gd__modules li { flex-flow: row wrap; align-items: center; justify-content: space-between; gap: .2rem .5rem; padding: .5rem .75rem; }
  .rsd-gd__modules li:nth-child(odd) { border-left: 0; }
  .rsd-gd__modules li:nth-child(n + 3) { border-top: 1px solid var(--rsd-line); }
}

/* ---------------------------------------------------------- RedSprout Hero — Intelligence System
   The Hero's fifth visual (rsd_hero_intelligence(), inc/hero-block.php;
   interaction assets/js/hero-intelligence.js, loaded only with it). An
   explanatory method diagram, not a dashboard: one window in the Digital
   Growth collage's language (white surface, hairline border, 8px radius,
   the same quiet shadow, a "Methodology" tag), five numbered stages on a
   vertical rail — signals → analytics → AI insight → action → improve —
   a detail line and the closing loop. Width capped like the Digital Growth
   window; height is its content's own.
   States: a highlighted stage gets the paper surface, a red left rule, a
   red number and a red outgoing connector; the others' labels quieten. A
   pinned stage also fills its number (a shape cue, not colour alone).
   Without JavaScript every description shows inline under its stage and
   there is no detail line. Transitions only under no-preference. */
.rsd-is {
  width: 100%; max-width: 29rem; margin-inline: auto; overflow: hidden;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-hc-shadow);
}
/* Density: compact rows (a 20px number box, the terms set tight under the
   label), a slim header, detail area and loop — every stage and term still
   on view on desktop, no scrolling inside the window. */
.rsd-is__top { display: flex; align-items: center; justify-content: space-between; gap: .6rem; padding: .4rem .85rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-is__brand { display: inline-flex; align-items: center; gap: .45rem; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .76rem; color: var(--rsd-charcoal); }
.rsd-is__brand i { width: 10px; height: 10px; border-radius: 2px; background: var(--rsd-red); }
.rsd-is__tag {
  padding: 0 .35rem; font-family: var(--rsd-mono); font-size: .64rem; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap;
  color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-is__flow { margin: 0; padding: .25rem; list-style: none; }
.rsd-is__stage { position: relative; margin: 0; padding: .3rem .7rem; border-radius: 6px; }
/* The rail: from this stage's number down to the next one's. */
.rsd-is__stage:not(:last-child)::before {
  content: ""; position: absolute; left: calc(1.575rem - .5px); top: 1.55rem; bottom: -.3rem; width: 1px; background: var(--rsd-line);
}
.rsd-is__btn {
  position: static; display: flex; align-items: center; gap: .6rem; width: 100%; margin: 0; padding: 0;
  background: none; border: 0; font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.rsd-is.is-ready .rsd-is__btn::after { content: ""; position: absolute; inset: 0; border-radius: 6px; } /* the whole row is the button */
.rsd-is__num {
  position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; flex: none; width: 1.75rem; height: 1.25rem;
  font-family: var(--rsd-mono); font-size: .64rem; font-weight: var(--rsd-weight-semibold); color: var(--rsd-muted);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 3px;
}
.rsd-is__label { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .74rem; line-height: 1.2; letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-charcoal); }
.rsd-is__terms { display: block; margin: .1rem 0 0 2.35rem; font-size: .68rem; line-height: 1.35; color: var(--rsd-muted); }
.rsd-is__desc { display: block; margin: .15rem 0 0 2.35rem; font-size: .74rem; line-height: 1.4; color: var(--rsd-charcoal); }
/* Scripted: the descriptions move to the detail line (still read through
   each button's aria-describedby, so they stay in the accessibility tree). */
.rsd-is.is-ready .rsd-is__desc {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.rsd-is.has-current .rsd-is__stage:not(.is-current) .rsd-is__label { color: var(--rsd-muted); }
.rsd-is__stage.is-current { background: var(--rsd-paper); box-shadow: inset 2px 0 0 var(--rsd-red); }
.rsd-is__stage.is-current .rsd-is__num { color: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-is__stage.is-current::before { background: var(--rsd-red); }
.rsd-is__stage.is-pinned .rsd-is__num { color: var(--rsd-white); background: var(--rsd-red); border-color: var(--rsd-red); }
/* Focus rings the stage row (inset: the window clips its edges). */
@supports selector(:has(*)) {
  .rsd-is__stage:has(.rsd-is__btn:focus-visible) { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
  .rsd-is__btn:focus-visible { outline: none; }
}
.rsd-is__detail { display: none; }
.rsd-is.is-ready .rsd-is__detail { display: grid; gap: .15rem; padding: .45rem .85rem .5rem; border-top: 1px solid var(--rsd-line); }
.rsd-is__detail-label { font-family: var(--rsd-mono); font-size: .64rem; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-red); }
.rsd-is__detail-text { min-height: 2.8em; font-size: .76rem; line-height: 1.4; color: var(--rsd-charcoal); } /* two lines reserved: no shift as it changes */
.rsd-is__detail-terms { display: none; }
.rsd-is__loop {
  display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .4rem; margin: 0; padding: .3rem .85rem;
  background: var(--rsd-paper); border-top: 1px solid var(--rsd-line);
  font-family: var(--rsd-mono); font-size: .62rem; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-muted);
}
.rsd-is__loop i { font-style: normal; color: var(--rsd-muted); opacity: .6; }
.rsd-is__loop .rsd-is__return { margin-left: auto; font-size: .78rem; line-height: 1; opacity: 1; }
.rsd-is.is-last .rsd-is__return { color: var(--rsd-red); }
@media (prefers-reduced-motion: no-preference) {
  .rsd-is__stage, .rsd-is__stage::before, .rsd-is__num, .rsd-is__label, .rsd-is__return {
    transition: background-color var(--rsd-motion-fast) var(--rsd-ease-out), color var(--rsd-motion-fast) var(--rsd-ease-out),
      border-color var(--rsd-motion-fast) var(--rsd-ease-out), box-shadow var(--rsd-motion-fast) var(--rsd-ease-out);
  }
}
/* Tablet / phones: under the text, lined up with its left edge (as the
   Digital Growth window); slightly tighter rows on small phones. */
/* Stacked under the text (below 1024px) and scripted, the visual stays
   compact: each row is number + label only — a 44px tap target — and the
   supporting terms join the description in the detail line for the
   selected stage (both stay each button's screen-reader description).
   Without JavaScript the terms stay inline. */
@media (max-width: 1023px) {
  .rsd-hero-block--align-left .rsd-is { margin-inline: 0; }
  .rsd-is.is-ready .rsd-is__flow { padding-block: .15rem; }
  .rsd-is.is-ready .rsd-is__stage { padding-block: .75rem; } /* 12 + 20 + 12 = 44px rows */
  /* The selected row, right above, already names the stage. */
  .rsd-is.is-ready .rsd-is__detail-label { display: none; }
  .rsd-is.is-ready .rsd-is__stage:not(:last-child)::before { top: 2rem; bottom: -.75rem; }
  .rsd-is.is-ready .rsd-is__terms {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .rsd-is.is-ready .rsd-is__detail-terms { display: block; min-height: 2.7em; font-size: .68rem; line-height: 1.35; color: var(--rsd-muted); }
}
@media (max-width: 599px) {
  .rsd-is__stage { padding-inline: .55rem; }
  .rsd-is__stage:not(:last-child)::before { left: calc(1.425rem - .5px); }
  .rsd-is__detail, .rsd-is.is-ready .rsd-is__detail { padding-inline: .75rem; }
}
/* Open — the system visuals' shared presentation (see "Open visuals"
   below; the --hvo-* tokens are defined there): no window, the top bar as
   a kicker, the highlighted row a faint red tint with its red rule, the
   detail on a left rule, the loop a quiet mono line. On a dark surface it
   keeps the framed window above. */
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) {
  --rsd-white: var(--rsd-hv-surface, var(--rsd-body-bg, var(--rsd-paper)));
  max-width: 31rem; overflow: visible; color: var(--hvo-ink); background: none; border: 0; border-radius: 0; box-shadow: none;
}
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__top {
  justify-content: flex-start; margin: 0 0 1rem; padding: 0; background: none; border: 0;
}
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__top::before { content: ""; flex: none; width: 1.5rem; height: 1px; background: var(--rsd-red); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__brand { gap: .6rem; font-size: .82rem; color: var(--hvo-ink); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__brand i { order: 1; width: 1px; height: .8rem; border-radius: 0; background: var(--hvo-line); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__tag { padding: 0; font-size: .66rem; letter-spacing: .08em; color: var(--hvo-muted); border: 0; }
/* The rows' numbers line up with the kicker; the row highlight keeps its padding. */
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__flow { margin-inline: -.7rem; padding: 0; }
@media (max-width: 599px) {
  .rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__flow { margin-inline: -.55rem; }
}
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__stage.is-current { background: var(--hvo-on); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *).is-ready .rsd-is__detail { margin-top: 1.25rem; padding: .15rem 0 .15rem 1rem; border-top: 0; border-left: 2px solid var(--hvo-line); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *).has-current .rsd-is__detail { border-left-color: var(--hvo-accent); }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__detail-text { font-size: .86rem; line-height: 1.5; }
.rsd-is:not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) .rsd-is__loop { margin-top: 1rem; padding: 0; background: none; border-top: 0; color: var(--hvo-muted); }

/* ---------------------------------------------------------- RedSprout Hero — system visuals
   The Hero's fifteen system visuals (rsd_hero_system(), inc/hero-visuals.php;
   interaction assets/js/hero-visuals.js, loaded only with them). One window
   in the Digital Growth / Intelligence System language — white surface,
   hairline border, 8px radius, the same quiet shadow, a visible tag —
   holding a scene, the stage controls, a detail panel and a footer line.
   Width capped like the other Hero windows (29rem); each visual's height is
   fixed by its parts: the scene has a set height, stage buttons a set
   height, and the detail panel stacks every entry in one grid cell, so
   selecting a stage never moves anything.
   States: .has-cur on the window while a stage is current; .is-on on that
   stage's button and scene parts (red accents) while the other scene parts
   quieten; a pinned stage (aria-pressed) also fills its number. .is-sweep
   is the first-view sweep — accents only, nothing quietens. Motion (signal
   dots, pulses, orbit) runs only while .is-playing, for a finite number of
   passes, and only under no-preference; state transitions likewise.
   Narrow windows adapt by container width (the window is the container),
   so the same rules hold beside the text, under it, and in the editor. */
.rsd-hv {
  --hv-cycle: 5.2s;
  --hv-link: rgba(99, 99, 106, .45);
  container: rsd-hv / inline-size;
  position: relative; width: 100%; max-width: 29rem; margin-inline: auto; overflow: hidden;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-hc-shadow);
  color: var(--rsd-charcoal); text-align: left;
}
.rsd-hv :is(b, i) { font-style: normal; font-weight: inherit; }
.rsd-hv__top { display: flex; align-items: center; justify-content: space-between; gap: .6rem; margin: 0; padding: .4rem .85rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-hv__brand { display: inline-flex; align-items: center; gap: .45rem; min-width: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .76rem; line-height: 1.3; color: var(--rsd-charcoal); }
.rsd-hv__brand i { flex: none; width: 10px; height: 10px; border-radius: 2px; background: var(--rsd-red); }
.rsd-hv__tag {
  flex: none; padding: 0 .35rem; font-family: var(--rsd-mono); font-size: .64rem; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap;
  color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-hv__scene { position: relative; min-width: 0; height: var(--hv-h, 8.75rem); margin: .75rem .85rem; }

/* Primitives — shapes, never words or figures. */
.rsd-hv-box { display: block; min-width: 0; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 4px; }
.rsd-hv-sk { display: block; width: var(--w, 100%); max-width: 100%; height: 4px; border-radius: 2px; background: var(--rsd-line); }
.rsd-hv-sk + .rsd-hv-sk { margin-top: .3rem; }
.rsd-hv-sk--thin { height: 3px; }
.rsd-hv-sk--title { height: 6px; background: rgba(26, 26, 28, .2); }
.rsd-hv-sk--bar { height: 7px; }
.rsd-hv-cap {
  display: block; min-width: 0; overflow: hidden; font-family: var(--rsd-mono); font-size: .6rem; line-height: 1.25; letter-spacing: .05em;
  text-transform: uppercase; white-space: nowrap; text-overflow: ellipsis; color: var(--rsd-muted);
}
.rsd-hv-chip {
  display: inline-flex; align-items: center; gap: .25rem; padding: .1rem .4rem; font-size: .64rem; line-height: 1.3; white-space: nowrap;
  color: var(--rsd-charcoal); background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 3px;
}
.rsd-hv-chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.rsd-hv-sys { display: grid; gap: .3rem; }
.rsd-hv-tag {
  align-self: flex-start; padding: 0 .3rem; font-family: var(--rsd-mono); font-size: .56rem; line-height: 1.5; letter-spacing: .05em; text-transform: uppercase;
  white-space: nowrap; color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-hv-ico { display: block; flex: none; width: 1.1rem; height: 1.1rem; color: var(--rsd-charcoal); }
.rsd-hv-dot { display: block; flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-muted); opacity: .5; }
.rsd-hv-cta {
  align-self: flex-start; display: inline-flex; align-items: center; padding: .15rem .55rem; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold);
  font-size: .6rem; line-height: 1.4; white-space: nowrap; color: var(--rsd-white); background: var(--rsd-charcoal); border-radius: var(--rsd-radius-pill);
}
/* A search field (a pill, not any real search engine's UI). */
.rsd-hv-q { display: flex; align-items: center; gap: .5rem; padding: .3rem .35rem .3rem .65rem; border-radius: var(--rsd-radius-pill); }
.rsd-hv-q .rsd-hv-ico { width: .95rem; height: .95rem; color: var(--rsd-muted); }
.rsd-hv-q .rsd-hv-sk { flex: 0 1 var(--w); }
.rsd-hv-q .rsd-hv-chip { margin-left: auto; }
/* A compact page (browser dots, body, an action). */
.rsd-hv-page { display: flex; flex-direction: column; overflow: hidden; }
.rsd-hv-page__bar { display: flex; flex: none; gap: 3px; padding: .25rem .4rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-hv-page__bar i { width: 4px; height: 4px; border-radius: 50%; background: var(--rsd-line); }
.rsd-hv-page__body { display: block; padding: .45rem .5rem .4rem; }
.rsd-hv-page .rsd-hv-cta { margin: auto .5rem .5rem; }
/* A return connector (optimise / improve → back to the start). */
.rsd-hv-back { display: flex; align-items: center; gap: .4rem; min-width: 0; padding: .25rem .5rem; border: 1px dashed var(--rsd-line); border-radius: 4px; }
.rsd-hv-back .rsd-hv-ico { width: .85rem; height: .85rem; color: var(--rsd-muted); }
.rsd-hv-back .rsd-hv-cap { flex: 0 1 auto; }
.rsd-hv-back__line { position: relative; flex: 1 1 0; min-width: 1rem; height: 1px; background: var(--hv-link); }
.rsd-hv-back__line::before {
  content: ""; position: absolute; top: -3.5px; left: -1px; border-style: solid; border-width: 3.5px 5px 3.5px 0;
  border-color: transparent var(--hv-link) transparent transparent;
}
/* A forward connector. */
.rsd-hv-to { position: relative; display: block; height: 1px; background: var(--hv-link); }
.rsd-hv-to::after {
  content: ""; position: absolute; top: -3.5px; right: -1px; border-style: solid; border-width: 3.5px 0 3.5px 5px;
  border-color: transparent transparent transparent var(--hv-link);
}
.rsd-hv-svg-ln { fill: none; stroke: var(--hv-link); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rsd-hv-svg-node { fill: var(--rsd-white); stroke: var(--rsd-muted); stroke-width: 1; vector-effect: non-scaling-stroke; }

/* Scene state: the current stage's parts get the red accents; the rest
   quieten while a stage is current (hover / focus / pin, not the sweep). */
.rsd-hv.has-cur [data-on]:not(.is-on) { opacity: .35; }
.rsd-hv :is(.rsd-hv-box, .rsd-hv-chip, .rsd-hv-back):is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) :is(.rsd-hv-ico, .rsd-hv-cap),
.rsd-hv :is(.is-on, .is-sweep) > .rsd-hv-ico { color: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-sk--title { background: rgba(196, 8, 8, .7); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-sk:not(.rsd-hv-sk--title) { background: rgba(26, 26, 28, .26); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-dot { background: var(--rsd-red); opacity: .9; }
.rsd-hv .rsd-hv-chip:is(.is-on, .is-sweep),
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-chip { color: var(--rsd-red-ink); background: var(--rsd-white); border-color: var(--rsd-red); }
.rsd-hv .rsd-hv-cta:is(.is-on, .is-sweep) { background: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-back__line { background: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-back__line::before { border-right-color: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-svg-ln { stroke: var(--rsd-red); }
.rsd-hv :is(.is-on, .is-sweep) .rsd-hv-svg-node--core { stroke: var(--rsd-red); }

/* Stage controls — the shared row: numbered buttons on one signal track,
   each a fixed height (two label lines reserved) and a full column wide. */
.rsd-hv__steps { --hv-pad: .5rem; --hv-gap: .25rem; position: relative; padding: .5rem var(--hv-pad) .4rem; border-top: 1px solid var(--rsd-line); }
.rsd-hv__track {
  --hv-col: calc((100% - 2 * var(--hv-pad) - (var(--n) - 1) * var(--hv-gap)) / var(--n));
  position: absolute; top: calc(.5rem + .6875rem); left: calc(var(--hv-pad) + var(--hv-col) / 2); right: calc(var(--hv-pad) + var(--hv-col) / 2); height: 1px; background: var(--rsd-line);
}
.rsd-hv__list { margin: 0; padding: 0; list-style: none; }
.rsd-hv__item { min-width: 0; margin: 0; }
.rsd-hv__list--steps { position: relative; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: var(--hv-gap); }
.rsd-hv__btn {
  -webkit-appearance: none; appearance: none; margin: 0; padding: 0; background: none; border: 0; border-radius: 4px;
  font: inherit; color: inherit; text-align: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.rsd-hv__btn:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
.rsd-hv__list--steps .rsd-hv__btn { display: flex; flex-direction: column; align-items: center; gap: .3rem; width: 100%; height: 3.6rem; padding: 0 .1rem .2rem; text-align: center; }
.rsd-hv__num {
  position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; flex: none; width: 1.75rem; height: 1.375rem;
  font-family: var(--rsd-mono); font-size: .64rem; font-weight: var(--rsd-weight-semibold); line-height: 1; color: var(--rsd-muted);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 3px;
}
.rsd-hv__label { display: block; min-width: 0; max-width: 100%; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .7rem; line-height: 1.2; color: var(--rsd-charcoal); }
.rsd-hv__list--steps .rsd-hv__label { -webkit-hyphens: auto; hyphens: auto; overflow-wrap: break-word; }
.rsd-hv__btn:is(.is-on, .is-sweep) .rsd-hv__num { color: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-hv__btn[aria-pressed="true"] .rsd-hv__num { color: var(--rsd-white); background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-hv.has-cur .rsd-hv__btn:not(.is-on) .rsd-hv__label { color: var(--rsd-muted); }
/* Signal: a dot (or card) per lane, still and hidden until .is-playing.
   The element is a lane-sized carrier with the dot at its start; it moves
   by transform (100% of itself = the lane), so the motion never counts as
   a layout shift. */
.rsd-hv__sig { position: absolute; top: 0; left: 0; width: 100%; height: 0; opacity: 0; pointer-events: none; }
.rsd-hv__sig::before { content: ""; position: absolute; top: -2.5px; left: -3px; width: 6px; height: 6px; border-radius: 50%; background: var(--rsd-red); }
.rsd-hv__sig--v { width: 0; height: 100%; }

/* Detail panel — every entry in one cell; only the current one shows. */
.rsd-hv__detail { display: grid; padding: .5rem .85rem .55rem; border-top: 1px solid var(--rsd-line); }
.rsd-hv__dt { grid-area: 1 / 1; display: grid; align-content: start; gap: .15rem; margin: 0; visibility: hidden; opacity: 0; }
.rsd-hv__dt.is-shown { visibility: visible; opacity: 1; }
.rsd-hv__dl { font-family: var(--rsd-mono); font-size: .64rem; line-height: 1.3; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-red); }
.rsd-hv__dd { font-size: .76rem; line-height: 1.4; color: var(--rsd-charcoal); }
.rsd-hv__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .4rem; margin: 0; padding: .3rem .85rem;
  background: var(--rsd-paper); border-top: 1px solid var(--rsd-line);
  font-family: var(--rsd-mono); font-size: .62rem; line-height: 1.4; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-muted);
}
.rsd-hv__foot i { color: var(--rsd-muted); opacity: .6; }
.rsd-hv__foot .rsd-hv__return { margin-left: auto; font-size: .78rem; line-height: 1; opacity: 1; }
/* Without JavaScript: hover or focus on a stage shows its entry. */
.rsd-hv:not(.is-ready):has(.rsd-hv__btn:is(:hover, :focus)) .rsd-hv__dt--rest { visibility: hidden; opacity: 0; }
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="0"]:is(:hover, :focus)) .rsd-hv__dt[data-i="0"],
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="1"]:is(:hover, :focus)) .rsd-hv__dt[data-i="1"],
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="2"]:is(:hover, :focus)) .rsd-hv__dt[data-i="2"],
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="3"]:is(:hover, :focus)) .rsd-hv__dt[data-i="3"],
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="4"]:is(:hover, :focus)) .rsd-hv__dt[data-i="4"],
.rsd-hv:not(.is-ready):has(.rsd-hv__btn[data-i="5"]:is(:hover, :focus)) .rsd-hv__dt[data-i="5"] { visibility: visible; opacity: 1; }
.rsd-hv:not(.is-ready) .rsd-hv__btn:is(:hover, :focus) .rsd-hv__num { color: var(--rsd-red); border-color: var(--rsd-red); }

/* Open visuals — the shared presentation of every system visual (the
   About diagram set it): no window. A kicker (red rule, the visual's name,
   its "How it works" tag), the scene, the stage row and the detail sit
   directly on the Hero's background — no frame, shadow or divider lines;
   the detail hangs off a left rule that turns red while a stage is
   current; the footer is a quiet mono line. Inside, --rsd-white means the
   surface the visual sits on (paper, or white in a White section), so the
   scene's boxes become open outlines and the step numbers still mask
   their track.
   On a dark surface (Charcoal / Red section or group) the scenes, drawn in
   charcoal ink, keep the framed window — the base .rsd-hv rules — with
   the kicker as its top bar; About alone re-themes (its own tokens). The
   guard below, "About, or not on a dark surface", is
   :is(.rsd-hv--ring, :not(:where(<dark surfaces>) *)). Colours are local
   tokens from the theme palette. */
.rsd-hv--open, .rsd-is {
  --hvo-ink: var(--rsd-charcoal); --hvo-muted: var(--rsd-muted); --hvo-accent: var(--rsd-red);
  --hvo-line: var(--rsd-line); --hvo-edge: rgba(26, 26, 28, .09); --hvo-link: rgba(99, 99, 106, .55);
  --hvo-tint: rgba(26, 26, 28, .022); --hvo-on: rgba(196, 8, 8, .035); --hvo-on-edge: rgba(196, 8, 8, .45); --hvo-core: var(--rsd-white); --hvo-grid: rgba(26, 26, 28, .05);
}
.rsd-section--bg-white { --rsd-hv-surface: var(--rsd-white); }
:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) .rsd-hv--open.rsd-hv--ring {
  --hvo-ink: var(--rsd-paper); --hvo-muted: rgba(247, 246, 244, .7); --hvo-accent: var(--rsd-paper);
  --hvo-line: rgba(247, 246, 244, .22); --hvo-edge: rgba(247, 246, 244, .16); --hvo-link: rgba(247, 246, 244, .45);
  --hvo-tint: rgba(247, 246, 244, .04); --hvo-on: rgba(247, 246, 244, .08); --hvo-on-edge: rgba(247, 246, 244, .5); --hvo-core: rgba(247, 246, 244, .06); --hvo-grid: rgba(247, 246, 244, .06);
}
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) {
  max-width: 31rem; color: var(--hvo-ink); background: none; border: 0; border-radius: 0; box-shadow: none;
}
.rsd-hv--open.rsd-hv--ring { overflow: visible; }
.rsd-hv--open:not(.rsd-hv--ring):not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) {
  --rsd-white: var(--rsd-hv-surface, var(--rsd-body-bg, var(--rsd-paper)));
}
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__kicker {
  justify-content: flex-start; gap: .6rem; margin: 0 0 1.25rem; padding: 0; background: none; border: 0;
  font-family: var(--rsd-mono); font-size: .66rem; line-height: 1.3; letter-spacing: .08em; text-transform: uppercase; color: var(--hvo-muted);
}
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__kicker::before { content: ""; flex: none; width: 1.5rem; height: 1px; background: var(--rsd-red); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__brand {
  gap: .6rem; font-size: .82rem; letter-spacing: 0; text-transform: none; color: var(--hvo-ink);
}
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__brand i { order: 1; width: 1px; height: .8rem; border-radius: 0; background: var(--hvo-line); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__tag { flex: 0 1 auto; padding: 0; font-size: inherit; letter-spacing: inherit; color: inherit; border: 0; }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__scene { margin: 0; }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__steps { --hv-pad: 0px; margin-top: 1.25rem; padding: 0 var(--hv-pad); border-top: 0; }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__track { top: .6875rem; background: var(--hvo-line); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__detail { margin-top: 1.6rem; padding: .15rem 0 .15rem 1rem; border-top: 0; border-left: 2px solid var(--hvo-line); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)).has-cur .rsd-hv__detail { border-left-color: var(--hvo-accent); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__dl { color: var(--hvo-accent); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__dd { font-size: .86rem; line-height: 1.5; color: var(--hvo-ink); }
.rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__foot { margin-top: 1rem; padding: 0; background: none; border-top: 0; color: var(--hvo-muted); }

/* The loop: four stages in a clockwise 2×2 grid. Rows have a set height
   (--st-h), so every connector is placed from the same grid numbers —
   centred in its gap, on the row's centre line (horizontal) or the
   column's centre line (vertical) — and stays aligned at any width. Each
   connector is one horizontal lane (connection dot → line → chevron)
   rotated to its direction; the left one is the dashed return. The loop
   mark sits where the gaps cross; a faint grid fades out behind it all. */
.rsd-hv-ring { --hv-h: auto; --st-h: 5.5rem; --gap-c: 4.5rem; --gap-r: 4.75rem; --core: 3rem; margin: 0; }
.rsd-hv-ring::before {
  content: ""; position: absolute; z-index: 0; inset: -1.5rem 0; pointer-events: none;
  background-image: linear-gradient(var(--hvo-grid) 1px, transparent 1px), linear-gradient(90deg, var(--hvo-grid) 1px, transparent 1px);
  background-size: 1.5rem 1.5rem; background-position: center;
  -webkit-mask-image: radial-gradient(closest-side, #000 30%, transparent); mask-image: radial-gradient(closest-side, #000 30%, transparent);
}
.rsd-hv-ring__list {
  position: relative; z-index: 1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, var(--st-h));
  grid-template-areas: "a b" "d c"; gap: var(--gap-r) var(--gap-c);
}
.rsd-hv-ring__list > :nth-child(1) { grid-area: a; }
.rsd-hv-ring__list > :nth-child(2) { grid-area: b; }
.rsd-hv-ring__list > :nth-child(3) { grid-area: c; }
.rsd-hv-ring__list > :nth-child(4) { grid-area: d; }
.rsd-hv-ring .rsd-hv__btn {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: .55rem; width: 100%; height: 100%; padding: 0 1.1rem;
  background: var(--hvo-tint); border: 1px solid var(--hvo-edge); border-radius: 10px;
}
.rsd-hv-ring .rsd-hv__btn:focus-visible { outline-offset: 2px; }
.rsd-hv-ring .rsd-hv__num { width: auto; height: auto; margin-left: -.35rem; padding: .15rem .35rem; letter-spacing: .06em; color: var(--hvo-muted); background: none; border-color: transparent; }
.rsd-hv-ring .rsd-hv__label { max-width: 100%; font-size: 1.05rem; line-height: 1.15; letter-spacing: -.005em; color: var(--hvo-ink); overflow-wrap: break-word; -webkit-hyphens: auto; hyphens: auto; }
.rsd-hv-ring .rsd-hv__btn:is(.is-on, .is-sweep) { background: var(--hvo-on); border-color: var(--hvo-on-edge); }
.rsd-hv-ring .rsd-hv__btn:is(.is-on, .is-sweep) .rsd-hv__num { color: var(--hvo-accent); border-color: transparent; }
.rsd-hv-ring .rsd-hv__btn[aria-pressed="true"] .rsd-hv__num { color: var(--rsd-white); background: var(--rsd-red); }
.rsd-hv.has-cur .rsd-hv-ring .rsd-hv__btn:not(.is-on) .rsd-hv__label { color: var(--hvo-muted); }
.rsd-hv:not(.is-ready) .rsd-hv-ring .rsd-hv__btn:is(:hover, :focus) .rsd-hv__num { color: var(--hvo-accent); border-color: transparent; }

.rsd-hv-ring__arrow {
  --len: var(--gap-c); position: absolute; z-index: 1; width: calc(var(--len) - 1rem); height: 0;
  color: var(--hvo-link); border-top: 1px solid currentColor; transform: translate(-50%, -50%) rotate(var(--rot, 0deg));
}
.rsd-hv-ring__arrow::before { content: ""; position: absolute; top: -3px; left: -2.5px; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.rsd-hv-ring__arrow::after {
  content: ""; position: absolute; top: -4px; right: 1px; width: 6px; height: 6px;
  border-top: 1px solid currentColor; border-right: 1px solid currentColor; transform: rotate(45deg);
}
.rsd-hv-ring__arrow--t { top: calc(var(--st-h) / 2); left: 50%; }
.rsd-hv-ring__arrow--r { --len: var(--gap-r); --rot: 90deg; top: 50%; left: calc(75% + var(--gap-c) / 4); }
.rsd-hv-ring__arrow--b { --rot: 180deg; top: calc(100% - var(--st-h) / 2); left: 50%; }
.rsd-hv-ring__arrow--l { --len: var(--gap-r); --rot: 270deg; top: 50%; left: calc(25% - var(--gap-c) / 4); border-top-style: dashed; }
.rsd-hv .rsd-hv-ring__arrow:is(.is-on, .is-sweep) { color: var(--hvo-accent); }
/* Signal: a lane-sized carrier, dot at its start, moved by transform. */
.rsd-hv-ring__sig { position: absolute; top: -1px; left: 0; width: 100%; height: 0; opacity: 0; pointer-events: none; }
.rsd-hv-ring__sig::before { content: ""; position: absolute; top: -3px; left: -3px; width: 7px; height: 7px; border-radius: 50%; background: var(--rsd-red); }

.rsd-hv-ring__core {
  position: absolute; z-index: 1; top: 50%; left: 50%; display: flex; align-items: center; justify-content: center;
  width: var(--core); height: var(--core); margin: calc(var(--core) / -2) 0 0 calc(var(--core) / -2);
  color: var(--hvo-accent); background: var(--hvo-core); border: 1px solid var(--hvo-line); border-radius: 50%;
}
.rsd-hv-ring__core::before { content: ""; position: absolute; inset: -.6rem; border: 1px dashed var(--hvo-line); border-radius: 50%; }
.rsd-hv-ring__core .rsd-hv-ico { width: 1.15rem; height: 1.15rem; color: inherit; }

/* Local SEO — six signal buttons around the business and Local Visibility,
   each with its own connector (and a pulse along it on first view). The
   signals are unordered, so no numbers; a pinned signal gets a red edge. */
.rsd-hv-hub { --hv-h: 12rem; --hv-mid: 8.5rem; }
.rsd-hv-hub__list {
  position: relative; z-index: 1; display: grid; height: 100%;
  grid-template-columns: minmax(0, 1fr) var(--hv-mid) minmax(0, 1fr); grid-template-rows: repeat(3, minmax(0, 1fr)); row-gap: .6rem;
}
.rsd-hv-hub__list > :nth-child(1) { grid-area: 1 / 1; }
.rsd-hv-hub__list > :nth-child(2) { grid-area: 2 / 1; }
.rsd-hv-hub__list > :nth-child(3) { grid-area: 3 / 1; }
.rsd-hv-hub__list > :nth-child(4) { grid-area: 1 / 3; }
.rsd-hv-hub__list > :nth-child(5) { grid-area: 2 / 3; }
.rsd-hv-hub__list > :nth-child(6) { grid-area: 3 / 3; }
.rsd-hv-hub .rsd-hv__btn { display: flex; align-items: center; width: 100%; height: 100%; padding: .3rem .65rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; }
.rsd-hv-hub__list > :nth-child(n + 4) .rsd-hv__btn { justify-content: flex-end; text-align: right; }
.rsd-hv-hub .rsd-hv__num { display: none; }
.rsd-hv-hub .rsd-hv__label { font-size: .72rem; line-height: 1.2; }
.rsd-hv-hub .rsd-hv__btn:is(.is-on, .is-sweep) { background: var(--rsd-paper); border-color: var(--rsd-red); }
.rsd-hv-hub .rsd-hv__btn[aria-pressed="true"] { box-shadow: inset 3px 0 0 var(--rsd-red); }
.rsd-hv-hub__list > :nth-child(n + 4) .rsd-hv__btn[aria-pressed="true"] { box-shadow: inset -3px 0 0 var(--rsd-red); }
.rsd-hv-hub__lines { position: absolute; z-index: 0; top: 0; left: calc((100% - var(--hv-mid)) / 2); width: var(--hv-mid); height: 100%; overflow: visible; }
.rsd-hv-hub__ln { stroke: var(--hv-link); stroke-width: 1; vector-effect: non-scaling-stroke; }
.rsd-hv-hub__ln:is(.is-on, .is-sweep) { stroke: var(--rsd-red); stroke-width: 1.5; }
.rsd-hv-hub__pulse { fill: none; stroke: var(--rsd-red); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 14 100; stroke-dashoffset: 14; opacity: 0; }
.rsd-hv-hub__core { position: absolute; z-index: 2; top: 50%; left: 50%; display: flex; flex-direction: column; width: calc(var(--hv-mid) - 1.6rem); transform: translate(-50%, -50%); text-align: center; }
.rsd-hv-hub__biz {
  display: flex; align-items: center; justify-content: center; gap: .25rem; padding: .3rem .35rem; font-size: .64rem; line-height: 1.2;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-bottom: 0; border-radius: 6px 6px 0 0;
}
.rsd-hv-hub__biz .rsd-hv-ico { width: .85rem; height: .85rem; color: var(--rsd-red); }
.rsd-hv-hub__vis {
  padding: .5rem .35rem; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .66rem; line-height: 1.25; letter-spacing: .1em;
  text-transform: uppercase; color: var(--rsd-paper); background: var(--rsd-charcoal); border-top: 2px solid var(--rsd-red); border-radius: 0 0 6px 6px;
}

/* WordPress — five layer buttons stacked on one spine (it runs under the
   numbers; a dot travels down it on first view). */
.rsd-hv-stack { --hv-h: auto; }
.rsd-hv-stack__list { display: grid; gap: .45rem; }
.rsd-hv-stack .rsd-hv__btn { display: flex; align-items: center; gap: .65rem; width: 100%; min-height: 2.75rem; padding: .3rem .7rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 4px; }
.rsd-hv-stack .rsd-hv__label { flex: none; font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; }
.rsd-hv-stack__tag { min-width: 0; margin-left: auto; overflow: hidden; font-size: .66rem; line-height: 1.2; white-space: nowrap; text-overflow: ellipsis; color: var(--rsd-muted); }
.rsd-hv-stack .rsd-hv__btn.is-on { background: var(--rsd-paper); box-shadow: inset 2px 0 0 var(--rsd-red); }
.rsd-hv-stack__rail { position: absolute; top: 1.375rem; bottom: 1.375rem; left: calc(.7rem + 1px + .875rem); width: 1px; background: var(--rsd-line); }

/* Digital Marketing — attention narrowing to an outcome: a broad audience,
   fewer engaged, an enquiry, then the retention loop. Columns line up with
   the stage buttons below. */
.rsd-hv-funnel { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); align-items: center; gap: .25rem; margin-inline: .5rem; }
.rsd-hv-funnel__seg {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .5rem; min-width: 0; height: 100%; padding: .5rem .4rem;
  background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 4px;
}
.rsd-hv-funnel__seg:nth-child(2) { height: 80%; }
.rsd-hv-funnel__seg:nth-child(3) { height: 62%; }
.rsd-hv-funnel__seg:nth-child(4) { height: 62%; border-style: dashed; }
.rsd-hv-funnel__seg > .rsd-hv-ico { width: 1.35rem; height: 1.35rem; color: var(--rsd-muted); }
.rsd-hv-funnel__dots { display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem; max-width: 4.2rem; }
.rsd-hv-funnel__card { position: relative; display: block; width: 100%; max-width: 5rem; padding: .45rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 3px; }
.rsd-hv-funnel__ok {
  position: absolute; top: -.5rem; right: -.45rem; display: flex; align-items: center; justify-content: center; width: 1rem; height: 1rem;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 50%;
}
.rsd-hv-funnel__ok .rsd-hv-ico { width: .65rem; height: .65rem; }
.rsd-hv .rsd-hv-funnel__seg:is(.is-on, .is-sweep) { background: var(--rsd-white); border-color: var(--rsd-red); }

/* SEO — a search query; an indexed result with its on-page foundations;
   authority links; measure and learn. */
.rsd-hv-search {
  display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas: "q q" "res auth" "res learn"; gap: .45rem;
}
.rsd-hv-search__q { grid-area: q; }
.rsd-hv-search__res { grid-area: res; display: flex; flex-direction: column; gap: .45rem; padding: .5rem .6rem; overflow: hidden; }
.rsd-hv-search__res > span { display: block; }
.rsd-hv-search__res > .rsd-hv-search__tags { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: auto; }
.rsd-hv-search__tags b {
  padding: 0 .3rem; font-family: var(--rsd-mono); font-size: .56rem; line-height: 1.5; letter-spacing: .04em; text-transform: uppercase;
  color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-hv-search__tags:is(.is-on, .is-sweep) b { color: var(--rsd-red-ink); border: 1px solid var(--rsd-red); }
.rsd-hv-search__auth { grid-area: auth; display: flex; flex-direction: column; gap: .2rem; padding: .35rem .5rem; overflow: hidden; }
.rsd-hv-search__links { display: block; flex: 1 1 0; width: 100%; height: 0; min-height: 0; }
.rsd-hv-search__learn { grid-area: learn; display: flex; align-items: center; gap: .4rem; padding: .35rem .5rem; }
.rsd-hv-search__learn .rsd-hv-ico { width: 1rem; height: 1rem; }

/* Google Ads — a search-inspired query and campaign result leading to a
   landing page and its action; the optimisation return below. */
.rsd-hv-ads {
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "q page" "ad page" "back back"; column-gap: 1.5rem; row-gap: .45rem;
}
.rsd-hv-ads__q { grid-area: q; }
.rsd-hv-ads__ad { grid-area: ad; position: relative; display: flex; flex-direction: column; padding: .45rem .55rem; }
.rsd-hv-ads__ad .rsd-hv-tag { margin-bottom: .4rem; }
.rsd-hv-ads__ad::after { content: "\2192"; position: absolute; top: 50%; right: -1.2rem; transform: translateY(-50%); font-size: .8rem; line-height: 1; color: var(--rsd-muted); }
.rsd-hv-ads__ad:is(.is-on, .is-sweep)::after { color: var(--rsd-red); }
.rsd-hv-ads__page { grid-area: page; }
.rsd-hv-ads__back { grid-area: back; }

/* Website Development — one browser frame built in layers: dashed
   structure, interface blocks, build markers, the live address bar and
   the iteration notes. */
.rsd-hv-web { --hv-h: 9.5rem; }
.rsd-hv-web__frame { display: flex; flex-direction: column; height: 100%; overflow: hidden; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; }
.rsd-hv-web__bar { display: flex; flex: none; align-items: center; gap: .25rem; padding: .3rem .45rem; background: var(--rsd-paper); border-bottom: 1px solid var(--rsd-line); }
.rsd-hv-web__bar > i { flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-line); }
.rsd-hv-web__addr {
  display: flex; flex: 1 1 auto; align-items: center; gap: .35rem; min-width: 0; margin: 0 .35rem; padding: .1rem .45rem;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius-pill);
}
.rsd-hv-web__addr .rsd-hv-ico { width: .75rem; height: .75rem; color: var(--rsd-muted); }
.rsd-hv-web__addr .rsd-hv-sk { flex: 0 1 var(--w); }
.rsd-hv-web__live { display: inline-flex; align-items: center; gap: .25rem; margin-left: auto; font-family: var(--rsd-mono); font-size: .56rem; letter-spacing: .05em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-hv-web__live::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-muted); }
.rsd-hv-web__addr:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-hv-web__addr:is(.is-on, .is-sweep) .rsd-hv-web__live { color: var(--rsd-red-ink); }
.rsd-hv-web__addr:is(.is-on, .is-sweep) .rsd-hv-web__live::before { background: var(--rsd-red); }
.rsd-hv-web__iter {
  display: inline-flex; flex: none; align-items: center; gap: .2rem; padding: 0 .3rem; font-family: var(--rsd-mono); font-size: .56rem; line-height: 1.6;
  letter-spacing: .05em; text-transform: uppercase; color: var(--rsd-muted); border: 1px dashed var(--rsd-line); border-radius: 3px;
}
.rsd-hv-web__iter .rsd-hv-ico { width: .7rem; height: .7rem; color: inherit; }
.rsd-hv .rsd-hv-web__iter:is(.is-on, .is-sweep) { color: var(--rsd-red-ink); border: 1px solid var(--rsd-red); }
.rsd-hv .rsd-hv-web__iter:is(.is-on, .is-sweep) .rsd-hv-ico { color: inherit; }
.rsd-hv-web__body {
  flex: 1 1 auto; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: 1.1rem minmax(0, 1fr) 2.2rem;
  grid-template-areas: "nav nav nav" "hero hero hero" "c1 c2 c3"; gap: .35rem; min-height: 0; padding: .4rem;
}
.rsd-hv-web__r { position: relative; display: flex; flex-direction: column; justify-content: center; min-width: 0; padding: .25rem .4rem; }
.rsd-hv-web__r--nav { grid-area: nav; padding-block: 0; }
.rsd-hv-web__r--hero { grid-area: hero; }
.rsd-hv-web__wire { position: absolute; inset: 0; border: 1px dashed rgba(99, 99, 106, .4); border-radius: 3px; }
.rsd-hv-web__wire:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-hv-web__ux { display: block; }
.rsd-hv-web__ux--nav { display: flex; align-items: center; justify-content: space-between; }
.rsd-hv-web__links { display: flex; gap: .3rem; width: 36%; }
.rsd-hv-web__links .rsd-hv-sk { flex: 1 1 0; margin: 0; }
.rsd-hv-web__btn { display: block; width: 2.2rem; height: .55rem; margin-top: .4rem; border-radius: var(--rsd-radius-pill); background: rgba(26, 26, 28, .2); }
.rsd-hv-web__ux:is(.is-on, .is-sweep) .rsd-hv-web__btn { background: var(--rsd-red); }
.rsd-hv-web__code {
  position: absolute; top: .3rem; right: .35rem; padding: 0 .2rem; font-family: var(--rsd-mono); font-size: .56rem; line-height: 1.5;
  color: var(--rsd-muted); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 2px;
}
.rsd-hv-web__code:is(.is-on, .is-sweep) { color: var(--rsd-red-ink); border-color: var(--rsd-red); }
.rsd-hv-web__stack { position: absolute; right: .35rem; bottom: .3rem; display: flex; gap: .2rem; }
.rsd-hv-web__stack .rsd-hv-chip { padding: 0 .3rem; font-size: .56rem; }
.rsd-hv-web__note { position: absolute; top: .45rem; left: 52%; width: .8rem; height: .8rem; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
.rsd-hv-web__note:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }

/* Marketing Automation — five workflow nodes on one lane (a dashed return
   from Message to Condition: not ready yet, nurture again); contact cards
   travel the lane on first view, passing behind each node. */
.rsd-hv-flow { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); align-items: center; gap: .25rem; margin-inline: .5rem; }
.rsd-hv-flow__lane {
  --hv-col: calc((100% - (var(--n) - 1) * .25rem) / var(--n));
  position: absolute; top: calc(50% - .575rem); left: calc(var(--hv-col) / 2); right: calc(var(--hv-col) / 2); height: 1px; background: var(--hv-link);
}
.rsd-hv-flow__node { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: .4rem; min-width: 0; }
.rsd-hv-flow__node .rsd-hv-cap { max-width: 100%; }
.rsd-hv-flow__ico { display: flex; align-items: center; justify-content: center; width: 2.6rem; height: 2.6rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; }
.rsd-hv-flow__ico .rsd-hv-ico { width: 1.2rem; height: 1.2rem; }
.rsd-hv-flow__node:is(.is-on, .is-sweep) .rsd-hv-flow__ico { border-color: var(--rsd-red); }
.rsd-hv-flow__branch {
  --hv-col: calc((100% - (var(--n) - 1) * .25rem) / var(--n));
  position: absolute; top: calc(50% - 1.875rem - .8rem); left: calc(var(--hv-col) * 1.5 + .25rem); width: calc(var(--hv-col) + .25rem); height: .8rem;
  border: 1px dashed var(--hv-link); border-bottom: 0; border-radius: 6px 6px 0 0;
}
.rsd-hv-flow__branch:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-hv__sig--card::before {
  top: -.4rem; left: -.575rem; width: 1.15rem; height: .8rem; box-sizing: border-box; border-radius: 2px;
  background: var(--rsd-white); border: 1px solid var(--rsd-charcoal);
}
.rsd-hv__sig--card::after { content: ""; position: absolute; top: calc(-.4rem + 2px); left: calc(-.575rem + 2px); width: 4px; height: 4px; border-radius: 50%; background: var(--rsd-red); }

/* CRM & Revenue — one contact record whose lifecycle bar fills to the
   selected stage, over the systems involved at that stage. */
.rsd-hv-crm { display: flex; flex-direction: column; gap: .5rem; }
.rsd-hv-crm__rec { display: flex; flex: 1 1 auto; flex-direction: column; gap: .4rem; min-height: 0; padding: .5rem .6rem; }
.rsd-hv-crm__head { display: flex; align-items: center; gap: .5rem; }
.rsd-hv-crm__avatar { display: flex; flex: none; align-items: center; justify-content: center; width: 1.6rem; height: 1.6rem; background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 50%; }
.rsd-hv-crm__avatar .rsd-hv-ico { width: .95rem; height: .95rem; color: var(--rsd-muted); }
.rsd-hv-crm__id { flex: 1 1 auto; min-width: 0; }
.rsd-hv-crm__fields { display: grid; grid-template-columns: minmax(0, .6fr) minmax(0, 1fr); align-items: center; gap: .3rem .6rem; }
.rsd-hv-crm__fields .rsd-hv-sk { margin: 0; }
.rsd-hv-crm__bar { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 3px; }
.rsd-hv-crm__bar i { display: block; height: 6px; border-radius: 2px; background: var(--rsd-line); }
.rsd-hv-crm__bar i:is(.is-on, .is-sweep) { background: var(--rsd-red); }

/* Data & Analytics — signals stream into connected data and an analytics
   layer (data points flow on first view); an insight, a decision between
   options, and the improvement that feeds back. */
.rsd-hv-an {
  display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.15fr) minmax(0, 1.1fr); grid-template-rows: minmax(0, 1fr) auto;
  column-gap: 1.1rem; row-gap: .45rem;
}
.rsd-hv-an__src { display: flex; flex-direction: column; justify-content: center; gap: .3rem; min-width: 0; }
.rsd-hv-an__src .rsd-hv-chip { justify-content: center; }
.rsd-hv-an__col { display: flex; flex-direction: column; gap: .35rem; min-width: 0; min-height: 0; }
.rsd-hv-an__data { display: flex; align-items: center; gap: .4rem; padding: .3rem .45rem; }
.rsd-hv-an__data .rsd-hv-ico { width: .95rem; height: .95rem; }
.rsd-hv-an__ana { display: flex; flex: 1 1 auto; flex-direction: column; gap: .3rem; min-height: 0; padding: .3rem .45rem; }
.rsd-hv-an__pts { display: grid; flex: 1 1 auto; grid-template-columns: repeat(6, minmax(0, 1fr)); place-items: center; gap: .2rem; }
.rsd-hv .rsd-hv-an__ana:is(.is-on, .is-sweep) .rsd-hv-dot:not(.rsd-hv-dot--key) { background: var(--rsd-charcoal); opacity: .4; }
.rsd-hv-an__ins { flex: 1 1 auto; padding: .3rem .45rem; }
.rsd-hv-an__ins .rsd-hv-cap { margin-bottom: .35rem; }
.rsd-hv-an__dec { display: grid; gap: .25rem; padding: .3rem .45rem; }
.rsd-hv-an__opt { display: flex; align-items: center; gap: .35rem; }
.rsd-hv-an__opt > i:first-child { display: flex; flex: none; align-items: center; justify-content: center; width: .7rem; height: .7rem; border: 1px solid var(--rsd-line); border-radius: 2px; }
.rsd-hv-an__opt.is-pick > i:first-child { border-color: var(--rsd-charcoal); }
.rsd-hv-an__opt .rsd-hv-ico { width: .6rem; height: .6rem; }
.rsd-hv-an__opt .rsd-hv-sk { flex: 0 1 var(--w); margin: 0; }
.rsd-hv-an__lane { position: absolute; z-index: 2; top: calc(18% + var(--l) * 20%); left: 17%; width: 22%; height: 0; }
.rsd-hv-an__back { grid-column: 1 / -1; }

/* AI & Automation — the workflow runs left to right with a person's review
   as its gate (charcoal, the decision point); AI assistance sits beside
   it, dashed — it supports Context → Action, it never decides. */
.rsd-hv-ai { display: flex; flex-direction: column; justify-content: center; gap: 1.25rem; }
.rsd-hv-ai__row, .rsd-hv-ai__sup { position: relative; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .4rem; }
.rsd-hv-ai__row::before { content: ""; position: absolute; top: 50%; left: 10%; right: 10%; height: 1px; background: var(--hv-link); }
.rsd-hv-ai__node { position: relative; display: flex; flex-direction: column; align-items: center; gap: .25rem; padding: .45rem .2rem .4rem; }
.rsd-hv-ai__node .rsd-hv-cap { max-width: 100%; }
.rsd-hv-ai__node .rsd-hv-ico { width: 1.05rem; height: 1.05rem; }
.rsd-hv .rsd-hv-ai__node--human { background: var(--rsd-charcoal); border-color: var(--rsd-charcoal); box-shadow: inset 0 2px 0 var(--rsd-red); }
.rsd-hv .rsd-hv-ai__node--human :is(.rsd-hv-ico, .rsd-hv-cap) { color: var(--rsd-paper); }
.rsd-hv .rsd-hv-ai__node--human:is(.is-on, .is-sweep) { border-color: var(--rsd-red); box-shadow: inset 0 0 0 1px var(--rsd-red); }
.rsd-hv-ai__sup { align-items: start; }
.rsd-hv-ai__assist { position: relative; display: flex; grid-column: 2 / span 2; align-items: center; gap: .45rem; padding: .35rem .5rem; border-style: dashed; }
.rsd-hv-ai__assist > span { min-width: 0; }
.rsd-hv-ai__assist::before, .rsd-hv-ai__assist::after { content: ""; position: absolute; bottom: 100%; height: calc(1.25rem + 1px); border-left: 1px dashed var(--rsd-muted); }
.rsd-hv-ai__assist::before { left: calc(25% - .1rem); }
.rsd-hv-ai__assist::after { left: calc(75% + .1rem); }
.rsd-hv-ai__assist:is(.is-on, .is-sweep)::before, .rsd-hv-ai__assist:is(.is-on, .is-sweep)::after { border-color: var(--rsd-red); }
.rsd-hv-ai__note { display: block; overflow: hidden; font-size: .6rem; line-height: 1.3; white-space: nowrap; text-overflow: ellipsis; color: var(--rsd-muted); }
.rsd-hv-ai__decide { position: relative; grid-column: 4 / span 2; padding-top: .15rem; padding-right: 50%; text-align: center; }
.rsd-hv-ai__decide .rsd-hv-ai__note { margin-right: -60%; }
.rsd-hv-ai__decide::before { content: ""; position: absolute; bottom: 100%; left: 25%; height: 1.25rem; border-left: 1px solid var(--rsd-charcoal); }
.rsd-hv-ai__decide:is(.is-on, .is-sweep) .rsd-hv-ai__note { color: var(--rsd-red-ink); }
.rsd-hv-ai__decide:is(.is-on, .is-sweep)::before { border-color: var(--rsd-red); }

/* Conversion Optimisation — visitors arrive at a compact page; behaviour
   markers (attention, scroll depth, a click) show intent at the action;
   an A/B pair carries the learning. */
.rsd-hv-cro { display: grid; grid-template-columns: minmax(0, .45fr) minmax(0, 1.65fr) minmax(0, .95fr); column-gap: .6rem; }
.rsd-hv-cro__in { display: flex; flex-direction: column; justify-content: center; gap: .85rem; }
.rsd-hv-cro__in i { position: relative; display: block; height: 1px; background: var(--hv-link); }
.rsd-hv-cro__in i::before { content: ""; position: absolute; top: -2px; left: 0; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-muted); }
.rsd-hv-cro__in i::after {
  content: ""; position: absolute; top: -3.5px; right: -1px; border-style: solid; border-width: 3.5px 0 3.5px 5px;
  border-color: transparent transparent transparent var(--hv-link);
}
.rsd-hv-cro__in:is(.is-on, .is-sweep) i { background: var(--rsd-red); }
.rsd-hv-cro__in:is(.is-on, .is-sweep) i::before { background: var(--rsd-red); }
.rsd-hv-cro__in:is(.is-on, .is-sweep) i::after { border-left-color: var(--rsd-red); }
.rsd-hv-cro__page { position: relative; }
.rsd-hv-cro__marks { position: absolute; inset: 0; pointer-events: none; }
.rsd-hv-cro__focus { position: absolute; top: 1.15rem; left: .3rem; width: 72%; height: 1.15rem; border: 1px dashed var(--rsd-muted); border-radius: 3px; }
.rsd-hv-cro__scroll { position: absolute; top: 1.3rem; right: .3rem; bottom: .5rem; width: 2px; border-radius: 1px; background: var(--rsd-line); }
.rsd-hv-cro__scroll::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 55%; border-radius: 1px; background: var(--rsd-muted); }
.rsd-hv-cro__click { position: absolute; bottom: .35rem; left: 3.1rem; width: 1.15rem; height: 1.15rem; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
.rsd-hv-cro__marks:is(.is-on, .is-sweep) :is(.rsd-hv-cro__focus, .rsd-hv-cro__click) { border-color: var(--rsd-red); }
.rsd-hv-cro__marks:is(.is-on, .is-sweep) .rsd-hv-cro__scroll::after { background: var(--rsd-red); }
.rsd-hv-cro__ab { display: flex; flex-direction: column; justify-content: center; gap: .4rem; }
.rsd-hv-cro__ab .rsd-hv-box { padding: .35rem .45rem; }
.rsd-hv-cro__ab .rsd-hv-cap { margin-bottom: .3rem; }
.rsd-hv-cro__ab:is(.is-on, .is-sweep) .rsd-hv-box { border-color: var(--rsd-red); }

/* Performance Marketing — demand from several channels converges on the
   campaigns, a landing experience and a conversion; one measurement layer
   spans the whole run and optimisation feeds back. */
.rsd-hv-perf { display: flex; flex-direction: column; gap: .5rem; }
.rsd-hv-perf__top {
  display: grid; flex: 1 1 auto; align-items: center; min-height: 0;
  grid-template-columns: minmax(0, .9fr) .9rem minmax(0, 1fr) .9rem minmax(0, 1fr) .9rem minmax(0, .75fr);
}
.rsd-hv-perf__src { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.rsd-hv-perf__src .rsd-hv-chip { justify-content: center; }
.rsd-hv-perf__join { display: block; width: 100%; height: 3.9rem; }
.rsd-hv-perf__camp { display: flex; flex-direction: column; gap: .3rem; padding: .35rem .45rem; }
.rsd-hv-perf__camp .rsd-hv-sk { margin: 0; }
.rsd-hv-perf__land { min-height: 4.4rem; }
.rsd-hv-perf__btn { display: block; width: 1.8rem; height: .5rem; margin-top: .35rem; border-radius: var(--rsd-radius-pill); background: rgba(26, 26, 28, .2); }
.rsd-hv-perf__land:is(.is-on, .is-sweep) .rsd-hv-perf__btn { background: var(--rsd-red); }
.rsd-hv-perf__conv { display: flex; flex-direction: column; align-items: center; gap: .3rem; min-width: 0; }
.rsd-hv-perf__conv .rsd-hv-cap { max-width: 100%; }
.rsd-hv-perf__ok { display: flex; align-items: center; justify-content: center; width: 2.1rem; height: 2.1rem; background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 50%; }
.rsd-hv-perf__ok .rsd-hv-ico { width: 1rem; height: 1rem; }
.rsd-hv-perf__conv:is(.is-on, .is-sweep) .rsd-hv-perf__ok { border-color: var(--rsd-red); }
.rsd-hv-perf__base { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .5rem; }
.rsd-hv-perf__meas { display: flex; align-items: center; gap: .5rem; min-width: 0; padding: .3rem .5rem; background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 4px; }
.rsd-hv-perf__ticks { display: flex; flex: 1 1 auto; justify-content: space-between; height: .5rem; border-bottom: 1px solid var(--hv-link); }
.rsd-hv-perf__ticks i { width: 1px; height: 100%; background: var(--hv-link); }
.rsd-hv-perf__meas:is(.is-on, .is-sweep) { border-color: var(--rsd-red); }
.rsd-hv-perf__meas:is(.is-on, .is-sweep) .rsd-hv-perf__ticks { border-color: var(--rsd-red); }
.rsd-hv-perf__meas:is(.is-on, .is-sweep) .rsd-hv-perf__ticks i { background: var(--rsd-red); }
.rsd-hv-perf__opt .rsd-hv-ico { width: .8rem; height: .8rem; }

/* Ecommerce Growth — the commerce journey as five compact cards (aligned
   with the stage buttons), over the growth signals involved. */
.rsd-hv-com { display: flex; flex-direction: column; gap: .55rem; margin-inline: .5rem; }
.rsd-hv-com__row { display: grid; flex: 1 1 auto; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: .25rem; min-height: 0; }
.rsd-hv-com__card { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .35rem; padding: .4rem; }
.rsd-hv-com__card > .rsd-hv-sk { margin: 0; }
.rsd-hv-com__grid { display: grid; grid-template-columns: repeat(2, .45rem); gap: 2px; }
.rsd-hv-com__grid i { display: block; width: .45rem; height: .45rem; border-radius: 1px; background: var(--rsd-line); }
.rsd-hv-com__img { display: block; width: 1.6rem; height: 1.3rem; background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 2px; }
.rsd-hv-com__card:is(.is-on, .is-sweep) .rsd-hv-com__img { border-color: var(--rsd-red); }
.rsd-hv-com__card:is(.is-on, .is-sweep) .rsd-hv-com__grid i { background: rgba(196, 8, 8, .45); }
.rsd-hv-com__ok, .rsd-hv-com__again { position: absolute; top: .3rem; right: .3rem; display: flex; }
.rsd-hv-com__ok .rsd-hv-ico, .rsd-hv-com__again .rsd-hv-ico { width: .7rem; height: .7rem; color: var(--rsd-muted); }

/* Digital Products — a product interface composed of modular blocks. */
.rsd-hv-mod {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.15fr); grid-template-rows: repeat(3, minmax(0, 1fr));
  grid-template-areas: "brief core core ui" "brief core core ui" "rel fb fb ui"; gap: .35rem;
}
.rsd-hv-mod__b { display: flex; flex-direction: column; gap: .3rem; min-height: 0; padding: .35rem .45rem; overflow: hidden; }
.rsd-hv-mod__b .rsd-hv-sk { margin: 0; }
.rsd-hv-mod__brief { grid-area: brief; border-style: dashed; }
.rsd-hv-mod__core { grid-area: core; }
.rsd-hv-mod__tiles { display: grid; flex: 1 1 auto; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .3rem; min-height: 0; }
.rsd-hv-mod__tiles i { display: block; background: var(--rsd-paper); border: 1px solid var(--rsd-line); border-radius: 3px; }
.rsd-hv-mod__core:is(.is-on, .is-sweep) .rsd-hv-mod__tiles i { border-color: rgba(196, 8, 8, .5); }
.rsd-hv-mod__ui { grid-area: ui; }
.rsd-hv-mod__input { display: block; height: .8rem; border: 1px solid var(--rsd-line); border-radius: 3px; }
.rsd-hv-mod__btn { display: block; width: 60%; height: .7rem; margin-top: auto; border-radius: var(--rsd-radius-pill); background: rgba(26, 26, 28, .2); }
.rsd-hv-mod__ui:is(.is-on, .is-sweep) .rsd-hv-mod__btn { background: var(--rsd-red); }
.rsd-hv-mod__rel { grid-area: rel; flex-direction: row; align-items: center; }
.rsd-hv-mod__fb { grid-area: fb; flex-direction: row; align-items: center; }
.rsd-hv-mod__rel .rsd-hv-ico, .rsd-hv-mod__fb .rsd-hv-ico { width: .95rem; height: .95rem; }
.rsd-hv-mod__dots { display: flex; gap: 3px; margin-left: auto; }
.rsd-hv-mod__dots i { display: block; width: 5px; height: 5px; border-radius: 50%; background: var(--rsd-muted); opacity: .5; }
.rsd-hv-mod__fb:is(.is-on, .is-sweep) .rsd-hv-mod__dots i { background: var(--rsd-red); opacity: .9; }

/* Motion — only for visitors without a reduced-motion preference: state
   changes ease (300ms, the theme's --rsd-motion-base); the first-view
   signal runs a set number of passes, then stops. */
@media (prefers-reduced-motion: no-preference) {
  .rsd-hv [data-on], .rsd-hv [data-on] *, .rsd-hv [data-on]::before, .rsd-hv [data-on]::after, .rsd-hv__btn, .rsd-hv__num, .rsd-hv__label {
    transition: opacity var(--rsd-motion-base) var(--rsd-ease-out), color var(--rsd-motion-base) var(--rsd-ease-out),
      background-color var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-base) var(--rsd-ease-out),
      box-shadow var(--rsd-motion-base) var(--rsd-ease-out), stroke var(--rsd-motion-base) var(--rsd-ease-out);
  }
  .rsd-hv__dt { transition: opacity var(--rsd-motion-base) var(--rsd-ease-out), visibility var(--rsd-motion-base); }
  .rsd-hv.is-playing .rsd-hv__sig { animation: rsd-hv-x var(--hv-cycle) linear calc(var(--k, 0) * var(--hv-cycle) / 3) 2 both; }
  .rsd-hv.is-playing .rsd-hv__sig--v { animation-name: rsd-hv-y; }
  .rsd-hv.is-playing .rsd-hv-ring__sig { animation: rsd-hv-run var(--hv-cycle) var(--rsd-ease-out) calc(var(--k, 0) * var(--hv-cycle) / 4) 2 both; }
  .rsd-hv.is-playing .rsd-hv-hub__pulse { animation: rsd-hv-dash calc(var(--hv-cycle) / 2.5) var(--rsd-ease-out) calc(var(--k, 0) * var(--hv-cycle) / 7) 2 both; }
}
@keyframes rsd-hv-x { 0% { transform: translateX(0); opacity: 0; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { transform: translateX(100%); opacity: 0; } }
@keyframes rsd-hv-y { 0% { transform: translateY(0); opacity: 0; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { transform: translateY(100%); opacity: 0; } }
/* One connector's share of the loop: it runs during its stage's quarter. */
@keyframes rsd-hv-run { 0% { transform: translateX(0); opacity: 0; } 3% { opacity: 1; } 21% { opacity: 1; } 25%, 100% { transform: translateX(100%); opacity: 0; } }
@keyframes rsd-hv-dash { 0% { stroke-dashoffset: 14; opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { stroke-dashoffset: -100; opacity: 0; } }

/* Stacked under the text (below 1024px): lined up with its left edge, as
   the other Hero windows. */
@media (max-width: 1023px) {
  .rsd-hero-block--align-left .rsd-hv { margin-inline: 0; }
}
/* Narrow windows (≈ 1024px desktops, large phones): six-label rows tighten. */
@container rsd-hv (max-width: 25.5rem) {
  .rsd-hv--many .rsd-hv__list--steps .rsd-hv__label { font-size: .64rem; }
  .rsd-hv-hub { --hv-mid: 7.75rem; }
  .rsd-hv-ring { --st-h: 5.25rem; --gap-c: 4rem; --gap-r: 4.25rem; --core: 2.75rem; }
  .rsd-hv-ring .rsd-hv__btn { padding-inline: .95rem; }
  .rsd-hv-ring .rsd-hv__label { font-size: 1rem; }
}
/* Phones: compact. Five- and six-stage rows show numbers only (the label is
   still each button's name and heads the detail panel); About's cards stack
   number over label; Local SEO's centre moves above a two-column grid; the
   WordPress layer notes and the CRM record fields drop out. Every target
   stays at least 44px. */
@container rsd-hv (max-width: 22.5rem) {
  .rsd-hv__top, .rsd-hv__detail, .rsd-hv__foot { padding-inline: .75rem; }
  .rsd-hv__scene { height: var(--hv-hm, var(--hv-h, 8.25rem)); margin: .65rem .75rem; }
  .rsd-hv-funnel, .rsd-hv-flow, .rsd-hv-com { margin-inline: .5rem; }
  .rsd-hv--many .rsd-hv__list--steps .rsd-hv__label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .rsd-hv--many .rsd-hv__steps { --hv-pad: .3rem; --hv-gap: 0px; }
  .rsd-hv--many .rsd-hv__list--steps .rsd-hv__btn { justify-content: center; height: 2.75rem; padding: 0; }
  .rsd-hv--many .rsd-hv__track { top: calc(.5rem + 1.375rem); }

  .rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__kicker { margin-bottom: 1rem; }
  .rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__steps { margin-top: 1rem; }
  .rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)).rsd-hv--many .rsd-hv__track { top: 1.375rem; }
  .rsd-hv--open:is(.rsd-hv--ring, :not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)) .rsd-hv__detail { margin-top: 1.25rem; padding-left: .85rem; }
  .rsd-hv-ring { --st-h: 4.75rem; --gap-c: 2.75rem; --gap-r: 3.5rem; --core: 2.25rem; margin: 0; }
  .rsd-hv-ring .rsd-hv__btn { gap: .4rem; padding-inline: .75rem; border-radius: 8px; }
  .rsd-hv-ring .rsd-hv__label { font-size: .92rem; }
  .rsd-hv-ring__arrow { width: calc(var(--len) - .7rem); }
  .rsd-hv-ring__core::before { display: none; }
  .rsd-hv-ring__core .rsd-hv-ico { width: 1rem; height: 1rem; }

  .rsd-hv-hub { --hv-hm: auto; }
  .rsd-hv-hub__lines { display: none; }
  .rsd-hv-hub__core { position: static; flex-direction: row; width: auto; margin-bottom: .55rem; transform: none; }
  .rsd-hv-hub__biz { flex: none; border: 1px solid var(--rsd-line); border-right: 0; border-radius: 6px 0 0 6px; }
  .rsd-hv-hub__vis { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; border-top: 0; border-left: 2px solid var(--rsd-red); border-radius: 0 6px 6px 0; }
  .rsd-hv-hub__list { height: auto; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(3, 2.9rem); column-gap: .45rem; row-gap: .45rem; }
  .rsd-hv-hub__list > :nth-child(n + 4) { grid-column: 2; }
  .rsd-hv-hub__list > :nth-child(n + 4) .rsd-hv__btn { justify-content: flex-start; text-align: left; }
  .rsd-hv-hub__list > :nth-child(n + 4) .rsd-hv__btn[aria-pressed="true"] { box-shadow: inset 3px 0 0 var(--rsd-red); }
  .rsd-hv-hub .rsd-hv__btn { padding-inline: .55rem; }
  .rsd-hv-hub .rsd-hv__label { font-size: .68rem; }

  .rsd-hv__scene .rsd-hv-cap { font-size: .56rem; letter-spacing: 0; }
  .rsd-hv-stack__tag { display: none; }
  .rsd-hv-crm { --hv-hm: 9.25rem; }
  .rsd-hv-crm__fields { display: none; }
  .rsd-hv-mod__rel .rsd-hv-ico, .rsd-hv-mod__fb .rsd-hv-ico { display: none; }
  .rsd-hv-ai__node, .rsd-hv-flow__node .rsd-hv-cap { padding-inline: 0; }
  .rsd-hv-web { --hv-hm: 8.75rem; }
  .rsd-hv-web__stack { display: none; }
  .rsd-hv-search__tags b:nth-child(n + 3) { display: none; }
  .rsd-hv-ads { column-gap: 1.2rem; }
  .rsd-hv-ads__ad::after { right: -1rem; }
  .rsd-hv-ai__assist { grid-column: 1 / span 3; }
  .rsd-hv-ai__assist::before { left: 50%; }
  .rsd-hv-ai__assist::after { left: 83.3%; }
  .rsd-hv-ai__note { font-size: .56rem; }
  .rsd-hv-ai__decide { grid-column: 4 / span 2; }
  .rsd-hv-ai__decide::before { left: 25%; }
  .rsd-hv-an { column-gap: .7rem; }
  .rsd-hv-an__src .rsd-hv-chip { padding-inline: .2rem; font-size: .58rem; }
  .rsd-hv-cro { column-gap: .45rem; }
  .rsd-hv-perf__top { grid-template-columns: minmax(0, .9fr) .6rem minmax(0, 1fr) .6rem minmax(0, 1fr) .6rem minmax(0, .75fr); }
  .rsd-hv-perf__src .rsd-hv-chip { padding-inline: .2rem; font-size: .58rem; }
  .rsd-hv-com__card { padding: .3rem .2rem; }
  .rsd-hv-com__card > .rsd-hv-sk { display: none; }
  .rsd-hv-com__card .rsd-hv-com__img { width: 1.3rem; height: 1.1rem; }
  .rsd-hv-mod { grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.05fr); }
}

/* Mission & Vision (mission-vision, rsd_hv_scene_mv()) — two panels, each
   a toggle button with its statement, joined through the RedSprout mark by
   one quiet connection (hung off the Mission item into the gap). The
   active panel: red top rule + filled marker (shape, not colour alone);
   the other turns paper with a muted statement; the connection turns red
   while either is current. A slow dot crosses Mission → Vision on first
   view. Side by side wherever the window allows; stacked (Mission over
   Vision, the connection vertical) in narrow windows. Without JavaScript
   both supporting paragraphs show in the detail panel. */
.rsd-hv--mv { --hv-cycle: 7s; }
.rsd-hv-mv { --hv-h: auto; --mv-gap: 5.5rem; margin: 1rem .85rem; }
.rsd-hv-mv__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--mv-gap); align-items: stretch; }
.rsd-hv-mv__item { position: relative; display: flex; min-width: 0; }
.rsd-hv-mv__panel {
  position: relative; display: flex; flex-direction: column; gap: .55rem; width: 100%; min-height: 7rem; padding: .85rem .85rem .9rem;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; text-align: left;
}
.rsd-hv-mv__head { display: flex; align-items: center; gap: .45rem; }
.rsd-hv-mv__mark { flex: none; width: 8px; height: 8px; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
.rsd-hv-mv .rsd-hv__label { font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; }
.rsd-hv-mv__line { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .84rem; line-height: 1.3; color: var(--rsd-charcoal); overflow-wrap: break-word; }
.rsd-hv-mv__panel.is-on { border-color: var(--rsd-red); box-shadow: inset 0 2px 0 var(--rsd-red); }
.rsd-hv-mv__panel.is-on .rsd-hv__label { color: var(--rsd-red-ink); }
.rsd-hv-mv__panel:is(.is-on, [aria-pressed="true"]) .rsd-hv-mv__mark { background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-hv.has-cur .rsd-hv-mv__panel:not(.is-on) { background: var(--rsd-paper); }
.rsd-hv.has-cur .rsd-hv-mv__panel:not(.is-on) .rsd-hv-mv__line { color: var(--rsd-muted); }
.rsd-hv-mv__link { position: absolute; top: 0; bottom: 0; left: 100%; display: flex; align-items: center; justify-content: center; width: var(--mv-gap); pointer-events: none; }
.rsd-hv-mv__lane { position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: var(--hv-link); }
.rsd-hv-mv__link.is-on .rsd-hv-mv__lane { background: var(--rsd-red); }
.rsd-hv-mv__core {
  position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: .2rem; padding: .35rem .5rem;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .62rem; line-height: 1.2; letter-spacing: .08em; text-transform: uppercase;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 4px;
}
.rsd-hv-mv__core i { width: 8px; height: 8px; border-radius: 2px; background: var(--rsd-red); }
.rsd-hv-mv__core small { font-family: var(--rsd-mono); font-size: .54rem; font-weight: var(--rsd-weight-regular); letter-spacing: .06em; color: var(--rsd-muted); }
.rsd-hv-mv__link.is-on .rsd-hv-mv__core { border-color: var(--rsd-red); }
.rsd-hv--mv .rsd-hv__foot { font-family: var(--rsd-body); font-size: .72rem; letter-spacing: 0; text-transform: none; }
/* Scripting off only (not "before the script runs"), so with JavaScript the
   first render is already the final layout — nothing collapses on load. */
@media (scripting: none) {
  .rsd-hv--mv .rsd-hv__dt--rest { display: none; }
  .rsd-hv--mv .rsd-hv__dt[data-i] { grid-area: auto; visibility: visible; opacity: 1; }
  .rsd-hv--mv .rsd-hv__detail { gap: .6rem; }
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-hv-mv__panel *, .rsd-hv-mv__lane, .rsd-hv-mv__core {
    transition: color var(--rsd-motion-base) var(--rsd-ease-out), background-color var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-base) var(--rsd-ease-out);
  }
}
@container rsd-hv (max-width: 25.5rem) {
  .rsd-hv-mv { --mv-gap: 4.5rem; }
  .rsd-hv-mv__core { padding-inline: .35rem; font-size: .56rem; letter-spacing: .05em; }
  .rsd-hv-mv__panel { padding-inline: .7rem; }
  .rsd-hv-mv__line { font-size: .8rem; }
}
/* Stacked: Mission over Vision, the connection running down between. */
@container rsd-hv (max-width: 22.5rem) {
  .rsd-hv-mv { --mv-gap: 2.6rem; margin: .7rem .75rem; }
  .rsd-hv-mv__list { grid-template-columns: minmax(0, 1fr); row-gap: var(--mv-gap); }
  .rsd-hv-mv__panel { gap: .4rem; min-height: 0; padding: .65rem .75rem .7rem; }
  .rsd-hv--mv .rsd-hv__detail { padding-block: .45rem .5rem; }
  .rsd-hv--mv .rsd-hv__dd { font-size: .72rem; }
  .rsd-hv-mv__core { padding-block: .25rem; }
  .rsd-hv-mv__link { top: 100%; bottom: auto; left: 0; right: 0; width: auto; height: var(--mv-gap); }
  .rsd-hv-mv__lane { top: 0; bottom: 0; left: 50%; right: auto; width: 1px; height: auto; }
  .rsd-hv-mv__core { flex-direction: row; gap: .35rem; }
  .rsd-hv__sig--mv { width: 0; height: 100%; }
  @media (prefers-reduced-motion: no-preference) {
    .rsd-hv.is-playing .rsd-hv__sig--mv { animation-name: rsd-hv-y; }
  }
}

/* Mission & Vision — Digital Growth Intelligence (mission-vision-growth,
   rsd_hv_scene_mvg()). Three rows in the shared window: the story line
   running into the Revenue Growth point (top right); four capability
   cards wired into the central RedSprout Direction node, over a faint
   network (dot grid + arcs) and a rising trajectory that ends at that
   point; then Mission and Vision — the toggles — forked into the node.
   States follow the shared engine: the current stage's button, fork half
   and the node go red; the other button quietens. All figures are
   conceptual (sparklines, arrows), never numbers. The intro (≈2.9s, CSS,
   once) runs on the page only — never in the editor preview, never under
   reduced motion — and every animation ends on its base style. Phones:
   the node over a 2×2 of cards, the story under them, the buttons
   stacked; wires, fork, arcs and trajectory drop out. */
.rsd-hv--mvg { --hv-cycle: 6s; }
.rsd-hv-mvg {
  --mvg-core: 7rem; --hv-h: calc(var(--mvg-core) + 6.9rem); --mvg-node: 5.75rem; --mvg-gap: 1.1rem;
  position: relative; isolation: isolate; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 1.3rem var(--mvg-core) 4.5rem; row-gap: .55rem;
  margin: .8rem .85rem;
}
/* The network: a dot grid fading out from the centre, and a few arcs. */
.rsd-hv-mvg::before {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-image: radial-gradient(circle, rgba(99, 99, 106, .2) .7px, transparent 1.1px); background-size: 12px 12px;
  -webkit-mask-image: radial-gradient(ellipse at 50% 42%, #000 25%, transparent 72%); mask-image: radial-gradient(ellipse at 50% 42%, #000 25%, transparent 72%);
}
.rsd-hv-mvg__net { position: absolute; top: 1.6rem; left: 0; z-index: -1; width: 100%; height: calc(var(--mvg-core) + .6rem); fill: none; stroke: var(--rsd-line); stroke-width: 1; opacity: .75; pointer-events: none; }
.rsd-hv-mvg__traj { position: absolute; inset: 0; z-index: -1; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.rsd-hv-mvg__traj path { fill: none; stroke: rgba(26, 26, 28, .5); stroke-width: 1.5; stroke-linecap: round; vector-effect: non-scaling-stroke; }
/* Row 1: the story, into the outcome (its dot sits on the trajectory's end, 96% / 6%). */
.rsd-hv-mvg__story {
  grid-row: 1; align-self: center; max-width: 62%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font-family: var(--rsd-mono); font-size: .56rem; line-height: 1.2; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-muted);
}
.rsd-hv-mvg__story i { opacity: .7; }
.rsd-hv-mvg__rev { position: absolute; top: calc(6% - .5rem); right: calc(4% - 4.5px); display: flex; align-items: center; gap: .4rem; height: 1rem; }
.rsd-hv-mvg__rev b { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .68rem; line-height: 1; color: var(--rsd-charcoal); white-space: nowrap; }
.rsd-hv-mvg__rev-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--rsd-red); box-shadow: 0 0 0 4px rgba(196, 8, 8, .14); }
/* Row 2: cards | node | cards. */
.rsd-hv-mvg__core { grid-row: 2; display: grid; grid-template-columns: minmax(0, 1fr) var(--mvg-node) minmax(0, 1fr); column-gap: var(--mvg-gap); align-items: center; min-width: 0; }
.rsd-hv-mvg__cards { display: grid; gap: .5rem; min-width: 0; }
.rsd-hv-mvg__card {
  position: relative; display: flex; flex-direction: column; justify-content: center; gap: .2rem; min-width: 0; height: 3.25rem; padding: .4rem .55rem;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px; box-shadow: 0 1px 2px rgba(26, 26, 28, .04);
}
.rsd-hv-mvg__card-head { display: flex; align-items: center; gap: .35rem; min-width: 0; }
.rsd-hv-mvg__card-head .rsd-hv-ico { width: .8rem; height: .8rem; color: var(--rsd-muted); }
.rsd-hv-mvg__card-head b { flex: 1 1 auto; min-width: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .66rem; line-height: 1.15; color: var(--rsd-charcoal); }
.rsd-hv-mvg__up { flex: none; font-size: .66rem; line-height: 1; color: var(--rsd-charcoal); opacity: .7; }
.rsd-hv-mvg__card-sub { display: flex; align-items: center; gap: .3rem; min-width: 0; }
.rsd-hv-mvg__card-sub span { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: .56rem; line-height: 1.2; color: var(--rsd-muted); }
.rsd-hv-mvg__spark { flex: none; width: 1.4rem; height: .6rem; fill: none; stroke: var(--rsd-muted); stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
/* Each card's wire into the node (across the gap, under the node's edge). */
.rsd-hv-mvg__wire { position: absolute; top: 50%; width: calc(var(--mvg-gap) + .75rem); height: 1px; background: var(--hv-link); pointer-events: none; }
.rsd-hv-mvg__cards--l .rsd-hv-mvg__wire { left: 100%; }
.rsd-hv-mvg__cards--r .rsd-hv-mvg__wire { right: 100%; }
.rsd-hv-mvg__sig { position: absolute; top: 0; left: 0; width: 100%; height: 0; opacity: 0; }
.rsd-hv-mvg__sig::before { content: ""; position: absolute; top: -2.5px; left: -3px; width: 6px; height: 6px; border-radius: 50%; background: var(--rsd-red); }
.rsd-hv-mvg__cards--r .rsd-hv-mvg__sig::before { left: auto; right: -3px; }
.rsd-hv-mvg__node {
  position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .2rem;
  width: var(--mvg-node); aspect-ratio: 1; border-radius: 50%; text-align: center;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); box-shadow: var(--rsd-hc-shadow);
}
.rsd-hv-mvg__node::before { content: ""; position: absolute; inset: .3rem; border: 1px dashed var(--rsd-line); border-radius: 50%; pointer-events: none; }
.rsd-hv-mvg__node i { width: 8px; height: 8px; border-radius: 2px; background: var(--rsd-red); }
.rsd-hv-mvg__node b { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .6rem; line-height: 1.1; letter-spacing: .12em; text-transform: uppercase; color: var(--rsd-charcoal); }
.rsd-hv-mvg__node small { font-family: var(--rsd-mono); font-size: .5rem; line-height: 1.1; letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-muted); }
/* The node's stem down into the Mission / Vision fork. */
.rsd-hv-mvg__node::after { content: ""; position: absolute; top: 100%; left: 50%; width: 1px; height: calc((var(--mvg-core) - var(--mvg-node)) / 2 + .55rem - .575rem); background: var(--hv-link); }
.rsd-hv-mvg__node.is-on { border-color: var(--rsd-red); box-shadow: 0 0 0 4px rgba(196, 8, 8, .08), var(--rsd-hc-shadow); }
.rsd-hv-mvg__node.is-on::after { background: var(--rsd-red); }
/* Row 3: Mission | Vision, each a toggle (≥ 44px). */
.rsd-hv-mvg__list { grid-row: 3; position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: .75rem; margin: 0; padding: 0; list-style: none; }
.rsd-hv-mvg__fork { position: absolute; top: -.575rem; height: .575rem; margin: 0; border: 1px solid var(--hv-link); border-bottom: 0; pointer-events: none; }
.rsd-hv-mvg__fork--0 { left: calc(25% - .1875rem); right: 50%; border-right: 0; border-top-left-radius: 6px; }
.rsd-hv-mvg__fork--1 { left: 50%; right: calc(25% - .1875rem); border-left: 0; border-top-right-radius: 6px; }
.rsd-hv-mvg__fork.is-on { border-color: var(--rsd-red); }
.rsd-hv-mvg__item { display: flex; min-width: 0; margin: 0; }
.rsd-hv-mvg__panel {
  display: flex; flex-direction: column; gap: .3rem; width: 100%; min-height: 2.75rem; padding: .5rem .65rem; text-align: left;
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 6px;
}
.rsd-hv-mvg__head { display: flex; align-items: center; gap: .4rem; }
.rsd-hv-mvg__mark { flex: none; width: 8px; height: 8px; border: 1.5px solid var(--rsd-muted); border-radius: 50%; }
.rsd-hv-mvg .rsd-hv__label { font-size: .62rem; line-height: 1.2; letter-spacing: .12em; text-transform: uppercase; }
.rsd-hv-mvg__line {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .66rem; line-height: 1.3; color: var(--rsd-charcoal);
}
.rsd-hv-mvg__panel.is-on { border-color: var(--rsd-red); box-shadow: inset 0 2px 0 var(--rsd-red); }
.rsd-hv-mvg__panel.is-on .rsd-hv__label { color: var(--rsd-red-ink); }
.rsd-hv-mvg__panel:is(.is-on, [aria-pressed="true"]) .rsd-hv-mvg__mark { background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-hv.has-cur .rsd-hv-mvg__panel:not(.is-on) { background: var(--rsd-paper); }
.rsd-hv.has-cur .rsd-hv-mvg__panel:not(.is-on) .rsd-hv-mvg__line { color: var(--rsd-muted); }
.rsd-hv--mvg .rsd-hv__foot { letter-spacing: .05em; }
/* Scripting off only: both details show (as Mission & Vision does). */
@media (scripting: none) {
  .rsd-hv--mvg .rsd-hv__dt--rest { display: none; }
  .rsd-hv--mvg .rsd-hv__dt[data-i] { grid-area: auto; visibility: visible; opacity: 1; }
  .rsd-hv--mvg .rsd-hv__detail { gap: .6rem; }
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-hv-mvg__panel, .rsd-hv-mvg__panel *, .rsd-hv-mvg__fork, .rsd-hv-mvg__node, .rsd-hv-mvg__node::after {
    transition: color var(--rsd-motion-base) var(--rsd-ease-out), background-color var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-base) var(--rsd-ease-out), box-shadow var(--rsd-motion-base) var(--rsd-ease-out);
  }
  /* The intro: page only (the editor canvas body is .editor-styles-wrapper). */
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__item { animation: rsd-hv-mvg-fade .4s ease-out .15s backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__card { animation: rsd-hv-mvg-in .4s var(--rsd-ease-out) calc(.25s + var(--k, 0) * .15s) backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__cards--l .rsd-hv-mvg__sig { animation: rsd-hv-mvg-sig .5s ease-in calc(1.05s + var(--k, 0) * .06s) backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__cards--r .rsd-hv-mvg__sig { animation: rsd-hv-mvg-sig-r .5s ease-in calc(1.05s + var(--k, 0) * .06s) backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__node { animation: rsd-hv-mvg-node .5s var(--rsd-ease-out) 1.55s backwards; }
  /* Revealed left → right (a dash draw breaks on a non-scaling stroke). */
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__traj { animation: rsd-hv-mvg-reveal .8s cubic-bezier(.45, 0, .2, 1) 1.85s backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__rev b { animation: rsd-hv-mvg-fade .3s ease-out 2.5s backwards; }
  body:not(.editor-styles-wrapper) .rsd-hv-mvg__rev-dot { animation: rsd-hv-mvg-pop .35s var(--rsd-ease-out) 2.55s backwards; }
}
@keyframes rsd-hv-mvg-fade { from { opacity: 0; } }
@keyframes rsd-hv-mvg-in { from { opacity: 0; transform: translateY(4px); } }
@keyframes rsd-hv-mvg-sig { 0% { opacity: 0; transform: none; } 20%, 85% { opacity: 1; } 100% { opacity: 0; transform: translateX(100%); } }
@keyframes rsd-hv-mvg-sig-r { 0% { opacity: 0; transform: none; } 20%, 85% { opacity: 1; } 100% { opacity: 0; transform: translateX(-100%); } }
@keyframes rsd-hv-mvg-node { from { border-color: var(--rsd-line); box-shadow: var(--rsd-hc-shadow); transform: scale(.94); } }
@keyframes rsd-hv-mvg-reveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes rsd-hv-mvg-pop { from { opacity: 0; transform: scale(.3); box-shadow: 0 0 0 0 rgba(196, 8, 8, 0); } }
/* Narrower windows (≈ 1024px desktops): a smaller node and gap. */
@container rsd-hv (max-width: 25.5rem) {
  /* Subtitles wrap (two lines) rather than truncate; the sparkline gives way. */
  .rsd-hv-mvg { --mvg-node: 5.25rem; --mvg-gap: .8rem; --mvg-core: 8.1rem; }
  .rsd-hv-mvg__card { height: 3.8rem; padding-inline: .45rem; }
  .rsd-hv-mvg__card-sub span { white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  .rsd-hv-mvg__spark { display: none; }
  .rsd-hv-mvg__wire { width: calc(var(--mvg-gap) + 1.15rem); } /* taller cards meet the circle further in */
}
/* Phones: the node over a 2×2 of cards, the story under them, the buttons stacked. */
@container rsd-hv (max-width: 22.5rem) {
  .rsd-hv-mvg { --hv-hm: auto; --mvg-node: 4.75rem; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: none; row-gap: .7rem; column-gap: .5rem; margin: .7rem .75rem; }
  .rsd-hv-mvg__net, .rsd-hv-mvg__traj, .rsd-hv-mvg__wire, .rsd-hv-mvg__fork, .rsd-hv-mvg__node::after { display: none; }
  .rsd-hv-mvg__core { grid-row: 1; grid-column: 1 / -1; grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: .6rem; column-gap: .5rem; }
  .rsd-hv-mvg__node { grid-row: 1; grid-column: 1 / -1; justify-self: center; }
  .rsd-hv-mvg__cards--l { grid-row: 2; grid-column: 1; }
  .rsd-hv-mvg__cards--r { grid-row: 2; grid-column: 2; }
  .rsd-hv-mvg__card { height: auto; min-height: 3.1rem; }
  .rsd-hv-mvg__story { grid-row: 2; grid-column: 1; max-width: none; white-space: normal; }
  .rsd-hv-mvg__rev { position: static; grid-row: 2; grid-column: 2; align-self: center; }
  .rsd-hv-mvg__list { grid-row: 3; grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr); row-gap: .5rem; }
  .rsd-hv-mvg__line { -webkit-line-clamp: unset; }
}
/* Market visuals (market-uk, rsd_hv_scene_market()) — the digital growth
   system leading to its business outcome. Left: six stages on one rail,
   top to bottom, the last (Business Growth) the red accent, with a hairline
   arrow from it into the outcome. Right: a dashed "Business outcome" panel —
   "Revenue Growth" over a chart that rises left to right to a red endpoint,
   its value axis marked only with the currency symbol (no amounts, no
   percentages); a small line above names the market (country, currency,
   locale). Phones: one column — Business Growth ↓ Revenue Growth, the
   market line moving under the chart. Base styles are the final state; the
   one-time intro (~3s, CSS only) runs on the page — not under reduced
   motion, and not in the editor preview (.is-ready, hero-editor.js). Fill
   mode "backwards": every animation ends on its base style, so nothing
   stays composited afterwards. */
.rsd-hv-mk { --hv-h: auto; display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); column-gap: 1rem; align-items: stretch; }
.rsd-hv-mk__flow { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
.rsd-hv-mk__track { position: relative; display: block; }
.rsd-hv-mk__steps { display: grid; gap: .5rem; margin: 0; padding: 0 0 0 1rem; list-style: none; }
.rsd-hv-mk__rail { position: absolute; top: .75rem; bottom: .75rem; left: .3rem; width: 1px; background: var(--hv-link); }
.rsd-hv-mk__step {
  position: relative; display: flex; align-items: center; gap: .45rem; min-width: 0; height: 1.5rem; margin: 0; padding: 0 .5rem;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .72rem; line-height: 1.2; white-space: nowrap;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 4px;
}
.rsd-hv-mk__step span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rsd-hv-mk__step .rsd-hv-ico { width: .85rem; height: .85rem; color: var(--rsd-muted); }
/* Its node on the rail. */
.rsd-hv-mk__step::before {
  content: ""; position: absolute; top: 50%; left: calc(-1rem + .3rem - 3px); width: 7px; height: 7px; margin-top: -3.5px;
  background: var(--rsd-white); border: 1px solid var(--rsd-muted); border-radius: 50%;
}
.rsd-hv-mk__step--goal { color: var(--rsd-red-ink); border-color: var(--rsd-red); box-shadow: inset 2px 0 0 var(--rsd-red); }
.rsd-hv-mk__step--goal .rsd-hv-ico { color: var(--rsd-red); }
.rsd-hv-mk__step--goal::before { background: var(--rsd-red); border-color: var(--rsd-red); }
/* Business Growth → the outcome panel: across the column gap (down on phones). */
.rsd-hv-mk__to { position: absolute; top: 50%; left: 100%; width: calc(1rem - 1px); }
.rsd-hv-mk__sig { position: absolute; top: 0; left: 0; width: 0; height: 100%; opacity: 0; pointer-events: none; }
.rsd-hv-mk__sig::before { content: ""; position: absolute; top: -3px; left: -3px; width: 7px; height: 7px; border-radius: 50%; background: var(--rsd-red); }
.rsd-hv-mk__ctx { display: flex; flex-direction: column; gap: .2rem; min-width: 0; padding: .55rem .7rem .5rem; border: 1px dashed var(--rsd-line); border-radius: 4px; }
.rsd-hv-mk__market { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .35rem; margin-bottom: .4rem; }
.rsd-hv .rsd-hv-mk__country { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .68rem; line-height: 1.25; color: var(--rsd-charcoal); }
.rsd-hv-mk__market .rsd-hv-chip { padding: 0 .3rem; font-size: .58rem; }
.rsd-hv .rsd-hv-mk__outcome { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .9rem; line-height: 1.2; color: var(--rsd-charcoal); }
.rsd-hv-mk__note { font-family: var(--rsd-mono); font-size: .54rem; line-height: 1.3; letter-spacing: .04em; color: var(--rsd-muted); opacity: .8; }
.rsd-hv-mk__chart { position: relative; display: block; margin-top: auto; padding-top: .35rem; }
.rsd-hv-mk__unit { position: absolute; top: 0; left: 0; font-family: var(--rsd-mono); font-size: .62rem; line-height: 1; color: var(--rsd-muted); }
.rsd-hv-mk__path { display: block; width: 100%; height: auto; overflow: visible; }
.rsd-hv-mk__grid { fill: none; stroke: var(--rsd-line); stroke-width: 1; stroke-dasharray: 2 4; }
.rsd-hv-mk__axis { fill: none; stroke: var(--rsd-line); stroke-width: 1; }
.rsd-hv-mk__line { fill: none; stroke: var(--rsd-charcoal); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.rsd-hv-mk__node { fill: var(--rsd-white); stroke: var(--rsd-muted); stroke-width: 1.1; }
.rsd-hv-mk__hub { fill: var(--rsd-red); }
.rsd-hv-mk__ring { fill: none; stroke: var(--rsd-red); stroke-width: 1; opacity: .3; }
.rsd-hv-mk__node, .rsd-hv-mk__hub, .rsd-hv-mk__ring { transform-box: fill-box; transform-origin: center; }
/* The story: the stages arrive, a signal runs down the rail and lights
   Business Growth, the arrow reaches the outcome, the panel opens, the
   revenue line draws upward point by point, the red endpoint lands with
   one soft pulse (≈3s, once). */
@media (prefers-reduced-motion: no-preference) {
  .rsd-hv:not(.is-ready) .rsd-hv-mk__step { animation: rsd-hv-mk-in .35s var(--rsd-ease-out) calc(.2s + var(--k, 0) * .1s) backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__rail { transform-origin: top; animation: rsd-hv-mk-grow .7s cubic-bezier(.45, 0, .2, 1) .25s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__sig { animation: rsd-hv-mk-down .6s ease-in-out .95s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__step--goal { animation: rsd-hv-mk-in .35s var(--rsd-ease-out) calc(.2s + var(--k, 0) * .1s) backwards, rsd-hv-mk-goal .3s ease-out 1.5s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__step--goal::before { animation: rsd-hv-mk-goal-dot .3s ease-out 1.5s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__to { animation: rsd-hv-mk-reach .25s ease-out 1.65s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__ctx { animation: rsd-hv-mk-fade .35s ease-out 1.75s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__line { stroke-dasharray: 1; animation: rsd-hv-mk-draw .65s linear 1.9s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__node { animation: rsd-hv-mk-pop .25s var(--rsd-ease-out) calc(1.9s + var(--k, 0) * .12s) backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__hub { animation: rsd-hv-mk-pop .3s var(--rsd-ease-out) 2.5s backwards; }
  .rsd-hv:not(.is-ready) .rsd-hv-mk__ring { animation: rsd-hv-mk-ring .45s var(--rsd-ease-out) 2.55s backwards; }
}
@keyframes rsd-hv-mk-in { from { opacity: 0; transform: translateY(4px); } }
@keyframes rsd-hv-mk-fade { from { opacity: 0; } }
@keyframes rsd-hv-mk-grow { from { transform: scaleY(0); } }
@keyframes rsd-hv-mk-reach { from { clip-path: inset(0 100% 100% 0); } to { clip-path: inset(-4px -6px -6px -4px); } }
@keyframes rsd-hv-mk-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes rsd-hv-mk-down { 0% { opacity: 0; transform: none; } 10%, 90% { opacity: 1; } 100% { opacity: 0; transform: translateY(100%); } }
@keyframes rsd-hv-mk-goal { from { color: var(--rsd-charcoal); border-color: var(--rsd-line); box-shadow: none; } }
@keyframes rsd-hv-mk-goal-dot { from { background: var(--rsd-white); border-color: var(--rsd-muted); } }
@keyframes rsd-hv-mk-pop { from { opacity: 0; transform: scale(.4); } }
@keyframes rsd-hv-mk-ring { 0% { opacity: 0; transform: scale(.5); } 50% { opacity: .45; transform: scale(1.35); } 100% { opacity: .3; transform: scale(1); } }
/* Phones: one column — Business Growth ↓ Revenue Growth. Tighter stages,
   a shorter chart, the market line under it. */
@container rsd-hv (max-width: 22.5rem) {
  .rsd-hv-mk { grid-template-columns: minmax(0, 1fr); row-gap: .9rem; }
  .rsd-hv-mk__steps { gap: .35rem; }
  .rsd-hv-mk__step { height: 1.4rem; }
  .rsd-hv-mk__rail { top: .7rem; bottom: .7rem; }
  .rsd-hv-mk__to { top: 100%; left: 50%; width: 1px; height: calc(.9rem - 1px); margin-top: 1px; }
  .rsd-hv-mk__to::after { top: auto; right: auto; bottom: -1px; left: -3px; border-width: 5px 3.5px 0; border-color: var(--hv-link) transparent transparent; }
  .rsd-hv-mk__ctx { padding: .5rem .65rem; }
  .rsd-hv-mk__market { order: 1; margin: .45rem 0 0; }
  .rsd-hv-mk__path { width: auto; height: 3.4rem; max-width: 100%; }
}

/* ---------------------------------------------------------- 404 page
   "The page took a wrong turn" (404.php). Scoped to .rsd-404 only.
   Base styles are the final, static state; the one-time motion lives in
   the no-preference block below, so reduced motion shows the complete
   route with nothing moving. The 404 uses its own class, not .rsd-h1, so
   the global reveal engine does not animate it a second time. */
.rsd-404 { padding-block: var(--rsd-block); text-align: center; }
.rsd-404 .rsd-404__eyebrow { margin-inline: auto; }
.rsd-404 .rsd-404__eyebrow::after { left: 50%; transform: translateX(-50%); }
.rsd-404__code {
  margin: .25rem 0 0; padding-left: .05em; color: var(--rsd-charcoal);
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-bold);
  font-size: clamp(5.625rem, 3.2rem + 12vw, 13.75rem); line-height: .86; letter-spacing: -.05em;
}
.rsd-404__route { display: block; width: min(100%, 32.5rem); height: auto; margin: clamp(1rem, 2.4vw, 1.75rem) auto clamp(1.5rem, 3.2vw, 2.5rem); overflow: visible; }
/* The route: start → junction (red signal) → the wrong branch, the car
   parked just past its end; the intended route breaks off past the
   junction, its destination (a hollow ring) unreached. */
.rsd-404__path, .rsd-404__stub, .rsd-404__branch { fill: none; stroke: var(--rsd-muted); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.rsd-404__start { fill: var(--rsd-charcoal); }
.rsd-404__break line { stroke: var(--rsd-muted); stroke-width: 1.5; stroke-linecap: round; }
.rsd-404__lost { fill: none; stroke: var(--rsd-muted); stroke-width: 1.25; stroke-linecap: round; stroke-dasharray: 2 6; opacity: .45; }
.rsd-404__goal { fill: none; stroke: var(--rsd-muted); stroke-width: 1.25; opacity: .45; }
/* The car (30 user units ≈ 30px wide at full size): a charcoal silhouette,
   the windows cut in the page colour. Its parked position is the SVG
   transform; where CSS motion paths exist it sits at the end of the same
   path it drives (offset-distance 100%, nose along the route: ≈9.5° down). */
.rsd-404__car { fill: var(--rsd-charcoal); }
.rsd-404__car-glass { fill: var(--rsd-body-bg, var(--rsd-paper)); }
.rsd-404__car-body { transform-box: view-box; transform-origin: 0 0; }
@media (min-width: 768px) and (max-width: 1199px) {
  .rsd-404__car-body { transform: scale(.87); }
}
@supports (offset-path: path("M0 0")) {
  .rsd-404__car {
    transform: none; transform-box: view-box; transform-origin: 0 0;
    offset-path: path("M27 16H150C176 16 186 12 212 12H286C314 12 322 37 354 38H390Q402 38 414 40");
    offset-anchor: 0 0; offset-rotate: auto; offset-distance: 100%;
  }
}
.rsd-404__node { fill: var(--rsd-red); }
.rsd-404__ring { fill: none; stroke: var(--rsd-red); stroke-width: 1.25; opacity: .3; }
.rsd-404__node, .rsd-404__ring { transform-box: fill-box; transform-origin: center; }
.rsd-404__title { margin: 0 0 .75rem; font-size: var(--rsd-t-h2); color: var(--rsd-charcoal); }
.rsd-404 .rsd-404__text { margin: 0 auto; }
.rsd-404__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; margin-top: clamp(1.5rem, 3vw, 2.25rem); }
@media (max-width: 479px) {
  .rsd-404__actions { flex-direction: column; align-items: stretch; width: min(100%, 20rem); margin-inline: auto; }
  .rsd-404__actions .wp-block-button__link { width: 100%; }
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-404__code { animation: rsd-404-rise .7s var(--rsd-ease-out) both; }
  /* The car appears at the start, drives the route (the line drawing in
     behind it), pauses with its nose at the junction as the red signal
     appears, takes the wrong branch, rolls a short way off its end and
     stops; then the intended route shows broken (~2.9s, once). */
  .rsd-404__path, .rsd-404__stub, .rsd-404__branch { stroke-dasharray: 1; }
  .rsd-404__start { animation: rsd-404-fade .3s ease-out .05s both; }
  .rsd-404__path { animation: rsd-404-draw .8s cubic-bezier(.45, 0, .35, 1) .4s both; }
  .rsd-404__node { animation: rsd-404-node .3s var(--rsd-ease-out) 1.15s both; }
  .rsd-404__ring { animation: rsd-404-ring 1.2s var(--rsd-ease-out) 1.2s both; }
  .rsd-404__stub { animation: rsd-404-draw .25s linear 1.2s both; }
  .rsd-404__branch { animation: rsd-404-draw .7s cubic-bezier(.4, 0, 1, 1) 1.4s both; }
  .rsd-404__break, .rsd-404__lost, .rsd-404__goal { animation: rsd-404-fade .5s ease-out 2.4s both; }
  /* Without motion-path support the car simply appears, parked. Fill
     "backwards": both animations end on the car's base (parked) style, so
     it is not left on its own compositing layer. */
  .rsd-404__car { animation: rsd-404-fade .4s ease-out 2.1s backwards; }
  @supports (offset-path: path("M0 0")) {
    .rsd-404__car { animation: rsd-404-fade .3s ease-out .1s backwards, rsd-404-drive 2.1s linear .4s backwards; }
  }
  .rsd-404__title, .rsd-404__text, .rsd-404__actions { animation: rsd-404-rise .6s var(--rsd-ease-out) both; }
  .rsd-404__title { animation-delay: .25s; }
  .rsd-404__text { animation-delay: .35s; }
  .rsd-404__actions { animation-delay: .45s; }
}
@keyframes rsd-404-rise { from { opacity: 0; transform: translateY(12px); } }
@keyframes rsd-404-fade { from { opacity: 0; } }
@keyframes rsd-404-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes rsd-404-node { from { opacity: 0; transform: scale(.4); } }
@keyframes rsd-404-ring { 0% { opacity: 0; transform: scale(.5); } 45% { opacity: .45; transform: scale(1.5); } 100% { opacity: .3; transform: scale(1); } }
/* Along the motion path (lengths measured: the car's nose stops just
   short of the junction signal at 60.56%, the end of the drawn branch is
   at 93.87%), over 2.1s from 0.4s: to the junction by 1.2s, a 0.2s pause,
   the branch by 2.1s, then easing to a stop by 2.5s. */
@keyframes rsd-404-drive {
  0% { offset-distance: 0%; animation-timing-function: cubic-bezier(.45, 0, .35, 1); }
  38.1% { offset-distance: 60.56%; animation-timing-function: linear; }
  47.6% { offset-distance: 60.56%; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  81% { offset-distance: 93.87%; animation-timing-function: cubic-bezier(0, 0, .3, 1); }
  100% { offset-distance: 100%; }
}
/* ---------------------------------------------------------- Single Career
   single-careers.php (data: inc/careers.php). A standard 1180px page
   (.rsd-shell): the head (eyebrow, H1, summary, Apply button), a hairline
   strip of job details, then two columns — the Apply panel on the left
   (4/12; sticky while it fits, i.e. the email CTA), the job content on the
   right (8/12: each section's heading over its content, the skills as
   quiet tags). White/paper surfaces, hairline borders, no decoration. At
   900px and below the columns stack in reading order: the job, then the
   application. Scoped to .rsd-career only. */
.rsd-career { padding-bottom: var(--rsd-block); }
.rsd-career__head { max-width: 52rem; margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem); }
.rsd-career__head .rsd-eyebrow { margin-bottom: 1rem; }
/* Wider than the shared .rsd-h1 measure (16ch), so long job titles wrap
   later; same type size. */
.rsd-career .rsd-career__title { max-width: min(100%, 50rem); margin: 0 0 .35em; overflow-wrap: break-word; }
.rsd-career__summary { margin: 0; }
.rsd-career__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: clamp(1.25rem, 2.5vw, 1.75rem); }
/* Job details: label over value, in a wrapping row between two hairlines. */
.rsd-career__details {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8.75rem, 1fr)); gap: 1.1rem 1.5rem;
  margin: 0 0 clamp(2.5rem, 5vw, 4rem); padding: 1.25rem 0; border-block: 1px solid var(--rsd-line);
}
.rsd-career__detail { min-width: 0; }
.rsd-career__detail dt { margin: 0 0 .3rem; font-family: var(--rsd-mono); font-size: .68rem; line-height: 1.3; letter-spacing: .08em; text-transform: uppercase; color: var(--rsd-muted); }
.rsd-career__detail dd { margin: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: 1rem; line-height: 1.35; color: var(--rsd-charcoal); overflow-wrap: break-word; }
/* The body: Apply left (4/12), the job right (8/12). The panel comes after
   the job in the markup, so it is placed into the left column here. */
.rsd-career__body { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); column-gap: clamp(2.5rem, 5vw, 4.5rem); align-items: start; }
.rsd-career__main { grid-column: 2; grid-row: 1; min-width: 0; }
.rsd-career__section { padding-block: clamp(1.75rem, 3.5vw, 2.5rem); border-top: 1px solid var(--rsd-line); }
.rsd-career__section:first-child { border-top: 0; padding-top: 0; }
.rsd-career__label { margin: 0 0 1rem; font-size: var(--rsd-t-h3); line-height: 1.2; color: var(--rsd-charcoal); }
.rsd-career .rsd-career__content { max-width: none; min-width: 0; }
.rsd-career__content > :first-child { margin-top: 0; }
.rsd-career__content > :last-child { margin-bottom: 0; }
.rsd-career__tags { display: flex; flex-wrap: wrap; align-content: flex-start; gap: .5rem; margin: 0; padding: 0; list-style: none; }
.rsd-career__tags li {
  margin: 0; padding: .35rem .75rem; font-size: var(--rsd-t-sm); line-height: 1.3; color: var(--rsd-charcoal);
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: var(--rsd-radius-pill);
}
/* Apply: one white panel — the invitation, then the form or email CTA. */
.rsd-career__apply {
  grid-column: 1; grid-row: 1; display: flex; flex-direction: column; gap: 1.5rem; min-width: 0;
  padding: clamp(1.5rem, 2.5vw, 2rem); scroll-margin-top: calc(96px + var(--rsd-tagline-space, 0px));
  background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 8px; box-shadow: var(--rsd-shadow-subtle);
}
/* The email CTA is short, so it stays in view beside the job; a HubSpot
   form may be taller than the screen, so that one scrolls normally. */
.rsd-career__apply:has(.rsd-career__form--link) { position: sticky; top: calc(68px + var(--rsd-tagline-space, 0px) + var(--rsd-utility-pad, 0px) + 1.5rem); }
.rsd-career__apply-title { margin: 0 0 .6rem; font-size: var(--rsd-t-h3); line-height: 1.2; color: var(--rsd-charcoal); }
.rsd-career__apply-text { margin: 0; color: var(--rsd-muted); }
.rsd-career__applying { margin: 1.1rem 0 0; font-size: var(--rsd-t-sm); color: var(--rsd-muted); }
.rsd-career__applying strong { color: var(--rsd-charcoal); font-weight: var(--rsd-weight-semibold); }
.rsd-career__form { min-width: 0; }
.rsd-career__form--link { display: flex; flex-direction: column; align-items: flex-start; gap: .6rem; }
@media (max-width: 900px) {
  .rsd-career__body { grid-template-columns: minmax(0, 1fr); }
  .rsd-career__main, .rsd-career__apply { grid-column: auto; grid-row: auto; }
  .rsd-career__apply, .rsd-career__apply:has(.rsd-career__form--link) { position: static; margin-top: clamp(2rem, 5vw, 3rem); }
}@media (max-width: 479px) {
  .rsd-career__details { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
  .rsd-career__actions .wp-block-button, .rsd-career__form--link .wp-block-button { width: 100%; }
  .rsd-career__actions .wp-block-button__link, .rsd-career__form--link .wp-block-button__link { width: 100%; }
}
/* ---------------------------------------------------------- Editorial Card — visual
   The optional visual of redsprout-digital/editorial-card
   (rsd_editorial_card_visual(); slider behaviour assets/js/editorial-card.js).
   Only cards with "Show visual" on and an image get .rsd-ecard--media and a
   .rsd-ecard__media; every other card is untouched. The visual runs edge to
   edge across the top of the card (inside its border, top corners rounded)
   at a fixed 16:9, so its space is reserved before any image loads. The
   slider is a native scroll-snap row (swipe / scroll work without
   JavaScript); its arrows and dots appear once the script is ready and sit
   above the card's stretched link, so they stay clickable. */
.rsd-ecard .rsd-ecard__media {
  position: relative; grid-column: 1 / -1; justify-self: stretch; overflow: hidden;
  width: calc(100% + 2 * var(--rsd-ecard-pad)); aspect-ratio: 16 / 9;
  margin: calc(-1 * var(--rsd-ecard-pad)) calc(-1 * var(--rsd-ecard-pad)) 1.25rem;
  background: var(--rsd-paper); border-radius: 5px 5px 0 0;
}
.rsd-ecard--compact .rsd-ecard__media { margin-top: -1.1rem; margin-bottom: 1rem; }
.rsd-ecard--dark .rsd-ecard__media { background: rgba(247, 246, 244, .06); }
.rsd-ecard .rsd-ecard__media img { display: block; width: 100%; height: 100%; max-width: none; margin: 0; object-fit: cover; }
.rsd-ecard--media.rsd-ecard--accent .rsd-ecard__card::before { z-index: 2; }
/* Slider. */
.rsd-ecard .rsd-ecard__slider { z-index: 1; }
.rsd-ecard .rsd-ecard__track {
  display: flex; height: 100%; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.rsd-ecard .rsd-ecard__track::-webkit-scrollbar { display: none; }
.rsd-ecard .rsd-ecard__track:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: -2px; }
.rsd-ecard .rsd-ecard__slide { flex: 0 0 100%; height: 100%; scroll-snap-align: start; scroll-snap-stop: always; }
.rsd-ecard .rsd-ecard__nav {
  position: absolute; top: 50%; z-index: 1; display: none; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; margin: -1.25rem 0 0; padding: 0; cursor: pointer;
  font-family: var(--rsd-display); font-size: 1rem; line-height: 1; color: var(--rsd-charcoal);
  background: rgba(255, 255, 255, .92); border: 1px solid var(--rsd-line); border-radius: 50%; box-shadow: 0 1px 3px rgba(26, 26, 28, .12);
}
.rsd-ecard .rsd-ecard__nav--prev { left: .75rem; }
.rsd-ecard .rsd-ecard__nav--next { right: .75rem; }
.rsd-ecard .rsd-ecard__nav:disabled { opacity: .4; cursor: default; }
.rsd-ecard .rsd-ecard__nav:focus-visible, .rsd-ecard .rsd-ecard__dot:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; }
.rsd-ecard .rsd-ecard__dots {
  position: absolute; left: 50%; bottom: .6rem; z-index: 1; display: none; gap: .1rem; padding: 0 .35rem; transform: translateX(-50%);
  background: rgba(26, 26, 28, .45); border-radius: var(--rsd-radius-pill);
}
/* 24px targets around an 8px dot. */
.rsd-ecard .rsd-ecard__dot { position: relative; width: 1.5rem; height: 1.5rem; margin: 0; padding: 0; cursor: pointer; background: none; border: 0; border-radius: 50%; }
.rsd-ecard .rsd-ecard__dot::before { content: ""; position: absolute; top: 50%; left: 50%; width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; background: rgba(255, 255, 255, .55); }
.rsd-ecard .rsd-ecard__dot[aria-current="true"]::before { background: var(--rsd-white); box-shadow: 0 0 0 2px var(--rsd-red); }
.rsd-ecard .rsd-ecard__slider.is-ready .rsd-ecard__nav { display: inline-flex; }
.rsd-ecard .rsd-ecard__slider.is-ready .rsd-ecard__dots { display: flex; }
/* Editor preview: how many slides (the controls are the published page's). */
.rsd-ecard .rsd-ecard__count {
  position: absolute; right: .6rem; bottom: .6rem; padding: .15rem .5rem; font-family: var(--rsd-mono); font-size: .7rem; line-height: 1.4;
  color: var(--rsd-white); background: rgba(26, 26, 28, .6); border-radius: var(--rsd-radius-pill);
}
@media (prefers-reduced-motion: no-preference) {
  .rsd-ecard .rsd-ecard__nav { transition: opacity var(--rsd-motion-fast) var(--rsd-ease-out); }
}
/* ---------------------------------------------------------- Success Stories
   redsprout-digital/success-stories (inc/success-stories.php; the Featured
   result panel's behaviour: assets/js/success-stories.js). Three layouts
   from the same stories, each sized by its own container (the block is the
   container, so it adapts beside a sidebar, in a column and in the editor):
    - Editorial Mosaic: 12 columns from 56rem (6 from 40rem, 1 below); the
      lead tile 7 × 2 beside two 5-wide tiles, then rows of 4/4/4, 5/7, 7/5
      — spans come from PHP (--sd / --st / --rd), the last row always full.
      Surfaces mix white, paper, one red accent per few and charcoal.
    - Rectangular Grid: 3 / 2 / 1 equal columns, rows of equal height, the
      Featured result across the top.
    - Masonry: 3 / 2 / 1 CSS columns, cards at their natural height.
   Cards never have a fixed height — text is never clipped. Card positions
   never change after load: the reveal (theme engine) fades each card up
   in place, hover lifts it 4px, and the Featured result panel crossfades
   inside its own cell, which is as tall as its tallest slide.
   Reveal, hover lift and every transition run only under no-preference. */
.rsd-ss {
  --ss-gap: clamp(.9rem, 1.6vw, 1.25rem);
  --ss-pad: clamp(1.25rem, 2.4vw, 1.9rem);
  --ss-radius: 14px;
  container: rsd-ss / inline-size;
}
.rsd-ss__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ss-gap); align-items: stretch; }

/* Card. */
.rsd-ss__card {
  position: relative; display: flex; flex-direction: column; min-width: 0; overflow: hidden;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: var(--ss-radius);
  box-shadow: 0 1px 2px rgba(26, 26, 28, .04);
}
.rsd-ss__card--paper { background: var(--rsd-paper); }
.rsd-ss__card--accent { color: var(--rsd-white); background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-ss__card--dark { color: var(--rsd-paper); background: var(--rsd-charcoal); border-color: var(--rsd-charcoal); }
.rsd-ss__card:focus-within { border-color: color-mix(in srgb, var(--rsd-red) 40%, var(--rsd-line)); }
.rsd-ss__card:is(.rsd-ss__card--accent, .rsd-ss__card--dark):focus-within { border-color: var(--rsd-paper); }
/* The card of the story the Featured result panel is showing. */
.rsd-ss__card::before { content: ""; position: absolute; top: 0; left: var(--ss-pad); width: 2.25rem; height: 3px; background: var(--rsd-red); opacity: 0; }
.rsd-ss__card.is-featured::before { opacity: 1; }
.rsd-ss__card--accent::before { background: var(--rsd-white); }
.rsd-ss__media { aspect-ratio: 16 / 9; max-height: 15rem; overflow: hidden; background: var(--rsd-line); } /* capped: a wide tile never gets a banner-sized image */
.rsd-ss__img { display: block; width: 100%; height: 100%; object-fit: cover; }
.rsd-ss__body { display: flex; flex: 1 1 auto; flex-direction: column; gap: 1.1rem; padding: var(--ss-pad); }

/* Brand: the logo, or the company name. On a dark or red surface the logo
   sits on a white plate (logos are drawn for light backgrounds). */
.rsd-ss__brand { display: flex; align-items: center; min-height: 2rem; }
.rsd-ss__logo { display: inline-flex; align-items: center; }
.rsd-ss__logo-img { display: block; width: auto; max-width: 9rem; height: auto; max-height: 2rem; object-fit: contain; object-position: left center; }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark, .rsd-ss__spot) .rsd-ss__logo { padding: .4rem .65rem; background: var(--rsd-white); border-radius: 8px; }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark, .rsd-ss__spot) .rsd-ss__logo-img { max-height: 1.6rem; }
.rsd-ss__company-mark { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .95rem; line-height: 1.25; letter-spacing: -.005em; }

/* Story text — set by length: a short story reads large. */
.rsd-ss__text p { margin: 0; font-size: var(--rsd-t-base); line-height: 1.6; }
.rsd-ss__text p + p { margin-top: .75em; }
.rsd-ss__card--short .rsd-ss__text p { font-family: var(--rsd-display); font-weight: var(--rsd-weight-medium); font-size: clamp(1.15rem, .95rem + .7vw, 1.4rem); line-height: 1.4; letter-spacing: -.01em; }
.rsd-ss__card--lead.rsd-ss__card--short .rsd-ss__text p { font-weight: var(--rsd-weight-semibold); font-size: clamp(1.4rem, 1rem + 1.6vw, 2.1rem); line-height: 1.28; letter-spacing: -.015em; }
.rsd-ss__card--lead.rsd-ss__card--medium .rsd-ss__text p { font-family: var(--rsd-display); font-weight: var(--rsd-weight-medium); font-size: clamp(1.15rem, .95rem + .7vw, 1.4rem); line-height: 1.45; }

/* Metric. */
.rsd-ss__metric { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .6rem; margin: 0; }
.rsd-ss__metric-value { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: clamp(1.75rem, 1.3rem + 1.4vw, 2.4rem); line-height: 1; letter-spacing: -.02em; color: var(--rsd-red); }
.rsd-ss__metric-label { font-family: var(--rsd-mono); font-size: .72rem; line-height: 1.3; letter-spacing: .06em; text-transform: uppercase; color: var(--rsd-muted); }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark) .rsd-ss__metric-value { color: inherit; }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark) .rsd-ss__metric-label { color: inherit; opacity: .78; }

/* Attribution and CTA. */
.rsd-ss__foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .75rem 1rem; margin-top: auto; padding-top: 1rem; border-top: 1px solid var(--rsd-line); }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark, .rsd-ss__spot) .rsd-ss__foot { border-top-color: rgba(247, 246, 244, .2); }
.rsd-ss__by { display: inline-flex; align-items: center; gap: .7rem; min-width: 0; }
.rsd-ss__photo { flex: none; width: 2.5rem; height: 2.5rem; border-radius: 50%; object-fit: cover; background: var(--rsd-line); }
.rsd-ss__who { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.rsd-ss__name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .95rem; line-height: 1.3; }
.rsd-ss__role { font-size: var(--rsd-t-sm); line-height: 1.35; color: var(--rsd-muted); }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark, .rsd-ss__spot) .rsd-ss__role { color: inherit; opacity: .75; }
.rsd-ss__cta {
  display: inline-flex; align-items: center; gap: .35rem; min-height: 2.75rem; padding-block: .25rem;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .92rem; line-height: 1.2;
  color: var(--rsd-red); text-decoration: none;
}
.rsd-ss__cta:hover { text-decoration: underline; text-underline-offset: .2em; }
.rsd-ss__cta:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 2px; }
:is(.rsd-ss__card--accent, .rsd-ss__card--dark, .rsd-ss__spot) .rsd-ss__cta { color: inherit; }

/* Featured result panel. */
.rsd-ss__spot {
  position: relative; display: flex; flex-direction: column; min-width: 0; padding: calc(var(--ss-pad) * 1.15);
  color: var(--rsd-paper); background: var(--rsd-charcoal); border-radius: var(--ss-radius);
}
.rsd-ss__label {
  display: flex; align-items: center; gap: .6rem; margin: 0 0 1.25rem;
  font-family: var(--rsd-mono); font-size: .7rem; line-height: 1.3; letter-spacing: .1em; text-transform: uppercase; color: rgba(247, 246, 244, .72);
}
.rsd-ss__label::before { content: ""; flex: none; width: 1.5rem; height: 1px; background: var(--rsd-red); }
.rsd-ss__slides { flex: 0 0 auto; }
.rsd-ss__slide { display: flex; flex-direction: column; gap: 1.15rem; min-width: 0; }
.rsd-ss__big { display: flex; flex-direction: column; gap: .45rem; margin: 0; }
.rsd-ss__big-value { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: clamp(2.6rem, 1.6rem + 3.4vw, 4.4rem); line-height: .95; letter-spacing: -.03em; }
.rsd-ss__big-label { font-family: var(--rsd-mono); font-size: .75rem; line-height: 1.35; letter-spacing: .08em; text-transform: uppercase; color: rgba(247, 246, 244, .72); }
.rsd-ss__parts { display: grid; gap: .9rem; margin: 0; }
.rsd-ss__part dt { margin: 0 0 .25rem; font-family: var(--rsd-mono); font-size: .68rem; line-height: 1.3; letter-spacing: .08em; text-transform: uppercase; color: rgba(247, 246, 244, .62); }
.rsd-ss__part dd { margin: 0; }
.rsd-ss__part dd p { margin: 0; font-size: var(--rsd-t-sm); line-height: 1.55; }
.rsd-ss__part dd p + p { margin-top: .5em; }
.rsd-ss__spot .rsd-ss__foot { margin-top: .25rem; }
/* Without the script (and in the editor): the slides scroll sideways, each
   a full panel wide, so every story's details stay reachable. */
.rsd-ss__slides { display: flex; gap: 1.5rem; overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; scrollbar-width: thin; }
.rsd-ss__slides > .rsd-ss__slide { flex: 0 0 100%; scroll-snap-align: start; }
.rsd-ss__slides:focus-visible { outline: 2px solid var(--rsd-paper); outline-offset: 4px; border-radius: 4px; }
.rsd-ss__spot--single .rsd-ss__slides, .rsd-ss__spot--preview .rsd-ss__slides { display: block; overflow: visible; }
/* Scripted: one cell, one slide shown, crossfading. */
.rsd-ss__spot.is-ready .rsd-ss__slides { display: grid; overflow: visible; }
.rsd-ss__spot.is-ready .rsd-ss__slide { grid-area: 1 / 1; visibility: hidden; opacity: 0; }
.rsd-ss__spot.is-ready .rsd-ss__slide.is-shown { visibility: visible; opacity: 1; }
.rsd-ss__controls { display: flex; align-items: center; gap: .5rem; margin-top: auto; padding-top: 1.5rem; } /* at the panel's foot, however tall its tile */
.rsd-ss__controls[hidden] { display: none; }
.rsd-ss__count { min-width: 4.5ch; font-family: var(--rsd-mono); font-size: .8rem; text-align: center; color: rgba(247, 246, 244, .78); }
.rsd-ss__nav {
  display: inline-flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; margin: 0; padding: 0;
  font: inherit; font-size: 1rem; line-height: 1; color: var(--rsd-paper); cursor: pointer;
  background: transparent; border: 1px solid rgba(247, 246, 244, .28); border-radius: 50%;
}
.rsd-ss__nav:hover { border-color: var(--rsd-paper); }
.rsd-ss__nav:focus-visible { outline: 2px solid var(--rsd-paper); outline-offset: 2px; }
.rsd-ss__nav--pause { margin-right: .25rem; }
.rsd-ss__nav--pause span { display: inline-flex; gap: 3px; }
.rsd-ss__nav--pause span::before, .rsd-ss__nav--pause span::after { content: ""; width: 2px; height: 10px; background: currentColor; }
.rsd-ss__nav--pause.is-paused span { gap: 0; }
.rsd-ss__nav--pause.is-paused span::before { width: 0; height: 0; background: none; border-style: solid; border-width: 5px 0 5px 8px; border-color: transparent transparent transparent currentColor; }
.rsd-ss__nav--pause.is-paused span::after { display: none; }
.rsd-ss__note { margin: 1rem 0 0; font-size: var(--rsd-t-sm); color: var(--rsd-muted); }

/* Editorial Mosaic. */
@container rsd-ss (min-width: 40rem) {
  .rsd-ss--mosaic .rsd-ss__grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .rsd-ss--mosaic .rsd-ss__grid > * { grid-column: span var(--st, 3); }
}
@container rsd-ss (min-width: 56rem) {
  .rsd-ss--mosaic .rsd-ss__grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .rsd-ss--mosaic .rsd-ss__grid > * { grid-column: span var(--sd, 4); grid-row: span var(--rd, 1); }
  .rsd-ss--mosaic .rsd-ss__spot { padding: calc(var(--ss-pad) * 1.4); }
}

/* Rectangular Grid. */
.rsd-ss--grid .rsd-ss__spot { grid-column: 1 / -1; }
@container rsd-ss (min-width: 40rem) {
  .rsd-ss--grid .rsd-ss__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container rsd-ss (min-width: 56rem) {
  .rsd-ss--grid .rsd-ss__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* The featured result across the top: the figure left, the details right. */
  .rsd-ss--grid .rsd-ss__slide {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); grid-template-areas: "brand parts" "big parts" "big foot";
    grid-template-rows: auto 1fr auto; column-gap: clamp(1.5rem, 4cqi, 3.5rem); row-gap: 1.15rem;
  }
  .rsd-ss--grid .rsd-ss__slide > .rsd-ss__brand { grid-area: brand; }
  .rsd-ss--grid .rsd-ss__slide > .rsd-ss__big { grid-area: big; }
  .rsd-ss--grid .rsd-ss__slide > .rsd-ss__parts { grid-area: parts; }
  .rsd-ss--grid .rsd-ss__slide > .rsd-ss__foot { grid-area: foot; }
}

/* Masonry. */
.rsd-ss--masonry .rsd-ss__grid { display: block; columns: 1; column-gap: var(--ss-gap); }
.rsd-ss--masonry .rsd-ss__grid > * { break-inside: avoid; margin-bottom: var(--ss-gap); }
@container rsd-ss (min-width: 40rem) { .rsd-ss--masonry .rsd-ss__grid { columns: 2; } }
@container rsd-ss (min-width: 56rem) { .rsd-ss--masonry .rsd-ss__grid { columns: 3; } }

@media (prefers-reduced-motion: no-preference) {
  .rsd-ss__card { transition: transform var(--rsd-motion-base) var(--rsd-ease-out), box-shadow var(--rsd-motion-base) var(--rsd-ease-out), border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ss__card::before { transition: opacity var(--rsd-motion-base) var(--rsd-ease-out); }
  .rsd-ss__arrow { display: inline-block; transition: transform var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ss__cta:hover .rsd-ss__arrow { transform: translateX(3px); }
  .rsd-ss__nav { transition: border-color var(--rsd-motion-fast) var(--rsd-ease-out); }
  .rsd-ss__spot.is-ready .rsd-ss__slide { transition: opacity .4s var(--rsd-ease-out), visibility .4s; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .rsd-ss__card:hover { transform: translateY(-4px); box-shadow: var(--rsd-shadow-medium); }
}
/* ---------------------------------------------------------- RedSprout Hero — background styles
   Background Style (inc/hero-block.php 'background'): Default adds no class
   (the hero exactly as before); the three soft gradients add
   .rsd-hero-block--bg-{soft-red|soft-warm|soft-rose}. Static CSS only — no
   image, no request. Each paints one layer (::before) behind the hero:
   full viewport width (the .rsd-shell's centre ± 50vw — .rsd-main's
   overflow-x: clip, and the editor rule below, keep the scrollbar's few px
   from ever scrolling), the hero's own height, with its top and bottom
   faded into whatever is around it (paper, a White section) — each base wash
   itself ends transparent, so the page shows through, never a white band —
   so there is
   never a seam or a band and nothing before or after the hero is painted
   over. Tints are the brand red mixed into white, plus soft peach / cream /
   blush for Soft Warm; all stay near-white, so the hero's charcoal text,
   muted proof line and buttons keep their contrast. Not on a dark (Charcoal
   / Red) surface: there the hero keeps that surface, its text paper. */
.rsd-hero-block:is(.rsd-hero-block--bg-soft-red, .rsd-hero-block--bg-soft-warm, .rsd-hero-block--bg-soft-rose):not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *) {
  position: relative; isolation: isolate;
}
.rsd-hero-block:is(.rsd-hero-block--bg-soft-red, .rsd-hero-block--bg-soft-warm, .rsd-hero-block--bg-soft-rose):not(:where(.has-charcoal-background-color, .has-red-background-color, .has-red-ink-background-color, .rsd-section--bg-charcoal) *)::before {
  content: ""; position: absolute; z-index: -1; top: 0; bottom: 0; left: calc(50% - 50vw); right: calc(50% - 50vw);
  pointer-events: none; background: var(--rsd-hero-bg);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 clamp(2.5rem, 9%, 5rem), #000 calc(100% - clamp(3rem, 14%, 7rem)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 clamp(2.5rem, 9%, 5rem), #000 calc(100% - clamp(3rem, 14%, 7rem)), transparent 100%);
}
/* Soft Red — warm white with one pale rose-red glow behind the visual side,
   and a fainter one low on the text side. */
.rsd-hero-block--bg-soft-red {
  --rsd-hero-bg:
    radial-gradient(48% 78% at 78% 38%, color-mix(in srgb, var(--rsd-red) 9%, transparent), transparent 72%),
    radial-gradient(36% 60% at 8% 92%, color-mix(in srgb, var(--rsd-red) 4%, transparent), transparent 70%),
    linear-gradient(180deg, color-mix(in srgb, var(--rsd-red) 2.5%, var(--rsd-white)) 0%, color-mix(in srgb, var(--rsd-white) 65%, transparent) 60%, transparent 100%);
}
/* Soft Warm — cream base, a peach light from the top left, a light blush
   to the right. */
.rsd-hero-block--bg-soft-warm {
  --rsd-hero-bg:
    radial-gradient(55% 80% at 6% 4%, rgba(255, 201, 160, .32), transparent 70%),
    radial-gradient(45% 75% at 94% 46%, rgba(241, 176, 176, .2), transparent 72%),
    linear-gradient(170deg, #FFF8EF 0%, rgba(255, 252, 248, .7) 55%, transparent 100%);
}
/* Soft Rose — near-white with rose undertones: a rose wash from the top
   right, gently red low on the left. */
.rsd-hero-block--bg-soft-rose {
  --rsd-hero-bg:
    radial-gradient(62% 90% at 100% 0%, color-mix(in srgb, var(--rsd-red) 10%, transparent), transparent 66%),
    radial-gradient(40% 70% at 0% 100%, color-mix(in srgb, var(--rsd-red) 5%, transparent), transparent 70%),
    linear-gradient(160deg, var(--rsd-white) 0%, color-mix(in srgb, color-mix(in srgb, var(--rsd-red) 4%, var(--rsd-white)) 75%, transparent) 60%, transparent 100%);
}
/* Block editor: no .rsd-main there — keep the full-width layer from adding
   a horizontal scrollbar to the canvas (only when such a hero is on it). */
.editor-styles-wrapper:has(.rsd-hero-block:is(.rsd-hero-block--bg-soft-red, .rsd-hero-block--bg-soft-warm, .rsd-hero-block--bg-soft-rose)) { overflow-x: clip; }

/* ---------------------------------------------------------- RedSprout Hero — visual size (laptop / desktop)
   Beside the text (1024px and up) the visual column grows a little: the
   7 : 5 split becomes 13 : 10 on laptops (≈ +4% visual width — the text
   column there is already tight, so it gives up only ≈ 3%) and 9 : 7 with
   the standard gap from 1280px (≈ +7%; the text gives up ≈ 2%). A larger
   split (6 : 5, ≈ +9%) was measured and rejected: it cost a typical H1 an
   extra line and pushed the CTAs ≈ 70px down. The HTML/CSS visuals that were capped at the old column
   width (Digital Growth 29rem, the system visuals and Intelligence System
   31rem) may now fill the wider column (33rem cap); images keep their
   square crop (focal point), forms simply have more room. Tablet and phone
   layouts are untouched (the visual sits under the text there). */
@media (min-width: 1024px) {
  .rsd-hero-block--has-visual { grid-template-columns: minmax(0, 13fr) minmax(0, 10fr); }
  .rsd-hero-block--has-visual :is(.rsd-gd, .rsd-is, .rsd-hv--open) { max-width: 33rem; }
}
@media (min-width: 1280px) {
  .rsd-hero-block--has-visual { grid-template-columns: minmax(0, 9fr) minmax(0, 7fr); gap: var(--rsd-gap); }
}
/* ---------------------------------------------------------- RedSprout Hero — Success Stories visual
   rsd_hero_success_stories() (inc/hero-success-stories.php): floating story
   cards in two columns — left the highlighted case study (white, a red top
   rule, the "Read case study" link) over a dark "Client stories" card;
   right, set lower, the result (brand red, its value large) over a second
   story (warm paper). Different widths (7 : 5), heights and surfaces; no
   card overlaps another. Sized by its own container: under 28rem only the
   highlight and the result remain, stacked. Excerpts are clamped to a few
   lines (the full text stays in the markup).
   Motion — page only (never in the editor), only under no-preference: each
   card fades up once, 90ms apart, and the highlight then settles forward
   (a slightly deeper shadow). Nothing moves after that. */
.rsd-hero-collage--stories { --rsd-hss-shadow: 0 18px 40px -22px rgba(26, 26, 28, .28), 0 2px 6px rgba(26, 26, 28, .05); }
.rsd-hss { container: rsd-hss / inline-size; position: relative; width: 100%; max-width: 33rem; margin-inline: auto; }
.rsd-hss__cols { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: .85rem; align-items: start; }
.rsd-hss__cols:has(> :only-child) { grid-template-columns: minmax(0, 1fr); }
.rsd-hss__col { display: flex; flex-direction: column; gap: .85rem; min-width: 0; }
.rsd-hss__col--offset { padding-top: 2.25rem; }
.rsd-hss__card {
  position: relative; display: flex; flex-direction: column; gap: .7rem; min-width: 0; padding: 1.15rem 1.2rem;
  color: var(--rsd-charcoal); background: var(--rsd-white); border: 1px solid var(--rsd-line); border-radius: 12px; box-shadow: var(--rsd-hss-shadow);
}
.rsd-hss__card--hl { padding: 1.35rem 1.4rem 1.25rem; }
.rsd-hss__card--hl::before { content: ""; position: absolute; top: -1px; left: 1.4rem; width: 2.25rem; height: 3px; background: var(--rsd-red); }
.rsd-hss__card--paper { background: var(--rsd-paper); }
.rsd-hss__card--metric { color: var(--rsd-white); background: var(--rsd-red); border-color: var(--rsd-red); }
.rsd-hss__card--dark { color: var(--rsd-paper); background: var(--rsd-charcoal); border-color: var(--rsd-charcoal); }
.rsd-hss__kicker {
  display: block; font-family: var(--rsd-mono); font-size: .62rem; line-height: 1.3; letter-spacing: .1em; text-transform: uppercase;
  color: var(--rsd-muted);
}
:is(.rsd-hss__card--metric, .rsd-hss__card--dark) .rsd-hss__kicker { color: inherit; opacity: .78; }
.rsd-hss__brand { display: flex; align-items: center; min-height: 1.6rem; }
.rsd-hss__logo { display: block; width: auto; max-width: 8rem; height: auto; max-height: 1.6rem; object-fit: contain; object-position: left center; }
.rsd-hss__brand--name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .92rem; line-height: 1.25; }
.rsd-hss__excerpt {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; margin: 0;
  font-size: .84rem; line-height: 1.5;
}
.rsd-hss__excerpt--hl { -webkit-line-clamp: 4; font-family: var(--rsd-display); font-weight: var(--rsd-weight-medium); font-size: 1.02rem; line-height: 1.42; letter-spacing: -.005em; }
.rsd-hss__by { display: flex; align-items: center; gap: .55rem; min-width: 0; }
.rsd-hss__photo { flex: none; width: 2rem; height: 2rem; border-radius: 50%; object-fit: cover; background: var(--rsd-line); }
.rsd-hss__who { display: flex; flex-direction: column; min-width: 0; }
.rsd-hss__name { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .82rem; line-height: 1.3; }
.rsd-hss__role { font-size: .74rem; line-height: 1.35; color: var(--rsd-muted); }
.rsd-hss__cta {
  display: inline-flex; align-items: center; gap: .35rem; align-self: flex-start; min-height: 2.75rem; margin: -.35rem 0 -.6rem;
  font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .86rem; color: var(--rsd-red); text-decoration: none;
}
.rsd-hss__cta:hover { text-decoration: underline; text-underline-offset: .2em; }
.rsd-hss__cta:focus-visible { outline: 2px solid var(--rsd-red); outline-offset: 2px; border-radius: 2px; }
.rsd-hss__cta--off { min-height: 0; margin: 0; color: var(--rsd-muted); }
.rsd-hss__metric { display: flex; flex-direction: column; gap: .3rem; margin: 0; }
.rsd-hss__metric-value { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: clamp(2rem, 9cqi, 2.75rem); line-height: 1; letter-spacing: -.025em; overflow-wrap: anywhere; }
.rsd-hss__metric-label { font-size: .8rem; line-height: 1.35; }
.rsd-hss__metric-by { font-family: var(--rsd-display); font-weight: var(--rsd-weight-semibold); font-size: .78rem; opacity: .85; }
.rsd-hss__line { margin: 0; font-family: var(--rsd-display); font-weight: var(--rsd-weight-medium); font-size: .92rem; line-height: 1.35; }
.rsd-hss__marks { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.rsd-hss__mark { display: inline-flex; align-items: center; min-height: 1.9rem; padding: .3rem .55rem; background: var(--rsd-white); border-radius: 6px; color: var(--rsd-charcoal); }
.rsd-hss__mark .rsd-hss__logo { max-width: 5.5rem; max-height: 1.1rem; }
.rsd-hss__mark.rsd-hss__brand--name { font-size: .74rem; }
/* Illustrative (no published stories): shapes, a visible tag. */
.rsd-hss__tag {
  position: absolute; top: -.6rem; right: 0; z-index: 1; padding: .1rem .45rem; font-family: var(--rsd-mono); font-size: .6rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--rsd-muted); background: var(--rsd-white); border: 1px dashed var(--rsd-line); border-radius: 4px;
}
.rsd-hss__sk { display: block; width: var(--w, 100%); height: 7px; border-radius: 4px; background: var(--rsd-line); }
.rsd-hss__card--hl .rsd-hss__sk { height: 9px; }
:is(.rsd-hss__card--metric, .rsd-hss__card--dark) .rsd-hss__sk { background: rgba(247, 246, 244, .3); }
.rsd-hss--empty .rsd-hss__card { min-height: 6.5rem; }
.rsd-hss--empty .rsd-hss__card--hl { min-height: 11rem; }
/* Narrow: the highlight and the result. */
@container rsd-hss (max-width: 28rem) {
  .rsd-hss__cols { grid-template-columns: minmax(0, 1fr); }
  .rsd-hss__col { display: contents; }
  .rsd-hss__col--offset { padding-top: 0; }
  .rsd-hss__card--dark, .rsd-hss__card--paper { display: none; }
  .rsd-hss__card--metric { order: 2; }
}
@media (max-width: 1023px) {
  .rsd-hero-block--align-left .rsd-hss { margin-inline: 0; }
}
@media (prefers-reduced-motion: no-preference) {
  body:not(.editor-styles-wrapper) .rsd-hss__card { animation: rsd-hss-in .7s var(--rsd-ease-out) calc(.15s + var(--k, 0) * .09s) both; }
  body:not(.editor-styles-wrapper) .rsd-hss__card--hl { animation: rsd-hss-in .7s var(--rsd-ease-out) .15s both, rsd-hss-lift .6s var(--rsd-ease-out) .75s both; }
}
@keyframes rsd-hss-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes rsd-hss-lift { from { box-shadow: var(--rsd-hss-shadow); } to { box-shadow: 0 26px 52px -24px rgba(26, 26, 28, .34), 0 3px 8px rgba(26, 26, 28, .06); } }
