/* ==========================================================================
   20-system.css — the .sx design system for the rebuilt /aisuite/ landing page.
   Replaces 10-system.css + 11-motifs.css. Load AFTER tokens.css, and after
   the Elementor kit (post-15.css), so the element-level rules here win ties.

   WHAT CHANGED, AND WHY — the three notes from the client, answered.

   1. NO MONO, NO WIDE TRACKING.
      --mono (IBM Plex Mono) does not appear once in this file. Neither does
      --ls-label (0.08em) nor --ls-eyebrow (0.14em). Everything is --sans
      (Inter). Digits keep `font-variant-numeric: tabular-nums lining-nums`,
      which is an OpenType feature of Inter itself and does not reintroduce a
      second family. Eyebrows are sentence case rather than tracked-out caps:
      uppercase without tracking sets cramped, and tracked-out uppercase is
      precisely the look that was rejected.

   2. THE MARGINS NOW MATCH THE REST OF THE SITE.
      See section 4. The old .sx-wrap was wrong twice over and the two errors
      compounded; the numbers are in the block comment there.

   3. BLACK, NOT NAVY, WITH AN ANIMATED GRID.
      See sections 2 and 5. The ground is pure black; the grid is static paint
      and the impulses are composited transforms.

   --------------------------------------------------------------------------
   DEVIATIONS — every value in this file that is not a token, and why.
   The rule is tokens only; each of these has no token to read, so it is
   declared once as a local custom property on `.sx` and never repeated.

     --sx-black       tokens.css has no pure black. The darkest neutral is
                      --n-900 #0B141B, which is a navy-tinted near-black — the
                      exact colour the client rejected. #000000 is the brief.
     --sx-hair        1px. The space scale starts at 4px and has no hairline.
     --sx-hair-lit    2px. The width of a travelling impulse; a 1px band on a
                      1px rule reads as a flicker, 2px reads as light.
     --sx-tap         44px. The accessible minimum touch target. Not on the
                      4px scale (44 is 11 steps, and no token names it).
     --sx-cell        grid pitch. Reads --sp-16 / --sp-10, so it IS a token
                      value; the property exists so one instance can override
                      the pitch without touching two background properties.
     --sx-fs-display  --fs-display tops out at 80px, which the site's 0.85
     --sx-fs-statement desktop zoom renders at 68px. This page is 65% shorter
                      than the one it replaces and carries its weight in three
                      or four statement lines, so they are sized past the
                      shared scale rather than repeated at it.
     --sx-card-w      carousel track width. A scroll-snap column has to be a
                      single value; no token is a card width.
     --sx-pulse-*     impulse geometry and timing. --dur / --dur-slow are UI
     --sx-glow-*      response times (120-240ms) and are wrong by two orders
     --sx-p-*         of magnitude for ambient motion.
     percentages      inside mask and gradient stops. Those are the shape of a
                      decorative gradient, not spacing.

   --------------------------------------------------------------------------
   CONTRAST — computed with the WCAG 2.x relative-luminance formula,
   ((L1 + 0.05) / (L2 + 0.05)), not estimated. Body >= 4.5:1, large/UI >= 3:1.

   GROUNDS   ground   #000000  (--sx-black)
             ground-2 #0F0F0F  (--n-0 6% into black)   cards, inputs, pills
             ground-3 #1A1A1A  (--n-0 10% into black)  panel heads, wells

                              ground   ground-2  ground-3
     ink        n-0   #FFFFFF   21.00    19.13     17.49
     ink-2      n-100 #E9EDF1   17.85    16.26     14.87
     ink-dim    n-300 #B9C4CE   11.85    10.79      9.87
     ink-faint  n-400 #8E9CA9    7.48     6.81      6.23
     line-strong n-500 #7A8C9A   6.05     5.51      5.04   (UI boundary, >=3)
     accent-ink sky-400 #67BBD6  9.66     8.79      8.04
     accent-hi  sky-300 #9BD2E6 12.75    11.62     10.63

     --sx-line (--n-0 14% into black, #242424) is 1.35:1 on ground. It is a
     DECORATIVE hairline and is never a control's only boundary — controls
     take --sx-line-strong at 6.05:1. This is the defect the previous sheet
     had to correct after the fact; it is correct here by construction.

   ACCENT FILL  --navy-900 #001A27 on --sky-400 #67BBD6 = 8.20:1.
     BRAND.md's rule holds: navy is the label colour on a sky fill, not white.
     sky-400 is 2.18:1 on white and 9.66:1 on this page's black — it is the
     right accent here precisely because the ground is black.

   STATUS  the tokens' light values are dark inks and would vanish on black,
   so they are lifted 46% into --n-0, the same construction the old dark band
   used. Under a dark OS theme the tokens are already light and are read raw.
     lifted   ok #96C2AE 10.60 · warn #C2A68A 9.09 · bad #E2A49D 10.03
     raw dark ok #45C795  9.86 · warn #C79A4E 8.16 · bad #E26D6D  6.64

   PILLS  ground = currentColor 12% over ground-2
     ink-dim on #232526 8.70 · accent on #1A2427 7.32

   FOCUS RING  2px solid --sx-accent-ink, 2px offset: 9.66:1 on ground.

   GRID AND IMPULSES  1.12:1 to 1.61:1 on black. Decorative, behind content,
   never carries meaning and never touched by a pointer.
   ========================================================================== */


/* ==========================================================================
   1. ROOT AND ROLES
   ========================================================================== */

.sx{
  /* --- Deviations. Declared once. See the header. --------------------- */
  --sx-black:   #000000;
  --sx-hair:    1px;
  --sx-hair-lit: 2px;
  --sx-tap:     44px;

  /* --- Grounds -------------------------------------------------------- */
  --sx-ground:   var(--sx-black);
  --sx-ground-2: color-mix(in srgb, var(--n-0) 6%,  var(--sx-black));
  --sx-ground-3: color-mix(in srgb, var(--n-0) 10%, var(--sx-black));

  /* --- Ink ------------------------------------------------------------ */
  --sx-ink:       var(--n-0);
  --sx-ink-2:     var(--n-100);
  --sx-ink-dim:   var(--n-300);
  --sx-ink-faint: var(--n-400);

  /* --- Rules. --sx-line is decorative; --sx-line-strong bounds controls. */
  --sx-line:        color-mix(in srgb, var(--n-0) 14%, var(--sx-black));
  --sx-line-2:      color-mix(in srgb, var(--n-0) 22%, var(--sx-black));
  --sx-line-strong: var(--n-500);

  /* --- Accent. --sx-accent is a FILL, --sx-accent-ink is TEXT. --------- */
  --sx-accent:       var(--sky-400);
  --sx-accent-hover: var(--sky-300);
  --sx-accent-ink:   var(--sky-400);
  --sx-on-accent:    var(--navy-900);
  --sx-accent-wash:  color-mix(in srgb, var(--sky-400) 12%, var(--sx-ground-2));

  /* --- Status, pinned to the dark ramp because this page has ONE ground ---
   *
   * These used to be `color-mix(var(--ok) 46%, --n-0)`, lifting tokens.css's
   * LIGHT status inks -- which are dark, built for a white page -- up toward
   * white so they would read on black. That is the right move for a surface
   * whose ground follows the reader's theme. This page's ground does not: it
   * is black in every theme state.
   *
   * So the lift only ever fired for readers whose OS is in light mode, and it
   * gave them a different palette from everyone else: --warn came out #C2A68A,
   * a desaturated tan, where a dark-OS reader saw #C79A4E and a real amber.
   * Henri asked for amber on the Conditional band and would have got tan
   * roughly half the time, depending on a setting that has no bearing on a
   * page that is always black.
   *
   * Pinned to the dark ramp, which is the one built for a dark ground. On the
   * card ground #070C11: ok 9.21, warn 7.63, bad 6.21; at the glow's worst
   * point #0B1419: 8.74 / 7.23 / 5.89. Every value clears 4.5:1 as text and
   * 3:1 as UI, and now does so identically for every reader.
   */
  --sx-ok:   #45C795;
  --sx-warn: #C79A4E;
  --sx-bad:  #E26D6D;

  /* How much of a status colour is mixed into a pill's ground. */
  --sx-tint: 12%;

  /* --- Type scale beyond the shared one. See the header. --------------- */
  --sx-fs-display:   clamp(2.75rem, 7.4vw, 6.25rem);   /*  44 -> 100 */
  --sx-fs-statement: clamp(2rem,    4.6vw, 3.75rem);   /*  32 ->  60 */

  /* BODY AND LEDE ARE LOCAL, A STEP ABOVE THE SHARED TOKENS.
     --fs-md is 16px and --fs-lg 18px, which are right for a page rendered at
     1:1. This one is not: the site scales body > main to zoom:.85 above 1025px
     (see the compensation block below), so 16px reached the reader at 13.6px
     and 18px at 15.3px. That is the "very small" in the review, and lifting the
     shared tokens would enlarge every other page. Lifted here instead, so body
     lands at 15.8px effective on a desktop and 17px on a phone, where there is
     no zoom to fight. */
  --sx-fs-body: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);   /*  17 ->  19 */
  --sx-fs-lede: clamp(1.1875rem, 1.1rem + 0.4vw, 1.375rem);   /*  19 ->  22 */

  /* --- Ambient motion -------------------------------------------------- */
  --sx-cell:        var(--sp-16);
  --sx-grid-ink:    color-mix(in srgb, var(--sky-400) 14%, transparent);
  --sx-pulse-ink:   color-mix(in srgb, var(--sky-400) 55%, transparent);
  --sx-pulse-hot:   var(--sky-300);
  --sx-pulse-len:   clamp(90px, 14vh, 200px);
  --sx-pulse-alpha: 0.85;
  --sx-p-ease:      cubic-bezier(.45, 0, .55, 1);
  --sx-glow-ink:    color-mix(in srgb, var(--sky-500) 26%, transparent);
  --sx-glow-size:   clamp(320px, 52vw, 720px);
  --sx-glow-alpha:  0.5;
  --sx-glow-dur:    26s;

  /* --- Misc ------------------------------------------------------------ */
  --sx-card-w:  min(78vw, 21rem);
  --sx-shadow:  var(--e-2);
  --sx-reveal-y: 16px;

  position: relative;
  z-index: 0;
  background: var(--sx-ground);
  color: var(--sx-ink-2);
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-normal);
  letter-spacing: var(--ls-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* The page is black in both themes — that is the point, not a theme. The only
   thing the OS preference changes is the status ramp, because tokens.css has
   already lightened --ok / --warn / --bad by the time this block applies and
   lifting them a second time would wash them to pastel. */
/* The three per-scheme status overrides that used to sit here are gone. They
   existed to keep the lift correct in each theme state, and with the ramp
   pinned above there is nothing left to keep correct: one ground, one palette,
   for every reader. */

/* The site scales body > main to zoom:.85 above 1025px (tblocks-brand.css).
   It is a reviewed, site-wide decision and is not ours to undo — undoing it
   would make this page's type larger than every other page's. The two small
   sizes land badly under it (11px -> 9.35px, 12px -> 10.2px), so they are
   compensated locally. The shared tokens are untouched. */
@media (min-width: 1025px) {
  .sx{ --fs-micro: 0.8125rem; --fs-2xs: 0.875rem; }
}

/* A tighter pitch where 64px would tile only three columns. */
@media (max-width: 700px) {
  .sx{ --sx-cell: var(--sp-10); }
}


/* ==========================================================================
   2. RESET — scoped, nothing escapes .sx
   ========================================================================== */

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

.sx h1, .sx h2, .sx h3, .sx h4, .sx h5, .sx h6,
.sx p, .sx figure, .sx blockquote, .sx dl, .sx dd{ margin: 0; }

.sx h1, .sx h2, .sx h3, .sx h4, .sx h5, .sx h6{
  font-family: var(--sans);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
}

.sx ul, .sx ol{ margin: 0; padding: 0; }
.sx li{ list-style: none; }
.sx ol > li + li,
.sx ul > li + li{ margin-top: var(--sp-2); }

.sx img, .sx video, .sx svg{ max-width: 100%; height: auto; display: block; }

.sx a{
  color: var(--sx-accent-ink);
  text-decoration: underline;
  text-decoration-thickness: var(--sx-hair);
  text-underline-offset: 0.18em;
  transition: color var(--dur) var(--ease),
              text-decoration-color var(--dur) var(--ease);
}
.sx a:hover{ color: var(--sx-accent-hover); text-decoration-thickness: 2px; }

.sx button,
.sx input,
.sx select,
.sx textarea{
  font-family: var(--sans);
  font-size: inherit;
  letter-spacing: var(--ls-normal);
  color: inherit;
}

/* Grid and flex children must be allowed to shrink, or wide content pushes
   the page sideways. Nothing in .sx may cause a horizontal scrollbar. */
.sx .sx-grid > *,
.sx .sx-split > *,
.sx .sx-cluster > *,
.sx .sx-inline > *{ min-width: 0; }

/* Focus — visible on everything interactive, ringed in the accent (9.66:1). */
.sx :focus-visible{
  outline: 2px solid var(--sx-accent-ink);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

.sx .sx-vh{
  position: absolute;
  width: var(--sx-hair);
  height: var(--sx-hair);
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ==========================================================================
   3. MOTION POLICY — stated once, before anything animates.

   prefers-reduced-motion: reduce means STATIC, not slower. The grid stays,
   the impulses are removed from the box tree, the reveal never runs and the
   carousel stops smooth-scrolling. Nothing is left visible-but-crawling.

   A hidden tab is capped by the two-line script in 20-background.html, which
   stamps :root[data-sx-motion="idle"]. If that script never runs the
   attribute is simply absent and the animations play — the correct default.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .sx *,
  .sx *::before,
  .sx *::after{
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .sx .sx-bg__pulses,
  .sx .sx-bg__glow{ display: none; }
  .sx .sx-carousel{ scroll-behavior: auto; }
}

:root[data-sx-motion="idle"] .sx .sx-bg__pulse,
:root[data-sx-motion="idle"] .sx .sx-bg__glow{ animation-play-state: paused; }


/* ==========================================================================
   4. LAYOUT — and the margin bug, named.

   THE DEFECT. The old rule was

       .sx-wrap { max-width: 1200px; padding-inline: var(--gutter); }

   and it was wrong in two independent ways that compounded.

     a. 1200px is not this site's container. Elementor's kit sets
        `--container-max-width: 1400px` (post-15.css) and tokens.css agrees:
        `--container: 1400px`. 1200 is 200px narrower than every other page.

     b. The gutter was subtracted from the max-width instead of sitting
        outside it. Elementor's box is `.e-con > .e-con-inner { max-width:
        min(100%, 1400px) }` with the padding on the PARENT, so 1400px is the
        content width. Here 1200px was the border-box width and the two 4vw
        gutters ate into it, leaving 1079px of content.

   MEASURED, at a 1512px viewport (1497px client width, body > main at
   zoom:.85), against site/about-us/index.html rendered side by side:

                                left     right    content width
       site (.e-con-inner)      153.5    1343.5   1190 real px  (= 1400 CSS)
       old .sx-wrap content     289.9    1207.1    917 real px  (= 1079 CSS)
       new .sx-wrap content     153.5    1343.5   1190 real px

   The hero text started 136.4 real px inside the site's own left edge, and
   stopped 136.4 real px short of its right edge — which is what "too much on
   the right, not aligned with the margins of the other pages" describes. The
   headline's own 18ch cap then ended it at 1115, a further 92px in, so the
   block read as floated rather than set to a margin.

   The fix restores both halves: the site's container token, and the gutter
   outside it rather than inside.

   Verified against the About page's real Elementor container at nine widths.
   Every pair is identical to 0.1px:

       vw    site left / right      new left / right
       1512  153.5 / 1343.5         153.5 / 1343.5
       1440  117.5 / 1307.5         117.5 / 1307.5
       1280   43.5 / 1221.5          43.5 / 1221.5
       1100   37.4 / 1047.6          37.4 / 1047.6
       1024   41.0 /  968.0          41.0 /  968.0
        900   36.0 /  849.0          36.0 /  849.0
        768   30.7 /  722.3          30.7 /  722.3
        600   24.0 /  561.0          24.0 /  561.0
        390   24.0 /  351.0          24.0 /  351.0

   --gutter is clamp(24px, 4vw, 64px), which is exactly the padding the site's
   own containers carry, so the narrow end matches without a second rule.
   ========================================================================== */

.sx .sx-wrap{
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
  position: relative;
  z-index: 1;
}

/* A narrower measure that still hangs off the SAME left edge — for a reading
   column that must not run to 1400px. It sets a max-width, never a margin, so
   the left edge is shared with every other page. */
.sx .sx-wrap--narrow > *{ max-width: var(--container-app); }

.sx .sx-sec{
  position: relative;
  z-index: 1;
  /*
   * TIGHTER THAN THE SITE'S OWN RHYTHM, DELIBERATELY.
   *
   * `--section-y` is clamp(64px, 8vw, 120px) and it is right for the marketing
   * pages, which are long-form and want air. Here it put 120px above and 120px
   * below every section -- 240px of empty black between one statement and the
   * next, which on a page whose whole brief is "punchy" reads as the page
   * having run out of things to say. Measured in the browser at 1512: every
   * inter-section gap was 240px against section heights of 272-1001px.
   *
   * Two thirds of it, floored high enough that the sections never touch.
   */
  padding-block: clamp(var(--sp-12), 5.5vw, var(--sp-20));
  background: transparent;
  color: var(--sx-ink-2);
}
.sx .sx-sec--tight{ padding-block: clamp(var(--sp-10), 5vw, var(--sp-20)); }
.sx .sx-sec--flush{ padding-block: 0; }

/* An opaque band, for a section that must sit above the grid rather than in
   it — a form, a dense table, anything where the moving light would compete. */
.sx .sx-sec--solid{ background: var(--sx-ground-2); }

/* The site header is position:absolute with zero flow height, so <main>
   starts at y=0 and the first line of the hero sits under it. 165 / 158 / 118
   are the site's own header-clearance constants (tblocks-brand.css), not new
   numbers. Three bands, because the header keeps its 60px margin down to
   768px with no zoom to shrink it. */
@media (min-width: 1025px) { .sx .sx-sec--hero{ padding-top: 165px; } }
@media (min-width: 768px) and (max-width: 1024px) { .sx .sx-sec--hero{ padding-top: 158px; } }
@media (max-width: 767px) { .sx .sx-sec--hero{ padding-top: 118px; } }

/* Vertical rhythm inside a section, so a fragment invents no margins. */
.sx .sx-stack{ display: grid; align-content: start; gap: var(--sp-6); }
.sx .sx-stack--tight{ gap: var(--sp-3); }
.sx .sx-stack--loose{ gap: clamp(var(--sp-8), 4vw, var(--sp-16)); }

.sx .sx-grid{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-6);
}
@media (min-width: 760px) {
  .sx .sx-grid--2{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sx .sx-grid--4{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 980px) {
  .sx .sx-grid{ gap: var(--sp-8); }
  .sx .sx-grid--3{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sx .sx-grid--4{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.sx .sx-split{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-8);
}
@media (min-width: 980px) {
  .sx .sx-split{
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: clamp(var(--sp-8), 5vw, var(--sp-20));
    align-items: start;
  }
}

/* A row of things that wraps. Buttons, pills, logos. */
.sx .sx-cluster{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
}
.sx .sx-cluster--gap{ gap: var(--sp-4) var(--sp-8); }


/* ==========================================================================
   5. THE BACKGROUND — black, a static grid, and impulses running along it.

   TECHNIQUE. Three layers inside one fixed, pointer-transparent box.

     .sx-bg__grid    two repeating linear-gradients. Painted once into the
                     layer and never repainted: no animation touches it.
     .sx-bg__pulse   one element per impulse. Each is the FULL height (or
                     width) of the viewport, 2px thick, and carries a short
                     lit band inside its own gradient. The band is moved by
                     translating the element from -100% to 100% of ITS OWN
                     size — no vh, no vw, no percentage of a parent, so the
                     site's zoom:.85 on body > main cannot desynchronise it.
     .sx-bg__glow    one radial blob, transform-only drift.

   COST. Every animation is `transform` and nothing else, on eight small
   elements plus one blob. That is compositor work: no style recalc, no
   layout, no paint after the first frame. The grid never animates, so the
   large layer is rasterised once. The box is position:fixed, so scrolling
   does not move or repaint it either. `contain: layout paint` fences the
   whole thing off from the document's layout.

   The impulses are placed ON grid lines rather than near them:
   `background-position: calc(50% + var(--sx-cell) / 2) 0` puts a vertical
   rule at exactly `50% + n * cell` (a calc mixing % and length resolves the
   tile origin to 50% of the box), and horizontal rules at `n * cell` from the
   top. The pulses read the same two expressions.

   FAILS TO NOTHING. Every layer is a bare div with no content and no size of
   its own beyond inset. With this stylesheet absent the whole box is invisible
   and contributes no layout. With JavaScript absent it is a static grid plus
   moving light — there is no script in the render path at all; the only script
   in 20-background.html sets one attribute on visibilitychange and the page is
   correct without it.
   ========================================================================== */

.sx .sx-bg{
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  user-select: none;
  overflow: hidden;
  contain: layout paint;
  background: var(--sx-ground);
}

.sx .sx-bg__grid{
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right,  var(--sx-grid-ink) 0 var(--sx-hair), transparent var(--sx-hair)),
    linear-gradient(to bottom, var(--sx-grid-ink) 0 var(--sx-hair), transparent var(--sx-hair));
  background-size: var(--sx-cell) var(--sx-cell);
  background-position: calc(50% + var(--sx-cell) / 2) 0;
  /* Fade the grid off at the edges so it never runs into type. currentColor
     is an opaque alpha source only — a mask reads alpha, not hue — so this
     introduces no colour of its own. */
  -webkit-mask-image: radial-gradient(120% 92% at 50% 34%, currentColor 0%, currentColor 42%, transparent 100%);
          mask-image: radial-gradient(120% 92% at 50% 34%, currentColor 0%, currentColor 42%, transparent 100%);
}

.sx .sx-bg__pulses{
  position: absolute;
  inset: 0;
  -webkit-mask-image: radial-gradient(120% 92% at 50% 34%, currentColor 0%, currentColor 46%, transparent 100%);
          mask-image: radial-gradient(120% 92% at 50% 34%, currentColor 0%, currentColor 46%, transparent 100%);
}

.sx .sx-bg__pulse{
  position: absolute;
  opacity: var(--sx-pulse-alpha);
  will-change: transform;
  animation-duration: var(--sx-p-dur, 9s);
  animation-delay: var(--sx-p-delay, 0s);
  animation-timing-function: var(--sx-p-ease);
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}

/* Vertical: full height, sits on the rule at 50% + n * cell, runs downward. */
.sx .sx-bg__pulse--v{
  top: 0;
  height: 100%;
  width: var(--sx-hair-lit);
  left: calc(50% + var(--sx-cell) * var(--sx-p-line, 0));
  margin-left: calc(var(--sx-hair-lit) / -2);
  background-image: linear-gradient(to bottom,
    transparent 0,
    transparent calc(50% - var(--sx-pulse-len)),
    var(--sx-pulse-ink) calc(50% - var(--sx-pulse-len) * 0.35),
    var(--sx-pulse-hot) 50%,
    transparent calc(50% + var(--sx-pulse-len) * 0.18),
    transparent 100%);
  animation-name: sx-pulse-y;
}

/* Horizontal: full width, sits on the rule at n * cell from the top. */
.sx .sx-bg__pulse--h{
  left: 0;
  width: 100%;
  height: var(--sx-hair-lit);
  top: calc(var(--sx-cell) * var(--sx-p-line, 0));
  margin-top: calc(var(--sx-hair-lit) / -2);
  background-image: linear-gradient(to right,
    transparent 0,
    transparent calc(50% - var(--sx-pulse-len)),
    var(--sx-pulse-ink) calc(50% - var(--sx-pulse-len) * 0.35),
    var(--sx-pulse-hot) 50%,
    transparent calc(50% + var(--sx-pulse-len) * 0.18),
    transparent 100%);
  animation-name: sx-pulse-x;
}

/* "from one way to another" — half the impulses run against the other half. */
.sx .sx-bg__pulse--rev{ animation-direction: reverse; }

@keyframes sx-pulse-y{
  from { transform: translate3d(0, -100%, 0); }
  to   { transform: translate3d(0,  100%, 0); }
}
@keyframes sx-pulse-x{
  from { transform: translate3d(-100%, 0, 0); }
  to   { transform: translate3d( 100%, 0, 0); }
}

/* Line, speed and phase per impulse, so the markup is eight bare elements and
   every number lives here. Primes-ish durations: nothing resynchronises. */
.sx .sx-bg__pulse:nth-child(1){ --sx-p-line:  -9; --sx-p-dur:  7s;  --sx-p-delay:  -1s; }
.sx .sx-bg__pulse:nth-child(2){ --sx-p-line:  -4; --sx-p-dur: 11s;  --sx-p-delay:  -6s; }
.sx .sx-bg__pulse:nth-child(3){ --sx-p-line:   2; --sx-p-dur:  9s;  --sx-p-delay:  -3s; }
.sx .sx-bg__pulse:nth-child(4){ --sx-p-line:   7; --sx-p-dur: 13s;  --sx-p-delay:  -9s; }
.sx .sx-bg__pulse:nth-child(5){ --sx-p-line:  12; --sx-p-dur:  8s;  --sx-p-delay:  -4s; }
.sx .sx-bg__pulse:nth-child(6){ --sx-p-line:   3; --sx-p-dur: 12s;  --sx-p-delay:  -2s; }
.sx .sx-bg__pulse:nth-child(7){ --sx-p-line:   6; --sx-p-dur: 15s;  --sx-p-delay: -11s; }
.sx .sx-bg__pulse:nth-child(8){ --sx-p-line:   9; --sx-p-dur: 10s;  --sx-p-delay:  -5s; }

.sx .sx-bg__glow{
  position: absolute;
  left: 50%;
  top: 22%;
  width: var(--sx-glow-size);
  height: var(--sx-glow-size);
  margin: calc(var(--sx-glow-size) / -2);
  border-radius: var(--r-pill);
  background: radial-gradient(closest-side, var(--sx-glow-ink), transparent 72%);
  opacity: var(--sx-glow-alpha);
  will-change: transform;
  animation: sx-glow-drift var(--sx-glow-dur) var(--sx-p-ease) infinite alternate;
}
@keyframes sx-glow-drift{
  from { transform: translate3d(-14%,  4%, 0) scale(1); }
  to   { transform: translate3d( 16%, 24%, 0) scale(1.14); }
}

/* Fewer moving parts on a phone: three impulses, no glow. Not a nicety —
   a small screen is usually a battery. */
@media (max-width: 700px) {
  .sx .sx-bg__pulse:nth-child(n + 4){ display: none; }
  .sx .sx-bg__glow{ display: none; }
}

@media (forced-colors: active) {
  .sx .sx-bg{ display: none; }
}
@media print {
  .sx .sx-bg{ display: none; }
}


/* ==========================================================================
   6. TYPE — Inter throughout, no tracking beyond the display negatives.
   Scale: display / statement / h1 / h2 / h3 / lede / body / small / micro
   ========================================================================== */

/* Sentence case, no tracking, no mono. The old eyebrow was 11px IBM Plex Mono
   at 0.14em uppercase; this is the same signal without the wide caps. */
.sx .sx-eyebrow{
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-normal);
  line-height: var(--lh-normal);
  text-transform: none;
  color: var(--sx-accent-ink);
}
.sx .sx-eyebrow::before{
  content: "";
  flex: 0 0 var(--sp-8);
  height: var(--sx-hair);
  background: currentColor;
}

.sx .sx-display{
  font-family: var(--sans);
  font-size: var(--sx-fs-display);
  font-weight: var(--fw-black);
  line-height: 1.02;
  letter-spacing: var(--ls-display);
  color: var(--sx-ink);
  text-wrap: balance;
  max-width: 16ch;
}

.sx .sx-statement{
  font-family: var(--sans);
  font-size: var(--sx-fs-statement);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-ink);
  text-wrap: balance;
  max-width: 22ch;
}

.sx .sx-h1{
  font-size: var(--fs-h1);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-ink);
  text-wrap: balance;
  max-width: 20ch;
}

.sx .sx-h2{
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
  text-wrap: balance;
  max-width: 26ch;
}

.sx .sx-h3{
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
}

.sx .sx-lede{
  font-size: var(--sx-fs-lede);
  font-weight: var(--fw-regular);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-dim);
  max-width: 58ch;
}

.sx .sx-body{
  font-size: var(--sx-fs-body);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-2);
  max-width: 66ch;
}
.sx .sx-body + .sx-body{ margin-top: var(--sp-4); }

/* EMPHASIS, SO THE EYE LANDS ON THE LOAD-BEARING CLAUSE. Two levels and no
   more: `strong` lifts a phrase to full ink and semibold, `em` puts it in the
   block's own accent -- which [data-engine] has already re-pointed, so the same
   two elements come out Atlas teal in one panel and Meridian amber in the next
   with no second rule. The italic is dropped for the same reason section 6
   drops it on display type: Inter's italic reads as a different voice, and the
   colour is the emphasis. */
.sx .sx-body strong,
.sx .sx-step__d strong,
.sx .sx-role__d strong,
.sx .sx-note strong,
.sx .sx-fig__t strong{ font-weight: var(--fw-semibold); color: var(--sx-ink); }

.sx .sx-body em,
.sx .sx-step__d em,
.sx .sx-role__d em,
.sx .sx-note em{ font-style: normal; font-weight: var(--fw-medium); color: var(--sx-accent-ink); }

.sx .sx-micro{
  font-size: var(--fs-2xs);
  line-height: var(--lh-normal);
  color: var(--sx-ink-faint);   /* 7.48:1 — a disclaimer is still body text */
  max-width: 76ch;
}

/* Inline emphasis inside a display line. `em` is used for the semantics; the
   italic is removed because Inter's italic at 100px is a different voice. */
.sx .sx-display em,
.sx .sx-statement em,
.sx .sx-h1 em,
.sx .sx-h2 em{
  font-style: normal;
  color: var(--sx-accent-ink);
}

.sx .sx-dim{ color: var(--sx-ink-dim); }
.sx .sx-accent-ink{ color: var(--sx-accent-ink); }

/* Figures line up in a column. This is an Inter OpenType feature, not a
   second family — the mono is gone and this does not bring it back. */
.sx .sx-num{
  font-family: var(--sans);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: var(--ls-normal);
  font-weight: var(--fw-medium);
}

/* Measure overrides, for the times a headline must run wider than its cap. */
.sx .sx-measure-wide{ max-width: 32ch; }
.sx .sx-measure-full{ max-width: none; }


/* ==========================================================================
   7. CONTROLS
   ========================================================================== */

.sx .sx-btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--sx-tap);
  padding: var(--sp-3) var(--sp-6);
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--sx-ink);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-normal);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.sx .sx-btn:hover{ border-color: var(--sx-ink); color: var(--sx-ink); }
.sx .sx-btn:active{ transform: translateY(1px); }

.sx .sx-btn--lg{
  min-height: calc(var(--sx-tap) + var(--sp-3));
  padding: var(--sp-4) var(--sp-8);
  font-size: var(--fs-md);
}

.sx .sx-btn--primary{
  background: var(--sx-accent);
  border-color: var(--sx-accent);
  color: var(--sx-on-accent);          /* navy on sky-400 = 8.20:1 */
  text-decoration: none;
}
.sx .sx-btn--primary:hover{
  background: var(--sx-accent-hover);
  border-color: var(--sx-accent-hover);
  color: var(--sx-on-accent);          /* navy on sky-300 = 10.84:1 */
}

.sx .sx-btn--ghost{
  background: transparent;
  border-color: var(--sx-line-strong);
  color: var(--sx-ink);
  text-decoration: none;
}
.sx .sx-btn--ghost:hover{
  background: color-mix(in srgb, var(--n-0) 8%, transparent);
  border-color: var(--sx-ink);
}

/* Not disabled in the DOM — aria-disabled="true", so it stays focusable and
   readable. Ink holds at ink-dim (11.85:1); nothing is greyed below the floor. */
.sx .sx-btn--soon,
.sx .sx-btn[aria-disabled="true"]{
  background: transparent;
  border-style: dashed;
  border-color: var(--sx-line-strong);
  color: var(--sx-ink-dim);
  cursor: not-allowed;
}
.sx .sx-btn--soon:hover,
.sx .sx-btn[aria-disabled="true"]:hover{
  background: transparent;
  border-color: var(--sx-line-strong);
  color: var(--sx-ink-dim);
}
.sx .sx-btn--soon:active,
.sx .sx-btn[aria-disabled="true"]:active{ transform: none; }

/* A text link that reads as an action. */
.sx .sx-link{
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-medium);
  color: var(--sx-accent-ink);
  text-decoration: none;
  border-bottom: var(--sx-hair) solid color-mix(in srgb, var(--sky-400) 45%, transparent);
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.sx .sx-link:hover{ color: var(--sx-accent-hover); border-bottom-color: currentColor; }


/* ==========================================================================
   8. SURFACES
   ========================================================================== */

.sx .sx-card{
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background: var(--sx-ground-2);
  /* line-strong, not line: a card edge is a boundary, and --sx-line is
     1.35:1 on this ground. The old sheet had to fix this after shipping. */
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-lg);
  color: var(--sx-ink-2);
  transition: border-color var(--dur) var(--ease),
              background-color var(--dur) var(--ease),
              transform var(--dur-slow) var(--ease);
}
.sx a.sx-card,
.sx a.sx-card:hover{ text-decoration: none; color: var(--sx-ink-2); }
.sx a.sx-card:hover,
.sx .sx-card--hover:hover{
  border-color: var(--sx-accent-ink);
  background: var(--sx-ground-3);
  transform: translateY(-2px);
}

/* A card that carries a number or a claim rather than a paragraph. */
.sx .sx-card--feature{
  gap: var(--sp-4);
  padding: clamp(var(--sp-6), 3vw, var(--sp-10));
  background: linear-gradient(160deg,
    var(--sx-ground-3) 0%,
    var(--sx-ground-2) 62%);
}
.sx .sx-card--quiet{
  background: transparent;
  border-color: var(--sx-line-2);
}

.sx .sx-card__k{
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-normal);
  color: var(--sx-accent-ink);
}
.sx .sx-card__t{
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
}
.sx .sx-card__b{
  font-size: var(--sx-fs-body);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-dim);
}
.sx .sx-card__fig{
  font-family: var(--sans);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  font-size: var(--sx-fs-statement);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-ink);
}

.sx .sx-panel{
  position: relative;
  background: var(--sx-ground-2);
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.sx .sx-panel__hd{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-6);
  background: var(--sx-ground-3);
  border-bottom: var(--sx-hair) solid var(--sx-line);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-normal);
  line-height: var(--lh-normal);
  text-transform: none;
  color: var(--sx-ink);
}
.sx .sx-panel__hd > *{ margin: 0; font: inherit; color: inherit; letter-spacing: inherit; }
.sx .sx-panel__body{ padding: var(--sp-6); color: var(--sx-ink-2); }
.sx .sx-panel__body > * + *{ margin-top: var(--sp-4); }

.sx .sx-rule{
  border: 0;
  border-top: var(--sx-hair) solid var(--sx-line-2);
  height: 0;
  margin: 0;
  width: 100%;
}

/* Status pill. The colour is set once on `color`; the ground is mixed from it,
   so a modifier is one declaration and the contrast pairs stay computed.
   Inter, sentence case, no tracking. */
.sx .sx-pill{
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--r-pill);
  border: var(--sx-hair) solid color-mix(in srgb, currentColor 40%, transparent);
  background: color-mix(in srgb, currentColor var(--sx-tint), var(--sx-ground-2));
  color: var(--sx-ink-dim);
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-normal);
  line-height: var(--lh-normal);
  text-transform: none;
  white-space: nowrap;
  text-decoration: none;
}
.sx .sx-pill--accent{ color: var(--sx-accent-ink); }
.sx .sx-pill--strong{ color: var(--sx-ok); }
.sx .sx-pill--conditional{ color: var(--sx-warn); }
.sx .sx-pill--notready{ color: var(--sx-bad); }
.sx .sx-pill--scope{ color: var(--sx-accent-ink); border-style: dashed; }


/* ==========================================================================
   9. FEATURE LINES — what replaced the five tables.
   A numbered claim, one line of support, no cells.
   ========================================================================== */

.sx .sx-lines{
  display: grid;
  gap: 0;
  border-top: var(--sx-hair) solid var(--sx-line-2);
}
.sx .sx-lines > li{ margin-top: 0; }

.sx .sx-line{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-4) var(--sp-6);
  padding-block: clamp(var(--sp-5), 2.4vw, var(--sp-8));
  border-bottom: var(--sx-hair) solid var(--sx-line-2);
  transition: background-color var(--dur) var(--ease);
}
.sx .sx-line:hover{ background: color-mix(in srgb, var(--n-0) 3%, transparent); }

.sx .sx-line__n{
  font-family: var(--sans);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-normal);
  color: var(--sx-accent-ink);
  min-width: 2.5ch;
}
.sx .sx-line__t{
  font-size: clamp(var(--fs-lg), 2.2vw, 1.75rem);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
  text-wrap: balance;
}
.sx .sx-line__d{
  grid-column: 2;
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-dim);
  max-width: 62ch;
}

@media (min-width: 900px) {
  .sx .sx-line{ grid-template-columns: auto minmax(0, 26ch) minmax(0, 1fr); }
  .sx .sx-line__d{ grid-column: 3; margin-top: 0; }
}


/* ==========================================================================
   10. CAROUSEL — CSS only. scroll-snap, no script, no library.
   Keyboard reachable because the track itself is focusable (tabindex="0" in
   the markup) and arrow keys scroll a focused scroll container natively.
   ========================================================================== */

.sx .sx-carousel{
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--sx-card-w);
  gap: var(--sp-4);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  padding-block-end: var(--sp-4);
  scrollbar-width: thin;
  scrollbar-color: var(--sx-line-strong) transparent;
}
.sx .sx-carousel > *{ scroll-snap-align: start; }

@media (min-width: 900px) {
  .sx .sx-carousel{ gap: var(--sp-6); grid-auto-columns: var(--sx-card-w); }
}

/* Runs the track out through the wrap's gutter so cards bleed off the edge,
   while the FIRST card still snaps to the site's content edge. The bleed is
   exactly one gutter, so the alignment established in section 4 survives. */
.sx .sx-carousel--bleed{
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  scroll-padding-inline: var(--gutter);
}

.sx .sx-carousel__hint{
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-2xs);
  color: var(--sx-ink-faint);
}

.sx .sx-carousel::-webkit-scrollbar{ height: var(--sp-2); }
.sx .sx-carousel::-webkit-scrollbar-track{ background: transparent; }
.sx .sx-carousel::-webkit-scrollbar-thumb{
  background: var(--sx-line-2);
  border-radius: var(--r-pill);
}


/* ==========================================================================
   11. FORM — the waitlist.

   `.elementor-kit-15 input:not([type="button"]):not([type="submit"])` is
   (0,3,1) and sets background-color to --e-global-color-primary (#002232) and
   color to --e-global-color-text (#2D3E50): navy on navy, 1.50:1. It beat the
   old sheet's (0,2,0) input rules and shipped an illegible field.

   Matched on its own terms rather than with !important: the two :not()
   clauses carry their arguments' specificity, so `.sx input.sx-input:not(...)
   :not(...)` is (0,4,1) and wins on merit. Restated for hover, focus and
   placeholder because each of those loses separately.
   ========================================================================== */

.sx .sx-form{ display: grid; gap: var(--sp-4); }

.sx .sx-field{ display: grid; gap: var(--sp-2); }

.sx .sx-label{
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-normal);
  line-height: var(--lh-normal);
  text-transform: none;
  color: var(--sx-ink-2);
}

.sx .sx-input{
  width: 100%;
  min-height: var(--sx-tap);
  padding: var(--sp-3) var(--sp-4);
  background: var(--sx-ground-2);
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-pill);
  color: var(--sx-ink);
  font-family: var(--sans);
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
  transition: border-color var(--dur) var(--ease),
              background-color var(--dur) var(--ease);
}

.sx input.sx-input:not([type="button"]):not([type="submit"]),
.sx input.sx-input:not([type="button"]):not([type="submit"]):hover,
.sx input.sx-input:not([type="button"]):not([type="submit"]):focus,
.sx textarea.sx-input,
.sx select.sx-input{
  background-color: var(--sx-ground-2);
  color: var(--sx-ink);
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-pill);
  font-family: var(--sans);
  font-size: var(--fs-md);
  accent-color: var(--sx-accent);
}
.sx input.sx-input:not([type="button"]):not([type="submit"])::placeholder{
  color: var(--sx-ink-faint);
  opacity: 1;
}
.sx input.sx-input:not([type="button"]):not([type="submit"]):hover{
  border-color: var(--sx-ink-dim);
}
.sx input.sx-input:not([type="button"]):not([type="submit"]):focus{
  border-color: var(--sx-accent-ink);
  background-color: var(--sx-ground-3);
}

/* Chrome paints an autofilled field near-white and the ink near-black, which
   on this ground is the second illegible-field bug waiting to happen. The
   inset shadow is the only thing that overrides it. */
.sx input.sx-input:-webkit-autofill,
.sx input.sx-input:-webkit-autofill:hover,
.sx input.sx-input:-webkit-autofill:focus{
  -webkit-text-fill-color: var(--sx-ink);
  -webkit-box-shadow: inset 0 0 0 100px var(--sx-ground-3);
          box-shadow: inset 0 0 0 100px var(--sx-ground-3);
  caret-color: var(--sx-ink);
}

.sx .sx-help{
  font-size: var(--fs-2xs);
  line-height: var(--lh-normal);
  color: var(--sx-ink-faint);
  max-width: 60ch;
}
.sx .sx-help--bad{ color: var(--sx-bad); }
.sx .sx-help--ok{ color: var(--sx-ok); }

/* Field + button on one line above 560px, stacked below it. */
.sx .sx-inline{
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--sp-3);
}
.sx .sx-inline > .sx-input,
.sx .sx-inline > .sx-field{ flex: 1 1 18rem; }
.sx .sx-inline > .sx-btn{ flex: 0 0 auto; }

@media (max-width: 559px) {
  .sx .sx-inline{ flex-direction: column; align-items: stretch; }
  /* flex-basis is on the MAIN axis, and this query flips that axis, so 18rem
     would become a 288px-tall email field. It did, once. */
  .sx .sx-inline > .sx-input,
  .sx .sx-inline > .sx-field{ flex: 0 0 auto; }
  .sx .sx-inline > .sx-btn{ width: 100%; }
}


/* ==========================================================================
   12. REVEAL ON SCROLL — no JavaScript, and visible at rest.

   `animation-timeline: view()` is a scroll-driven animation: the browser
   advances it from the element's own position in the viewport. No observer,
   no script, no library.

   EVERYTHING IS VISIBLE AT REST. The base `.sx-reveal` rule sets no opacity
   and no transform. The animation exists only inside @supports AND only when
   motion is allowed, so a browser without scroll-driven animations, a printer,
   a crawler, a reduced-motion user and a failed stylesheet all get the page
   fully painted. There is no state in which a section is parked at opacity 0
   waiting for something to arrive.

   The range ends at `cover 30%`, well before the element leaves — an element
   is never animated back out on the way up.
   ========================================================================== */

.sx .sx-reveal,
.sx .sx-stagger > *{
  /* Deliberately empty of visual state. See above. */
  animation-fill-mode: both;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .sx .sx-reveal{
      animation: sx-reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 30%;
    }
    /* Children of a stagger each carry their own view() timeline, so they
       arrive in document order for free — no per-child delay to maintain. */
    .sx .sx-stagger > *{
      animation: sx-reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 2% cover 34%;
    }
    .sx .sx-reveal--rise{ --sx-reveal-y: 32px; }
    .sx .sx-reveal--near{ animation-range: entry 10% cover 22%; }
  }
}

@keyframes sx-reveal-in{
  from{ opacity: 0; transform: translate3d(0, var(--sx-reveal-y), 0); }
  to  { opacity: 1; transform: translate3d(0, 0, 0); }
}

@media print {
  .sx .sx-reveal,
  .sx .sx-stagger > *{ animation: none; opacity: 1; transform: none; }
}
@media (forced-colors: active) {
  .sx .sx-reveal,
  .sx .sx-stagger > *{ animation: none; opacity: 1; transform: none; }
}


/* ==========================================================================
   13. HOST-PAGE CORRECTIONS
   The page is a WordPress/Elementor export. These exist because of the host,
   not because of the system.
   ========================================================================== */

/* Elementor's kit types headings at (0,1,1); a bare `.sx h1` ties and would
   depend on load order. The class rules in section 6 are (0,2,0) and win, so
   this only has to catch the untagged case. */
.sx .sx-sec h1,
.sx .sx-sec h2,
.sx .sx-sec h3{ font-family: var(--sans); color: var(--sx-ink); }

/* The theme sets a page background on wrappers outside .sx. Painting the
   ground on .sx itself is not enough if <main> is shorter than the viewport. */
.sx .sx-bleed-ground{
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--sx-ground);
  pointer-events: none;
}
/* ==========================================================================
   Atlas Private scorecard — hero centrepiece
   ==========================================================================

   Sibling of the Atlas Public feature card (site/atlas/atlas-app.css,
   `.feature-card` and friends). Same visual language: a band strip across the
   top edge, a corner reference, a band pill, a headline block with a line-art
   watermark beside it, an identity block over a hairline, stacked
   label + bar rows, and a hairline footer.

   Three things were fine-tuned for the private engine, and they are the
   substance of the difference:

     1. NO COMPOSITE. The public card's 78px 0–100 score is the loudest thing on
        it. Atlas Private publishes no composite and no per-dimension figure to
        an unauthenticated reader, so the BAND takes that slot and is set large
        instead. Bars carry magnitude visually; a word ("Strong", "Adequate",
        "Limited") carries it in text. No number is printed anywhere on this card
        except coverage, which is a fact about how much was read rather than a
        score.

     2. FIVE DIMENSIONS, ONE COLUMN. The public card grids six short principle
        names two-up. "Capital Markets Readiness" does not fit that, and there
        are five rather than six, so the rows run full width.

     3. AN UNSCORED DIMENSION IS DRAWN, NOT ZEROED. `.sx-dim--unscored` gets an
        empty dashed track and never a fill at zero, because a dimension nothing
        was read for and a dimension that scored nothing are different facts.

   TYPE. Inter only, and no uppercase-plus-wide-tracking anywhere — the public
   card leans on it heavily and it was rejected here. Small labels are sentence
   case at their natural tracking. The only negative tracking is on the band
   wordmark, which is display type.

   SCOPE. Every selector is under `.sx`, which is on <html>. Nothing leaks.

   TOKENS. `/assets/tokens.css` only. The locals declared on `.sx` below are the
   complete set of values that are not tokens, each with the reason it exists.
   Per-row bar lengths arrive as an inline `--sx-level` in the markup: those are
   assessment data, not design values, exactly as the public card sets
   `style="width: 100%"` on its principle bars.
   ========================================================================== */

.sx {
  /* --------------------------------------------------------------- colour --
     The hero is black in BOTH themes. That rules out the semantic tokens
     (--bg-surface, --fg, --border, --ok/--warn), because those flip with
     prefers-color-scheme and half of them are unreadable on black in light
     mode. So this card is built from the theme-invariant raw scale (--n-*,
     --sky-*) and from translucent lifts derived from it. */

  --sx-ink:      var(--n-0);     /* card name, band wordmark      21:1 on black */
  --sx-ink-2:    var(--n-200);   /* prose                        ~14:1          */
  --sx-ink-3:    var(--n-400);   /* labels, meta                 ~6.2:1         */
  --sx-ink-4:    var(--n-500);   /* footer, reference code       ~4.9:1         */

  /* The band accent. `BAND_TONES` in packages/ui gives Conditional Fit the
     `info` tone, and `--info` resolves to --sky-400 on dark. Named once here so
     a band change is one declaration; see the band modifiers at the foot. */
  --sx-band: var(--sky-400);

  /* Surfaces and rules. tokens.css bottoms out at --n-900 (#0B141B, a
     navy-tinted near-black) and has no pure black and no translucent-on-black
     surface, so these are mixed from token colours toward `transparent` rather
     than introduced as new hexes. They therefore work over whatever the page
     paints behind them. */
  --sx-surface:    color-mix(in srgb, var(--n-900) 62%, transparent);
  --sx-surface-2:  color-mix(in srgb, var(--n-300)  4%, transparent);
  --sx-hairline:   color-mix(in srgb, var(--n-300) 13%, transparent);
  --sx-hairline-2: color-mix(in srgb, var(--n-300) 22%, transparent);
  --sx-track:      color-mix(in srgb, var(--n-300) 12%, transparent);

  /* ------------------------------------------------------------- geometry --
     The spacing scale starts at 4px and the radius scale at 2px. A 3px band
     strip and a 3px bar are below both, and they are the public card's own
     values — matching them is the point. */
  --sx-strip: 3px;
  --sx-bar-h: 3px;
  --sx-hair: 1px;   /* the public card's hairline weight */
  --sx-rule: 2px;   /* the gap list's marker rule */

  /* The public card is a fixed 360px. This one is wider because its rows are
     full-width and it carries prose; no container token is anywhere near this
     size (--container-app is 1100px, --container 1400px). */
  --sx-card-w: 27.5rem;

  /* Reading measure for the hero lede. tokens.css sizes containers, not
     measures. */
  --sx-measure: 34rem;

  /* The watermark's footprint, matched to `.feature-watermark` exactly so the
     two cards' headline blocks have the same proportions. */
  --sx-mark-w: 104px;
  --sx-mark-h: 82px;

  /* A hero reveal is slower than a UI state change. --dur-slow is 240ms and is
     tuned for the latter, so the two timings the reveal needs are local. */
  --sx-reveal: 620ms;
  --sx-stagger: 70ms;

  /* PREVIEW HARNESS ONLY — the one literal in this file. The live page paints
     the hero black itself and the card never assumes a ground colour (every
     surface above is translucent). This exists so the file opens standalone.
     If black becomes a real page ground, it wants a token in tokens.css. */
  --sx-preview-ground: #000;
}

/* ============================================================ hero harness
   Preview scaffolding. Copy left, card centre-right. The real hero replaces
   this; the card below is what ships. */

.sx,
.sx body {
  margin: 0;
  background: var(--sx-preview-ground);
}

.sx body {
  font-family: var(--sans);
  color: var(--sx-ink-2);
  -webkit-font-smoothing: antialiased;
}

.sx .sx-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-10);
  align-items: center;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding: var(--section-y) var(--gutter);
}

@media (min-width: 62rem) {
  .sx .sx-hero {
    grid-template-columns: 1.05fr 1fr;
    gap: var(--sp-16);
  }
}

.sx .sx-hero__eyebrow {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-normal);
  color: var(--sky-400);
}

.sx .sx-hero__title {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-h1);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-ink);
  text-wrap: balance;
}

.sx .sx-hero__lede {
  margin: 0 0 var(--sp-8);
  max-inline-size: var(--sx-measure);
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-3);
}

.sx .sx-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.sx .sx-hero__cta {
  display: inline-flex;
  align-items: center;
  padding: var(--sp-3) var(--sp-6);
  border: var(--sx-hair) solid transparent;
  border-radius: var(--r-xs);
  background: var(--accent-fill);
  color: var(--accent-on-fill);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.sx .sx-hero__cta:hover { background: var(--sky-400); }

.sx .sx-hero__cta--ghost {
  background: transparent;
  border-color: var(--sx-hairline-2);
  color: var(--sx-ink-2);
}

.sx .sx-hero__cta--ghost:hover { border-color: var(--sky-400); color: var(--sky-400); }

.sx .sx-hero__cta:focus-visible {
  outline: var(--sx-rule) solid var(--sky-400);
  outline-offset: var(--sp-1);
}

.sx .sx-hero__stage {
  display: flex;
  justify-content: center;
}

@media (min-width: 62rem) {
  .sx .sx-hero__stage { justify-content: flex-end; }
}

/* ==================================================================== card */

.sx .sx-card {
  position: relative;
  inline-size: 100%;
  max-inline-size: var(--sx-card-w);
  display: flex;
  flex-direction: column;
  overflow: hidden;

  background: var(--sx-surface);
  /* The public card's 1px hairline border, same weight, mixed rather than
     hard-coded. Squared corners are its signature; --r-xs is the smallest
     radius the scale offers and keeps the edge from reading as raw HTML. */
  border: var(--sx-hair) solid var(--sx-hairline-2);
  border-radius: var(--r-xs);
  box-shadow: var(--e-3);

  animation: sx-rise var(--sx-reveal) var(--ease) both;
}

@keyframes sx-rise {
  from { opacity: 0; transform: translateY(var(--sp-3)); }
}

/* Band strip across the top edge — `.feature-card-strip`, same 3px, same
   position, colour driven by the band modifier instead of by eligible/
   conditional/notEligible. Decorative: the band is written out in text below. */
.sx .sx-card__strip {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: var(--sx-strip);
  background: var(--sx-band);
  z-index: 2;
}

/* -------------------------------------------------------------- top row --
   `.feature-card-top`: reference code left, marker right. The public card's
   right-hand slot holds the band pill; here the band has moved down into the
   headline, so this slot carries the illustrative marker, which is the thing a
   reader most needs to see first on a demo card. */
.sx .sx-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-5) 0;
}

.sx .sx-card__ref {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--sx-ink-4);
}

/* ------------------------------------------------------- maker's mark --
   The house mark, signing the card beside its reference code.

   A MARK, NOT A LOGO PLACEMENT. It takes --sx-ink-4 through `color` on the
   wrapper, which is the same ink the reference code already uses, so the two
   read as one line of provenance and neither pulls against the band. The mark
   is solid geometry (eight filled cells), so at this size it survives where an
   outline icon would go to mush; the size is --sp-4, the smallest step at which
   the jog in the stem is still legible. Nothing here is a second accent. */
.sx .sx-card__origin {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-inline-size: 0;
  color: var(--sx-ink-4);
}

.sx .sx-card__house {
  inline-size: var(--sp-4);
  block-size: var(--sp-4);
  flex: none;
  display: block;
}

.sx .sx-card__tag {
  padding: var(--sp-1) var(--sp-2);
  border: var(--sx-hair) solid var(--sx-hairline-2);
  border-radius: var(--r-xs);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--sx-ink-3);
}

/* ------------------------------------------------------- the band, large --
   `.feature-score-block`: headline left, watermark right, same proportions.
   What sits on the left is a BAND rather than a composite. */
.sx .sx-card__verdict {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5) var(--sp-2);
}

.sx .sx-verdict {
  margin: 0;
  min-inline-size: 0;
}

.sx .sx-verdict__label {
  display: block;
  margin-block-end: var(--sp-1);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  color: var(--sx-ink-4);
}

.sx .sx-verdict__band {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-band);
}

/* The pill's dot, kept from `.feature-pill .dot` — the one piece of the public
   pill worth carrying over now that the pill itself is a wordmark. */
.sx .sx-verdict__dot {
  inline-size: var(--sp-2);
  block-size: var(--sp-2);
  border-radius: var(--r-pill);
  background: currentcolor;
  flex: none;
}

/* `.feature-watermark`, and now literally the same drawing: the lighthouse the
   public Atlas build already ships, copied rather than redrawn. It is what you
   consult before you commit, which is what an assessment is; the other two motifs
   in that build (a bridge and a tower crane) read as construction, which is
   Meridian's half of the story rather than Atlas's.

   Same footprint and the public card's own .18, so the two headline blocks have
   identical proportions and weight. The one change is the ink: the public sheet
   hard-codes rgba white, and here the stroke arrives through currentColor from a
   token role, so it works on this ground. Stroke only, never filled, and with no
   stroke declared in the markup at all — if this sheet fails to load the drawing
   resolves to stroke:none and disappears rather than blocking the card. */
.sx .sx-card__mark {
  inline-size: var(--sx-mark-w);
  block-size: var(--sx-mark-h);
  flex: none;
  opacity: .18;
  color: var(--sx-ink);
}

.sx .sx-card__mark svg { inline-size: 100%; block-size: 100%; display: block; }
.sx .sx-mark__stroke { stroke: currentcolor; fill: none; }

/* ------------------------------------------------------------- coverage --
   Not on the public card at all. Coverage caps the band in Atlas Private, so it
   is load-bearing and sits directly under the band it constrains. The figure is
   written out; the track is decorative and a reader who cannot see it loses
   nothing. It carries no threshold marker — a mark on this track would be a
   fact on screen that appears in no sentence. */
.sx .sx-coverage {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  padding: 0 var(--sp-5) var(--sp-3);
  font-size: var(--fs-2xs);
}

.sx .sx-coverage__label { color: var(--sx-ink-3); }
.sx .sx-coverage__value { color: var(--sx-ink-2); font-weight: var(--fw-semibold); }

.sx .sx-coverage__track {
  flex: 1 1 auto;
  block-size: var(--sx-bar-h);
  min-inline-size: var(--sp-16);
  background: var(--sx-track);
  border-radius: var(--r-xs);
  overflow: hidden;
}

.sx .sx-coverage__fill {
  display: block;
  block-size: 100%;
  inline-size: var(--sx-coverage, 0%); /* data: the figure printed beside it */
  /* NOT the band colour. Coverage is how much was read, not how good it was --
     the comment under the gap list has always said so -- and now that the band
     carries the page's green/amber/red vocabulary, painting a completeness
     figure amber would state a judgement the number does not make. Neutral ink,
     6.98:1 on the card ground. */
  background: var(--sx-ink-3);
  transform-origin: left center;
  animation: sx-grow var(--sx-reveal) var(--ease) both;
}

/* ------------------------------------------------------------- identity --
   `.feature-info` / `.feature-name` / `.feature-exchange-row`, over the same
   hairline. Title case, no tracking. */
.sx .sx-card__identity {
  padding: 0 var(--sp-5) var(--sp-3);
  border-block-end: var(--sx-hair) solid var(--sx-hairline);
}

.sx .sx-card__name {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
  text-wrap: balance;
}

.sx .sx-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-2xs);
  color: var(--sx-ink-4);
}

/* Hairline separators rather than middle dots. A dot is a character: it can be
   left orphaned at the end of a wrapped line, and it lands in the accessibility
   tree where it reads as a word. A border does neither, and it is the same
   hairline the card already uses everywhere else. */
.sx .sx-card__meta > span + span {
  padding-inline-start: var(--sp-2);
  border-inline-start: var(--sx-hair) solid var(--sx-hairline-2);
}

.sx .sx-card__meta-flag { color: var(--sky-400); font-weight: var(--fw-semibold); }

/* ----------------------------------------------------------- dimensions --
   `.feature-principles` / `.feature-principle-row` / `.feature-bar-track` /
   `.feature-bar-fill`, one column instead of two, and a level word where the
   public card prints a 0–5 figure. */
.sx .sx-dims {
  list-style: none;
  margin: 0;
  padding: var(--sp-3) var(--sp-5);
  display: grid;
  gap: var(--sp-3);
}

.sx .sx-dim {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.sx .sx-dim__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--sx-ink-3);
}

.sx .sx-dim__name { min-inline-size: 0; }

.sx .sx-dim__level {
  flex: none;
  font-weight: var(--fw-medium);
  color: var(--sx-ink-2);
}

.sx .sx-bar {
  display: block;
  block-size: var(--sx-bar-h);
  background: var(--sx-track);
  border-radius: var(--r-xs);
  overflow: hidden;
}

.sx .sx-bar__fill {
  display: block;
  block-size: 100%;
  /* Bar LENGTH is the magnitude encoding; colour is uniform. The public card
     runs green/amber/red per principle, which on a card that prints no figures
     would read as a rating scale rather than as an indication. */
  inline-size: var(--sx-level, 0%);
  background: var(--sx-band);
  transform-origin: left center;
  animation: sx-grow var(--sx-reveal) var(--ease) both;
  animation-delay: calc(var(--sx-i, 0) * var(--sx-stagger));
}

@keyframes sx-grow {
  from { transform: scaleX(0); }
}

/* An empty dashed track. Never a fill at zero. */
.sx .sx-bar--unscored {
  background: none;
  border-block-start: var(--sx-hair) dashed var(--sx-hairline-2);
  block-size: 0;
  margin-block-start: var(--sx-hair);
}

.sx .sx-dim--unscored .sx-dim__level { color: var(--sx-ink-4); font-style: italic; }
.sx .sx-dim--unscored .sx-dim__name { color: var(--sx-ink-4); }

/* The completeness sentence. `.feature-commentary`'s slot and register. */
.sx .sx-card__cap {
  margin: 0;
  padding: 0 var(--sp-5) var(--sp-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-3);
}

/* ------------------------------------------------------------ gap list --
   `.feature-routing`'s banded strip, carrying the thing that has no public
   equivalent: the named work, who does it, and how long it takes. */
.sx .sx-gaps {
  padding: var(--sp-3) var(--sp-5);
  border-block-start: var(--sx-hair) solid var(--sx-hairline);
  background: var(--sx-surface-2);
}

.sx .sx-gaps__head {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--sx-ink-4);
}

.sx .sx-gaps__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}

.sx .sx-gap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  padding-inline-start: var(--sp-3);
  border-inline-start: var(--sx-rule) solid var(--sx-hairline-2);
}

.sx .sx-gap__title {
  margin: 0;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  color: var(--sx-ink-2);
}

.sx .sx-gap__meta {
  margin: 0;
  font-size: var(--fs-micro);
  color: var(--sx-ink-4);
}

/* --------------------------------------------------------------- footer --
   `.feature-footer`: hairline above, two quiet spans, smallest type on the
   card. The right-hand span is the regulatory line and is never conditional. */
.sx .sx-card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  border-block-start: var(--sx-hair) solid var(--sx-hairline);
}

.sx .sx-card__foot-note,
.sx .sx-card__disclaimer {
  margin: 0;
  font-size: var(--fs-micro);
  line-height: var(--lh-normal);
  color: var(--sx-ink-4);
}

/* ------------------------------------------------------ band modifiers --
   One knob, and it is now the SAME knob the band pills further down the page
   already turn. See section 16 for why this reverses the earlier decision and
   for the measured contrast of every value. --sx-ok / --sx-warn / --sx-bad are
   the roles section 1 declares and `.sx-pill--strong` / `--conditional` /
   `--notready` already read; nothing new is introduced here. */
.sx .sx-card--strong-fit   { --sx-band: var(--sx-ok); }
.sx .sx-card--conditional  { --sx-band: var(--sx-warn); }
.sx .sx-card--notready     { --sx-band: var(--sx-bad); }
.sx .sx-card--out-of-scope { --sx-band: var(--sx-accent-ink); }

/* ============================================================= responsive */

@media (max-width: 30rem) {
  .sx .sx-card__mark { display: none; }        /* the band takes the full width */
  .sx .sx-card__top,
  .sx .sx-card__verdict,
  .sx .sx-coverage,
  .sx .sx-card__identity,
  .sx .sx-dims,
  .sx .sx-card__cap,
  .sx .sx-gaps,
  .sx .sx-card__foot {
    padding-inline: var(--sp-4);
  }
  .sx .sx-verdict__band { font-size: var(--fs-h3); }
}

/* ====================================================== reduced motion ====
   The reveal is a one-shot; there is no loop to stop. Every animated element's
   resting state is its unanimated state (the `from` frame is the only frame
   that differs), so switching the animations off leaves the card fully drawn. */

@media (prefers-reduced-motion: reduce) {
  .sx *,
  .sx *::before,
  .sx *::after {
    animation: none !important;
    transition: none !important;
  }
}


/* ==========================================================================
   14. RECONCILIATION — the two sheets above are independent fragments and
   collide on two names. Neither fragment is edited; the collision is resolved
   here, once, where it can be read.

   1. `--sx-card-w` means two things. Section 10 uses it as the carousel's
      scroll-snap column (min(78vw, 21rem)); the scorecard sheet redeclares it
      on `.sx` as the card's own 27.5rem width. The scorecard sheet loads last,
      so the carousel inherited a 440px column — wider than a phone viewport.
      The carousel's value is restored on the carousel element itself, so the
      scorecard keeps the `.sx` declaration it needs.

   2. `.sx .sx-sec h3` (0,2,1) in section 13 outranks `.sx .sx-gaps__head`
      (0,2,0) and repainted the scorecard's "Gap analysis" label from
      --sx-ink-4 to full white. The card sits inside `.sx-sec--hero`, so the
      host-page correction is the thing that has to yield, not the card.
   ========================================================================== */

.sx .sx-carousel{ --sx-card-w: min(78vw, 21rem); }

.sx .sx-sec .sx-gaps__head{ color: var(--sx-ink-4); }

/* --------------------------------------------------------------------------
   3. THE AMBIENT LAYER OUTLIVED ITS OWN PAGE.

   `.sx-bg` is position:fixed, which was correct for the preview harness it was
   written against: that page ended at its last section. This one does not. The
   site footer follows </main>, its containers are position:relative with
   z-index:auto and carry no background of their own, so a viewport-fixed black
   ground painted straight through the footer and left "Latest Insights" as
   dark type on black.

   The layer is pinned to the extent of `.sx` instead of to the viewport: an
   out-of-flow track spanning `.sx`, and the layer sticky inside it at exactly
   one viewport height. Every child of `.sx-bg` is sized in percentages of
   `.sx-bg` itself, so 100vh reproduces the fixed geometry to the pixel — the
   pulses keep their lines, lengths and phases — and the layer simply stops
   when the page's own content does. Reset the other three insets: `inset: 0`
   above sets all four, and a sticky box offered both top and bottom is not the
   box that was meant.
   -------------------------------------------------------------------------- */

.sx .sx-bg-track{
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  user-select: none;
}

.sx .sx-bg{
  position: sticky;
  top: 0;
  right: auto;
  bottom: auto;
  left: auto;
  width: 100%;
  height: 100vh;
}

/* The site scales body > main to zoom:.85 above 1025px (tblocks-brand.css).
   A fixed box did not care: its containing block is the viewport itself. A
   sticky box is inside the zoomed subtree, and `vh` there is an unzoomed CSS
   pixel, so 100vh renders at 85% of the viewport and leaves the grid ending
   on a visible horizontal edge partway up the screen — the radial mask is
   still ~49% opaque at that boundary, so it does not hide it. Divided back
   out by the site's own constant, which is the same number and the same
   reason as the --fs-micro compensation in section 1. */
@media (min-width: 1025px) {
  .sx .sx-bg{ height: calc(100vh / 0.85); }
}

/* --------------------------------------------------------------------------
   4. THE GRANT STRIP SAT UNDER THE AMBIENT LAYER.

   Every content band on this page is `.sx-sec`, which section 4 gives
   `position: relative; z-index: 1` so it paints above the background layer.
   The grant strip is not a `.sx-sec` — it is carried across whole from the
   page this one replaces, where there was no background layer to sit above —
   so it stayed static at z-index auto and the ambient layer painted its navy
   ground and both logos out. Same two declarations as every other band.
   -------------------------------------------------------------------------- */

.sx .sx-grant{
  position: relative;
  z-index: 1;
}


/* ==========================================================================
   15. THE MERIDIAN VENN — the requirement set, drawn.

   WHY IT EXISTS. Atlas has a scorecard and Meridian had nothing, so the two
   panels read as a product and a paragraph. This is Meridian's picture, and it
   is true rather than decorative: the engine takes an assessed asset and
   derives the document set an issuance requires, and that set is the place
   where three things agree — the instrument being issued, the asset backing
   it, and the parties who owe each document. The pack is the intersection, so
   the intersection is the only region drawn filled and the only one in accent.

   HOW THE MEANING REACHES A SCREEN READER. It does not reach it through the
   SVG. The drawing is aria-hidden and its <text> is decoration; the figcaption
   beneath is real prose naming the same three sets and the same conclusion,
   followed by the five document tiers as a real list. Delete the picture and
   nothing is lost but the picture.

   GEOMETRY. Three circles of r=78 on near-equilateral centres 88 apart, which
   is the deepest overlap that still leaves the three-way region wide enough to
   letter at the size this figure is capped to. The centre path is three arcs of
   those same circles between the pairwise crossings that fall inside the third.
   Coordinates and stroke widths live in the markup, as they do on the card's
   watermark: they are drawing, not spacing.

   MOTION. One-shot, and there is nothing to stop. The rings sweep in on a
   scroll-driven view() timeline and the core fills last. Everything else — the
   tints, every label, the caption — is painted at rest and is never animated,
   so the figure is complete and readable with the animation removed, which is
   what a reduced-motion reader, a printer and a browser without scroll-driven
   animations all get.
   ========================================================================== */

.sx {
  /* The figure's cap, and it is a design decision rather than a fallback. The
     labels scale with the drawing, so a Venn allowed to fill the panel sets its
     own labels larger than the prose beside it and inverts the hierarchy: this
     is support for the copy, not the headline. 20rem holds the smallest label
     at ~11px on a 390px phone and ~11px in a desktop panel, i.e. the same size
     in both. No token is a figure width. */
  --sx-venn-w: 20rem;

  /* Set tints. Opacities are on no token scale. 8% singly composites to ~22%
     where all three overlap, which is enough to read as "all three" and still
     dark enough to carry white type. */
  --sx-venn-tint: 0.08;
  --sx-venn-core-tint: 0.16;
}

.sx .sx-venn {
  display: grid;
  gap: var(--sp-5);
  justify-items: center;
  margin: 0;
}

.sx .sx-venn__svg {
  inline-size: 100%;
  max-inline-size: var(--sx-venn-w);
  block-size: auto;
  display: block;
}

/* One ink for all three rings. Three different accents would imply a ranking
   between instrument, asset and parties, and there is none — all three are
   preconditions. --sx-ink-3 is 6.5:1 on this ground, well past the 3:1 a
   graphical boundary needs. */
.sx .sx-venn__set {
  fill: var(--sx-ink);
  fill-opacity: var(--sx-venn-tint);
  stroke: var(--sx-ink-3);
}

/* The derived pack is the one thing in accent, because it is the one thing the
   engine produces. */
.sx .sx-venn__core {
  fill: var(--sx-accent-ink);
  fill-opacity: var(--sx-venn-core-tint);
  stroke: var(--sx-accent-ink);
}

.sx .sx-venn__name {
  fill: var(--sx-ink);
  font-family: var(--sans);
  font-weight: var(--fw-semibold);
}

.sx .sx-venn__sub {
  fill: var(--sx-ink-3);
  font-family: var(--sans);
  font-weight: var(--fw-regular);
}

/* --sx-accent-ink is 4.02:1 over the stacked tints at the centre and would
   fail as body-sized type. The lighter accent is 5.31:1 on the same ground and
   is the one BRAND.md reaches for when the ground has been lifted. */
.sx .sx-venn__core-name {
  fill: var(--sx-accent-hover);
  font-family: var(--sans);
  font-weight: var(--fw-semibold);
}

/* HOST-PAGE CORRECTION, in the sense of section 13. hello-elementor's reset
   ships `figcaption{color:#333;font-size:16px;font-style:italic;font-weight:400;
   line-height:1.4}` at (0,0,1). It is the only element on this page that arrives
   pre-italicised, and it italicised the caption, the tier label and all five
   pills. The colour is the worse half: #333 on black is 1.4:1, and it would have
   applied to any text in here that did not carry its own class. Every inherited
   property that reset sets is put back to the system's own. */
.sx .sx-venn__cap {
  display: grid;
  gap: var(--sp-3);
  inline-size: 100%;
  color: var(--sx-ink-2);
  font-style: normal;
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-normal);
}

/* The tiers are a list, so they are a `ul`; section 2 puts --sp-2 between
   stacked items, which is wrong inside a wrapping flex row. */
.sx .sx-tiers > li + li { margin-top: 0; }

/* Draw-in. Gated on both scroll-driven animation support AND motion being
   allowed, exactly as section 12 is, so the resting state — solid ring, no
   dash — is what every other reader sees. pathLength normalises each circle to
   100 units so one keyframe pair serves all three. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .sx .sx-venn__set {
      stroke-dasharray: 100;
      animation: sx-venn-draw linear both;
      animation-timeline: view();
      animation-range: entry 12% cover 34%;
    }
    .sx .sx-venn__set--b { animation-range: entry 16% cover 38%; }
    .sx .sx-venn__set--c { animation-range: entry 20% cover 42%; }

    .sx .sx-venn__core {
      animation: sx-venn-core linear both;
      animation-timeline: view();
      animation-range: entry 26% cover 46%;
    }
  }
}

@keyframes sx-venn-draw {
  from { stroke-dashoffset: 100; }
  to   { stroke-dashoffset: 0; }
}

@keyframes sx-venn-core {
  from { fill-opacity: 0; }
  to   { fill-opacity: var(--sx-venn-core-tint); }
}

@media print {
  .sx .sx-venn__set,
  .sx .sx-venn__core { animation: none; stroke-dasharray: none; }
}
@media (forced-colors: active) {
  .sx .sx-venn__set,
  .sx .sx-venn__core { animation: none; stroke-dasharray: none; }
}

/* ==========================================================================
   13. ENGINE ACCENTS — Atlas on the scorecard, Meridian on its own panel
   ==========================================================================
   The platform varies exactly one value per product and does it with
   [data-engine] on a subtree (packages/tokens/src/tokens.css:520-540). Same
   mechanism here, so the marketing page and the application cannot drift: the
   attribute goes on the element, and every rule underneath keeps reading
   --sx-accent as before. Nothing below restates a component.

   THE BRAND VALUES ARE FOR A LIGHT PAGE AND THIS PAGE IS BLACK.

   Computed with the WCAG formula against #000 and against the card ground
   #0F0F0F, not carried over:

     --atlas-base        #1A5C6E   2.80 / 2.56   FAILS as ink here
     --atlas-lifted      #288FAA   5.60 / 5.11   used
     --meridian-base     #C4872D   6.85 / 6.25   used
     --meridian-deep     #996A23   4.44 / 4.05   the light-page ink, too dim here
     --meridian-grad-from#D9A055   9.11 / 8.32   used where the accent is display-scale

   So Atlas takes its LIFTED value, which exists in the token file precisely
   because the base fails on a dark ground, and Meridian takes its base, which
   on black is already stronger than its light-page ink. No colour is invented
   and no value is hard-coded outside this block.
   ========================================================================== */

.sx [data-engine="atlas"] {
  --sx-atlas-ink:     #288FAA;   /* --atlas-lifted */
  --sx-atlas-deep:    #1A5C6E;   /* --atlas-base, washes and hairlines only */
  --sx-accent:        var(--sx-atlas-ink);
  --sx-accent-ink:    var(--sx-atlas-ink);
  --sx-accent-hover:  #3AA6C4;
  --sx-on-accent:     var(--navy-900);
}

.sx [data-engine="meridian"] {
  --sx-meridian-ink:  #C4872D;   /* --meridian-base */
  --sx-meridian-lift: #D9A055;   /* --meridian-grad-from */
  --sx-accent:        var(--sx-meridian-ink);
  --sx-accent-ink:    var(--sx-meridian-ink);
  --sx-accent-hover:  var(--sx-meridian-lift);
  --sx-on-accent:     var(--navy-900);
}

/* THE CARD'S COLOUR RUNS THROUGH --sx-band, WHICH IS ALSO THE BAND SIGNAL, so
   [data-engine] must NOT capture it -- the engine accent would repaint a
   meaning. The band ramp is set by the modifiers above and by section 16;
   these three lines are deleted rather than re-pointed. --sx-accent-ink is
   still Atlas teal underneath, which is what the panel head, the links and the
   Out-of-scope band read. */

/* The venn core is Meridian's one display-scale accent. */
.sx [data-engine="meridian"] .sx-venn__core { stroke: var(--sx-meridian-lift); }

/* --- The panel head and the tier pills carry the engine, not just the art ---
   With only the venn core and the card bars repainted, the two engine panels
   still read as one undifferentiated pair: the head ("01 — Score" / "02 —
   Structure") was --sx-ink and the tier pills were --sx-ink-dim, so the colour
   sat inside the illustrations and nowhere on the panel itself. These are the
   two places a reader looks first, so they are where the engine belongs.

   Both take --sx-accent, which [data-engine] has already re-pointed, so this
   is one rule serving both products rather than two rules naming two colours.
   Contrast on the panel ground: Atlas #288FAA 5.11:1, Meridian #C4872D 6.25:1
   -- both clear 4.5:1 as text. */
.sx [data-engine] .sx-panel__hd { color: var(--sx-accent-ink); }
.sx [data-engine="meridian"] .sx-pill {
  color: var(--sx-accent-ink);
  border-color: color-mix(in srgb, var(--sx-accent-ink) 42%, transparent);
}

/* ==========================================================================
   14. THE CARD READ FLAT, AND THE ART VANISHED ON A PHONE
   ==========================================================================
   Two things Henri caught on a live handset.

   1. THE BARS. Every bar, the coverage fill, the strip and the band were one
   Atlas teal, so the card had a colour but no contrast -- four dimension bars
   of identical hue differing only in length, which at a glance is a texture
   rather than a reading.

   The bars now step along the Atlas ramp, keyed to the level word ALREADY
   PRINTED at the end of each row. That is the whole reason this is safe: the
   colour restates a word the reader can see, so it adds no signal of its own
   and it is not information conveyed by colour alone. It is emphatically not
   the public card's green/amber/red, which on a card that prints no figures
   would read as a rating scale.

     strong    #45B4D1   7.94:1 on the card ground
     adequate  #288FAA   5.11:1
     limited   #207187   3.44:1   (UI threshold is 3)
     not scored           unchanged: a dashed empty track, never a fill at zero

   2. THE ART. `@media (max-width: 30rem) { .sx-card__mark { display: none } }`
   removed the lighthouse entirely on a phone -- which is most of the traffic,
   and the one place the card most needs a mark to be recognisable. It stays
   now: smaller, and pulled to the band's baseline so it sits beside the
   verdict instead of competing with it for the top row.
   ========================================================================== */

/* The Atlas ramp these three lines used to carry is superseded by section 16.
   The bars now step along --sx-ok / --sx-warn / --sx-bad, which is what the
   band pills in the Atlas panel below already use. */

@media (max-width: 30rem) {
  .sx .sx-card__mark {
    display: block;
    inline-size: var(--sp-16);
    block-size: auto;
    opacity: .14;                /* one step quieter: it is nearer the type here */
    margin-block-start: calc(var(--sp-2) * -1);
  }
}


/* ==========================================================================
   16. THE DESIGN PASS — eight things the client named on a live page
   ==========================================================================

   Everything below is new structure or a re-pointed colour. Nothing above is
   deleted except the three Atlas band lines and the three Atlas bar lines,
   which section 13 and section 14 now say were superseded here.

   ---------------------------------------------------------------- 4. COLOUR
   THE CARD WAS DISAGREEING WITH THE PAGE. The scorecard ran a uniform Atlas
   teal ramp, on the argument that green/amber/red would read as a rating scale.
   That argument loses to a fact about this page: the Atlas panel four sections
   down ships `.sx-pill--strong` green, `--conditional` amber, `--notready` red
   and `--scope` teal, and has since the sheet was written. A card that paints
   "Conditional Fit" teal is therefore not avoiding a rating scale -- it is
   contradicting the legend printed on the same page, which is worse. The card
   is aligned to the pills, and the pills are unchanged.

   The values are the roles section 1 already declares. They are NOT new hexes:
   --sx-ok / --sx-warn / --sx-bad resolve to the shared status tokens, lifted
   46% toward white when the OS is light (because tokens.css has not lifted them
   yet at that point) and taken raw when it is dark (because tokens.css already
   has). Both states are computed below.

   CONTRAST, computed with the WCAG formula. The ground is the card itself:
   --sx-surface is n-900 at 62% over black = #070C11, and #0B1419 where the
   ambient glow is at its strongest under the card. Both are given; the second
   is the worse of the two and is the one that has to pass.

     role   OS light   value      vs #070C11   vs #0B1419
     ok     yes        #96C2AE       9.89         9.40
     warn   yes        #C2A68A       8.49         8.07
     bad    yes        #E2A49D       9.36         8.90
     ok     no         #45C795       9.20         8.75
     warn   no         #C79A4E       7.62         7.24
     bad    no         #E26D6D       6.20         5.89
     coverage fill     --n-400       6.98         6.64

   Worst case 5.89:1. Body text needs 4.5, a UI boundary needs 3, and every
   value here is used as both (the verdict wordmark is text; the dot, the strip
   and the four bars are UI). All pass in both theme states.

   The bar colour still restates a word already printed at the end of its own
   row -- Strong, Adequate, Limited -- so it remains a second encoding of
   something visible, never information carried by colour alone.
   ========================================================================== */

.sx .sx-dim[data-level="strong"]   .sx-bar__fill{ background: var(--sx-ok); }
.sx .sx-dim[data-level="adequate"] .sx-bar__fill{ background: var(--sx-warn); }
.sx .sx-dim[data-level="limited"]  .sx-bar__fill{ background: var(--sx-bad); }


/* --------------------------------------------------------------------------
   1. THE HERO GAP, AND THE CARD THAT SAT TOO FAR RIGHT

   MEASURED at 1512 before this change: the left column ended at y=540 and the
   card's footer at y=911, so 371px of the first screen was empty black. On the
   other axis the split was `1fr 1.05fr` with a 75.6px gap and the card
   right-aligned inside a 678px column at its own 440px, which left 238px of
   dead column between text and card -- a 314px channel in all.

   Both are closed here. The figures fill the column (see .sx-figs), the card
   column is sized TO the card so no dead column remains, and the gap is cut to
   3vw. The card also grows to 31rem, which is what actually moves it left: its
   right edge stays on the site's own content margin, where every other page's
   content ends, so widening it is the only way its LEFT edge travels.
   -------------------------------------------------------------------------- */

.sx{ --sx-hero-card: 31rem; }

@media (min-width: 980px) {
  .sx .sx-sec--hero .sx-split{
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--sx-hero-card));
    gap: clamp(var(--sp-8), 3vw, var(--sp-12));
  }
  .sx .sx-sec--hero .sx-hero__stage{ justify-content: flex-end; }
  .sx .sx-sec--hero .sx-card{ --sx-card-w: var(--sx-hero-card); }
}

/* The four outcome figures, in the hero's left column. Two up, because the
   column is ~860px and four across would set 200px measures under a 100px
   headline. Four across only in the band where the hero has already stacked and
   the row has the full container to itself. */
.sx .sx-figs{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-5) var(--sp-6);
  margin: 0;
  padding-block-start: var(--sp-5);
  border-block-start: var(--sx-hair) solid var(--sx-line-2);
}
.sx .sx-figs > li + li{ margin-top: 0; }

.sx .sx-fig{
  display: grid;
  gap: var(--sp-1);
  align-content: start;
}

.sx .sx-fig__n{
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  color: var(--sx-accent-ink);
}

.sx .sx-fig__t{
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--sx-ink-3);
}

@media (min-width: 560px) and (max-width: 979px) {
  .sx .sx-figs{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 760px) {
  .sx .sx-fig__t{ font-size: var(--sx-fs-body); }
}


/* --------------------------------------------------------------------------
   2. THE TWO ENGINE PANELS WERE NOT THE SAME HEIGHT

   They already stretched -- they are grid items -- so the complaint was the
   other half: Atlas ran out of content and left its bottom empty while Meridian
   carried the Venn. The fix is content, not padding. The four bands were
   already on the Atlas panel as a bare row of pills with no statement of what
   any of them MEANS; each now has its sentence, which is the thing a reader
   most needs and the thing that squares the two columns.
   -------------------------------------------------------------------------- */

.sx .sx-panel{ display: flex; flex-direction: column; }
.sx .sx-panel__body{ display: flex; flex-direction: column; flex: 1 1 auto; }

/* Both panels stretch, so the residual difference lands somewhere. Put it ABOVE
   the Atlas legend rather than below the last line: the two panels then end
   flush and the slack reads as a rhythm between two blocks, which is what
   alignment is for. Nothing is padded and no element is stretched. */
.sx [data-engine="atlas"] .sx-bands{ margin-block-start: auto; }

.sx .sx-bands{
  display: grid;
  gap: var(--sp-3);
  padding-block-start: var(--sp-4);
  border-block-start: var(--sx-hair) solid var(--sx-line-2);
}

.sx .sx-bands__cap{
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-normal);
  color: var(--sx-ink-3);
}

.sx .sx-bands__list{ display: grid; gap: var(--sp-3); }
.sx .sx-bands__list > li + li{ margin-top: 0; }

.sx .sx-band-row{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
}
.sx .sx-band-row .sx-pill{ justify-self: start; }

.sx .sx-band-row__t{
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--sx-ink-2);
}

/* Below this the pill column and a readable measure cannot both fit. */
@media (max-width: 26rem) {
  .sx .sx-band-row{ grid-template-columns: minmax(0, 1fr); }
}


/* --------------------------------------------------------------------------
   3. BULLETS THAT WERE NOT BULLETS

   `.sx li{ list-style: none }` in section 2 is right for pill rows and card
   lists, and it silently applied to the three real bullet lists in the engine
   panels: they shipped as three unmarked lines that read as a paragraph with
   odd breaks. A marker is put back explicitly, in the block's own accent, so
   [data-engine] carries it.
   -------------------------------------------------------------------------- */

.sx .sx-ticks{ display: grid; gap: var(--sp-3); }
.sx .sx-ticks > li{
  position: relative;
  margin-top: 0;
  padding-inline-start: var(--sp-6);
}
.sx .sx-ticks > li::before{
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.55em;
  inline-size: var(--sp-2);
  block-size: var(--sp-2);
  border-radius: var(--r-pill);
  background: var(--sx-accent-ink);
}


/* --------------------------------------------------------------------------
   5. THE THIRD BLOCK — WHERE THE MANAGER ENDS UP

   Full width under the two engines, so the section reads 01 / 02 / 03 rather
   than as a pair with an appendix. No [data-engine]: going to market is not an
   engine, and it takes the house accent.
   -------------------------------------------------------------------------- */

.sx .sx-panel__body--split{
  display: grid;
  gap: var(--sp-6);
}
.sx .sx-panel__body--split > * + *{ margin-top: 0; }
.sx .sx-panel__body--split > * > * + *{ margin-top: var(--sp-4); }

@media (min-width: 760px) {
  .sx .sx-panel__body--split{
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-10);
  }
}


/* --------------------------------------------------------------------------
   6. "HOW IT WORKS" WAS NOT DESIGNED

   Four numerals over four sentences in a bare 4-up grid: no container, no
   boundary, and nothing anywhere that said the four were ordered. Numbered
   containers now, each with a title of its own, and a connector drawn by the
   step it leaves. The connector is hidden on the last item of each ROW as well
   as on the last item overall -- an `inset-inline-start: 100%` rule on an
   end-of-row item draws into the page gutter, which is a real horizontal
   overflow and shows no scrollbar on this site (overflow-x: clip).
   -------------------------------------------------------------------------- */

.sx .sx-steps{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-6);
}
.sx .sx-steps > li{ margin-top: 0; }

.sx .sx-step{
  position: relative;
  display: grid;
  gap: var(--sp-2);
  align-content: start;
  padding: var(--sp-5);
  background: var(--sx-ground-2);
  border: var(--sx-hair) solid var(--sx-line-strong);
  border-radius: var(--r-lg);
}

.sx .sx-step__n{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--sp-8);
  block-size: var(--sp-8);
  border-radius: var(--r-pill);
  border: var(--sx-hair) solid color-mix(in srgb, var(--sx-accent-ink) 45%, transparent);
  background: color-mix(in srgb, var(--sx-accent-ink) 14%, var(--sx-ground-2));
  color: var(--sx-accent-ink);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
}

.sx .sx-step__t{
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
}

.sx .sx-step__d{
  font-size: var(--sx-fs-body);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-2);
}

/* Stacked: the connector runs down from the badge's own centre line. */
.sx .sx-step::after{
  content: "";
  position: absolute;
  background: var(--sx-line-strong);
  inset-inline-start: calc(var(--sp-5) + var(--sp-4));
  inset-block-start: 100%;
  inline-size: var(--sx-hair);
  block-size: var(--sp-6);
}
.sx .sx-steps > .sx-step:last-child::after{ content: none; }

@media (min-width: 760px) {
  .sx .sx-steps{ grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-8); }
  .sx .sx-step::after{
    inset-inline-start: 100%;
    inset-block-start: calc(var(--sp-5) + var(--sp-4));
    inline-size: var(--sp-8);
    block-size: var(--sx-hair);
  }
}
@media (min-width: 760px) and (max-width: 979px) {
  .sx .sx-steps > .sx-step:nth-child(2n)::after{ content: none; }
}
@media (min-width: 980px) {
  .sx .sx-steps{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .sx .sx-steps > .sx-step:nth-child(2n)::after{ content: ""; }
  .sx .sx-steps > .sx-step:nth-child(4)::after{ content: none; }
}


/* --------------------------------------------------------------------------
   7. THE SAME CLASS OF PROBLEM, ELSEWHERE ON THE PAGE

   a. A SUBTITLE THAT DID NOT READ AS ONE. Every section opened eyebrow +
      statement and then dropped straight into prose set at the same weight as
      the prose three sections down. A subtitle now carries an accent rule at
      its start, which is the one mark on this page that means "this belongs to
      the heading above it".

   b. A TRAILING SENTENCE THAT READ AS A FIFTH STEP. Two sections ended on a
      full-width paragraph doing the work of a footnote -- the not-ready caveat
      and the investor-money clause. Both are now notes with a boundary.

   c. THREE ROLES INSIDE ONE 26-WORD SENTENCE. "Who is involved" stated the
      division of responsibility in prose, so a reader had to parse it to see
      that there were three of anything. One container each.

   d. THE CAROUSEL'S CARD TITLES DID NOT READ AS TITLES. They are h3, and they
      were set at --fs-sm, one step BELOW the body text beneath them, which is
      the definition of a heading that does not read as a heading. Sized up, and
      each card now carries its index so seven reads as a set rather than as an
      unbounded scroll.

   e. THE CAROUSEL'S BUTTONS SAT IN A BAND OF THEIR OWN between the headline and
      the track, where nothing connected them to it. They move onto the heading
      row (.sx-head-row in the markup).
   -------------------------------------------------------------------------- */

.sx .sx-subtitle{
  font-size: var(--sx-fs-lede);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-3);
  max-width: 54ch;
  padding-inline-start: var(--sp-4);
  border-inline-start: var(--sx-hair-lit) solid var(--sx-accent-ink);
}

.sx .sx-note{
  padding: var(--sp-4) var(--sp-5);
  border: var(--sx-hair) solid var(--sx-line-2);
  border-inline-start: var(--sx-hair-lit) solid var(--sx-accent-ink);
  border-radius: var(--r-xs);
  background: var(--sx-ground-3);
  font-size: var(--sx-fs-body);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-2);
  max-width: 72ch;
}

.sx .sx-roles{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4);
}
.sx .sx-roles > li{ margin-top: 0; }

.sx .sx-role{
  display: grid;
  gap: var(--sp-2);
  align-content: start;
  padding: var(--sp-5);
  background: var(--sx-ground-3);
  border: var(--sx-hair) solid var(--sx-line-2);
  border-block-start: var(--sx-hair-lit) solid var(--sx-accent-ink);
  border-radius: var(--r-lg);
}

.sx .sx-role__t{
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--sx-ink);
}

.sx .sx-role__d{
  font-size: var(--sx-fs-body);
  line-height: var(--lh-relaxed);
  color: var(--sx-ink-2);
}

@media (min-width: 760px) {
  .sx .sx-roles{ grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-6); }
}

.sx .sx-head-row{
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5) var(--sp-8);
}
.sx .sx-head-row > *{ min-width: 0; }

.sx .sx-carousel .sx-panel__hd{
  align-items: baseline;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  padding-block: var(--sp-5);
}

.sx .sx-panel__n{
  flex: none;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-normal);
  color: var(--sx-accent-ink);
}
