/* ============================================================
   SATOOMS CONSULTS CANADA INC. — Approved Homepage Visual System
   ============================================================
   Reconstruction of the approved Stitch homepage export
   (stitch.ui/hompage.ui/). Plain CSS3 — no framework, no build step.

   SCOPE:
   This file is the canonical site shell: every page links it first, and
   `stitch-pages.css` (page bodies) links after it. It deliberately does not
   import tokens.css / base.css / site-stitch.css so that no legacy rule can
   leak into the approved visual system. The `.sx-` class namespace keeps
   every rule specific to that system.

   REUSE:
   The top contact bar (`.sx-topbar`), main navbar (`.sx-nav`) and the global
   alignment tokens (section 1b) are the canonical site-wide shell shared by
   all 16 routes.

   FONT NOTE:
   Lato is loaded at 300/400/700/900 (+ italic 400/700) exactly as in the
   approved reference. Weights 500 and 600 are intentionally NOT loaded:
   the approved reference relies on the browser resolving 500 -> 400 and
   600 -> 700, and loading real 500/600 faces would change metric widths
   and drift the layout away from the approved visual.
   ============================================================ */

/* ------------------------------------------------------------
   1. TOKENS (approved homepage palette / type scale)
   ------------------------------------------------------------ */
:root {
  --sx-navy: #0b2341;
  --sx-navy-dark: #081c33;
  --sx-navy-deep: #051320;
  --sx-navy-topbar: #06192d;
  --sx-navy-panel: #071a2c;
  --sx-h1: #082032;
  --sx-nav-ink: #0e2b46;
  --sx-green: #187e46;
  --sx-green-dark: #136738;
  /* 4.40:1 on white was just under the 4.5:1 AA threshold; deepened to
     4.82:1 so the hero tagline accent and the president's name pass. */
  --sx-green-text: #147b45;
  /* The approved pale-green surface used by the outline button's hover state;
     also the hover wash behind the homepage Core Services tiles. */
  --sx-green-wash: #ecfdf5;
  --sx-surface-pale: #f8fafc;
  --sx-border-pale: #f1f5f9;
  --sx-border: #e2e8f0;

  --sx-text: #1e293b;
  --sx-text-body: #4a5568;
  --sx-text-muted: #475569;

  --sx-slate-200: #e2e8f0;
  --sx-slate-300: #cbd5e1;
  --sx-slate-400: #94a3b8;
  --sx-slate-500: #64748b;
  --sx-slate-700: #334155;
  --sx-slate-800: #1e293b;
  --sx-slate-900: #0f172a;

  /* The container/gutter pair is inferred from the approved geometry at the
     end of this block — see section 1b. */
  --sx-container: var(--site-container);
  --sx-gutter: var(--site-gutter);
  --sx-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --sx-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}

/* ------------------------------------------------------------
   1b. GLOBAL ALIGNMENT SYSTEM  (site-wide, shared by every route)
   ------------------------------------------------------------
   Two approved pages define the site grid. Both values below are MEASURED
   from those pages in the browser at the 1280px desktop reference width,
   never estimated:

   HORIZONTAL MASTER — Meet the Founder
     The founder hero copy starts 24px from the viewport edge at 1280px, from
     a 1280px container with a 24px inline gutter. That line is the master
     desktop content-start line.

   VERTICAL MASTER — Homepage
     `.sx-hero__content` is padded 40px below the header at >=1024px (32px
     below it on smaller screens), so the first meaningful hero content of
     every page starts on that same line.

   Anything that needs the site grid must consume these tokens instead of
   declaring its own container width or gutter.
   ------------------------------------------------------------ */
:root {
  --site-container: 1280px;
  --site-gutter: 20px;
  --site-hero-offset: 32px;
  /* Height of the sticky navbar — used to clear it when a same-page anchor
     (or the skip link) is chosen. */
  --site-nav-height: 82px;

  /* ----------------------------------------------------------
     Header control scale — ONE fluid proportional system
     ----------------------------------------------------------
     The logo, the Let's Connect CTA and the header row gap all scale from
     the same variable instead of carrying a hand-written size per device
     width, so no width can ever leave the CTA looking larger than the logo.

     The MEASURED constraint is the 320px row: 280px of content width has to
     hold the logo, the CTA and the 44px hamburger. The logo therefore floors
     at 42px and reaches its approved 56px desktop size at ~487px. The CTA
     min-height floors at 34px (above the 24px WCAG 2.2 target minimum) and
     tracks the logo at 0.72x, which is exactly its current 40.25px at the
     56px desktop logo. */
  --header-logo-h: clamp(42px, 11.5vw, 56px);
  --header-cta-h: clamp(34px, calc(var(--header-logo-h) * 0.72), 41px);
  --header-cta-pad-x: clamp(12px, 4vw, 20px);
  --header-cta-font: clamp(12.5px, 3.9vw, 13.5px);
  --header-gap: clamp(9px, 2.4vw, 16px);

  /* Distance from the bottom of the desktop link row to the bottom of the
     82px navbar. Used as the Services disclosure menu's transparent bridge,
     so the pointer can travel from the trigger down into the panel without
     crossing a dead gap, and so the panel's visible surface begins on the
     navbar's own bottom edge. MEASURED, not derived: re-measure if the
     navbar height or the link row's line-height changes. */
  --sx-nav-menu-bridge: 28.5px;

  /* Invisible artwork insets inside assets/images/brand/satooms-consults-logo.png
     (512x171 canvas; visible artwork occupies x 50-456, y 22-141). Expressed as
     a fraction of the rendered height so the optical correction scales with it. */
  --logo-art-inset-left: 0.2924;

  /* ONE motion language for the whole site: the nav indicator slide, the
     route-content entrance, the mobile menu, the hamburger transform, the
     page-entry sequence and the below-the-fold reveals all draw on these. */
  --motion-fast: 180ms;
  --motion-base: 240ms;
  --motion-slide: 260ms;
  --motion-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Mobile menu. Deliberately much slower than the shell chrome so the panel
     can actually be SEEN unfolding (measured open 760ms / close 520ms, inside
     the requested 650-850ms / 450-600ms ranges). The hamburger itself moves a
     little faster than the panel so the icon leads and the panel follows. */
  --motion-menu-open: 760ms;
  --motion-menu-close: 520ms;
  --motion-burger: 380ms;

  /* Page-entry — the hero resolving when a route becomes active. */
  --enter-duration: 480ms;
  --enter-stagger: 55ms;
  --enter-lead: 60ms;

  /* Below-the-fold scroll reveal. */
  --reveal-duration: 620ms;
  --reveal-distance: 28px;
  --reveal-stagger: 70ms;
  --reveal-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Contained content photographs. The frame never moves: the photograph
     settles INSIDE its frame as the visitor reaches it, which reads as a
     camera settling rather than as a card animating. The settle is slower than
     any other motion on the site on purpose — it is the least urgent effect.
     Hover is quicker and reverses the direction (settle zooms OUT, hover zooms
     IN) so the two can never be mistaken for each other. */
  --media-settle-from: 1.04;
  --media-settle-duration: 820ms;
  --media-settle-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --media-hover-to: 1.03;
  --media-hover-duration: 480ms;
}

@media (min-width: 640px) {
  :root {
    --site-gutter: 24px;
  }
}

@media (min-width: 1024px) {
  :root {
    --site-hero-offset: 40px;
  }
}

/* Same-page anchors scroll smoothly, but the sticky header is cleared by
   `scroll-margin-top` on the targets themselves. */
html {
  scroll-behavior: smooth;
}

/* EVERY element that can be the destination of a same-page anchor clears the
   sticky bar — the skip link's <main> and section anchors such as
   `#practice-areas` alike. `scroll-margin-top` on an un-targeted element has
   no effect, so this stays a single generic rule instead of a list of ids that
   would silently fall behind the header as pages change. */
.sx-page [id] {
  scroll-margin-top: var(--site-nav-height);
}

/* ------------------------------------------------------------
   2. PAGE BASE
   ------------------------------------------------------------ */
.sx-page {
  margin: 0;
  background-color: #ffffff;
  color: var(--sx-text);
  font-family: 'Lato', sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* `:where()` keeps the reset at zero intrinsic specificity so that no
   component rule below can be silently out-specified by it. */
.sx-page :where(h1, h2, h3, h4, h5, h6, p, ul, ol, li, form, figure) {
  margin: 0;
  padding: 0;
}

.sx-page :where(ul, ol) {
  list-style: none;
}

.sx-page :where(img) {
  display: block;
  max-width: 100%;
}

.sx-page :where(svg) {
  display: block;
}

.sx-page :where(a) {
  color: inherit;
  text-decoration: none;
}

.sx-page :where(button) {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

.sx-page :where(input) {
  font: inherit;
}

.sx-page ::selection {
  background-color: var(--sx-green);
  color: #ffffff;
}

.sx-page :focus-visible {
  outline: 2px solid var(--sx-green);
  outline-offset: 2px;
}

.sx-container {
  width: 100%;
  max-width: var(--sx-container);
  margin-inline: auto;
  padding-inline: var(--sx-gutter);
}

/* Screen-reader-only utility (status messages, skip target labels) */
.sx-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------
   3. SKIP LINK
   ------------------------------------------------------------ */
.sx-skip-link {
  position: absolute;
  top: -100px;
  left: 8px;
  z-index: 300;
  padding: 12px 18px;
  background: var(--sx-green);
  color: #ffffff;
  font-size: 14px;
  font-weight: 700;
  border-radius: 4px;
  transition: top 150ms ease;
}

.sx-skip-link:focus {
  top: 8px;
}

/* ------------------------------------------------------------
   4. R1 — TOP CONTACT BAR
   ------------------------------------------------------------ */
.sx-topbar {
  background-color: var(--sx-navy-topbar);
  color: rgb(255 255 255 / 0.9);
  font-size: 12.5px;
  line-height: 1.5;
  padding-block: 6px;
  padding-inline: var(--sx-gutter);
  border-bottom: 1px solid #0f2945;
}

.sx-topbar__inner {
  width: 100%;
  max-width: var(--sx-container);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  row-gap: 4px;
}

.sx-topbar__group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 28px;
  row-gap: 4px;
}

.sx-topbar__item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.sx-topbar__item svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.sx-topbar__item--location svg {
  color: var(--sx-green-text);
  fill: currentColor;
}

.sx-topbar__item--phone svg,
.sx-topbar__item--email svg {
  color: var(--sx-slate-300);
  fill: none;
}

.sx-topbar__label--tight {
  letter-spacing: -0.025em;
}

/* tel:/mailto: links keep the approved colour. The hover affordance uses
   text-decoration so it cannot shift the bar's baseline geometry. */
.sx-topbar__link:hover span,
.sx-topbar__link:focus-visible span {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.sx-topbar__social {
  color: rgb(255 255 255 / 0.9);
  transition: color 150ms ease;
}

.sx-topbar__social svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.sx-topbar__social:hover {
  color: #ffffff;
}

/* The bar's social area groups the icon links so the inner row's
   `justify-content: space-between` keeps them anchored to the right edge.
   Without a single group child, each icon would become its own flex item and
   the pair would be spread across the free space. The 28px gap matches the
   contact group's column rhythm. */
.sx-topbar__socials {
  display: flex;
  align-items: center;
  gap: 28px;
}

/* The LinkedIn destinations (top bar icon and footer icon) are now real links,
   so the only `[data-link-pending]` subjects left are genuinely pending ones:
   the Instagram icon and the Privacy Policy / Terms of Use footer items. Those
   are `<span>`s, not links, so they must not advertise clickability — the rule
   below is scoped to elements without an `href` so it can never soften a real
   link's cursor. */
[data-link-pending]:not([href]) {
  cursor: default;
}

/* Small devices — swipeable contact strip.
   The approved inline bar needs 657px of content width, so it starts wrapping
   below 768px (measured: two rows at 640px, three rows at 320px). Wrapping
   already reads as broken, so below the tablet breakpoint the whole bar becomes
   one horizontal row the visitor can swipe. Nothing is hidden and nothing is
   shrunk: every approved contact item keeps its full size and tap target.

   `display: contents` promotes the four contact items out of their group so
   the approved social icon joins the same single row, exactly as it does on
   desktop. The scroller carries the gutter as inline padding, so the first
   item still starts on the shared content line while the remaining width of
   the next item stays visible at the right edge as the swipe affordance. */
@media (max-width: 767.98px) {
  .sx-topbar {
    padding-inline: 0;
  }

  .sx-topbar__inner {
    flex-wrap: nowrap;
    row-gap: 0;
    column-gap: 20px;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--site-gutter);
    padding-inline: var(--site-gutter);
    -webkit-overflow-scrolling: touch;
    /* The strip is a deliberate horizontal scroller: its scrollbar is
       suppressed visually, but the content stays in the tab order and
       keyboard focus scrolls it into view via `scroll-padding-inline`. */
    scrollbar-width: none;
  }

  .sx-topbar__inner::-webkit-scrollbar {
    display: none;
  }

  .sx-topbar__group,
  .sx-topbar__socials {
    display: contents;
  }

  .sx-topbar__item,
  .sx-topbar__social {
    flex: 0 0 auto;
    scroll-snap-align: start;
  }
}

/* ------------------------------------------------------------
   5. R2 — MAIN NAVBAR
   ------------------------------------------------------------ */
.sx-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  min-height: 82px;
  padding-block: 10px;
  background-color: #ffffff;
  border-bottom: 1px solid var(--sx-border-pale);
}

.sx-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--header-gap);
}

.sx-nav__brand {
  display: flex;
  align-items: center;
  min-width: 0;
  user-select: none;
}

/* The logo asset carries 16.4px of fully transparent padding on its left at
   the 56px rendered height (50 of 512 asset pixels), which pushed the visible
   wordmark 16px to the right of the shared content line while the header box
   itself looked aligned. Pulling the image back by exactly that inset puts the
   VISIBLE artwork on the gutter, scaled with the logo so it holds at every
   width. The artwork's matching vertical inset is 7.2px top / 9.5px bottom — a
   1.15px optical difference at the 56px size, so no vertical nudge is applied. */
.sx-nav__logo {
  height: var(--header-logo-h);
  width: auto;
  max-width: none;
  margin-left: calc(var(--header-logo-h) * var(--logo-art-inset-left) * -1);
  object-fit: contain;
}

.sx-nav__links {
  display: none;
}

/* Positioning context for the shared active indicator. */
.sx-nav__links {
  position: relative;
}

/* Every text item carries the same 4px underline clearance so that the shared
   active indicator can sit 4px under any of them, and so switching the
   current page never reflows the row (a weight change alone used to move the
   neighbouring items). */
.sx-nav__link {
  color: var(--sx-nav-ink);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
  padding-bottom: 4px;
  transition: color 150ms ease;
}

.sx-nav__link:hover {
  color: var(--sx-green);
}

.sx-nav__link--current {
  font-weight: 600;
}

/* ONE shared active indicator instead of a per-item `::after` underline. The
   script positions it under the current item on load and animates it between
   items when a visitor navigates, so the indicator slides rather than
   blinking off in one place and on in another. */
.sx-nav__indicator {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2.5px;
  background-color: var(--sx-green);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--motion-slide) var(--motion-ease),
    width var(--motion-slide) var(--motion-ease), opacity 120ms ease;
}

.sx-nav__indicator.is-ready {
  opacity: 1;
}

/* Without JavaScript the indicator script cannot position anything, so the
   current item falls back to a static underline. The `aria-current="page"`
   attribute already carries the state for assistive technology. */
.no-js .sx-nav__link--current {
  position: relative;
}

.no-js .sx-nav__link--current::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2.5px;
  background-color: var(--sx-green);
}

.sx-nav__group {
  display: flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}

.sx-nav__group svg {
  width: 14px;
  height: 14px;
  stroke: currentColor;
  fill: none;
}

/* Nav label whose destination is not part of the approved site structure
   yet. Rendered as static text so the header never fakes a working link. */
.sx-nav__label {
  color: var(--sx-nav-ink);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}

.sx-nav__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-height: var(--header-cta-h);
  padding: 0 var(--header-cta-pad-x);
  background-color: var(--sx-green);
  color: #ffffff;
  font-size: var(--header-cta-font);
  font-weight: 600;
  line-height: 1.5;
  border-radius: 5px;
  box-shadow: var(--sx-shadow-sm);
  transition: background-color 150ms ease;
}

.sx-nav__cta:hover {
  background-color: var(--sx-green-dark);
}

/* The contact / consultation page has no primary-nav text item: the green
   Let's Connect CTA is the current destination. Restrained state only
   (same button geometry, darker green), so the header never grows a
   second, unofficial active underline. */
.sx-nav__cta[aria-current='page'] {
  background-color: var(--sx-green-dark);
}

/* Below the desktop breakpoint the primary links collapse into the disclosure
   panel, leaving the brand, the Let's Connect CTA and the hamburger as the only
   in-flow items. `margin-left: auto` pins the CTA against the hamburger so the
   two read as one compact right-side control group anchored to the shared right
   gutter, instead of the CTA floating into the middle of the header. The row
   gap between them comes from `--header-gap`, which tightens on narrow phones
   before either control has to give up any of its tap target. */
@media (max-width: 1023.98px) {
  .sx-nav__cta {
    margin-left: auto;
  }

  .sx-nav__toggle {
    flex: none;
  }
}

.sx-nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--sx-border);
  border-radius: 5px;
  color: var(--sx-nav-ink);
}

.sx-nav__toggle-bars {
  position: relative;
  display: block;
  width: 18px;
  height: 2px;
  background-color: currentColor;
  border-radius: 2px;
  transition: background-color var(--motion-fast) var(--motion-ease);
}

.sx-nav__toggle-bars::before,
.sx-nav__toggle-bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 18px;
  height: 2px;
  background-color: currentColor;
  border-radius: 2px;
  /* The bars travel by transform only, so the open/close state never
     re-triggers layout. Slower than the shell chrome (`--motion-burger`) so the
     icon visibly leads the panel instead of snapping while the panel is still
     unfolding. */
  transition: transform var(--motion-burger) var(--motion-ease);
}

.sx-nav__toggle-bars::before {
  top: -6px;
}

.sx-nav__toggle-bars::after {
  top: 6px;
}

/* Open state: the middle bar fades out while the two outer bars rotate into a
   close (x) mark. Same restrained motion language as the rest of the shell —
   a transform and an opacity change, no icon swap and no blink. */
.sx-nav__toggle[aria-expanded='true'] .sx-nav__toggle-bars {
  background-color: transparent;
}

.sx-nav__toggle[aria-expanded='true'] .sx-nav__toggle-bars::before {
  transform: translateY(6px) rotate(45deg);
}

.sx-nav__toggle[aria-expanded='true'] .sx-nav__toggle-bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

/* Mobile / tablet navigation panel — no reference exists below 1024px.
   Built from the same tokens so the header stays consistent and every
   primary destination remains reachable. */
.sx-nav__mobile {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background-color: #ffffff;
  border-bottom: 1px solid var(--sx-border);
  box-shadow: var(--sx-shadow-md);
  padding: 8px var(--sx-gutter) 20px;
}

/* The panel is an overlay (position: absolute), so it can be at its full height
   and clipped while the page behind it never moves. `clip-path` reveals it from
   the top down, which is a genuine unfold with no distortion — unlike a scaleY
   transform, which would squash the links inside. The transient `is-opening` /
   `is-closing` classes are removed when the animation ends, so the steady open
   state carries no clip and no animation. */
.sx-nav__mobile.is-open {
  display: block;
}

.sx-nav__mobile.is-opening {
  animation: sx-menu-open var(--motion-menu-open) var(--motion-ease) both;
}

.sx-nav__mobile.is-closing {
  animation: sx-menu-close var(--motion-menu-close) var(--motion-ease) both;
  pointer-events: none;
}

@keyframes sx-menu-open {
  from {
    clip-path: inset(0 0 100% 0);
    opacity: 0.35;
  }

  to {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }
}

@keyframes sx-menu-close {
  from {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }

  to {
    clip-path: inset(0 0 100% 0);
    opacity: 0;
  }
}

/* The panel is the primary motion; the items only settle a little as it opens,
   spread across the open duration so the unfold stays the thing you notice. */
.sx-nav__mobile.is-opening .sx-nav__mobile-list > *,
.sx-nav__mobile.is-opening .sx-nav__mobile-cta {
  animation: sx-menu-item var(--motion-base) var(--motion-ease) both;
}

@keyframes sx-menu-item {
  from {
    opacity: 0;
    transform: translate3d(0, -6px, 0);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(1) {
  animation-delay: 130ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(2) {
  animation-delay: 190ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(3) {
  animation-delay: 250ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(4) {
  animation-delay: 310ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(5) {
  animation-delay: 370ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-list > *:nth-child(6) {
  animation-delay: 430ms;
}

.sx-nav__mobile.is-opening .sx-nav__mobile-cta {
  animation-delay: 490ms;
}

.sx-nav__mobile-list {
  display: flex;
  flex-direction: column;
}

.sx-nav__mobile-link {
  display: block;
  padding: 13px 0;
  color: var(--sx-nav-ink);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.4;
  border-bottom: 1px solid var(--sx-border-pale);
}

.sx-nav__mobile-link[aria-current='page'] {
  color: var(--sx-green);
  font-weight: 600;
}

/* Mobile / tablet disclosure carries the same Let's Connect destination as
   the desktop CTA. Not part of the approved desktop reference — added so the
   consultation page stays reachable at small widths. */
.sx-nav__mobile-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 16px 0 4px;
  padding: 13px 20px;
  background-color: var(--sx-green);
  color: #ffffff;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  border-radius: 5px;
}

.sx-nav__mobile-cta[aria-current='page'] {
  background-color: var(--sx-green-dark);
}

.sx-nav__mobile-label {
  display: block;
  padding: 13px 0;
  color: var(--sx-slate-500);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.4;
  border-bottom: 1px solid var(--sx-border-pale);
}

/* Progressive enhancement: without JavaScript the panel is always shown so
   navigation stays usable. main.js removes `.no-js` when JS is available. */
.no-js .sx-nav__toggle {
  display: none;
}

.no-js .sx-nav__mobile {
  display: block;
  position: static;
  box-shadow: none;
  padding-inline: 0;
}

/* ------------------------------------------------------------
   6. R3 / R4 — HERO
   ------------------------------------------------------------ */
.sx-hero {
  position: relative;
  background-color: #ffffff;
  overflow: hidden;
}

.sx-hero__frame {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 460px;
  overflow: hidden;
}

.sx-hero__photo {
  display: none;
}

.sx-hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 65% center;
}

/* Seamless left fade that blends the full-bleed hero photograph into the
   white surface behind the headline. */
.sx-hero__photo--fade {
  mask-image: linear-gradient(to right, transparent 0%, rgb(0 0 0 / 0.2) 8%, rgb(0 0 0 / 0.7) 22%, rgb(0 0 0 / 1) 40%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgb(0 0 0 / 0.2) 8%, rgb(0 0 0 / 0.7) 22%, rgb(0 0 0 / 1) 40%);
}

.sx-hero__content {
  position: relative;
  z-index: 10;
  /* Canonical first-content offset — the vertical master for the whole site. */
  padding-block: var(--site-hero-offset);
}

.sx-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
}

.sx-hero__copy-col {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.sx-hero__heading {
  margin-bottom: 16px;
  color: var(--sx-h1);
  font-size: 38px;
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.02em;
}

.sx-hero__tagline {
  margin-bottom: 12px;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.025em;
}

.sx-hero__tagline-lead {
  color: var(--sx-h1);
}

.sx-hero__tagline-accent {
  color: var(--sx-green-text);
  font-weight: 600;
}

.sx-hero__body {
  max-width: 32rem;
  margin-bottom: 32px;
  color: var(--sx-text-body);
  font-size: 14.5px;
  font-weight: 400;
  line-height: 1.62;
}

.sx-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

/* Buttons */
.sx-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 28px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
  border-radius: 4px;
  box-shadow: var(--sx-shadow-sm);
  transition: background-color 150ms ease;
}

.sx-btn svg {
  width: 14px;
  height: 14px;
  stroke: currentColor;
  fill: none;
  flex-shrink: 0;
}

.sx-btn--green {
  background-color: var(--sx-green);
  color: #ffffff;
}

.sx-btn--green:hover {
  background-color: var(--sx-green-dark);
}

.sx-btn--outline {
  background-color: #ffffff;
  border: 1.5px solid var(--sx-green);
  color: var(--sx-green);
}

.sx-btn--outline:hover {
  background-color: var(--sx-green-wash);
}

/* Mobile-only hero image (shown below the 1024px breakpoint) */
.sx-hero__photo-inline {
  display: block;
  width: 100%;
  min-height: 340px;
  margin-top: 32px;
  border-radius: 8px;
  overflow: hidden;
}

.sx-hero__photo-inline img {
  width: 100%;
  height: 100%;
  min-height: 340px;
  object-fit: cover;
}

/* Tablet, image already stacked below the copy (640-1023px only). The copy
   column is full-width in this state, but the lede kept its 512px desktop cap,
   so with the photograph out of the row the copy read as a narrow desktop
   column with the right half of the hero left empty. Here only, the lede uses
   ~88% of the column, capped at 40rem so no line runs past a comfortable
   measure at the widest tablet widths.

   Deliberately bounded to this range: at >=1024px the photograph is back in the
   row, the copy column is 6 of 12 columns, and the 512px cap is correct. The
   heading, its line breaks, the type scale, the left alignment, the buttons and
   the photograph are all untouched - this is the wrapper's usable width only. */
@media (min-width: 640px) and (max-width: 1023px) {
  .sx-hero__body {
    max-width: min(40rem, 88%);
  }
}

/* ------------------------------------------------------------
   7. R5 — CORE SERVICES
   ------------------------------------------------------------ */
.sx-services {
  background-color: #ffffff;
  border-top: 1px solid var(--sx-border-pale);
  padding-block: 32px 48px;
}

.sx-services__heading-block {
  margin-bottom: 36px;
  text-align: center;
}

.sx-services__heading {
  color: var(--sx-h1);
  font-size: 24px;
  font-weight: 700;
  line-height: 32px;
  letter-spacing: -0.025em;
}

.sx-services__rule {
  width: 36px;
  height: 3px;
  margin: 8px auto 0;
  background-color: var(--sx-green);
  border-radius: 9999px;
}

/* The catalogue holds nine services. The grid is a complete 3 x 3 from 640px
   upward, and below that it is the approved two columns with the ninth tile
   deliberately centred — never stretched across both columns and never left
   hanging in the left column:
     >=1024px  3 x 3 inside the bordered desktop strip (hairlines between
               neighbouring cells, none on the outer edges)
     640-1023  3 x 3, spaced
     <640      2 x 4 + the ninth centred, at the SAME width as every other tile
     <320      1 x 9 (safety valve below the narrowest supported width; the
               2-column layout is verified to still fit at 320px)
   Measured 320px tile: 128px wide with a 100px text box, against a 93.4px
   longest service word ("Organizational") at 14px/700 Lato. */
.sx-services__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
}

/* The ninth tile keeps its column's width while being centred under the four
   complete rows: `grid-column: 1 / -1` gives it the whole track area and the
   explicit width restores exactly one column, so its padding, text box and
   wrapping stay identical to every other tile. 24px is the grid gap above. */
.sx-services__grid > .sx-service:last-child {
  grid-column: 1 / -1;
  justify-self: center;
  width: calc((100% - 24px) / 2);
}

@media (max-width: 319.98px) {
  .sx-services__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .sx-services__grid > .sx-service:last-child {
    width: auto;
  }
}

.sx-service {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-inline: 14px;
  text-align: center;
}

.sx-service__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  margin-bottom: 14px;
  color: var(--sx-green);
}

.sx-service__icon svg {
  width: 48px;
  height: 48px;
  stroke: currentColor;
  fill: none;
}

.sx-service__title {
  margin-bottom: 8px;
  color: var(--sx-h1);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.375;
}

.sx-service__desc {
  color: var(--sx-text-muted);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.625;
}

.sx-service__link {
  display: contents;
}

.sx-service__link:hover .sx-service__title {
  color: var(--sx-green);
}

/* ---- Click affordance ---------------------------------------------------
   These tiles are already links, but the approved design has no arrow, no
   chevron and no extra CTA, so the WHOLE tile has to carry the affordance
   instead: a soft green wash appears behind it, the service name takes the
   brand green, the icon scales very slightly, and the tile lifts 3px.

   The wash is drawn by an absolutely positioned pseudo-element with a
   NEGATIVE inset, so the visual padding it needs never enters layout — the
   tile's box, its text wrapping and the section height are unchanged. A
   pseudo-element is also unaffected by the containing block a transform
   creates, so the lift cannot re-position it.

   Hover is gated on a hover-capable fine pointer so a touch device can never
   hold a stuck hover state after a tap. Keyboard users are NOT gated: they get
   the identical treatment from `:focus-visible`. */
.sx-service {
  position: relative;
  z-index: 0;
  border-radius: 10px;
  transition: transform var(--motion-base) var(--motion-ease);
}

.sx-service::before {
  content: '';
  position: absolute;
  inset: -10px -8px;
  z-index: -1;
  background-color: var(--sx-green-wash);
  border-radius: 8px;
  opacity: 0;
  transition: opacity var(--motion-base) var(--motion-ease);
}

.sx-service > * {
  transition: transform var(--motion-base) var(--motion-ease);
}

.sx-service__title {
  transition: color var(--motion-fast) var(--motion-ease);
}

.sx-service__icon svg {
  transition: transform var(--motion-base) var(--motion-ease);
}

.sx-service:focus-visible {
  outline: 2px solid var(--sx-green);
  outline-offset: 4px;
  transform: translate3d(0, -3px, 0);
}

.sx-service:focus-visible::before {
  opacity: 1;
}

.sx-service:focus-visible .sx-service__title {
  color: var(--sx-green);
}

.sx-service:focus-visible .sx-service__icon svg {
  transform: scale(1.06);
}

@media (hover: hover) and (pointer: fine) {
  .sx-service:hover {
    transform: translate3d(0, -3px, 0);
  }

  .sx-service:hover::before {
    opacity: 1;
  }

  .sx-service:hover .sx-service__title {
    color: var(--sx-green);
  }

  .sx-service:hover .sx-service__icon svg {
    transform: scale(1.06);
  }
}

/* ------------------------------------------------------------
   8. R6 / R7 / R8 — IMPACT · APPROACH · PRESIDENT
   ------------------------------------------------------------ */
.sx-panels {
  border-top: 1px solid var(--sx-border);
}

.sx-panels__grid {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 490px;
}

.sx-panel {
  padding: 32px;
  border-top: 1px solid var(--sx-border);
}

.sx-panel__heading {
  position: relative;
  display: inline-block;
  margin-bottom: 32px;
  padding-bottom: 8px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: -0.025em;
}

.sx-panel__heading::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 32px;
  height: 2.5px;
  background-color: var(--sx-green);
}

/* R6 — Our Impact */
.sx-panel--impact {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background-color: var(--sx-navy-panel);
  color: #ffffff;
  border-top: 0;
}

.sx-panel--impact .sx-panel__heading {
  color: #ffffff;
}

.sx-impact__list > * + * {
  margin-top: 24px;
}

.sx-impact__item {
  display: flex;
  align-items: center;
}

.sx-impact__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  color: var(--sx-slate-200);
}

.sx-impact__icon svg {
  width: 32px;
  height: 32px;
  stroke: currentColor;
  fill: none;
}

.sx-impact__value {
  color: #ffffff;
  font-size: 29px;
  font-weight: 900;
  line-height: 1.25;
  letter-spacing: -0.025em;
}

.sx-impact__label {
  color: var(--sx-slate-300);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
}

/* R7 — Our Approach */
.sx-panel--approach {
  background-color: var(--sx-surface-pale);
}

.sx-panel--approach .sx-panel__heading {
  color: var(--sx-navy);
}

.sx-approach__list > * + * {
  margin-top: 16px;
}

.sx-approach__step {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

.sx-approach__badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  margin-top: 2px;
  background-color: var(--sx-green);
  color: #ffffff;
  border-radius: 9999px;
  box-shadow: var(--sx-shadow-sm);
}

.sx-approach__badge svg {
  width: 16px;
  height: 16px;
  stroke: currentColor;
  fill: none;
}

.sx-approach__title {
  color: var(--sx-navy);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.375;
}

.sx-approach__desc {
  color: var(--sx-text-muted);
  font-size: 12px;
  line-height: 1.375;
}

/* R8 — Welcome from the President */
.sx-panel--president {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background-color: #ffffff;
}

.sx-panel--president .sx-panel__heading {
  color: var(--sx-navy);
}

.sx-president__row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  margin-bottom: 20px;
}

.sx-president__portrait {
  flex-shrink: 0;
  width: 175px;
  height: 175px;
  border: 2px solid var(--sx-border);
  border-radius: 9999px;
  overflow: hidden;
  box-shadow: var(--sx-shadow-md);
}

.sx-president__portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}

.sx-president__quote {
  color: var(--sx-text-muted);
  font-size: 13px;
  line-height: 1.62;
  text-align: center;
}

.sx-president__quote > * + * {
  margin-top: 12px;
}

.sx-president__signature {
  padding-top: 8px;
}

.sx-president__name {
  color: var(--sx-green-text);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.25;
}

/* No line-height override: the approved reference inherits the quote block's
   1.62 leading, which decides this line's height. */
.sx-president__role {
  margin-top: 2px;
  color: var(--sx-slate-500);
  font-size: 12px;
  font-weight: 500;
}

.sx-president__actions {
  margin-top: 16px;
  text-align: center;
}

.sx-btn--navy {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 20px;
  background-color: var(--sx-navy);
  color: #ffffff;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  border-radius: 5px;
  box-shadow: var(--sx-shadow-sm);
  transition: background-color 150ms ease;
}

.sx-btn--navy svg {
  width: 14px;
  height: 14px;
  stroke: currentColor;
  fill: none;
}

.sx-btn--navy:hover {
  background-color: var(--sx-slate-800);
}

/* ------------------------------------------------------------
   9. R9 — PHOTOGRAPHIC CTA
   ------------------------------------------------------------ */
.sx-cta {
  position: relative;
  overflow: hidden;
  background-color: var(--sx-navy-dark);
  padding: 48px var(--sx-gutter);
}

.sx-cta__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.sx-cta__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: 0.15;
  filter: grayscale(100%);
}

.sx-cta__scrim {
  position: absolute;
  inset: 0;
  background-color: var(--sx-navy-dark);
  opacity: 0.9;
}

.sx-cta__inner {
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: var(--sx-container);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  text-align: center;
}

.sx-cta__lead {
  display: flex;
  align-items: center;
  gap: 20px;
  color: #ffffff;
}

.sx-cta__lead-icon {
  display: none;
  flex-shrink: 0;
  color: #ffffff;
}

.sx-cta__lead-icon svg {
  width: 64px;
  height: 64px;
  stroke: currentColor;
  fill: none;
}

.sx-cta__heading {
  color: #ffffff;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.25;
}

.sx-cta__heading br {
  display: none;
}

.sx-cta__body {
  max-width: 28rem;
  color: var(--sx-slate-300);
  font-size: 13.5px;
  line-height: 1.625;
}

.sx-cta__action {
  flex-shrink: 0;
}

.sx-cta__btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  background-color: var(--sx-green);
  color: #ffffff;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.5;
  border-radius: 5px;
  box-shadow: var(--sx-shadow-sm);
  transition: background-color 150ms ease;
}

.sx-cta__btn svg {
  width: 14px;
  height: 14px;
  stroke: currentColor;
  fill: none;
}

.sx-cta__btn:hover {
  background-color: var(--sx-green-dark);
}

/* ------------------------------------------------------------
   10. R10 / R11 — FOOTER + BOTTOM BAR
   ------------------------------------------------------------ */
.sx-footer {
  background-color: var(--sx-navy-deep);
  color: var(--sx-slate-300);
  border-top: 1px solid var(--sx-slate-800);
  padding-block: 40px 24px;
}

.sx-footer__columns {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  padding-bottom: 48px;
  border-bottom: 1px solid rgb(30 41 59 / 0.8);
}

.sx-footer__col > * + * {
  margin-top: 12px;
}

.sx-footer__col--brand > * + * {
  margin-top: 16px;
}

.sx-footer__logo {
  display: flex;
  align-items: center;
  gap: 12px;
}

.sx-footer__logo img {
  height: 40px;
  width: auto;
  object-fit: contain;
  /* The approved asset is a dark-single-colour mark; inverted for the dark
     footer exactly as in the approved reference. `brightness(0)` flattens every
     opaque pixel to black first, so `invert(1)` paints the whole lockup one flat
     white - which is why the "S+" inside the leaf (white ink on the leaf, the
     only light ink in the file) used to disappear into the leaf it sits on.

     The fix is in the SOURCE, not in the filter: the footer renders
     `satooms-consults-logo-footer.png`, the same approved artwork with that one
     glyph knocked out to transparency. Everything else in the file is
     byte-identical to the navbar artwork, so this filter still paints the mark
     and the wordmark the approved solid white and the knocked-out S+ now shows
     the footer's own background through it - a normal reversed lockup.

     Keeping the filter (rather than inverting lightness) is deliberate: any
     lightness-preserving chain renders the leaf's internal white detail as a
     grey, broken-up wash at this 40px size (measured: 795 px light vs 1827 px
     for this treatment) instead of the approved solid white silhouette.

     Footer-safe asset only. The NAVBAR keeps the original file - there the S+
     must stay white on the light navbar. See assets/images/SOURCES.md. */
  filter: brightness(0) invert(1);
}

.sx-footer__tagline {
  color: var(--sx-slate-400);
  font-size: 12.5px;
  line-height: 1.625;
}

.sx-footer__social {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 4px;
}

.sx-footer__social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background-color: var(--sx-slate-900);
  border: 1px solid var(--sx-slate-700);
  border-radius: 9999px;
  color: var(--sx-slate-300);
  transition: border-color 150ms ease, color 150ms ease;
}

.sx-footer__social-link svg {
  width: 12px;
  height: 12px;
  stroke: currentColor;
  fill: none;
}

.sx-footer__social-link svg[data-fill] {
  fill: currentColor;
  stroke: none;
}

.sx-footer__social-link:hover {
  border-color: var(--sx-green);
  color: #ffffff;
}

.sx-footer__heading {
  position: relative;
  display: inline-block;
  padding-bottom: 4px;
  color: #ffffff;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: -0.025em;
}

.sx-footer__heading::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 24px;
  height: 2px;
  background-color: var(--sx-green);
}

.sx-footer__list {
  color: var(--sx-slate-400);
  font-size: 13px;
  line-height: 1.5;
}

.sx-footer__list > * + * {
  margin-top: 8px;
}

.sx-footer__list--contact > * + * {
  margin-top: 10px;
}

.sx-footer__list a {
  transition: color 150ms ease;
}

.sx-footer__list a:hover {
  color: #ffffff;
}

.sx-footer__contact-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sx-footer__contact-item svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--sx-slate-400);
  stroke: currentColor;
  fill: none;
}

.sx-footer__contact-item--location svg {
  color: var(--sx-green);
  fill: currentColor;
  stroke: none;
}

/* The WhatsApp mark is a solid glyph, so it takes the fill treatment while
   keeping the same size and colour as the phone/email icons beside it. */
.sx-footer__contact-item--whatsapp svg {
  fill: currentColor;
  stroke: none;
}

.sx-footer__newsletter-text {
  color: var(--sx-slate-400);
  font-size: 12.5px;
  line-height: 1.375;
}

.sx-footer__form {
  padding-top: 4px;
}

/* The label is visually hidden and the honeypot is positioned off-screen rather
   than removed, so automated form fillers still find it. The 8px stack rhythm
   is put on the input itself rather than on `* + *`, because that selector
   would also count those nodes and push the form 8px taller than the target. */
.sx-footer__input {
  margin-bottom: 8px;
}

.sx-footer__input {
  display: block;
  width: 100%;
  padding: 10px 12px;
  background-color: #ffffff;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--sx-slate-800);
  font-size: 12px;
  line-height: 16px;
}

.sx-footer__input::placeholder {
  color: var(--sx-slate-400);
}

.sx-footer__input:focus {
  outline: none;
  box-shadow: 0 0 0 1px var(--sx-green);
  border-color: var(--sx-green);
}

.sx-footer__submit {
  display: block;
  width: 100%;
  padding: 10px 0;
  background-color: var(--sx-green);
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
  border-radius: 4px;
  transition: background-color 150ms ease;
}

.sx-footer__submit:hover {
  background-color: var(--sx-green-dark);
}

.sx-footer__submit[disabled] {
  cursor: progress;
  opacity: 0.75;
}

/* Reports the real outcome of the updates-interest submission. Empty until
   there is something to report, so it never disturbs the resting layout. */
.sx-footer__status {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.4;
  font-weight: 600;
}

.sx-footer__status[data-state='pending'] { color: var(--sx-slate-300); }
.sx-footer__status[data-state='success'] { color: #34d399; }
.sx-footer__status[data-state='error'] { color: #fca5a5; }
.sx-footer__status:empty { display: none; }

/* Honeypot: off-screen rather than display:none, so form-filling bots still
   see it while people and assistive technology never encounter it. */
.sx-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.sx-footer__bottom {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-top: 24px;
  color: var(--sx-slate-400);
  font-size: 11.5px;
  line-height: 1.5;
}

.sx-footer__legal {
  display: flex;
  align-items: center;
  gap: 16px;
}

.sx-footer__legal a {
  transition: color 150ms ease;
}

.sx-footer__legal a:hover {
  color: var(--sx-slate-200);
}

.sx-footer__legal-sep {
  color: var(--sx-text-muted);
}

/* ------------------------------------------------------------
   11. RESPONSIVE — sm (640px)
   ------------------------------------------------------------ */
@media (min-width: 640px) {
  .sx-hero__heading {
    font-size: 44px;
  }

  /* From here up the catalogue is always a 3 x 3, so the ninth tile returns to
     an ordinary grid cell. */
  .sx-services__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .sx-services__grid > .sx-service:last-child {
    grid-column: auto;
    justify-self: stretch;
    width: auto;
  }

  .sx-panel {
    padding: 40px;
  }

  .sx-president__row {
    flex-direction: row;
    align-items: flex-start;
  }

  .sx-president__quote {
    text-align: left;
  }

  .sx-president__actions {
    text-align: left;
  }

  .sx-cta__lead-icon {
    display: flex;
  }

  .sx-cta__heading {
    font-size: 28px;
  }

  .sx-cta__heading br {
    display: inline;
  }

  .sx-footer__bottom {
    flex-direction: row;
  }
}

/* ------------------------------------------------------------
   12. RESPONSIVE — md (768px)
   ------------------------------------------------------------ */
@media (min-width: 768px) {
  .sx-cta__inner {
    flex-direction: row;
    text-align: left;
  }

  .sx-cta__lead {
    text-align: left;
  }

  .sx-cta__body {
    text-align: left;
  }

  .sx-footer__columns {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------
   13. RESPONSIVE — lg (1024px) — approved desktop reference
   ------------------------------------------------------------ */
@media (min-width: 1024px) {
  .sx-hero__frame {
    min-height: 490px;
  }

  .sx-hero__content {
    padding-block: var(--site-hero-offset);
  }

  .sx-hero__grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
  }

  .sx-hero__copy-col {
    grid-column: span 6 / span 6;
    padding-right: 24px;
  }

  .sx-hero__heading {
    font-size: 49px;
  }

  .sx-hero__photo {
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    z-index: 0;
    width: 62%;
    height: 100%;
  }

  .sx-hero__photo-inline {
    display: none;
  }

  .sx-services__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
  }

  /* The approved desktop strip draws its separators on the tiles themselves.
     With a 3 x 3 shape the vertical hairline belongs BETWEEN columns and the
     horizontal one BETWEEN rows — never on the outer edges — so the block
     still reads as one divided strip rather than nine boxed cards. */
  .sx-services__grid > *:not(:nth-child(3n)) {
    border-right: 1px solid var(--sx-border);
  }

  .sx-services__grid > *:nth-child(-n + 6) {
    border-bottom: 1px solid var(--sx-border);
  }

  /* A three-row strip needs breathing room around each cell's content, and
     centring it keeps the cells visually equal when their descriptions
     differ in length. The single approved row did not need either. */
  .sx-service {
    justify-content: center;
    padding-block: 28px;
  }

  /* The approved desktop strip draws its separators as each tile's OWN left
     border, so lifting the tile would drag its separator off the strip's edge
     and leave a notch. The tile therefore stays put and its CONTENT lifts,
     which reads the same as the wrapped states. The wash fills the tile's own
     column instead of bleeding across a separator. */
  .sx-service:hover,
  .sx-service:focus-visible {
    transform: none;
  }

  .sx-service:hover > *,
  .sx-service:focus-visible > * {
    transform: translate3d(0, -3px, 0);
  }

  .sx-service:hover::before,
  .sx-service:focus-visible::before {
    inset: 0;
    border-radius: 0;
  }

  .sx-panels__grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
  }

  .sx-panel {
    border-top: 0;
    border-left: 1px solid var(--sx-border);
  }

  .sx-panel--impact {
    grid-column: span 4 / span 4;
    border-left: 0;
  }

  .sx-panel--approach {
    grid-column: span 3 / span 3;
  }

  .sx-panel--president {
    grid-column: span 5 / span 5;
  }

  /* Desktop navigation */
  .sx-nav__links {
    display: flex;
    align-items: center;
    font-size: 14.5px;
    font-weight: 500;
  }

  /* The canonical header is `Home / About Us / Services / Industries / Meet the
     Founder / Insights & Resources` + the Let's Connect CTA. It fits on one line
     with the approved 28px inter-item rhythm from 1100px upward. Below that the
     rhythm tightens only as far as it must (floor 20px) so the items, the logo
     and the CTA can never overflow or squeeze the logo at narrow desktop widths.
     28px is preserved exactly at the 1280px reference width. */
  .sx-nav__links > * + * {
    margin-left: clamp(20px, calc(28px - (1100px - 100vw) * 0.06), 28px);
  }

  /* The indicator is also a child of the links row, so the inter-item rhythm
     above would shift its absolutely positioned box. It is placed by
     transform, not by margins. */
  .sx-nav__links > .sx-nav__indicator {
    margin-left: 0;
  }

  /* ---- Services disclosure menu -------------------------------------------
     DECLARED ONLY AT THE DESKTOP BREAKPOINT on purpose: the entire primary
     link row is `display: none` below 1024px, so the disclosure cannot reach
     the mobile hamburger and no touch behaviour is introduced anywhere. The
     trigger stays an ordinary link to /services/ — hovering or focusing it
     reveals the menu, clicking it still navigates.

     The wrapper introduces a flex item where there used to be an anchor, so
     it is laid out as the anchor was (flex, centred) and the inter-item
     rhythm above still applies to it unchanged. */
  .sx-nav__item {
    position: relative;
    display: flex;
    align-items: center;
  }

  /* The panel hangs from the navbar's bottom edge. Its top padding IS the
     bridge to the trigger: that padding belongs to the panel, the panel is a
     child of the item, and hovering a descendant keeps `:hover` on the item —
     so moving the pointer from `Services` into the list never closes it. */
  .sx-nav__menu {
    position: absolute;
    top: 100%;
    left: -18px;
    z-index: 60;
    padding-top: var(--sx-nav-menu-bridge);
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity 140ms ease, visibility 0s linear 140ms;
  }

  .sx-nav__item:hover .sx-nav__menu,
  .sx-nav__item:focus-within:not(.is-suppressed) .sx-nav__menu {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transition-delay: 0s;
  }

  /* Dismissed by the script: after Escape, or once a service has been chosen
     and the pointer is still resting where the menu was. Declared AFTER the
     reveal rule so it wins on equal specificity, and held until the pointer
     leaves the item — a later hover opens the menu normally again. */
  .sx-nav__item.is-dismissed .sx-nav__menu {
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition-delay: 0s, 0s;
  }

  /* An overlay: absolutely positioned, so opening it can never shift the
     navbar, the hero or any other content. */
  .sx-nav__menu-list {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 272px;
    margin: 0;
    padding: 8px 0;
    list-style: none;
    background-color: #ffffff;
    border: 1px solid var(--sx-border-pale);
    border-radius: 6px;
    box-shadow: 0 12px 24px -8px rgb(11 35 65 / 0.18), 0 2px 6px -2px rgb(11 35 65 / 0.1);
  }

  /* Popover pointer back up to the Services trigger. The panel hangs flush from
     the navbar's bottom edge as a plain white rectangle, so without this it
     reads as unrelated to any nav item.

     A 10px square rotated 45deg whose centre sits ON the panel's top edge: the
     lower half is covered by the panel's own white surface, the upper half pokes
     out as the chevron. Its top/left borders become the pointer's two visible
     edges (already rotated into a ^ at 45deg), and it carries the panel's softer
     shadow so the two silhouettes read as one shape - the panel's border colour
     is #f1f5f9 on a white navbar, so the shadow, not the hairline, is what makes
     either shape visible.

     Positioned under the middle of the 'Services' word: the panel's left edge is
     `left: -18px` of the item, so the trigger's centre lands at 18 + 70.9/2 ~ 53px
     in panel coordinates; a 10px box centred there starts at left: 48px. The box
     stays well clear of the panel's 6px corner radius, so the pointer is never
     clipped.

     The shadow is tighter and slightly stronger than the panel's own pair on
     purpose: the pointer overlaps the white navbar, where the panel's hairline
     is invisible, so a shadow-hugging outline (-1px/-1px, 2px blur) is what
     makes the chevron read at all. Measured against the panel's own top edge
     (darkest pixel 242 over the navbar) it lands at 211 - a restrained outline,
     the same weight class as the edge it continues.

     The 28.5px transparent bridge above the panel is untouched: that padding is
     what keeps the menu open while the pointer travels from the trigger down to
     the panel. */
  .sx-nav__menu-list::before {
    content: '';
    position: absolute;
    top: -5px;
    left: 48px;
    width: 10px;
    height: 10px;
    background-color: #ffffff;
    border-top: 1px solid var(--sx-border-pale);
    border-left: 1px solid var(--sx-border-pale);
    border-top-left-radius: 2px;
    box-shadow: -1px -1px 2px rgb(11 35 65 / 0.22);
    transform: rotate(45deg);
  }

  .sx-nav__menu-link {
    display: block;
    padding: 8px 18px;
    color: var(--sx-nav-ink);
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    transition: color 150ms ease, background-color 150ms ease;
  }

  .sx-nav__menu-link:hover,
  .sx-nav__menu-link:focus-visible {
    background-color: var(--sx-green-wash);
    color: var(--sx-green);
  }

  /* `!important` is required here: the mobile panel can out-specify these bare
     selectors through `.sx-nav__mobile.is-open` (opened while the viewport was
     narrow) and through `.no-js .sx-nav__mobile`, and neither may be allowed to
     show a mobile panel beside the desktop navigation. */
  .sx-nav__toggle,
  .sx-nav__mobile {
    display: none !important;
  }

  .sx-footer__columns {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 24px;
  }
}

/* ------------------------------------------------------------
   14. ENHANCED PAGE NAVIGATION (progressive enhancement)
   ------------------------------------------------------------
   assets/js/site-header.js replaces only <main> on eligible same-origin links
   and leaves the top contact bar, the navbar and the footer exactly where they
   are, so the shell never blinks. The new content settles down into place
   (-10px -> 0, 240ms) instead of appearing abruptly.

   Two paths, both optional:
   - browsers with the View Transitions API animate the swap through
     `::view-transition-*` (the shell is identical, so the root cross-fade over
     it is invisible);
   - every other browser gets the same motion from `.is-entering`.
   Neither is required: without JavaScript the site is a plain multi-page site. */
#main-content {
  view-transition-name: sx-main;

  /* A below-the-fold reveal that arrives from the right starts 28px to the right
     of its final position, and a transform DOES contribute to the scrollable
     overflow region — so on the pages whose right-hand column sits on the
     content gutter (`/services/`, `/industries/`, the service-detail pages) the
     page briefly gained a horizontal scrollbar before the visitor scrolled.
     Measured: `.sv-row` reached right=1284 on a 1280px viewport.

     `clip` rather than `hidden`: it contains the offset without creating a
     scroll container, so the sticky `.sv-card` inside main still sticks to the
     viewport instead of to main. Nothing is lost — every full-bleed layer is
     exactly viewport-width, so nothing legitimately extends past it. */
  overflow-x: clip;
}

#main-content.is-entering {
  animation: sx-content-enter var(--motion-base) var(--motion-ease) both;
}

@keyframes sx-content-enter {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* `mix-blend-mode: normal` removes the default `plus-lighter` blend, which
   washes out the cross-fade on light surfaces. */
::view-transition-old(sx-main),
::view-transition-new(sx-main) {
  mix-blend-mode: normal;
}

/* MEASURED ROOT CAUSE OF THE VISIBLE SCROLL-UP. An element that carries its own
   `view-transition-name` is NOT part of the root cross-fade: the browser lifts
   it out, records its OLD and NEW viewport rects, and animates
   `::view-transition-group(<name>)` between them. `#main-content` is the whole
   page landmark, so its viewport rect at a deep scroll offset sits far above
   the viewport and its new rect starts under the shell — measured at 1280px
   navigating /about/ to /services/ from y=2400:

     ::view-transition-group(sx-main)  translateY  -2286px  ->  +114px

   That delta is exactly the scroll distance, so the transition itself carried
   the entire page upward past the viewport for ~300ms even though
   `window.scrollY` had already jumped to 0 in a single frame. Disabling the
   group's own animation pins it at the destination rect, and the cross-fade
   then resolves in place rather than travelling.

   The old snapshot is taken from the OUTGOING page at its deep scroll offset,
   so it is not a valid backdrop for the incoming page and is removed at once
   instead of being faded out. What remains is the intended effect and nothing
   else: the destination content settles -10px -> 0 while it fades in. */
::view-transition-group(sx-main) {
  animation: none;
}

::view-transition-old(sx-main) {
  animation: none;
  opacity: 0;
}

::view-transition-new(sx-main) {
  animation: sx-vt-in var(--motion-base) var(--motion-ease) both;
}

@keyframes sx-vt-in {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
}

/* ------------------------------------------------------------
   15. PAGE-ENTRY (HERO) AND BELOW-THE-FOLD SCROLL REVEAL
   ------------------------------------------------------------
   Two DIFFERENT mechanisms, deliberately.

   PAGE-ENTRY is a plain CSS animation on the hero's copy columns and its content
   image columns. It is declared in CSS with no JavaScript involved, which buys
   three properties at once:
     - it runs on a direct hard load, not only on an enhanced navigation;
     - it cannot leave anything hidden when JavaScript is unavailable, because
       the animation's final state is the element's natural state;
     - it replays on every enhanced navigation, because the destination <main>
       (hero included) is rebuilt each time and a CSS animation on a fresh
       element runs from the start.

   SCROLL REVEAL is JavaScript-driven and applies ONLY below the fold. Nothing
   is hidden until the route's motion manager arms, so a JavaScript failure or a
   missing script leaves every section visible. See section 6 of
   assets/js/site-header.js for the lifecycle that keeps automatic route
   positioning from firing these.

   The hero's full-bleed BACKDROP layers (`ab-hero__media`, `sv-hero__media`,
   `in-hero__media`, `sx-hero__photo`, `*-quote__bg`, `sx-cta__media`) are
   deliberately NOT animated: they are background, not content, and moving them
   would read as the page itself sliding.
   ------------------------------------------------------------ */
:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > * {
  /* `backwards`, never `both`: the fill must hold the pre-state during the
     stagger delay, but it must NOT linger afterwards. A finished animation with
     `both` keeps applying its final keyframe, and an identity transform still
     creates a containing block — which would silently re-parent any absolutely
     positioned decoration inside the hero for the life of the page. */
  animation: sx-page-enter var(--enter-duration) var(--motion-ease) backwards;
  animation-delay: calc(var(--enter-lead) + var(--enter-index, 0) * var(--enter-stagger));
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(1) {
  --enter-index: 0;
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(2) {
  --enter-index: 1;
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(3) {
  --enter-index: 2;
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(4) {
  --enter-index: 3;
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(5) {
  --enter-index: 4;
}

:is(.ab-hero__copy,
    .ct-hero__copy,
    .fo-hero__copy,
    .in-hero__copy,
    .ir-hero__copy,
    .sd-hero__copy,
    .sv-hero__copy,
    .sx-hero__copy-col,
    .sd-nf__copy)
  > *:nth-child(6) {
  --enter-index: 5;
}

/* The hero's content image column settles alongside the copy. It fades only — a
   transform here would briefly make the column a containing block for any
   absolutely positioned decoration inside it. */
:is(.sx-hero__photo-inline,
    .fo-hero__portrait-col,
    .ir-hero__media,
    .ct-hero__visual,
    .sd-hero__media) {
  animation: sx-page-enter-fade var(--enter-duration) var(--motion-ease) backwards;
  animation-delay: calc(var(--enter-lead) + 2 * var(--enter-stagger));
}

@keyframes sx-page-enter {
  from {
    opacity: 0;
    transform: translate3d(0, 16px, 0);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes sx-page-enter-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* ---- Below-the-fold scroll reveal --------------------------------------
   `sx-reveal-armed` is set on <html> by the route motion manager and is the
   ONLY thing that makes this block apply. Until it is set, `[data-sx-reveal]`
   carries no state at all, so the content cannot be left hidden by a script
   that never runs.

   The un-revealed state carries `transition: none` so that applying the
   attribute and the initial offset in one batch can never animate: the first
   transition only happens when `.is-revealed` is added, and the transition
   properties are read from the revealed state. */
.sx-reveal-armed [data-sx-reveal] {
  transition: opacity var(--reveal-duration) var(--reveal-ease),
    transform var(--reveal-duration) var(--reveal-ease);
  transition-delay: var(--reveal-delay, 0ms);
}

.sx-reveal-armed [data-sx-reveal]:not(.is-revealed) {
  opacity: 0;
  transition: none;
}

.sx-reveal-armed [data-sx-reveal='up']:not(.is-revealed) {
  transform: translate3d(0, var(--reveal-distance), 0);
}

.sx-reveal-armed [data-sx-reveal='down']:not(.is-revealed) {
  transform: translate3d(0, calc(var(--reveal-distance) * -1), 0);
}

.sx-reveal-armed [data-sx-reveal='left']:not(.is-revealed) {
  transform: translate3d(calc(var(--reveal-distance) * -1), 0, 0);
}

.sx-reveal-armed [data-sx-reveal='right']:not(.is-revealed) {
  transform: translate3d(var(--reveal-distance), 0, 0);
}

.sx-reveal-armed [data-sx-reveal='scale']:not(.is-revealed) {
  transform: scale(0.975);
}

.sx-reveal-armed [data-sx-reveal='fade']:not(.is-revealed) {
  transform: none;
}

/* ---- Contained content photographs: settle ------------------------------
   Applied to the PHOTOGRAPH, never to its frame. The frame keeps its own box,
   height, radius and crop, so a zoom can never resize a card, push text, shift
   layout or escape the frame — every frame this is used inside already clips
   its own overflow.

   A photograph is never hidden the way a text block is: the effect is the
   SETTLE, not a fade, so the un-revealed state keeps full opacity and all four
   rules below exist only to give the scale somewhere to travel from.

   These rules sit after the shared primitive block on purpose: they carry the
   same specificity, so their slower duration and their opacity override are
   decided by source order, the same way the `fade` primitive already does. */
.sx-reveal-armed [data-sx-reveal='zoom'] {
  transition: transform var(--media-settle-duration) var(--media-settle-ease);
  transition-delay: var(--reveal-delay, 0ms);
}

.sx-reveal-armed [data-sx-reveal='zoom']:not(.is-revealed) {
  opacity: 1;
  transform: scale(var(--media-settle-from));
  transition: none;
}

/* ---- Contained content photographs: hover ------------------------------
   Desktop/laptop pointers only, and only when the visitor has not asked for
   reduced motion, so a touch device can never keep a stuck hover state and a
   reduced-motion visitor never gets the movement at all. Once a reveal has
   settled the element sheds `data-sx-reveal`, so these rules take over cleanly
   and the photograph returns to exactly `scale(1)` when the pointer leaves. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  :is(.ab-apart__photo, .ir-feature__media, .ir-card__media, .sv-card__media) img {
    transition: transform var(--media-hover-duration) var(--motion-ease);
  }

  :is(.ab-apart__photo, .ir-feature__media, .ir-card__media, .sv-card__media):hover img {
    transform: scale(var(--media-hover-to));
  }
}

/* ------------------------------------------------------------
   16. MOTION PREFERENCES
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .sx-page *,
  .sx-page *::before,
  .sx-page *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }

  /* The enhanced navigation still swaps the content — it just arrives
     immediately instead of sliding. */
  #main-content.is-entering {
    animation: none !important;
  }

  /* The hero appears immediately rather than resolving in sequence. The reveal
     system is never armed under reduced motion (see the motion manager), so no
     below-the-fold content can be left hidden or displaced either. */
  :is(.ab-hero__copy,
      .ct-hero__copy,
      .fo-hero__copy,
      .in-hero__copy,
      .ir-hero__copy,
      .sd-hero__copy,
      .sv-hero__copy,
      .sx-hero__copy-col,
      .sd-nf__copy)
    > *,
  :is(.sx-hero__photo-inline,
      .fo-hero__portrait-col,
      .ir-hero__media,
      .ct-hero__visual,
      .sd-hero__media) {
    animation: none !important;
  }

  ::view-transition-old(sx-main),
  ::view-transition-new(sx-main) {
    animation: none !important;
  }
}
