/* ==========================================================================
   Soulogix overrides
   Loaded after the HighTech theme's style.css. Everything brand-specific lives
   here so the vendor stylesheet stays untouched and upgradeable.
   ========================================================================== */

/* --- Compact scale -------------------------------------------------------- */

/* The theme was tuned on a wide desktop. Laptops mostly run Windows display
   scaling at 125-150%, which hands the browser a 1200-1400px CSS viewport while
   the screen is physically 1920px — so everything arrives proportionally larger
   than it was designed to be, and the page feels cramped.
 *
 * Dropping the root font size in that band compacts the whole theme in one
 * move: Bootstrap's spacing utilities, the HighTech stylesheet and every clamp()
 * in this file are rem-based, so they all follow. Fixed pixel values that do not
 * follow — the header capsule, the logo lockup — are stepped down alongside it.
 *
 * Deliberately bounded. Below 992px the layout is already single-column and
 * shrinking type would only hurt legibility; above 1600px is the wide desktop
 * the design was drawn for, and it is left exactly as it was.
 */
@media (min-width: 992px) and (max-width: 1599.98px) {
    html { font-size: 15px; }
}

@media (min-width: 992px) and (max-width: 1279.98px) {
    html { font-size: 14.5px; }
}

:root {
    /* Black palette taken from evconnect.com: #091717 is a near-neutral black
       with only a whisper of teal. It reads sharper than a blue-leaning dark
       because the neutral ramp keeps edges crisp. */
    --sx-black:      #091717;
    --sx-black-deep: #050F0F;
    /* Strong diagonal grades in the brand teal. The resting card already reads
       as a gradient; the focused one drives the teal much harder at the top-left
       so the light plainly comes from in front. */
    --sx-surface:    linear-gradient(152deg,
                        rgba(24, 58, 55, .88) 0%,
                        rgba(14, 36, 37, .88) 42%,
                        rgba(8, 21, 22, .90) 100%);
    --sx-surface-hi: linear-gradient(145deg,
                        #235E54 0%,
                        #18463F 26%,
                        #103031 55%,
                        #0B2124 80%,
                        #081A1C 100%);
    --sx-hairline:   rgba(255, 255, 255, .07);

    --sx-header-from: #091717;
    --sx-header-mid:  #0B1B1B;
    --sx-header-to:   #071414;

    /* White menu on near-black is 18.9:1 — the highest contrast available. */
    --sx-header-ink:        #ffffff;
    --sx-header-ink-active: #32d9cb;

    --sx-header-height:        66px;
    --sx-header-height-mobile: 54px;
    /* Ramp the capsule and the lockup with the compact band below. Not as tight
       as the mid-page content — the header is chrome, and squeezing it reads as
       cramped rather than compact. */
    --sx-header-height-lap:    60px;
    --sx-logo-height-lap:      48px;
    /* Whole-lockup heights. The wordmark is 279 of the artwork's 452 rows, so
       52px here renders the letters at ~32px — the size they have always been.
       The rest is the tagline the artwork now carries. */
    --sx-logo-height:          52px;
    --sx-logo-height-mobile:   46px;

    /* Roughly the cookie banner's height plus its offset. Used by the hero to
       stay clear of it; only needs to be close, not exact. */
    --sx-cookie-reserve:       104px;
}

/* --- Hero ---------------------------------------------------------------- */

.sx-hero {
    position: relative;
    isolation: isolate;
    /* Full first screen, so the canvas is the whole opening view rather than a
       band with page behind it. svh is the viewport height with mobile browser
       chrome showing, which stops the hero jumping as the address bar hides. */
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    align-items: center;
    background: var(--sx-black);
    overflow: hidden;
}

/* Canvas carries both layers: falling dots, and the undulating logic surface. */
.sx-hero__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    z-index: 0;
}

/* Keeps the headline legible over the brightest part of the surface. */
.sx-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(ellipse 70% 55% at 50% 42%,
                rgba(9, 23, 23, .72) 0%,
                rgba(9, 23, 23, .35) 55%,
                rgba(9, 23, 23, 0) 100%);
}

/* Extra clearance at the top so the eyebrow never tucks under the floating
   capsule, which now overlaps the hero. */
.sx-hero__inner {
    position: relative;
    z-index: 2;
    text-align: center;
    padding-top: calc(var(--sx-header-height) + clamp(2rem, 5vh, 4rem));
    padding-bottom: clamp(3.5rem, 9vh, 6rem);
}

@media (max-width: 991.98px) {
    .sx-hero__inner { padding-top: calc(var(--sx-header-height-mobile) + 2.5rem); }
}

/* The H1 is the largest thing in the hero, because it is the page's heading and
   a heading that is smaller than the text beneath it reads as a label.
   It was previously set at eyebrow size, which left the visual order upside
   down: H1, then a rotating line three times its size, then a description the
   same size as the H1.
   The scale is now H1 > rotating service line > description, which is both the
   semantic order and the reading order. */
.sx-hero__h1 {
    color: #fff;
    font-size: clamp(2.05rem, 1.35rem + 3.1vw, 3.85rem);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.08;
    text-wrap: balance;
    /* The gap that separates the fixed heading from the rotating block. Wide
       enough that the two read as two distinct pieces rather than one wrapped
       sentence — at the old 1rem they ran together. */
    margin: 0 0 clamp(2.4rem, 4.4vw, 4rem);
}

.sx-hero__eyebrow {
    color: #32d9cb;
    font-size: clamp(.95rem, .85rem + .4vw, 1.15rem);
    font-weight: 600;
    letter-spacing: .04em;
    margin: 0 0 1rem;
}

/* Slides stack in one grid cell so rotating never shifts the layout below. */
.sx-hero__slides {
    display: grid;
    /* Was 1.5rem with a separate paragraph below contributing another 2rem.
       That paragraph is now inside each slide, so this carries the whole gap
       down to the buttons. */
    margin-bottom: 2.25rem;
    cursor: default;
}

/* Faint cue that hovering has held the rotation. */
.sx-hero__slides.is-paused .sx-hero__slide.is-active span {
    text-shadow: 0 0 26px rgba(50, 217, 203, .55);
}

/* Slides travel like a carousel: the outgoing line exits left while the next
   one comes in from the right. Idle slides wait off-stage on the right. */
.sx-hero__slide {
    grid-area: 1 / 1;
    margin: 0;
    color: #fff;
    /* Stepped down from a 4.25rem maximum so it sits clearly below the H1.
       Still the second-largest thing on the page, and still the element that
       moves, which is what draws the eye — size is not the only way to make
       something the focus. */
    font-size: clamp(1.35rem, 1.05rem + 1.45vw, 2.3rem);
    line-height: 1.2;
    font-weight: 600;
    letter-spacing: -.01em;
    text-wrap: balance;
    opacity: 0;
    transform: translateX(70px);
    transition: opacity .45s cubic-bezier(.22, .61, .36, 1),
                transform .55s cubic-bezier(.22, .61, .36, 1);
    pointer-events: none;
    will-change: transform, opacity;
}

/* The incoming line waits for the outgoing one to clear. Done with a delay
   rather than a JS timer so the two can never get out of sync. */
.sx-hero__slide.is-active {
    opacity: 1;
    transform: translateX(0);
    pointer-events: auto;
    transition: opacity .45s cubic-bezier(.16, 1, .3, 1) .38s,
                transform .6s cubic-bezier(.16, 1, .3, 1) .38s;
}

.sx-hero__slide.is-leaving {
    opacity: 0;
    transform: translateX(-70px);
}

.sx-hero__slide span { color: #32d9cb; }

.sx-hero__cta {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    justify-content: center;
    margin-bottom: clamp(2.5rem, 6vh, 4rem);
}

.sx-hero__btn {
    display: inline-block;
    padding: .95rem 2.4rem;
    border-radius: 999px;
    border: 1px solid rgba(50, 217, 203, .55);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
    background: rgba(9, 23, 23, .5);
    transition: background-color .25s ease, border-color .25s ease, box-shadow .25s ease;
}

.sx-hero__btn:hover,
.sx-hero__btn:focus-visible {
    color: #fff;
    border-color: #32d9cb;
    background: rgba(50, 217, 203, .14);
    box-shadow: 0 0 26px rgba(50, 217, 203, .28);
    outline: none;
}

.sx-hero__btn--primary {
    background: linear-gradient(90deg, #1fbfb2 0%, #32d9cb 100%);
    border-color: transparent;
    color: var(--sx-black);
}

.sx-hero__btn--primary:hover,
.sx-hero__btn--primary:focus-visible {
    color: var(--sx-black);
    background: linear-gradient(90deg, #32d9cb 0%, #5fe9dc 100%);
    box-shadow: 0 0 32px rgba(50, 217, 203, .42);
}

/* The figures float free over the animation, which leaves them competing with
   whatever the canvas happens to be drawing behind them. Sitting them in a
   frosted panel settles the contrast and gives the block an edge to read
   against — the treatment in Reference-1.
   inline-flex so the panel hugs its contents; .sx-hero__inner centres it. */
.sx-hero__stats {
    list-style: none;
    margin: 0 auto;
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: stretch;
    gap: 0;
    padding: clamp(.9rem, 1.6vw, 1.35rem) clamp(.5rem, 1.4vw, 1rem);
    border-radius: 20px;
    /* Haze, not a lid. The wash is kept faint and the blur short so the wave
       grid and the falling dots still read through the glass — the panel is
       defined by its edge and its softening, not by hiding what is behind it.
       The type is white on an already near-black animation, so it holds up
       without a heavier fill. */
    background: linear-gradient(160deg,
                rgba(22, 60, 60, .20) 0%,
                rgba(8, 28, 30, .12) 55%,
                rgba(4, 16, 18, .18) 100%);
    border: 1px solid rgba(153, 255, 255, .20);
    box-shadow: 0 20px 50px rgba(0, 0, 0, .38),
                inset 0 1px 0 rgba(153, 255, 255, .12);
    /* Short blur on purpose. The canvas draws 1px grid lines and small dots;
       anything past ~3px smears them out entirely and the panel turns into a
       flat slab no matter how transparent the wash is. This softens without
       erasing. */
    -webkit-backdrop-filter: blur(2.5px) saturate(125%);
    backdrop-filter: blur(2.5px) saturate(125%);
}

/* No backdrop-filter (older Firefox, some in-app browsers): there is no blur to
   separate the panel from the canvas, so the wash has to do it alone. Still
   translucent — just enough to hold an edge. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .sx-hero__stats {
        background: linear-gradient(160deg,
                    rgba(10, 34, 35, .58) 0%,
                    rgba(5, 18, 20, .52) 100%);
    }
}

.sx-hero__stats li {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .15rem;
    padding-inline: clamp(1.1rem, 3vw, 2.4rem);
}

/* Hairline dividers that fade out top and bottom, so they read as separators
   rather than as a table rule. */
.sx-hero__stats li + li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 10%;
    bottom: 10%;
    width: 1px;
    background: linear-gradient(180deg,
                rgba(153, 255, 255, 0) 0%,
                rgba(153, 255, 255, .26) 50%,
                rgba(153, 255, 255, 0) 100%);
}

.sx-hero__stats strong {
    color: #fff;
    font-size: clamp(1.15rem, 1rem + .6vw, 1.6rem);
    font-weight: 700;
    line-height: 1.2;
}

.sx-hero__stats span {
    color: rgba(200, 220, 218, .72);
    font-size: .88rem;
}

@media (max-width: 575.98px) {
    /* Wrapped rows make vertical dividers meaningless — drop them and let the
       panel itself do the grouping. */
    .sx-hero__stats {
        display: flex;
        gap: 1.1rem .25rem;
        padding-inline: .75rem;
        border-radius: 18px;
    }

    .sx-hero__stats li { padding-inline: .5rem; flex: 1 1 40%; }
    .sx-hero__stats li + li::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .sx-hero__slide { transition: none; }
}

/* --- Services bento ------------------------------------------------------ */

.sx-services {
    position: relative;
    isolation: isolate;
    background: var(--sx-black);
    padding-block: clamp(4rem, 9vw, 7rem);
}

/* Circuit-trace photograph of sorts: generated PCB routing, near-black, kept
   well under the content so it reads as texture rather than decoration. */
.sx-services__grid-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: url("../img/sx-services-bg.jpg");
    background-size: cover;
    background-position: center;
    opacity: 1;
}

/* Live circuit: static routing with data pulses running along it. Sits above
   the still image and below the content. */
.sx-services__canvas {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    display: block;
    pointer-events: none;
}

/* Light wash only — enough to keep type comfortable without erasing the texture.
   The live canvas sits above this, so the still image only has to supply depth. */
.sx-services__grid-bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse 75% 65% at 50% 45%, rgba(9, 23, 23, .2) 0%, rgba(9, 23, 23, .68) 100%),
        linear-gradient(var(--sx-black) 0%, transparent 14%, transparent 86%, var(--sx-black) 100%);
}

.sx-services__inner { position: relative; z-index: 2; }

.sx-services__head { text-align: center; max-width: 44rem; margin: 0 auto clamp(2.5rem, 5vw, 4rem); }
/* Section label: uppercase and tracked so it carries weight against the
   heading instead of reading smaller than the paragraph beneath it. */
.sx-services__eyebrow {
    display: inline-block;
    color: #32d9cb;
    font-size: clamp(.95rem, .9rem + .2vw, 1.1rem);
    font-weight: 700;
    letter-spacing: .2em;
    text-transform: uppercase;
    margin: 0 0 1rem;
    padding: .35rem .9rem;
    border: 1px solid rgba(50, 217, 203, .32);
    border-radius: 999px;
    background: rgba(50, 217, 203, .08);
}
.sx-services__title {
    color: #fff;
    font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.85rem);
    line-height: 1.15;
    letter-spacing: -.02em;
    margin: 0 0 1rem;
    text-wrap: balance;
}
.sx-services__lede { color: rgba(214, 230, 228, .74); margin: 0; }

/* Perspective on the grid means a focused tile travels toward the viewer on the
   Z axis rather than just getting bigger, and because the vanishing point sits
   at the centre, tiles at the edges lean inward as they come forward. */
.sx-bento {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: clamp(.9rem, 1.6vw, 1.4rem);
    align-items: stretch;
    perspective: 1400px;
    perspective-origin: 50% 50%;
}
/* Two tiles a row, and the wide one changes sides: 4+2, then 2+4, then 4+2.
   Every row fills the six columns exactly, and the alternation is what stops
   the grid reading as one wide tile with a column of offcuts beside it.

   Written as a four-step cycle rather than tile by tile so adding a service
   cannot leave a row half empty — which is what happened here: the count went
   to four, the rules only placed 4+2 then 2+2, and the second row ran two
   narrow tiles with a third of the grid left blank beside them. */
.sx-bento > :nth-child(4n+1),
.sx-bento > :nth-child(4n+4) { grid-column: span 4; }
.sx-bento > :nth-child(4n+2),
.sx-bento > :nth-child(4n+3) { grid-column: span 2; }
/* An odd count leaves the last tile on a row of its own, so it takes all six. */
.sx-bento > :last-child:nth-child(odd) { grid-column: span 6; }

@media (max-width: 991.98px) {
    .sx-bento { grid-template-columns: repeat(2, 1fr); }
    .sx-bento > * { grid-column: span 1 !important; }
}
@media (max-width: 575.98px) {
    .sx-bento { grid-template-columns: 1fr; }
}

.sx-tile {
    position: relative;
    z-index: 1;
    --sx-tile-pad: clamp(1.35rem, 2.4vw, 2rem);
    border: 1px solid var(--sx-hairline);
    border-radius: 14px;
    background: var(--sx-surface);
    /* The whole card responds to hover, so the pointer has to say so. */
    cursor: pointer;
    will-change: transform;
    /* Only transform and border-color animate here. Animating box-shadow and
       background-color forces a repaint on every frame, which is what made the
       hover feel gritty however the easing was tuned. */
    transition:
        transform .55s cubic-bezier(.16, 1, .3, 1),
        border-color .55s ease;
}

/* The hover surface and its shadow live on a pseudo-element and simply fade in.
   Opacity is composited, so nothing repaints mid-animation. */
.sx-tile::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    background: var(--sx-surface-hi);
    box-shadow: 0 26px 60px rgba(0, 0, 0, .7);
    opacity: 0;
    pointer-events: none;
    transition: opacity .5s cubic-bezier(.16, 1, .3, 1);
}

.sx-tile:hover::before,
.sx-tile:focus-within::before,
.sx-tile.is-open::before { opacity: 1; }

/* Hover pulls the tile forward: a modest zoom, a lighter surface so the content
   gains contrast, and a deep shadow that separates it from its neighbours.
   Scaling in place means nothing else on the grid moves. */
/* translateZ(70px) at 1400px perspective works out to roughly a 5% enlargement,
   but it arrives as depth rather than a flat scale. */
.sx-tile:hover,
.sx-tile:focus-within,
.sx-tile.is-open {
    z-index: 30;
    transform: translateZ(70px);
    border-color: rgba(50, 217, 203, .5);
}

.sx-tile__glow {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0;
    pointer-events: none;
    border-radius: inherit;
    transition: opacity .4s ease;
    background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%),
                rgba(50, 217, 203, .13), transparent 62%);
}
.sx-tile:hover .sx-tile__glow { opacity: 1; }

/* Sheen: a band of light sweeps diagonally across the card once on hover.
   Clipped by its own wrapper so the card can still cast a shadow. */
.sx-tile__sheen {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
    overflow: hidden;
    pointer-events: none;
}
.sx-tile__sheen::before {
    content: "";
    position: absolute;
    top: -60%;
    left: 0;
    width: 34%;
    height: 220%;
    background: linear-gradient(90deg,
                transparent 0%,
                rgba(255, 255, 255, .05) 35%,
                rgba(50, 217, 203, .16) 55%,
                transparent 100%);
    transform: rotate(18deg) translateX(-260%);
    transition: transform 1.05s cubic-bezier(.16, 1, .3, 1);
}
.sx-tile:hover .sx-tile__sheen::before,
.sx-tile:focus-within .sx-tile__sheen::before { transform: rotate(18deg) translateX(420%); }

/* Accent rule that opens outward from the centre of the top edge. */
.sx-tile__edge {
    position: absolute;
    top: -1px;
    left: 50%;
    z-index: 3;
    height: 2px;
    width: 0;
    transform: translateX(-50%);
    border-radius: 2px;
    background: linear-gradient(90deg, transparent, #32d9cb 30%, #8bf4e9 50%, #32d9cb 70%, transparent);
    box-shadow: 0 0 14px rgba(50, 217, 203, .55);
    opacity: 0;
    pointer-events: none;
    transition: width .6s cubic-bezier(.16, 1, .3, 1), opacity .35s ease;
}
.sx-tile:hover .sx-tile__edge,
.sx-tile:focus-within .sx-tile__edge,
.sx-tile.is-open .sx-tile__edge { width: 86%; opacity: 1; }

.sx-tile__body {
    position: relative;
    z-index: 1;
    /* Named because the hover panel below has to undo it: the panel spans the
       whole card, not the padded column the rest of the content sits in. */
    padding: var(--sx-tile-pad);
    display: flex;
    flex-direction: column;
    height: 100%;
}

.sx-tile__top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }

.sx-tile__icon {
    font-size: 2rem;
    color: #32d9cb;
    line-height: 1;
    transition: transform .45s cubic-bezier(.22, .61, .36, 1);
}
/* Only where the tile is actually the wide one. Below 992 the grid is two
   equal columns, so an enlarged icon and title on the tiles that happen to lead
   a row reads as an inconsistency rather than a hierarchy. */
@media (min-width: 992px) {
    .sx-tile--lead .sx-tile__icon { font-size: 2.75rem; }
}
.sx-tile:hover .sx-tile__icon { transform: translateY(-3px); }

.sx-tile__code {
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .72rem;
    letter-spacing: .12em;
    color: rgba(50, 217, 203, .55);
}

.sx-tile__name {
    color: #fff;
    font-size: clamp(1.15rem, 1rem + .5vw, 1.5rem);
    line-height: 1.2;
    letter-spacing: -.01em;
    margin: 0 0 1rem;
}
@media (min-width: 992px) {
    .sx-tile--lead .sx-tile__name { font-size: clamp(1.5rem, 1.1rem + 1.2vw, 2.1rem); }
}

/* Two panes share one grid cell, so hovering swaps content without changing any
   geometry. Where there is no hover — touch, and the toggle that comes with it —
   the cell is as tall as the fuller of the two, because the panel opens in flow
   there and the tile must already have the room. Where there is hover, the rule
   below lifts the panel out of the cell so only the resting content counts. */
.sx-tile__panes { display: grid; flex: 1; }
/* Sequenced rather than simultaneous: the old pane clears first, then the new
   one settles in. Crossfading both at once is what read as a hard cut. */
.sx-tile__pane {
    grid-area: 1 / 1;
    transition: opacity .28s ease, transform .5s cubic-bezier(.16, 1, .3, 1);
}
/* Rest content spreads to fill the height the fuller pane reserves, so the
   collapsed state never shows a void under the text. */
.sx-tile__pane--rest { opacity: 1; transform: none; display: flex; flex-direction: column; }
.sx-tile__pane--rest .sx-tile__cue { margin-top: auto; padding-top: 1.15rem; }
.sx-tile__pane--more { opacity: 0; transform: translateY(10px); pointer-events: none; }

/* The panel drops out of the card instead of being budgeted for inside it.
   Reserving its height was costing every tile 130 to 200px of empty space in
   the state it is actually in almost all the time: the resting content is 150
   to 235px tall and the panel is 310 to 370, so the card was sized for the
   larger and the difference showed as a void under the text. Taking it out of
   flow sizes the row on what you can see, which is what makes a whole row fit
   on one screen.

   Nothing reflows: the tile is already lifted above its neighbours on hover, so
   the panel lands over the row below rather than moving it. It carries the
   card's own surface, border and radius so what hangs below reads as the card
   extending, not as a loose rectangle.

   Keyed on hover alone, the exact complement of the (hover: none) block that
   swaps the cue for a toggle: wherever the panel opens on hover it can hang
   out, and wherever it opens on a tap it stays in flow with the room reserved
   above. Width does not come into it — a narrow desktop window is still a
   pointer. */
@media (hover: hover) {
    .sx-tile__panes { position: relative; }

    .sx-tile__pane--more {
        position: absolute;
        top: 0;
        /* Out past the body's padding and its own border, so the panel lines up
           with the edges of the card rather than with the text inside it. */
        left: calc(-1 * (var(--sx-tile-pad) + 1px));
        right: calc(-1 * (var(--sx-tile-pad) + 1px));
        min-height: 100%;
        padding: 0 var(--sx-tile-pad) var(--sx-tile-pad);
        background: var(--sx-surface-hi);
        border: 1px solid rgba(50, 217, 203, .5);
        border-top: 0;
        border-radius: 0 0 14px 14px;
        box-shadow: 0 26px 60px rgba(0, 0, 0, .7);
    }
}

.sx-tile:hover .sx-tile__pane--rest,
.sx-tile:focus-within .sx-tile__pane--rest,
.sx-tile.is-open .sx-tile__pane--rest { opacity: 0; transform: translateY(-10px); pointer-events: none; }

.sx-tile:hover .sx-tile__pane--more,
.sx-tile:focus-within .sx-tile__pane--more,
.sx-tile.is-open .sx-tile__pane--more {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    transition: opacity .42s ease .16s, transform .55s cubic-bezier(.16, 1, .3, 1) .16s;
}

.sx-tile:hover .sx-tile__icon,
.sx-tile:focus-within .sx-tile__icon { transition-duration: .62s; }

.sx-tile__sum { color: rgba(214, 230, 228, .8); font-size: .95rem; margin: 0 0 1.15rem; }

.sx-tile__meta {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.75rem;
    margin: 0;
    padding-top: 1rem;
    border-top: 1px solid var(--sx-hairline);
}
.sx-tile__meta dt {
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .64rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(168, 190, 188, .7);
    font-weight: 400;
}
.sx-tile__meta dd { color: #e4f3f1; font-size: .88rem; margin: .1rem 0 0; }

.sx-tile__cue {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-top: 1.15rem;
    color: rgba(50, 217, 203, .85);
    font-size: .82rem;
    font-weight: 600;
}
/* A plus in a ring, not an arrow: it reads as "expand", and rotating it into a
   cross on hover states plainly that the tile is now open. */
.sx-tile__cue-icon {
    position: relative;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    border: 1px solid rgba(50, 217, 203, .45);
    border-radius: 50%;
    transition: transform .5s cubic-bezier(.16, 1, .3, 1),
                background-color .4s ease,
                border-color .4s ease;
}
.sx-tile__cue-icon::before,
.sx-tile__cue-icon::after {
    content: "";
    position: absolute;
    background: currentColor;
    border-radius: 1px;
}
.sx-tile__cue-icon::before { inset: 10px 5px auto 5px; height: 2px; }
.sx-tile__cue-icon::after  { inset: 5px 10px 5px auto; width: 2px; }

.sx-tile:hover .sx-tile__cue-icon,
.sx-tile:focus-within .sx-tile__cue-icon,
.sx-tile.is-open .sx-tile__cue-icon {
    transform: rotate(135deg);
    background: rgba(50, 217, 203, .16);
    border-color: #32d9cb;
}

.sx-tile__caps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
@media (min-width: 992px) {
    .sx-tile--lead .sx-tile__caps { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem 1.5rem; }
    .sx-tile--wide .sx-tile__caps { display: grid; grid-template-columns: repeat(3, 1fr); gap: .55rem 1.5rem; }
}
.sx-tile__caps li { position: relative; padding-left: 1.4rem; color: rgba(219, 234, 232, .88); font-size: .88rem; }
.sx-tile__caps li::before {
    content: "";
    position: absolute;
    left: 0; top: .5em;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: #32d9cb;
}

.sx-tile__label {
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .64rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(168, 190, 188, .7);
    margin: 1.15rem 0 .5rem;
}

.sx-tile__chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.sx-tile__chips span {
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .7rem;
    padding: .22rem .6rem;
    border: 1px solid rgba(50, 217, 203, .3);
    border-radius: 4px;
    color: rgba(50, 217, 203, .95);
}

.sx-tile__link {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    margin-top: 1.1rem;
    color: #fff;
    font-weight: 600;
    font-size: .9rem;
    text-decoration: none;
    border-bottom: 1px solid rgba(50, 217, 203, .5);
}
.sx-tile__link:hover { color: #32d9cb; border-bottom-color: #32d9cb; }

/* Wide closing tile reads across rather than as a squat box. */
@media (min-width: 992px) {
    .sx-tile--wide .sx-tile__panes { grid-template-columns: 1fr; }
    .sx-tile--wide .sx-tile__pane--rest {
        display: grid;
        grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
        column-gap: 2.5rem;
        align-items: start;
    }
    .sx-tile--wide .sx-tile__meta { padding-top: 0; border-top: 0; flex-direction: column; gap: .75rem; }
    .sx-tile--wide .sx-tile__cue { grid-column: 1 / -1; }
}

/* Toggle exists only where there is no hover to rely on. */
.sx-tile__toggle {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    margin-top: 1.15rem;
    background: transparent;
    border: 1px solid rgba(50, 217, 203, .3);
    border-radius: 999px;
    padding: .6rem 1.1rem;
    color: #32d9cb;
    font-size: .85rem;
    font-weight: 600;
    cursor: pointer;
}
.sx-tile__toggle-icon { position: relative; width: 12px; height: 12px; flex-shrink: 0; }
.sx-tile__toggle-icon::before,
.sx-tile__toggle-icon::after {
    content: "";
    position: absolute;
    background: currentColor;
    transition: transform .3s ease, opacity .3s ease;
}
.sx-tile__toggle-icon::before { inset: 5px 0 auto 0; height: 2px; }
.sx-tile__toggle-icon::after  { inset: 0 5px 0 auto; width: 2px; }
.sx-tile.is-open .sx-tile__toggle-icon::after { transform: rotate(90deg); opacity: 0; }

@media (hover: none) {
    .sx-tile__cue { display: none; }
    .sx-tile__toggle { display: flex; }
    .sx-tile:hover, .sx-tile.is-open { transform: none; }
}

/* --- Entrance: tiles wipe up in a staggered pattern ---------------------- */

/* Scoped to .sx-js: without scripting the content is simply visible. */
.sx-js [data-reveal] {
    opacity: 0;
    transform: translateY(30px);
    clip-path: inset(0 0 100% 0 round 14px);
    transition:
        opacity .5s ease var(--d, 0s),
        transform .75s cubic-bezier(.22, .61, .36, 1) var(--d, 0s),
        clip-path .75s cubic-bezier(.22, .61, .36, 1) var(--d, 0s);
}
.sx-js [data-reveal].is-in {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 0 0 round 14px);
}

@media (prefers-reduced-motion: reduce) {
    .sx-js [data-reveal] { opacity: 1; transform: none; clip-path: none; transition: none; }
    .sx-tile, .sx-tile__glow, .sx-tile__pane, .sx-tile__icon,
    .sx-tile::before, .sx-tile__edge, .sx-tile__cue-icon { transition: none; }
    .sx-tile__sheen { display: none; }   /* the sweep is pure decoration */
}

/* --- Floating header ----------------------------------------------------- */

/* Fixed rather than sticky: the hero canvas runs from y=0 and the capsule rides
   over the top of it. */
.sx-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1040;
    background: transparent;
    padding-block: clamp(.6rem, 1.4vw, 1.1rem);
    pointer-events: none;          /* the gap either side of the pill stays clickable-through */
}
.sx-header__shell { pointer-events: auto; }

/* Inner pages open with the themed page-header band, so that band simply grows
   its own top padding and the capsule floats over the image — the same
   arrangement as the hero, and no blank strip above it. */
.sx-main { padding-top: 0; }

.page-header {
    padding-top: calc(var(--sx-header-height) + 3.5rem) !important;
}

@media (max-width: 991.98px) {
    .page-header { padding-top: calc(var(--sx-header-height-mobile) + 2.5rem) !important; }
}

/* The capsule. Near-black at the left, opening out to the bright teal at the
   right — the same weights as before, read in the opposite direction:
   20% #001a1a · 35% #003333 · 25% #004d4d · 15% #006666 · 5% #00b3b3 */
.sx-header__bar {
    position: relative;
    border-radius: 999px;
    padding-inline: clamp(.9rem, 1.8vw, 1.5rem);
    /* The flat #001a1a run holds to 42% so the logo — which is widest relative
       to the capsule on small screens — always sits on solid colour. The logo
       PNG has that same colour baked in, so the two join invisibly. */
    background: linear-gradient(95deg,
                #001a1a 0%,
                #001a1a 42%,
                #003333 64%,
                #004d4d 83%,
                #006666 95%,
                #00b3b3 100%);
    /* The teal the hero's "Our Services" button is drawn in, at its own .55,
       rather than the near-white hairline this was. It is also the fallback:
       where the ring below cannot be drawn, this is the edge that shows. */
    border: 1px solid rgba(50, 217, 203, .55);
    /* Outer shadow, plus that button's own hover glow at the same 26px radius,
       so the capsule is lit by the same light. No inset highlight and no sheen
       across the fill: either would lighten the capsule but not the logo image
       sitting on it, and the colour baked into that PNG would then read as a
       darker rectangle. The gloss below is confined to the edge for exactly
       that reason. */
    box-shadow:
        0 14px 34px rgba(0, 0, 0, .5),
        0 0 26px rgba(50, 217, 203, .28);
}

/* The thick glossy edge. A border cannot hold a gradient, so the ring is its
   own layer: a box the size of the capsule, filled with the gradient, then
   masked down to just its outer few pixels — the padding is the ring's width.

   Glass is what the gradient describes. It is brightest where a light above and
   in front would catch the top-left of a curved rim, dims through the middle,
   and picks up a second, weaker highlight as the surface turns away at the
   bottom right. Flat teal all the way round reads as a drawn outline; this
   reads as something with a surface.

   Drawn inside the capsule's own box rather than added to it, so the header
   does not change height by a single pixel. */
.sx-header__bar::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    /* The ring's width. 3px read as a drawn band around the capsule rather than
       an edge on it — at 1.5 it is a rim, and the gradient does the rest. */
    padding: 1.5px;
    pointer-events: none;
    background: linear-gradient(155deg,
        rgba(198, 255, 250, .95) 0%,
        rgba(50, 217, 203, .70) 26%,
        rgba(50, 217, 203, .30) 52%,
        rgba(50, 217, 203, .55) 74%,
        rgba(178, 250, 245, .88) 100%);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
}

/* The theme's own overlays must not paint over the header. */
.carousel-caption,
.page-header,
.back-to-top { z-index: 1020; }

/* --- Height -------------------------------------------------------------- */

.sx-header .navbar {
    min-height: var(--sx-header-height);
    padding-top: 0;
    padding-bottom: 0;
}

.sx-header .navbar-nav {
    padding: 0;
    align-items: center;
}

/* --- Logo ---------------------------------------------------------------- */

/* --- Brand lockup --------------------------------------------------------- */

/* One asset, used everywhere. The tagline is part of the artwork, so the lockup
   is a single image and its proportions cannot drift: --sx-lockup-height is the
   only thing header and footer disagree about. */
.sx-lockup {
    --sx-lockup-height: var(--sx-logo-height);
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

.sx-lockup img,
.sx-logo {
    height: var(--sx-lockup-height, var(--sx-logo-height));
    width: auto;
    max-width: 100%;
    display: block;
}

.sx-header .navbar-brand {
    padding: 0;
    margin-right: 1.25rem;
    position: relative;
    z-index: 1;
}

/* The tagline lives in the artwork now, so there is nothing here to style. Its
   proportions — Saira SemiBold at 22% of the mark height, .14em tracking, plain
   white, centred, with rules fading outward to the wordmark's edges — are baked
   by scratchpad/logo-lockup.ps1 at 8.64x and downscaled by the browser. Change
   the wording or the treatment there, then re-run it. */

/* --- About page ----------------------------------------------------------- */

/* Saira, matching the theme's own section eyebrows — those are h5 elements and
   pick the display face up from style.css, where this one is a <p> and was
   quietly falling back to the body font. */
.sx-eyebrow{
    font-family:"Saira",sans-serif;
    color:#0d7d75; font-size:.82rem; font-weight:600;
    letter-spacing:.14em; text-transform:uppercase; margin:0 0 .6rem;
}
.sx-eyebrow--light{ color:#5fe9dc; }

/* Buttons shared by the bands below. The theme's own .btn carries a lot of
   inherited padding, so these are standalone rather than overrides. */
.sx-btn{
    display:inline-block; padding:.85rem 2rem; border-radius:999px;
    font-weight:600; text-decoration:none; font-size:.95rem;
    border:1px solid #0d7d75; color:#0d7d75; background:transparent;
    transition:background-color .25s ease, color .25s ease, box-shadow .25s ease;
}
.sx-btn:hover,.sx-btn:focus-visible{
    background:rgba(13,125,117,.09); color:#0a5f59; outline:none;
    box-shadow:0 0 0 3px rgba(50,217,203,.28);
}
.sx-btn--primary{
    background:linear-gradient(100deg,#1fbfb2 0%,#32d9cb 100%);
    border-color:transparent; color:#04231f;
}
.sx-btn--primary:hover,.sx-btn--primary:focus-visible{
    background:linear-gradient(100deg,#32d9cb 0%,#5fe9dc 100%); color:#04231f;
}

/* --- home: about band ----------------------------------------------------- */

/* Stays white, as asked. The interest comes from two painted layers rather than
   a fill: a soft teal wash under the photographs, and a dot field that fades out
   behind the copy. Both are CSS, so no extra image request. */
/* Tighter than it was: the delivery steps below are the section that should
   carry this part of the page, and this one introduces them. */
.sx-ha{
    position:relative; overflow:hidden; background:#fff;
    padding-block:clamp(2.75rem,5vw,4.25rem);
}
.sx-ha::before{
    content:""; position:absolute; z-index:0; pointer-events:none;
    left:-12%; top:-6%; width:58%; aspect-ratio:1;
    background:radial-gradient(circle at 42% 42%,
               rgba(50,217,203,.20) 0%, rgba(50,217,203,.07) 45%, rgba(50,217,203,0) 70%);
}
.sx-ha::after{
    content:""; position:absolute; z-index:0; pointer-events:none;
    right:0; bottom:0; width:42%; height:66%;
    background-image:radial-gradient(rgba(13,125,117,.16) 1px, transparent 1px);
    background-size:20px 20px;
    -webkit-mask-image:linear-gradient(to top left,#000 0%,transparent 68%);
    mask-image:linear-gradient(to top left,#000 0%,transparent 68%);
}
.sx-ha .container{ position:relative; z-index:1; }

.sx-ha__grid{
    display:grid; gap:clamp(2.5rem,5vw,4.5rem);
    grid-template-columns:minmax(0,5fr) minmax(0,7fr); align-items:center;
}
@media (max-width:991.98px){ .sx-ha__grid{ grid-template-columns:1fr; } }

.sx-ha__art{ position:relative; padding:0 2rem 4.5rem 0; }
.sx-ha__img{ margin:0; border-radius:16px; overflow:hidden; }
.sx-ha__img img{ display:block; width:100%; height:auto; }
.sx-ha__img--main{
    width:88%; box-shadow:0 26px 60px rgba(4,25,26,.20);
}
.sx-ha__img--sub{
    position:absolute; right:0; bottom:2.25rem; width:52%;
    border:6px solid #fff; box-shadow:0 20px 44px rgba(4,25,26,.22);
}

/* The one promise worth pulling out of the list and into the picture. */
.sx-ha__chip{
    position:absolute; left:0; bottom:0; z-index:2;
    display:flex; flex-direction:column; line-height:1.15;
    padding:.85rem 1.25rem; border-radius:14px;
    background:linear-gradient(135deg,#1fbfb2 0%,#32d9cb 100%);
    box-shadow:0 18px 36px rgba(31,191,178,.34);
}
.sx-ha__chip strong{
    font-family:"Saira",sans-serif; font-size:1.35rem; font-weight:700; color:#04231f;
}
.sx-ha__chip span{
    font-size:.72rem; letter-spacing:.12em; text-transform:uppercase;
    color:rgba(4,35,31,.78); margin-top:.15rem;
}

.sx-ha__title{
    font-size:clamp(1.75rem,1.2rem+1.5vw,2.6rem); line-height:1.14;
    margin:0 0 1rem; text-wrap:balance;
}
/* Both paragraphs at one size. They were 1.06rem and .95rem, which is a big
   enough step to look like a mistake rather than a lead-in — the two read as
   continuous prose, so they are set as continuous prose. The lead keeps a
   slightly darker ink, which is enough to mark it as the opening. */
.sx-ha__lead{ font-size:1rem; line-height:1.7; color:#2f4a48; max-width:56ch; margin:0; }

.sx-ha__body{ margin:1rem 0 0; font-size:1rem; line-height:1.7; color:#4a6664; max-width:56ch; }
.sx-ha__lead strong,.sx-ha__body strong{ color:#0a2422; font-weight:600; }

/* Technology chips. They carry the same keywords and the same internal links
   the three described columns did, in a fraction of the height. */
.sx-ha__tags{
    list-style:none; margin:1.15rem 0 0; padding:0;
    display:flex; flex-wrap:wrap; gap:.5rem;
}
.sx-ha__tags a{
    display:inline-block; padding:.34rem .8rem; border-radius:999px;
    font-size:.82rem; font-weight:600; text-decoration:none;
    color:#0a5f59; background:#e6f5f3; border:1px solid #cbe9e5;
    transition:background-color .25s ease, color .25s ease, border-color .25s ease;
}
.sx-ha__tags a:hover,.sx-ha__tags a:focus-visible{
    background:#32d9cb; border-color:transparent; color:#04231f; outline:none;
}

/* --- home: delivery process ----------------------------------------------- */

/* The same painted ground as the About band above it, so the two read as one
   stretch of page rather than two unrelated white sections. */
.sx-process{
    position:relative; overflow:hidden; background:#fff;
    padding-block:clamp(3rem,6vw,5.5rem);
}
.sx-process::before{
    content:""; position:absolute; z-index:0; pointer-events:none;
    right:-14%; top:-8%; width:60%; aspect-ratio:1;
    background:radial-gradient(circle at 55% 45%,
               rgba(50,217,203,.20) 0%, rgba(50,217,203,.07) 45%, rgba(50,217,203,0) 70%);
}
.sx-process::after{
    content:""; position:absolute; z-index:0; pointer-events:none;
    left:0; bottom:0; width:44%; height:62%;
    background-image:radial-gradient(rgba(13,125,117,.16) 1px, transparent 1px);
    background-size:20px 20px;
    -webkit-mask-image:linear-gradient(to top right,#000 0%,transparent 68%);
    mask-image:linear-gradient(to top right,#000 0%,transparent 68%);
}
.sx-process .container{ position:relative; z-index:1; }

/* Full rows now, so the measure is wider than the two-up grid needed. */
.sx-process__head,
.sx-blocks{ max-width:1140px; margin-inline:auto; }
.sx-process__head{ margin-bottom:clamp(2rem,4vw,3rem); }
.sx-process__title{ font-size:clamp(1.6rem,1.15rem+1.3vw,2.35rem); line-height:1.16; margin:0 0 .75rem; text-wrap:balance; }
.sx-process__lead{ margin:0; color:#4a6664; font-size:.98rem; line-height:1.65; }

/* Two by two, so four steps land in one view. Capped and centred: at full
   container width a square block would be enormous, and two of them would sit
   marooned in their columns. */
/* One step per row. margin-inline stays auto — setting `margin:0` here silently
   un-centred the grid set above and let the columns run the full container
   width, which is what pushed the numerals over the text. */
.sx-blocks{
    list-style:none; padding:0; margin-block:0;
    display:flex; flex-direction:column;
    gap:clamp(2.5rem,5vw,4.5rem);
}

/* Each row is text beside artwork, and the two swap sides down the list — so
   the eye zig-zags through the sequence instead of scanning two columns. */
.sx-block{
    display:grid;
    grid-template-columns:1fr;
    /* Named because the numeral's placement below has to know it: the empty
       channel between the columns is the last space the digit is allowed to
       use before it would be on top of the words. */
    --sx-block-gap:clamp(1.25rem,3vw,3.5rem);
    gap:var(--sx-block-gap);
    align-items:center;
}

@media (min-width:768px){
    /* Not an even split. The numeral is as tall as the picture, which makes the
       widest of them — 4 — about 1.1 times the picture's width, and it has to
       show beside the picture rather than behind it. On even columns that left
       141px of clear space for a 443px digit, so every one of them either sat
       on the heading or came out as a fragment with the rest buried. 57/43
       leaves the digit the room it needs; the picture below is re-expressed as
       a share of the wider column so it stays exactly the size it is now.
       The picture's column is the second one on odd rows and the first on even
       rows, so the ratio flips with them. */
    .sx-block{ grid-template-columns:minmax(0,1fr) minmax(0,1.325fr); }
    .sx-block:nth-child(even){ grid-template-columns:minmax(0,1.325fr) minmax(0,1fr); }

    /* Markup order is stage-then-body; odd rows put the words first. */
    .sx-block__body { order:1; }
    .sx-block__stage{ order:2; }
    .sx-block:nth-child(even) .sx-block__body { order:2; }
    .sx-block:nth-child(even) .sx-block__stage{ order:1; }
}

.sx-block__stage{
    display:flex;
    position:relative;
    --sx-frame:min(65%, 54vh);
    /* The numeral is sized from this now rather than from the picture, so the
       stage is the container query's subject. */
    container-type:inline-size;
}
.sx-block:nth-child(odd)  .sx-block__stage{ justify-content:flex-end; }
.sx-block:nth-child(even) .sx-block__stage{ justify-content:flex-start; }

/* The frame is the artwork's real box, and the container the numeral is sized
   against — so both track the picture rather than the column.
 *
 * Capped by viewport height, not just column width: a square sized purely off
 * the column grows with the window and pushes the row past the fold on a
 * laptop. 54vh keeps one whole step on screen without scrolling. */
.sx-block__frame{
    position:relative;
    /* 74% is not cosmetic. The numeral is as tall as the block, which makes it
       about 0.56 of the block wide, and it hangs a further 0.78 of that off the
       left edge — so the block has to leave roughly a quarter of the column
       free or the digit lands on top of the words in the next column. */
    /* 74% of half a row and 65% of a 57% column are the same number of pixels,
       so the picture is unchanged — this just stops it growing into the space
       the column rebalance opened up for the numeral. Held in a variable
       because the numeral is both sized and placed from it. */
    width:var(--sx-frame);
    container-type:inline-size;
}

/* The block, exactly as in the reference: an oversized outlined numeral with
   the photograph laid over its right-hand side, so the digit reads as a frame
   the image sits inside rather than a caption beside it.
   No overflow:hidden here — that is what clipped the numeral last time. */
/* The numeral is set taller than the photograph so it breaks past the top and
   bottom, which is what makes the reference's block read the way it does. */
/* Anchored by its RIGHT edge, not its left. Anchoring left meant a narrow glyph
   like 1 finished well short of the artwork and left a gap, while 2 and 4 tucked
   underneath — the digits looked inconsistently spaced. Pinning the right edge
   gives every one of them the same overlap.

   Two numbers place it, and both are shares of the picture rather than of the
   column, so the digit tracks the artwork at any width:

     .71   how far in from the picture's outer edge the digit's own outer edge
           sits. That is what leaves the same sliver of every digit behind the
           picture: the overlap is constant and the protrusion varies with how
           wide the glyph is.
     --gw  that glyph's width as a share of the picture, measured in Saira at
           this stretch. It is the second term's whole purpose — the digit is
           held back to the boundary of the text column when it would otherwise
           cross it, and only a glyph's own width can say when that is. With one
           clamp for all five it has to be set by the widest, which is what
           buried narrow ones like 1 behind the picture. */
.sx-block__n{
    --gw:1.12;
    /* Positioned against the column, not the picture. min() takes whichever of
       the two is further in: the natural .71 placement, or the furthest the
       digit can go and still stop at the text column's edge — the column's own
       width plus the empty channel between the columns, less the glyph. So it
       sits where the design puts it whenever there is room and stops dead at
       the words when there is not, at any width. */
    position:absolute;
    right:min(calc(var(--sx-frame) * .71),
              calc(100% + var(--sx-block-gap) - var(--sx-frame) * var(--gw)));
    left:auto;
    top:50%;
    /* Widened — Saira ships as a single width, so the stretch has to be applied
       rather than selected. Origin at the right so the anchor above still holds:
       the glyph widens away from the edge it is pinned by, not across it. */
    transform:translateY(-50%) scaleX(1.22);
    transform-origin:right center;
    z-index:1; pointer-events:none;
    /* Saira's digits sit at about .72em cap height, so 139% of the picture's
       width puts the numeral's height level with the square block beside it.
       The picture is 65% of the column, so off the column that is 90.4% — the
       same rendered size, measured from the container the digit now belongs to.
       The vh term is the picture's own 54vh cap carried through by the same
       1.39, so the two stay locked together on a short window. */
    font-family:"Saira",sans-serif; font-weight:700; line-height:.74;
    font-size:clamp(9rem,24vw,23rem);

    /* The header capsule's ramp, stop for stop, so the numeral is lit with the
       same dark neon green rather than sitting flat beside it.

       Three things had it reading as grey charcoal. The gradient used to be
       black across its first half with the visible window parked on that half,
       so the glyph was deliberately unlit until hover; widening that window to
       150% still only reached the middle of the ramp, which on a near-black
       section is barely a colour. Both are fixed here — the window is the
       glyph's own width, so every numeral carries the whole sweep from deep
       teal to neon. The third was that the dark band overrode this fill with a
       translucent wash of its own, which is why changing it appeared to do
       nothing at all; that override is gone. */
    background-image:linear-gradient(95deg,
        #00514c 0%, #00726b 18%, #009288 38%, #00b3a8 58%, #12d4c2 80%, #3ce9d3 100%);
    background-size:100% 100%;
    background-position:0% 0;
    -webkit-background-clip:text;
    background-clip:text;
    color:transparent;
    -webkit-text-fill-color:transparent;

    /* A hard white edge round the glyph. text-stroke draws on the outline
       itself, so it survives the fill being a clipped gradient — a border or an
       outline would box the element, not follow the digit. Kept pure #fff and
       unblurred: a shadow at this size reads as a smudge, an edge reads as a
       cut. */
    -webkit-text-stroke:6px #fff;
    text-stroke:6px #fff;

    transition:filter .45s ease;
}
@supports (container-type:inline-size){
    .sx-block__n{ font-size:min(90.4cqw, 75vh); }
}

/* Measured widths, each divided by the picture's, with a little over the top so
   a rounding difference cannot push a digit into the text. 1 is the outlier —
   barely two thirds the width of the rest — and giving it the widest digit's
   clamp is what would leave it with a sliver showing. */
.sx-blocks > .sx-block:nth-child(1) .sx-block__n{ --gw:.69; }
.sx-blocks > .sx-block:nth-child(2) .sx-block__n{ --gw:1.05; }
.sx-blocks > .sx-block:nth-child(3) .sx-block__n{ --gw:1.05; }
.sx-blocks > .sx-block:nth-child(4) .sx-block__n{ --gw:1.12; }
.sx-blocks > .sx-block:nth-child(5) .sx-block__n{ --gw:1.08; }

/* The window is the glyph's own width now, so sliding the background has
   nowhere to travel and the hover has to lift the whole ramp instead. */
.sx-block:hover .sx-block__n{ filter:brightness(1.35) saturate(1.1); }

/* Without background-clip:text the numeral would be a solid block of gradient
   over the whole box, so fall back to a flat tint. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)) {
    .sx-block__n{
        background:none; color:#1fbfb2; -webkit-text-fill-color:#1fbfb2;
    }
}

/* 1 is a narrow glyph, so a little more of it goes behind the picture — at the
   shared .71 it would stand too far clear of the artwork to read as part of it. */
.sx-blocks > .sx-block:nth-child(1) .sx-block__n{
    right:min(calc(var(--sx-frame) * .78),
              calc(100% + var(--sx-block-gap) - var(--sx-frame) * var(--gw)));
}


/* Mirrored on the rows where the block sits left. Hanging the digit off the
   left there would push it past the edge of the page; this way it always
   protrudes into the row, never out of it. */
@media (min-width:768px){
    /* Odd rows carry the picture on the right and the digit hangs off its left;
       even rows are the mirror of that — same two terms, opposite edge. */
    .sx-blocks > .sx-block:nth-child(even) .sx-block__n{
        right:auto;
        left:min(calc(var(--sx-frame) * .71),
                 calc(100% + var(--sx-block-gap) - var(--sx-frame) * var(--gw)));
        transform:translateY(-50%) scaleX(1.22);
        transform-origin:left center;
    }

    /* No clipping: the digit runs whole, crossing into the neighbouring column
       rather than being cut off at the boundary. The stacking below is what
       makes that safe. */
    .sx-block__stage{ overflow:visible; }

    /* The words sit above the digit, so an overlap reads as the numeral passing
       behind the text rather than colliding with it. */
    .sx-block__stage{ position:relative; z-index:1; }
    .sx-block__body { position:relative; z-index:2; }
}




/* --- mobile: one card at a time, swiped -------------------------------------
   Below 768 the row stops being text-beside-artwork and stacks, and the numeral
   — which is sized off the artwork and hangs outside it by design — had nowhere
   to hang but over the words. The whole section was unreadable on a phone.

   A rail instead: each reason is a full card the width of the screen, snapped,
   and swiped one at a time. That keeps the numeral inside its own card where it
   belongs, and turns five tall rows into one screenful. */
@media (max-width:767.98px){
    .sx-blocks{
        display:flex;
        flex-direction:row;
        gap:1rem;
        overflow-x:auto;
        overscroll-behavior-x:contain;
        scroll-snap-type:x mandatory;
        /* No negative margins. Bleeding the rail past its container is the
           usual way to get a card sitting on the screen edge, but the container
           is already the full width here and pulling it wider gave the whole
           page a sideways scroll. The next card peeking is done by the card
           being 88% instead. */
        -webkit-overflow-scrolling:touch;
        scrollbar-width:none;
    }

    .sx-blocks::-webkit-scrollbar{ display:none; }

    .sx-block{
        flex:0 0 88%;
        scroll-snap-align:center;
        display:block;
    }

    /* Over the picture, not behind it. The digit sits outside the artwork on a
       desktop row, so being under it costs nothing there; inside a card it is
       covered completely and may as well not exist. z-index puts it on top,
       where the white edge is what makes it legible against the photograph.

       :nth-child(n) matches every row and costs nothing but the one point of
       specificity needed to outweigh the desktop anchors, 1's included. Leaving
       that one to the bare class let its `right` survive here, and an absolute
       box with both edges set is stretched between them rather than sized to
       its glyph. */
    .sx-blocks > .sx-block:nth-child(n) .sx-block__n{
        position:absolute;
        z-index:3;
        right:auto;
        left:.5rem;
        top:0;
        transform:none;
        font-size:5rem;
        line-height:1.1;
        -webkit-text-stroke-width:3px;
    }

    .sx-block__stage{ justify-content:stretch; }
    .sx-block__frame{ width:100%; max-width:none; }
    .sx-block__body{ padding-top:1rem; }
    .sx-block__body p{ max-width:none; }
}

/* Nothing here is clickable, so the text caret has no business appearing over
   the artwork — it reads as though something should happen. */
.sx-block__stage{ cursor:default; }

/* Square, as asked — the letterbox crop was fighting the numeral for height. */
/* The same near-black-to-teal gradient the header capsule uses, so the blocks
   belong to the brand rather than sitting on it. */
.sx-block__art{
    position:relative; z-index:2;
    width:100%; aspect-ratio:1 / 1; border-radius:16px;
    overflow:hidden;
    /* No pale edge — it was reading as a white frame around every block. The
       shape is held by the shadow and by the ground being so much darker than
       the page. */
    border:0;
    box-shadow:0 20px 44px rgba(4,25,26,.34);
    transition:transform .45s cubic-bezier(.16,1,.3,1),
               box-shadow .45s ease;

    background:linear-gradient(142deg,
               #0a2b2c 0%, #061e1f 36%, #030f10 66%, #061f21 100%);
    background-size:220% 220%;
    animation:sx-art-drift 18s ease-in-out infinite alternate;
}

@keyframes sx-art-drift{
    from{ background-position:0% 20%; }
    to  { background-position:100% 80%; }
}

/* A teal bloom that counter-drifts, so the two layers never move together. */
.sx-block__art::before{
    content:""; position:absolute; inset:-30%; z-index:0;
    background:radial-gradient(circle at 32% 30%,
               rgba(50,217,203,.34) 0%, rgba(50,217,203,.12) 40%, rgba(50,217,203,0) 68%);
    animation:sx-art-bloom 22s ease-in-out infinite alternate;
    pointer-events:none;
}

@keyframes sx-art-bloom{
    from{ transform:translate3d(-8%,-5%,0) scale(1); }
    to  { transform:translate3d(10%,7%,0) scale(1.18); }
}

/* Drafting grid, pulled back now that the sketch sits on top of it. */
.sx-block__art::after{
    content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
    background-image:
        linear-gradient(rgba(153,255,255,.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(153,255,255,.05) 1px, transparent 1px);
    background-size:26px 26px;
    -webkit-mask-image:radial-gradient(circle at 50% 50%, #000 40%, transparent 78%);
    mask-image:radial-gradient(circle at 50% 50%, #000 40%, transparent 78%);
    transition:opacity .45s ease;
    opacity:.8;
}

/* The block's whole content: on /home-v2 the photograph run through edge
   detection, so what shows is a white line drawing of the scene on the
   near-black ground. Regenerate with brand/build-sketches.ps1. The home page
   shows the photographs themselves — see the override further down. */
.sx-block__sketch{
    position:absolute; inset:0; z-index:2;
    width:100%; height:100%; object-fit:cover;
    /* transform belongs to the pan keyframes, so only opacity transitions —
       animating both would have hover fight the animation. */
    opacity:0;
    transition:opacity .5s ease;
    animation:sx-sketch-pan 26s ease-in-out infinite alternate;
    -webkit-mask-image:radial-gradient(circle at 50% 50%, #000 62%, transparent 96%);
    mask-image:radial-gradient(circle at 50% 50%, #000 62%, transparent 96%);
}

/* Faded up as the row arrives, rather than being there from the start. */
.sx-block.is-drawn .sx-block__sketch{ opacity:.88; }
.sx-block.is-drawn:hover .sx-block__sketch{ opacity:1; }

/* On the home page these are photographs, shown as they were supplied. Both of
   the rules above belong to the drawing: the radial mask faded a sketch's
   strokes into the block so they had somewhere to end, and the .88 held it just
   under full white so it read as a drawing. On a photograph the first vignettes
   the corners away and the second greys it. */
.sx-home .sx-block__sketch{
    -webkit-mask-image:none;
    mask-image:none;
}

.sx-home .sx-block.is-drawn .sx-block__sketch{ opacity:1; }

@keyframes sx-sketch-pan{
    from{ transform:scale(1.05) translate3d(-1.4%,-1%,0); }
    to  { transform:scale(1.14) translate3d(1.4%,1.4%,0); }
}


.sx-block:hover .sx-block__art{
    transform:translateY(-8px) scale(1.015);
    box-shadow:0 32px 64px rgba(4,25,26,.42), 0 0 36px rgba(50,217,203,.26);
}
.sx-block:hover .sx-block__art::after{ opacity:1; }

/* Set like the hero: Saira for the heading, the body face at the hero sub-copy's
   size, so this section reads as part of the same page rather than a caption. */
.sx-block__body h3{
    font-family:"Saira",sans-serif;
    font-size:clamp(1.4rem,1.1rem + .9vw,2rem);
    line-height:1.2; margin:0 0 .8rem;
}
.sx-block__body p{
    margin:0 0 .9rem;
    font-size:clamp(1rem,.95rem + .3vw,1.15rem);
    line-height:1.65; color:#4a6664; max-width:46ch;
}
.sx-block__body p:last-child{ margin-bottom:0; }

/* Where the artwork sits left, the words range right against it rather than
   floating at the far edge of their column. */
@media (min-width:768px){
    .sx-block:nth-child(even) .sx-block__body{ text-align:right; }
    .sx-block:nth-child(even) .sx-block__body p{ margin-left:auto; }
}

/* Reduced motion: the drawing is shown outright and the ground holds still. It
   is content, so it is never withheld — only the movement stops. */
@media (prefers-reduced-motion:reduce){
    .sx-block__art,.sx-block__n,.sx-block__sketch{ transition:none; animation:none; }
    .sx-block__art::before{ animation:none; }
    .sx-block:hover .sx-block__art{ transform:none; }
    .sx-block:hover .sx-block__n{ background-position:0 0; }
    .sx-block__sketch{ opacity:.88; transform:scale(1.05); }
}

.sx-ha__actions{ display:flex; flex-wrap:wrap; gap:.8rem; margin-top:2rem; }

/* Honeypot. Moved out of view rather than display:none — some bots skip fields
   that are display:none, and this still keeps it off screen and out of the tab
   order for everyone else. */
.sx-hp{
    position:absolute !important;
    left:-9999px !important;
    width:1px; height:1px;
    overflow:hidden;
}

/* --- why choose ----------------------------------------------------------- */

/* --- why choose (dark band) ---------------------------------------------- */
/* Ticked statements rather than cards. Five boxed panels read as five separate
   things to evaluate; a checklist reads as one list of reasons, which is what
   this is — and it is the pattern people already know from a spec sheet or a
   pricing table, so it needs no learning. It also survives the narrow column
   far better than a card grid, which collapses to five stacked boxes. */

.sx-reasons{
    position:relative;
    background:var(--sx-black);
    padding-block:clamp(3.5rem,7.5vw,6rem);
}

/* Faint green wash from the top corner, so the band is not a flat black
   rectangle between two white ones. */
.sx-reasons::before{
    content:"";
    position:absolute; inset:0;
    background:
        radial-gradient(60rem 26rem at 12% 0%, rgba(47,158,107,.16), transparent 62%),
        radial-gradient(46rem 22rem at 92% 100%, rgba(50,217,203,.10), transparent 60%);
    pointer-events:none;
}

.sx-reasons__inner{ position:relative; }

.sx-reasons__head{
    max-width:44rem;
    margin-bottom:clamp(2rem,4vw,3rem);
}

.sx-reasons__title{
    margin:0 0 .7rem;
    color:#fff;
    font-size:clamp(1.5rem,1.15rem + 1.4vw,2.35rem);
    line-height:1.15;
    font-weight:700;
    letter-spacing:-.015em;
    text-wrap:balance;
}

.sx-reasons__lede{
    margin:0;
    color:rgba(214,236,231,.72);
    font-size:1rem;
    line-height:1.65;
    text-wrap:pretty;
}

/* --- the pipeline ---------------------------------------------------------
   Five reasons as stops along a delivery pipeline that draws itself as the
   section scrolls, with a commit travelling down it.

   The path itself is generated in soulogix-path.js from the measured position
   of each node — see that file for why it is not hardcoded. Everything here is
   the styling around it, and all of it is safe to render before the script
   runs or if it never does. */

/* Capped and centred. Across a full-width container the two columns run to
   660px each while a readable card is barely 380px, so the content drifts to
   the middle of two large empty margins. */
.sx-path{ position:relative; max-width:64rem; margin-inline:auto; }

.sx-path__svg{
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    overflow:visible;
    pointer-events:none;
    /* Behind the cards, in front of the section wash. */
    z-index:0;
}

/* Doubled from 2. The line runs the whole way from the first node to the last,
   so both halves of it move together — the track is the unfilled remainder of
   the same stroke the progress draws over, and a difference of a pixel between
   them shows as a lip where the two meet. */
.sx-path__track{
    stroke:rgba(255,255,255,.10);
    stroke-width:4;
    stroke-linecap:round;
}

.sx-path__progress{
    stroke:#2f9e6b;
    stroke-width:4;
    stroke-linecap:round;
    filter:drop-shadow(0 0 6px rgba(47,158,107,.55));
    transition:stroke-dashoffset .12s linear;
}

/* The commit riding the pipeline. Hidden until the script has measured a
   position for it, so it never flashes at the top-left corner first. */
.sx-path__marker{
    position:absolute;
    top:0;
    left:0;
    z-index:2;
    display:grid;
    place-items:center;
    /* Round, not a rounded square: the mark it now carries is drawn on a disc,
       and a square would show its corners cut. Slightly larger too — the glyph
       inside is artwork rather than a single icon and needs the room. */
    width:2.9rem;
    height:2.9rem;
    border-radius:50%;
    overflow:hidden;
    background:#04211f;
    border:1px solid rgba(95,233,220,.55);
    box-shadow:0 0 0 6px rgba(47,158,107,.12), 0 12px 26px rgba(0,0,0,.45);
    color:#eafff8;
    opacity:0;
    transition:opacity .3s ease;
    will-change:transform;
}

.sx-path__marker.is-visible{ opacity:1; }

.sx-path__marker-mark{
    display:block;
    width:100%;
    height:100%;
    border-radius:50%;
    object-fit:cover;
}

.sx-path__list{
    position:relative;
    z-index:1;
    list-style:none;
    margin:0;
    padding:0;
    display:grid;
    gap:clamp(2.25rem,5vw,3.75rem);
}

/* Mobile: one column, nodes down the left. The same generated path still runs
   through them — it simply has very little sideways travel. */
.sx-path__item{
    display:grid;
    grid-template-columns:2.75rem 1fr;
    column-gap:1rem;
    align-items:start;
}

.sx-path__node{
    grid-column:1;
    grid-row:1;
    justify-self:center;
    display:grid;
    place-items:center;
    width:2.25rem;
    height:2.25rem;
    border-radius:50%;
    background:#0b1f1a;
    border:1px solid rgba(255,255,255,.16);
    color:rgba(255,255,255,.28);
    font-size:.7rem;
    transition:background-color .35s ease, border-color .35s ease,
               color .35s ease, box-shadow .35s ease, transform .35s ease;
}

/* Lights up once the commit has passed it. */
.sx-path__item.is-reached .sx-path__node{
    background:rgba(47,158,107,.22);
    border-color:#5fe9dc;
    color:#5fe9dc;
    box-shadow:0 0 0 5px rgba(47,158,107,.12);
    transform:scale(1.06);
}

.sx-path__card{
    grid-column:2;
    grid-row:1;
    padding-top:.15rem;
    opacity:.55;
    transition:opacity .35s ease;
}

.sx-path__item.is-reached .sx-path__card{ opacity:1; }

/* Sized to the rest of the page rather than to the diagram. The paragraph is
   the same clamp the reasons' body text uses — this is the site's standard
   reading size — and the heading steps up from it in proportion. Both were set
   small enough (1.05rem and .93rem) to read as captions on a graphic, which is
   not what they are: this is the process, in prose.

   The measure widens with them. Holding 38ch while the type grows would only
   make the column narrower in words and taller on the page. */
.sx-path__card h3{
    margin:0 0 .55rem;
    color:#fff;
    font-size:clamp(1.2rem, 1.02rem + .55vw, 1.5rem);
    line-height:1.3;
    font-weight:600;
}

.sx-path__card p{
    margin:0 0 .7rem;
    color:rgba(206,228,223,.74);
    font-size:clamp(1rem, .95rem + .3vw, 1.15rem);
    line-height:1.65;
    text-wrap:pretty;
    max-width:44ch;
}

.sx-path__card p:last-child{ margin-bottom:0; }

/* Desktop: cards alternate around a centre gutter, which is what gives the
   path something to weave between. */
@media (min-width:768px){
    .sx-path__list{ gap:clamp(2.5rem,4.5vw,4rem); }

    /* A wide centre gutter is what gives the path room to weave. With the nodes
       all stacked on one x the generated curve is a straight vertical line —
       the bend comes from the nodes themselves alternating sides, not from the
       drawing code. */
    .sx-path__item{
        grid-template-columns:1fr clamp(7rem,11vw,11rem) 1fr;
        column-gap:0;
        align-items:center;
    }

    .sx-path__node{ grid-column:2; }

    /* Each node sits at the edge of the gutter nearest its own card, so the
       pipeline leans toward whichever side is currently speaking. */
    .sx-path__item:nth-child(odd)  .sx-path__node{ justify-self:start; }
    .sx-path__item:nth-child(even) .sx-path__node{ justify-self:end; }

    .sx-path__item:nth-child(odd) .sx-path__card{
        grid-column:1;
        justify-self:end;
        padding-right:1.75rem;
    }

    .sx-path__item:nth-child(even) .sx-path__card{
        grid-column:3;
        justify-self:start;
        padding-left:1.75rem;
    }

    /* Text stays left-aligned on both sides. Mirroring the alignment to match
       the side would put a ragged left edge on half the section, which is
       measurably harder to read for the sake of a symmetry nobody asked for. */
    .sx-path__card{ text-align:left; }
    .sx-path__card p{ max-width:46ch; }
}

/* Until the script has measured and drawn, nothing is dimmed — content is
   never hidden behind an effect that might not run. */
.sx-path:not(.is-ready) .sx-path__card{ opacity:1; }
.sx-path:not(.is-ready) .sx-path__node{
    background:rgba(47,158,107,.22);
    border-color:#5fe9dc;
    color:#5fe9dc;
}

@media (prefers-reduced-motion:reduce){
    .sx-path__progress{ transition:none; }
    .sx-path__marker{ display:none; }
    .sx-path__node,
    .sx-path__card{ transition:none; }
    .sx-path__card{ opacity:1; }
}

/* --- story band --- */
.sx-about{ padding-block:clamp(3.5rem,7vw,6rem); }
.sx-about__grid{
    display:grid; gap:clamp(2rem,5vw,4.5rem);
    grid-template-columns:minmax(0,5fr) minmax(0,7fr);
    align-items:center;
}
@media (max-width:991.98px){ .sx-about__grid{ grid-template-columns:1fr; } }

.sx-about__art{ position:relative; padding-bottom:3.5rem; padding-right:2.5rem; }
.sx-about__frame{ border-radius:14px; overflow:hidden; box-shadow:0 22px 50px rgba(4,25,26,.22); }
.sx-about__frame img{ display:block; width:100%; height:auto; }
.sx-about__frame--back{ width:78%; }
.sx-about__frame--front{
    width:62%; position:absolute; right:0; bottom:0;
    border:5px solid #fff;
}

/* The founding year sits on the join of the two photographs, which is what
   turns them into one composition instead of two loose rectangles. */
.sx-about__badge{
    position:absolute; left:0; bottom:1.5rem; z-index:2;
    background:linear-gradient(135deg,#12363a 0%,#04191a 100%);
    color:#fff; border-radius:12px; padding:.9rem 1.3rem;
    box-shadow:0 16px 34px rgba(4,25,26,.34);
    display:flex; flex-direction:column; line-height:1.1;
}
.sx-about__badge strong{
    font-family:"Saira",sans-serif; font-size:1.7rem; font-weight:700; color:#5fe9dc;
}
.sx-about__badge span{ font-size:.74rem; letter-spacing:.12em; text-transform:uppercase; color:rgba(214,240,238,.72); margin-top:.15rem; }

.sx-about__title{ font-size:clamp(1.7rem,1.2rem+1.4vw,2.5rem); line-height:1.15; margin:0 0 1.1rem; text-wrap:balance; }
.sx-about__lead{ font-size:1.06rem; color:#2f4a48; }
.sx-about__copy p{ margin:0 0 1rem; max-width:60ch; }
.sx-about__actions{ display:flex; flex-wrap:wrap; gap:.8rem; margin-top:1.6rem; }

/* --- how we work --- */
.sx-how{
    position:relative; padding-block:clamp(3.5rem,7vw,5.5rem);
    background:linear-gradient(rgba(4,25,26,.86),rgba(4,25,26,.92)),
               url("../img/sx-about-bg.jpg") center center / cover no-repeat;
    color:#dfeeed;
}
.sx-how__head{ max-width:60ch; margin-bottom:clamp(1.75rem,4vw,2.75rem); }
.sx-how__title{ color:#fff; font-size:clamp(1.5rem,1.1rem+1.2vw,2.15rem); line-height:1.2; margin:0; text-wrap:balance; }

.sx-how__steps{
    list-style:none; margin:0; padding:0;
    display:grid; gap:clamp(1rem,2.5vw,1.75rem);
    grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr));
    counter-reset:none;
}
.sx-how__step{
    background:linear-gradient(150deg,rgba(22,60,60,.52) 0%,rgba(6,26,28,.46) 100%);
    border:1px solid rgba(153,255,255,.16);
    border-radius:14px; padding:clamp(1.2rem,2.4vw,1.6rem);
    -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
}
.sx-how__n{
    display:block; font-family:"Saira",sans-serif; font-size:.9rem; font-weight:700;
    letter-spacing:.14em; color:#5fe9dc; margin-bottom:.7rem;
    font-variant-numeric:tabular-nums;
}
.sx-how__step h3{ color:#fff; font-size:1.12rem; margin:0 0 .5rem; }
.sx-how__step p{ margin:0; color:rgba(210,232,230,.82); font-size:.94rem; line-height:1.6; }

/* --- practices --- */
.sx-practices{ padding-block:clamp(3.5rem,7vw,5.5rem); background:#f4faf9; }
.sx-practices__head{ max-width:58ch; margin-bottom:clamp(1.75rem,4vw,2.5rem); }
.sx-practices__title{ font-size:clamp(1.5rem,1.1rem+1.2vw,2.15rem); line-height:1.2; margin:0; text-wrap:balance; }

.sx-practices__grid{
    display:grid; gap:clamp(.9rem,2vw,1.4rem);
    grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr));
}
.sx-practice{
    display:flex; flex-direction:column; gap:.55rem;
    background:#fff; border:1px solid #d9e9e7; border-radius:14px;
    padding:clamp(1.15rem,2.2vw,1.5rem); text-decoration:none; color:inherit;
    transition:transform .3s cubic-bezier(.16,1,.3,1), box-shadow .3s ease, border-color .3s ease;
}
.sx-practice:hover,.sx-practice:focus-visible{
    transform:translateY(-4px); border-color:#32d9cb;
    box-shadow:0 18px 38px rgba(4,25,26,.13); outline:none;
}
.sx-practice__icon{
    width:46px; height:46px; border-radius:12px; display:flex;
    align-items:center; justify-content:center; font-size:1.15rem;
    background:linear-gradient(135deg,#e3f6f4 0%,#cceeea 100%); color:#0d7d75;
}
.sx-practice h3{ font-size:1.08rem; margin:0; }
.sx-practice p{ margin:0; font-size:.92rem; line-height:1.6; color:#4a6664; }
.sx-practice__more{
    margin-top:auto; padding-top:.5rem; font-size:.84rem; font-weight:600; color:#0d7d75;
}
.sx-practice__more::after{ content:" \2192"; }

@media (prefers-reduced-motion:reduce){
    .sx-practice{ transition:none; }
    .sx-practice:hover{ transform:none; }
}

/* --- Facts band ----------------------------------------------------------- */

/* A diagonal sweep in place of the flat teal, following the evconnect
   reference: deeper and slightly blue at the left, opening out to mint at the
   right. It stays inside the brand family — #32d9cb, the previous flat colour,
   is the middle stop, so the band still reads as the same green. */
.sx-facts.bg-secondary {
    background: linear-gradient(112deg,
                #17a8bd 0%,
                #25c6c6 34%,
                #32d9cb 58%,
                #55e4c9 82%,
                #6cecc5 100%) !important;
}

/* The labels stay near-black: 6.3:1 at the darkest stop of the band and 12.3:1
   at the lightest. */
.sx-facts__label {
    color: #04191a;
}

/* Figures in white, matching the logo and the menu.
   Worth knowing: white measures 2.9:1 against the darkest end of this band and
   1.5:1 against the lightest — under the 3:1 minimum for large text. The
   shadow below is what makes them legible in practice; the only way to make
   them pass outright is a darker band. */
/* These were <h1> elements purely for their size, which gave the home page
   eight competing headings. They are spans now, so the size is set here. */
.sx-facts__num {
    font-family: "Saira", sans-serif;
    font-size: clamp(1.9rem, 1.5rem + 1vw, 2.5rem);
    line-height: 1.2;
    color: #ffffff;
    font-weight: 700;
    text-shadow: 0 2px 10px rgba(2, 40, 44, .45),
                 0 0 2px rgba(2, 40, 44, .35);
}

/* --- Cookie consent ------------------------------------------------------- */

/* Registering the angle is what makes it animatable — an unregistered custom
   property is just a string and cannot be interpolated. Browsers without
   @property fall back to a static gradient, which still reads as a coloured
   border, only without the rotation. */
/* inherits: true so the blurred halo behind the frame resolves the *animated*
   angle rather than the initial one, and the two stay in step. */
@property --sx-cookie-angle {
    syntax: "<angle>";
    initial-value: 0deg;
    inherits: true;
}

/* While the banner is up, the hero gives back the height it occupies, so the
   stats strip finishes above it instead of behind it — the banner then reads as
   sitting directly under the strip rather than covering it. The class is put on
   <body> by soulogix-cookie.js and removed the moment a choice is made. */
/* While the banner is up the hero content settles to the bottom of the screen
   rather than the middle, so the stats strip finishes directly above the banner
   instead of leaving a gap the height of the animation between them. It returns
   to centred the moment a choice is made. */
body.sx-cookie-open .sx-hero { align-items: flex-end; }

body.sx-cookie-open .sx-hero__inner {
    padding-bottom: calc(.75rem + var(--sx-cookie-reserve, 104px));
}

.sx-cookie {
    position: fixed;
    left: 50%;
    bottom: clamp(.75rem, 2vh, 1.5rem);
    transform: translate(-50%, 0);
    width: min(1140px, calc(100vw - 1.5rem));
    /* Above the header capsule (1020) and the social rail (1019): a consent
       gate should not be paintable over by anything else on the page. */
    z-index: 1080;

    /* Entrance and exit. The banner is added to the DOM hidden and revealed by
       the script, so this only ever runs when it is genuinely needed. */
    opacity: 0;
    translate: 0 calc(100% + 2rem);
    transition: opacity .45s ease, translate .55s cubic-bezier(.16, 1, .3, 1);
}

.sx-cookie.is-in {
    opacity: 1;
    translate: 0 0;
}

.sx-cookie.is-out {
    opacity: 0;
    translate: 0 calc(100% + 2rem);
}

/* The rotating border. The frame is the gradient; the inner panel sits on top
   inset by 3px, so a 3px rim of the gradient shows. Thinner than that and the
   sweep reads as one flat colour instead of several. */
.sx-cookie__frame {
    /* Declared once and reused by the halo, so the two can never drift. */
    --sx-cookie-ring: conic-gradient(from var(--sx-cookie-angle),
                      #32d9cb 0%,
                      #99ffff 16%,
                      #00b3b3 32%,
                      #5fe9dc 48%,
                      #1fbfb2 64%,
                      #006666 80%,
                      #99ffff 90%,
                      #32d9cb 100%);

    position: relative;
    padding: 3px;
    border-radius: 21px;
    background: var(--sx-cookie-ring);
    animation: sx-cookie-rotate 7s linear infinite;
    box-shadow: 0 22px 60px rgba(0, 0, 0, .55);
}

/* The haze: the same rotating ring, blown out behind the frame and blurred, so
   the banner throws coloured light onto whatever it is sitting over. */
.sx-cookie__frame::before {
    content: "";
    position: absolute;
    inset: -7px;
    z-index: -1;
    border-radius: 28px;
    background: var(--sx-cookie-ring);
    filter: blur(15px);
    opacity: .55;
}

@keyframes sx-cookie-rotate {
    to { --sx-cookie-angle: 360deg; }
}

.sx-cookie__inner {
    display: flex;
    align-items: center;
    gap: clamp(.85rem, 2.4vw, 1.9rem);
    /* Tight, but not squeezed. The banner is fixed over the hero where the CTA
       buttons sit, so height matters — the copy is kept to one line to buy that
       height back rather than crushing the padding. */
    padding: .78rem clamp(.95rem, 1.8vw, 1.4rem);
    border-radius: 18px;
    /* Hazy: the wash is light enough that the animation behind it reads through,
       and the blur is short enough not to erase the canvas's thin grid lines.
       .60 is the floor — the banner passes over the bright teal facts band on
       scroll, and any lighter puts the body copy under 4.5:1 there. */
    background: linear-gradient(150deg,
                rgba(12, 38, 39, .66) 0%,
                rgba(5, 20, 22, .60) 55%,
                rgba(3, 14, 16, .66) 100%);
    -webkit-backdrop-filter: blur(6px) saturate(130%);
    backdrop-filter: blur(6px) saturate(130%);
}

/* Without the blur the wash has to carry legibility on its own. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .sx-cookie__inner {
        background: linear-gradient(150deg,
                    rgba(9, 30, 31, .96) 0%,
                    rgba(3, 14, 16, .96) 100%);
    }
}

.sx-cookie__copy { flex: 1 1 auto; }

.sx-cookie__title {
    margin: 0 0 .16rem;
    color: #fff;
    font-family: "Saira", sans-serif;
    font-size: .88rem;
    font-weight: 600;
    letter-spacing: .01em;
}

.sx-cookie__title i {
    color: #5fe9dc;
    margin-right: .35rem;
}

.sx-cookie__text {
    margin: 0;
    /* Lifted with the wash: 5.1:1 over the worst ground the banner crosses. */
    color: rgba(224, 242, 240, .92);
    font-size: .83rem;
    line-height: 1.45;
}

.sx-cookie__text a {
    color: #5fe9dc;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.sx-cookie__text a:hover { color: #99ffff; }

.sx-cookie__actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .6rem;
}

.sx-cookie__btn {
    appearance: none;
    border: 1px solid rgba(153, 255, 255, .32);
    background: rgba(4, 20, 21, .55);
    color: #cdeeee;
    border-radius: 999px;
    padding: .54rem 1.2rem;
    font-size: .81rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: transform .28s cubic-bezier(.16, 1, .3, 1),
                background-color .25s ease,
                border-color .25s ease,
                color .25s ease,
                box-shadow .25s ease;
}

.sx-cookie__btn:hover,
.sx-cookie__btn:focus-visible {
    color: #fff;
    border-color: #32d9cb;
    background: rgba(50, 217, 203, .16);
    transform: translateY(-2px);
    outline: none;
}

.sx-cookie__btn--primary {
    background: linear-gradient(120deg, #1fbfb2 0%, #32d9cb 100%);
    border-color: transparent;
    color: #00231f;                      /* 8.9:1 on the gradient */
}

.sx-cookie__btn--primary:hover,
.sx-cookie__btn--primary:focus-visible {
    color: #00231f;
    background: linear-gradient(120deg, #32d9cb 0%, #5fe9dc 100%);
    box-shadow: 0 0 26px rgba(50, 217, 203, .45);
}

.sx-cookie__btn:focus-visible {
    box-shadow: 0 0 0 3px rgba(50, 217, 203, .45);
}

@media (max-width: 767.98px) {
    .sx-cookie__inner {
        flex-direction: column;
        align-items: stretch;
        gap: .9rem;
    }

    .sx-cookie__actions > .sx-cookie__btn { flex: 1 1 0; }
    .sx-cookie__btn { padding-inline: .9rem; }
}

.sx-cookie-settings {
    appearance: none;
    border: 0;
    background: none;
    padding: 0;
    color: #32d9cb;
    font-size: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.sx-cookie-settings:hover { color: #99ffff; }

/* A rotating border is decoration; motion sensitivity outranks it. */
@media (prefers-reduced-motion: reduce) {
    .sx-cookie { transition: opacity .01ms; }
    /* The gradient stays, only the rotation stops — the banner keeps its
       coloured edge without the movement. */
    .sx-cookie__frame { animation: none; }
    .sx-cookie__btn { transition: none; }
    .sx-cookie__btn:hover { transform: none; }
}

/* --- Social rail ---------------------------------------------------------- */

/* Fixed rather than sticky: it stays put for the entire scroll instead of
   releasing at the end of a container. Vertically centred so it reads as page
   furniture rather than as part of any one section. */
.sx-social-rail {
    /* The two numbers everything else is derived from: the resting circle, and
       the width every chip opens to. --sx-rail-open is sized for the longest
       label so all four match. */
    --sx-rail-size: 46px;
    --sx-rail-open: 118px;

    position: fixed;
    top: 50%;
    right: clamp(.6rem, 1.4vw, 1.4rem);
    transform: translateY(-50%);
    z-index: 1019;                 /* just under the header capsule's 1020 */
    flex-direction: column;
    /* Right-aligned so a chip opening leftward keeps its right edge pinned. */
    align-items: flex-end;
    gap: .75rem;
    padding: .7rem .55rem;
    border-radius: 999px;
    /* Same frosted treatment as the hero stats, so the two read as one system. */
    background: linear-gradient(180deg,
                rgba(22, 60, 60, .34) 0%,
                rgba(5, 20, 22, .28) 100%);
    border: 1px solid rgba(153, 255, 255, .18);
    box-shadow: 0 14px 34px rgba(0, 0, 0, .38),
                inset 0 1px 0 rgba(153, 255, 255, .10);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
    backdrop-filter: blur(6px) saturate(120%);
}

/* No single fill highlights against every background this rail crosses. The
   page runs from near-black (hero, services, footer) to the bright teal stats
   band to white content sections, and nothing is high-contrast against both
   ends: white is 19:1 on the hero but only 1.8:1 on the teal band; a dark disc
   is the reverse.
   So the chip carries both. The near-opaque dark fill does the work on bright
   backgrounds, and the bright teal ring plus its glow do it on dark ones —
   whichever ground it lands on, one of the two is holding the edge. */
/* The anchor is the rail's footprint and never changes size. That is what stops
   the capsule from stretching: the chip that actually opens is absolutely
   positioned, so it is out of flow and contributes nothing to the width of the
   rail around it. It simply grows leftward over the capsule's border. */
.sx-social-rail__link {
    position: relative;
    display: block;
    flex: 0 0 auto;
    width: var(--sx-rail-size);
    height: var(--sx-rail-size);
    text-decoration: none;
}

/* A circle at rest that opens into a rounded rectangle. Every chip opens to the
   same width — sized for the longest label — so the four behave identically
   instead of each stopping at its own word. */
.sx-social-rail__chip {
    position: absolute;
    top: 0;
    right: 0;                      /* right edge pinned; growth goes left */
    display: flex;
    align-items: center;
    justify-content: flex-end;
    width: var(--sx-rail-size);
    height: var(--sx-rail-size);
    border-radius: calc(var(--sx-rail-size) / 2);   /* a true circle at rest */
    overflow: hidden;
    white-space: nowrap;
    color: #5fe9dc;                /* 12.2:1 on the chip */
    font-size: 1.05rem;
    border: 1.5px solid rgba(50, 217, 203, .70);   /* 5.2:1 against the hero */
    background: rgba(3, 17, 19, .82);
    box-shadow: 0 0 16px rgba(50, 217, 203, .22);
    /* Always on rather than added at hover: introducing a filter mid-transition
       forces a new compositing layer and pops. At rest the dark fill hides it;
       it only reads once the chip opens to the translucent teal. */
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    backdrop-filter: blur(8px) saturate(140%);
    transition: width .42s cubic-bezier(.16, 1, .3, 1),
                border-radius .42s cubic-bezier(.16, 1, .3, 1),
                background-color .28s ease,
                border-color .28s ease,
                box-shadow .28s ease,
                color .28s ease;
}

/* Fixed cell, so the icon holds still while the chip opens beside it. */
.sx-social-rail__icon {
    flex: 0 0 calc(var(--sx-rail-size) - 3px);      /* less the two 1.5px borders */
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Sized to exactly the space that opens up, and centred in it — so a one-letter
   label sits in the middle of the panel rather than hard against the icon.
   flex: 0 0 keeps that width at rest too, where it overflows left and is
   clipped by the chip. */
.sx-social-rail__label {
    flex: 0 0 calc(var(--sx-rail-open) - var(--sx-rail-size));
    text-align: center;
    font-family: "Inter", sans-serif;
    /* Trimmed with the panel — "Instagram" is the constraint, and it needs to
       keep visible padding either side of it in the narrower chip. */
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .02em;
    opacity: 0;
    transform: translateX(8px);
    transition: opacity .22s ease, transform .42s cubic-bezier(.16, 1, .3, 1);
}

.sx-social-rail__link:hover .sx-social-rail__chip,
.sx-social-rail__link:focus-visible .sx-social-rail__chip {
    width: var(--sx-rail-open);
    border-radius: 14px;
    /* Opening changes the shape, not the colour scheme — the panel stays the
       same near-black plate it is at rest, so collapsing returns it to exactly
       where it started. Only a shade deeper, to hold the wider area against a
       busy background, and still translucent so the backdrop blur reads.
       The teal label sits at 11.8:1 on this over the brightest band. */
    background: rgba(2, 12, 14, .88);
    color: #7ff2e6;
    border-color: rgba(50, 217, 203, .95);
    box-shadow: 0 0 26px rgba(50, 217, 203, .42),
                inset 0 1px 0 rgba(153, 255, 255, .14);
}

.sx-social-rail__link:hover .sx-social-rail__label,
.sx-social-rail__link:focus-visible .sx-social-rail__label {
    opacity: 1;
    transform: none;
}

.sx-social-rail__link:focus-visible { outline: none; }

.sx-social-rail__link:focus-visible .sx-social-rail__chip {
    box-shadow: 0 0 0 3px rgba(50, 217, 203, .45),
                0 0 24px rgba(50, 217, 203, .55);
}

/* Short viewports: the rail and the back-to-top button both live on the right,
   and centring stops being safe once there is not much height to centre in.
   Only the two sizes change; every dimension above is derived from them. */
@media (max-height: 680px) {
    .sx-social-rail {
        --sx-rail-size: 38px;
        --sx-rail-open: 104px;
        gap: .5rem;
        padding: .5rem .4rem;
    }

    .sx-social-rail__chip { font-size: .92rem; }
}

@media (prefers-reduced-motion: reduce) {
    .sx-social-rail__chip,
    .sx-social-rail__label { transition: none; }
}

/* --- Footer lockup -------------------------------------------------------- */

/* The logo PNG has #001a1a baked in so it joins the header capsule invisibly.
   Bootstrap's .bg-dark here is #000103, which would leave that ground showing
   as a lighter rectangle — so the footer band takes the same near-black. It
   also ties the foot of the page back to the head of it. */
.footer.bg-dark { background-color: #001a1a !important; }

/* Same asset, larger. Nothing else changes. */
.sx-lockup--footer { --sx-lockup-height: 78px; }

/* --- Menu ---------------------------------------------------------------- */

.sx-header .navbar-nav .nav-link {
    position: relative;
    color: var(--sx-header-ink);
    font-weight: 600;
    font-size: .92rem;
    letter-spacing: .2px;
    padding: 6px 12px;
    border-radius: 999px;
    border-bottom: 0;
    transition: color .25s ease, background-color .25s ease;
}

.sx-header .navbar-nav .nav-link:hover,
.sx-header .navbar-nav .nav-link:focus,
.sx-header .navbar-nav .nav-link.active {
    color: #99ffff !important;
    background: rgba(153, 255, 255, .12);
}

.sx-header .navbar-nav .nav-link:focus-visible {
    outline: 2px solid #99ffff;
    outline-offset: 2px;
}

/* Dropdown sits on the same dark family as the capsule. */
.sx-header .dropdown-menu {
    border: 1px solid rgba(153, 255, 255, .16);
    border-radius: 14px;
    background: linear-gradient(150deg, #063f3f 0%, #012626 60%, #001a1a 100%);
    box-shadow: 0 18px 40px rgba(0, 0, 0, .55);
    margin-top: .4rem;
    padding: .4rem;
}

.sx-header .dropdown-item {
    color: #dff6f6;
    font-weight: 500;
    padding: 9px 14px;
    border-radius: 9px;
}

.sx-header .dropdown-item:hover,
.sx-header .dropdown-item:focus {
    background: rgba(153, 255, 255, .14);
    color: #99ffff;
}

/* --- Actions ------------------------------------------------------------- */

.sx-header__actions {
    align-items: center;
    gap: 1rem;
    position: relative;
    z-index: 1;
}

.sx-header__phone {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    color: #cdeeee;
    font-size: .88rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: color .25s ease;
}
.sx-header__phone i { color: #99ffff; }
.sx-header__phone:hover { color: #99ffff; }

/* The button now lands on the bright end of the bar, so a teal pill would sink
   into it. White reads as the clear call to action instead. */
.sx-header__cta {
    display: inline-flex;
    align-items: center;
    padding: .5rem 1.2rem;
    border-radius: 999px;
    background: linear-gradient(120deg, #ffffff 0%, #dcfbfb 100%);
    color: #00302c;
    font-weight: 700;
    font-size: .85rem;
    white-space: nowrap;
    text-decoration: none;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
    transition: transform .3s cubic-bezier(.16, 1, .3, 1), box-shadow .3s ease;
}
.sx-header__cta:hover,
.sx-header__cta:focus-visible {
    color: #00302c;
    transform: translateY(-2px);
    box-shadow: 0 10px 26px rgba(0, 0, 0, .4);
}

/* --- Toggler ------------------------------------------------------------- */

.sx-header .navbar-toggler {
    border-color: rgba(153, 255, 255, .35);
    padding: 6px 10px;
    position: relative;
    z-index: 1;
}

.sx-header .navbar-toggler:focus {
    box-shadow: 0 0 0 .2rem rgba(153, 255, 255, .3);
}

.sx-header .navbar-toggler-icon {
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='%2399ffff' stroke-width='2.5' stroke-linecap='round' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
}

/* --- Collapsed navigation ------------------------------------------------ */

@media (max-width: 991.98px) {
    .sx-header .navbar { min-height: var(--sx-header-height-mobile); }
    .sx-header .sx-lockup { --sx-lockup-height: var(--sx-logo-height-mobile); }

    .sx-header__bar { border-radius: 26px; }

    .sx-header .navbar-collapse {
        max-height: calc(100vh - var(--sx-header-height-mobile) - 3rem);
        overflow-y: auto;
        padding-bottom: 12px;
    }

    .sx-header .navbar-nav .nav-link {
        border-radius: 10px;
        padding: 12px 14px;
    }
}


/* --- Compact scale: laptop overrides -------------------------------------- */

/* Kept at the very end of the file on purpose. These are plain class selectors
   competing with the base rules above at identical specificity, so the only
   thing that decides the winner is source order — a media query adds no weight
   of its own. Sitting this block anywhere earlier silently loses, which is
   exactly what happened the first time it was written.
 *
 * The band matches the html font-size steps near the top of this file: 992px to
 * 1600px is where display scaling puts most laptops. Above it, the wide desktop
 * the design was drawn for is untouched. */
@media (min-width: 992px) and (max-width: 1599.98px) {
    :root {
        --sx-header-height: var(--sx-header-height-lap);
        --sx-logo-height:   var(--sx-logo-height-lap);
    }

    /* The mid-page block carries the compacting, since the header and the cookie
       bar are chrome and read as cramped if squeezed. Type comes down, but so do
       the gaps between things — the spacing was doing as much of the damage as
       the sizes.

       The H1 is the loudest element on this band, as it is on the wide desktop.
       These two caps are the numbers to change if the hero still reads large:
       the H1 first, then the rotating line under it. Keep the gap between them
       — if they end up within a few pixels of each other the hierarchy stops
       reading and it looks like one heading that wrapped. */
    .sx-hero__h1 {
        font-size: clamp(1.7rem, 1.1rem + 2.2vw, 2.6rem);
        margin-bottom: clamp(1.9rem, 3.6vw, 3rem);
    }

    .sx-hero__slide { font-size: clamp(1.15rem, .9rem + 1.1vw, 1.6rem); }

    .sx-hero__eyebrow {
        font-size: clamp(.82rem, .78rem + .2vw, .92rem);
        margin-bottom: .5rem;
    }

    .sx-hero__slides { margin-bottom: 1.75rem; }

    /* The compact laptop sizing that used to live on .sx-hero__sub. That element
       is gone — each slide carries its own description now. */
    .sx-hero__slide-sub {
        max-width: 56ch;
        font-size: clamp(.86rem, .84rem + .16vw, .94rem);
        line-height: 1.5;
    }

    .sx-hero__cta {
        gap: .7rem;
        margin-bottom: clamp(1.5rem, 3.2vh, 2.25rem);
    }

    .sx-hero__btn {
        padding: .62rem 1.6rem;
        font-size: .9rem;
    }

    /* The stats panel was sized for a full-width desktop hero. */
    .sx-hero__stats { padding: .6rem .4rem; border-radius: 16px; }
    .sx-hero__stats li { padding-inline: clamp(.85rem, 2.2vw, 1.7rem); }
    .sx-hero__stats strong { font-size: clamp(1rem, .9rem + .35vw, 1.2rem); }
    .sx-hero__stats span { font-size: .76rem; }

    .sx-hero__inner {
        padding-top: calc(var(--sx-header-height) + clamp(1rem, 2.4vh, 1.75rem));
        padding-bottom: clamp(1.75rem, 4vh, 2.75rem);
    }

    .sx-services { padding-block: clamp(2.6rem, 5.5vw, 4.25rem); }

    .sx-social-rail { --sx-rail-size: 40px; --sx-rail-open: 106px; }
}

/* --- service hub: child links -------------------------------------------- */
/* Appended at the end deliberately: these rules have to win over the tile
   defaults above, and a media query adds no specificity — only source order
   settles it. */

.sx-tile__children{
    list-style:none;
    margin:0 0 .85rem;
    padding:0;
    display:flex;
    flex-wrap:wrap;
    gap:.35rem .5rem;
}

.sx-tile__children a{
    display:inline-block;
    padding:.2rem .6rem;
    border:1px solid rgba(255,255,255,.22);
    border-radius:999px;
    font-size:.76rem;
    line-height:1.5;
    color:rgba(255,255,255,.78);
    text-decoration:none;
    transition:border-color .18s ease, color .18s ease, background-color .18s ease;
}

.sx-tile__children a:hover,
.sx-tile__children a:focus-visible{
    border-color:var(--sx-accent, #2f9e6b);
    background:rgba(47,158,107,.14);
    color:#fff;
}

/* --- service detail: child and related cards ------------------------------ */

.sx-svc-card{
    border:1px solid transparent;
    transition:border-color .2s ease, transform .2s ease, box-shadow .2s ease;
}

.sx-svc-card:hover,
.sx-svc-card:focus-visible{
    border-color:var(--sx-accent, #2f9e6b);
    transform:translateY(-2px);
    box-shadow:0 10px 26px rgba(16,42,30,.10);
}

.sx-svc-card:focus-visible{
    outline:2px solid var(--sx-accent, #2f9e6b);
    outline-offset:2px;
}

@media (prefers-reduced-motion:reduce){
    .sx-svc-card{ transition:none; }
    .sx-svc-card:hover,
    .sx-svc-card:focus-visible{ transform:none; }
}

/* --- hero: line + description rotate together ----------------------------- */
/* Each slide now holds its own description, so both change on every tick. The
   slides still share one grid cell, which means the cell is as tall as the
   tallest slide and nothing below the hero moves as they rotate.
   Appended at the end of the file: the base .sx-hero__slide rules above set a
   display-size font that a nested paragraph would otherwise inherit, and only
   source order settles that. */

.sx-hero__slide{
    display:flex;
    flex-direction:column;
    align-items:center;
    gap:.85rem;
}

.sx-hero__slide-line{
    font-size:inherit;
    font-weight:inherit;
    line-height:inherit;
    letter-spacing:inherit;
    text-wrap:balance;
}

.sx-hero__slide-sub{
    max-width:56ch;
    margin:0;
    /* Reset every display-type property the slide sets, or this inherits a
       4rem bold headline. */
    font-size:clamp(1rem, .95rem + .3vw, 1.15rem);
    font-weight:400;
    line-height:1.6;
    letter-spacing:0;
    color:rgba(226,240,238,.82);
    text-wrap:pretty;
}

/* The accent colour applies to the headline only — the description stays
   readable body text. */
.sx-hero__slide-sub span{ color:inherit; }

@media (max-width:575.98px){
    .sx-hero__slide{ gap:.65rem; }
    .sx-hero__slide-sub{ font-size:.95rem; }

    /* Phones: the H1 keeps the lead, but the gap below it comes in — vertical
       space is the scarce thing here, not contrast. This sits outside the
       992-1600px laptop range above, so the two never fight. */
    .sx-hero__h1{
        font-size:clamp(1.65rem, 1.15rem + 2.4vw, 2.1rem);
        margin-bottom:1.35rem;
    }
    .sx-hero__slide-line{ font-size:1.15rem; }
}

/* --- service showcase ----------------------------------------------------- */
/* Every service as its own scroll section, with a sticky index that highlights
   whichever one is being read. Appended at the end of the file so these rules
   settle against anything above them by source order. */

.sx-showcase{
    position:relative;
    padding-block:clamp(3.5rem, 7vw, 6rem);
    background:#fff;
}

.sx-showcase__head{
    max-width:46rem;
    margin:0 auto clamp(2.5rem, 5vw, 4rem);
    text-align:center;
}

.sx-showcase__title{
    margin:.5rem 0 .9rem;
    font-size:clamp(1.6rem, 1.15rem + 1.7vw, 2.6rem);
    line-height:1.15;
    font-weight:700;
    letter-spacing:-.015em;
    text-wrap:balance;
}

.sx-showcase__lede{
    margin:0;
    color:#5b6b66;
    font-size:clamp(1rem, .96rem + .2vw, 1.08rem);
    line-height:1.65;
    text-wrap:pretty;
}

.sx-showcase__layout{ display:block; }

/* --- sticky index --- */

.sx-showcase__rail{ display:none; }

.sx-showcase__rail-list{
    list-style:none;
    margin:0;
    padding:0;
}

.sx-showcase__rail-item a{
    display:flex;
    align-items:center;
    gap:.6rem;
    padding:.34rem 0;
    color:#7b8b86;
    font-size:.86rem;
    line-height:1.35;
    text-decoration:none;
    transition:color .2s ease;
}

.sx-showcase__rail-item.is-child a{ padding-left:1.15rem; font-size:.82rem; }

.sx-showcase__rail-dot{
    flex:0 0 auto;
    width:7px;
    height:7px;
    border-radius:50%;
    background:#d3ddda;
    transition:background-color .2s ease, transform .2s ease;
}

.sx-showcase__rail-item.is-current a{ color:#14532d; font-weight:600; }
.sx-showcase__rail-item.is-current .sx-showcase__rail-dot{
    background:#2f9e6b;
    transform:scale(1.65);
}

.sx-showcase__rail-item a:hover{ color:#14532d; }

/* --- blocks --- */

.sx-showcase__blocks{
    display:flex;
    flex-direction:column;
    gap:clamp(1.6rem, 3.2vw, 2.6rem);
}

.sx-showcase__block{
    display:grid;
    grid-template-columns:auto 1fr;
    gap:clamp(.9rem, 2.4vw, 1.9rem);
    align-items:start;
    padding:clamp(1.3rem, 2.8vw, 2.1rem);
    border:1px solid #e6ecea;
    border-left:3px solid #e6ecea;
    border-radius:14px;
    background:#fff;
    /* Fixed header, so an anchor jump must stop short of it. */
    scroll-margin-top:6.5rem;
    transition:border-color .28s ease, box-shadow .28s ease, transform .28s ease;
}

/* A child sits visually inside its parent rather than beside it. */
.sx-showcase__block.is-child{
    margin-left:clamp(0rem, 3vw, 2.75rem);
    background:#fbfdfc;
}

.sx-showcase__block.is-current{
    border-color:#dbe7e2;
    border-left-color:#2f9e6b;
    box-shadow:0 14px 40px rgba(16,42,30,.09);
    transform:translateY(-2px);
}

.sx-showcase__num{
    font-family:"Saira", system-ui, sans-serif;
    font-size:clamp(1.5rem, 1rem + 1.9vw, 2.6rem);
    font-weight:700;
    line-height:1;
    color:#e2eae7;
    font-variant-numeric:tabular-nums;
    transition:color .28s ease;
}

.sx-showcase__block.is-current .sx-showcase__num{ color:#2f9e6b; }

.sx-showcase__body{ min-width:0; }

.sx-showcase__eyebrow{
    margin:0 0 .3rem;
    font-size:.74rem;
    font-weight:600;
    letter-spacing:.09em;
    text-transform:uppercase;
    color:#8a9994;
}

.sx-showcase__eyebrow a{ color:#2f9e6b; text-decoration:none; }
.sx-showcase__eyebrow a:hover{ text-decoration:underline; }

.sx-showcase__name{
    margin:0 0 .65rem;
    font-size:clamp(1.15rem, 1rem + .7vw, 1.55rem);
    line-height:1.25;
    font-weight:700;
}

.sx-showcase__name a{ color:#12241d; text-decoration:none; }
.sx-showcase__name a:hover{ color:#2f9e6b; }

.sx-showcase__intro{
    margin:0 0 .85rem;
    color:#46564f;
    font-size:.98rem;
    line-height:1.7;
    text-wrap:pretty;
}

.sx-showcase__note{
    margin:0 0 1rem;
    padding-left:.9rem;
    border-left:2px solid #d8e6e0;
    color:#63736d;
    font-size:.92rem;
    line-height:1.65;
}

.sx-showcase__label{
    margin:0 0 .4rem;
    font-size:.7rem;
    font-weight:700;
    letter-spacing:.1em;
    text-transform:uppercase;
    color:#9aa8a3;
}

.sx-showcase__chips{
    list-style:none;
    display:flex;
    flex-wrap:wrap;
    gap:.35rem;
    margin:0 0 .95rem;
    padding:0;
}

.sx-showcase__chips li{
    padding:.22rem .65rem;
    border:1px solid #dfe8e5;
    border-radius:999px;
    background:#f6faf8;
    font-size:.78rem;
    line-height:1.5;
    color:#46564f;
}

.sx-showcase__chips--muted li{ background:#fff; color:#63736d; }

.sx-showcase__meta{
    display:flex;
    flex-wrap:wrap;
    gap:.4rem 1.4rem;
    margin-bottom:.9rem;
    font-size:.8rem;
    color:#63736d;
}

.sx-showcase__meta strong{
    display:block;
    font-size:.68rem;
    font-weight:700;
    letter-spacing:.09em;
    text-transform:uppercase;
    color:#9aa8a3;
}

.sx-showcase__link{
    display:inline-flex;
    align-items:center;
    gap:.4rem;
    color:#14532d;
    font-size:.88rem;
    font-weight:600;
    text-decoration:none;
}

.sx-showcase__link:hover{ color:#2f9e6b; }
.sx-showcase__link span{ transition:transform .2s ease; }
.sx-showcase__link:hover span{ transform:translateX(3px); }

.sx-showcase__link:focus-visible,
.sx-showcase__name a:focus-visible{
    outline:2px solid #2f9e6b;
    outline-offset:3px;
    border-radius:3px;
}

/* The index only earns its space once there is room for it beside the text. */
@media (min-width:992px){
    .sx-showcase__layout{
        display:grid;
        grid-template-columns:15rem 1fr;
        gap:clamp(2rem, 4vw, 3.5rem);
        align-items:start;
    }

    .sx-showcase__rail{
        display:block;
        position:sticky;
        top:7rem;
        max-height:calc(100vh - 9rem);
        overflow-y:auto;
        padding-left:.9rem;
        border-left:1px solid #e6ecea;
    }
}

@media (max-width:575.98px){
    .sx-showcase__block{
        grid-template-columns:1fr;
        gap:.5rem;
    }
    .sx-showcase__block.is-child{ margin-left:0; }
    .sx-showcase__meta{ gap:.4rem 1rem; }
}

@media (prefers-reduced-motion:reduce){
    .sx-showcase__block,
    .sx-showcase__num,
    .sx-showcase__rail-dot,
    .sx-showcase__link span{ transition:none; }
    .sx-showcase__block.is-current{ transform:none; }
    .sx-showcase__link:hover span{ transform:none; }
}

/* --- theme variants for the two moved components -------------------------
   The numbered blocks and the pipeline swapped sections. Each was written for
   the background it used to sit on, so each needs the opposite treatment now.
   Appended at the end because these have to win over the base rules above, and
   source order is the only thing that decides that between equal specificity. */

/* Numbered blocks, now on the dark "Why choose us" band. The frame and the
   sketch already suit a dark ground — it is the body text either side of it
   that was written for white. */
.sx-reasons .sx-block__body h3{ color:#fff; }
.sx-reasons .sx-block__body p{ color:rgba(206,228,223,.74); }

/* The numerals are meant to run under the words — the digit is set to pass
   behind the text rather than stop short of it, and did so quietly while it was
   near-black. A 6px white edge round it is a different matter: white outline
   under white type is where the two stopped separating, which is what looked
   like a collision on rows four and five.

   The words carry their own ground now, so the digit can keep its size and its
   place and still pass behind them. Tight and dark rather than a glow: enough
   to hold a letter off whatever is under it, not enough to read as a shadow. */
.sx-reasons .sx-block__body h3,
.sx-reasons .sx-block__body p{
    text-shadow:
        0 1px 2px rgba(2, 14, 14, .95),
        0 0 10px rgba(2, 14, 14, .85),
        0 0 22px rgba(2, 14, 14, .55);
}

/* The pipeline, now on the white process band. */
.sx-path--light .sx-path__track{ stroke:rgba(10,36,34,.12); }

.sx-path--light .sx-path__progress{
    stroke:#0d7d75;
    filter:drop-shadow(0 0 5px rgba(13,125,117,.35));
}

.sx-path--light .sx-path__marker{
    background:#04211f;
    border-color:rgba(13,125,117,.5);
    box-shadow:0 0 0 6px rgba(13,125,117,.10), 0 12px 26px rgba(4,25,26,.20);
    color:#eafffb;
}

/* Numerals rather than ticks in the node, so the stage number is readable at
   a glance without counting down the list. */
.sx-path--light .sx-path__node{
    background:#fff;
    border-color:#d3e3e0;
    color:#8aa19d;
    font-family:"Saira",system-ui,sans-serif;
    font-size:.9rem;
    font-weight:700;
}

.sx-path--light .sx-path__item.is-reached .sx-path__node{
    background:#0d7d75;
    border-color:#0d7d75;
    color:#fff;
    box-shadow:0 0 0 5px rgba(13,125,117,.12);
}

/* Colour only. The size belongs to the base rule, which sets it from the same
   clamp the rest of the page's headings use — pinning 1.1rem here left the
   heading smaller than its own paragraph once the body text came up to the
   site's standard size. */
.sx-path--light .sx-path__card h3{ color:#0a2422; }
.sx-path--light .sx-path__card p{ color:#4a6664; }

/* Two paragraphs per stage here, against one line per reason, so the cards
   need more room than the dark variant allowed. */
.sx-path--light .sx-path__card p{ max-width:46ch; margin-bottom:.7rem; }
.sx-path--light .sx-path__card p:last-child{ margin-bottom:0; }

.sx-path--light:not(.is-ready) .sx-path__node{
    background:#0d7d75;
    border-color:#0d7d75;
    color:#fff;
}

@media (min-width:768px){
    .sx-path--light{ max-width:72rem; }
    .sx-path--light .sx-path__card p{ max-width:46ch; }
}

/* No ramp of its own any more. This section used to override the numeral's fill
   because the shared gradient was black across its first half — invisible on a
   dark band — but that half is gone: the numerals now carry the header's own
   teal-to-neon ramp, which is what the fill was asked to be. Overriding it here
   was why the fill appeared not to change at all. */

/* --- header: gradient anchored to the logo -------------------------------- */
/* The flat near-black run used to end at 42% of the capsule. A percentage is
   the wrong unit for it: the logo is a fixed width, so as the capsule grows the
   flat run grows with it and the colour gets pushed off the right-hand end —
   which is exactly what happens on a wide monitor.
   A length instead. The flat run now ends just past the logo whatever the
   capsule is doing, so the gradient starts where the brand mark stops.
   On narrow screens the length is a large fraction of a small capsule, and the
   later stops fall behind it — browsers clamp a stop to the one before it, so
   the ramp simply compresses to the right of the logo rather than breaking. */
:root{ --sx-header-flat:155px; }

@media (min-width:992px){  :root{ --sx-header-flat:190px; } }
@media (min-width:1600px){ :root{ --sx-header-flat:215px; } }
@media (min-width:1920px){ :root{ --sx-header-flat:238px; } }

/* Every stop after the logo is placed as a fraction of the space that is left,
   not of the whole capsule. Anchoring only the first stop was not enough: the
   next one was #003333 at 40%, and #001a1a to #003333 is black to black, so
   nothing visibly happened until #004d4d at 64% — which on a wide bar is most
   of the way to the right-hand end. The ramp now begins brightening
   immediately after the mark and spreads evenly across whatever remains, so it
   reads the same at 390px and at 2560px. */
.sx-header__bar{
    --sx-header-ramp:calc(100% - var(--sx-header-flat));

    background:linear-gradient(95deg,
        #001a1a 0,
        #001a1a var(--sx-header-flat),
        #003333 calc(var(--sx-header-flat) + var(--sx-header-ramp) * .10),
        #004d4d calc(var(--sx-header-flat) + var(--sx-header-ramp) * .32),
        #006666 calc(var(--sx-header-flat) + var(--sx-header-ramp) * .56),
        #009999 calc(var(--sx-header-flat) + var(--sx-header-ramp) * .80),
        #00b3b3 100%);
}

/* --- header: big screens -------------------------------------------------- */
/* Everything above 1600px was previously left at the size the design was drawn
   at, on the assumption that was the widest target. On a physically wide
   monitor the capsule then reads as a small pill floating in a lot of empty
   space — the bar is pinned to Bootstrap's container, which stops growing.
   Two tiers, so the header keeps pace with the screen instead of stopping. */

@media (min-width:1600px){
    :root{
        --sx-logo-height:60px;
        /* Kept in step with the logo: the hero and every page-header band pad
           themselves off this value, so a taller capsule that did not update it
           would sit over the content it is meant to clear. */
        --sx-header-height:76px;
    }

    /* Wider than the content container. The capsule is chrome, so it can use
       more of the screen than a column of reading text should. */

    .sx-header__bar{ padding-inline:clamp(1.15rem, 1.5vw, 1.9rem); }

    .sx-header .navbar-nav .nav-link{
        font-size:1rem;
        padding:8px 15px;
    }

    .sx-header .navbar-brand{ margin-right:1.6rem; }

    /* The CTA is sized in rem but the root font size is not scaled above
       1600px, so without this it would stay laptop-sized while everything
       beside it grew. */
    .sx-header__cta{ font-size:.95rem; padding:.62rem 1.5rem; }
}

@media (min-width:1920px){

    :root{
        --sx-logo-height:66px;
        --sx-header-height:84px;
    }

    .sx-header__bar{ padding-inline:clamp(1.4rem, 1.6vw, 2.2rem); }

    .sx-header .navbar-nav .nav-link{
        font-size:1.06rem;
        padding:9px 17px;
    }

    .sx-header .navbar-brand{ margin-right:2rem; }

    .sx-header__cta{ font-size:1rem; padding:.7rem 1.75rem; }
}

/* --- about: radial diagram ------------------------------------------------ */
/* The brand mark at the hub, six arms out to what defines the business, and a
   pulse of light running one arm at a time.

   The SVG viewBox is 1000x620 and the labels are positioned as percentages of
   the same box, so the drawn arms and the HTML text stay joined at every width
   with nothing measuring anything at runtime. */

.sx-ha__head{
    max-width:52rem;
    margin:0 auto clamp(1.75rem,3.5vw,3rem);
    text-align:center;
}

.sx-ha__head .sx-ha__lead{ margin-inline:auto; }

.sx-ha__tags--center{ justify-content:center; margin-top:clamp(1.5rem,3vw,2.5rem); }
.sx-ha__actions--center{ justify-content:center; }

.sx-orbit{ position:relative; }

.sx-orbit__stage{
    position:relative;
    width:100%;
    max-width:64rem;
    margin-inline:auto;
    aspect-ratio:1000 / 620;
}

.sx-orbit__svg{
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    overflow:visible;
}

/* The strips at rest. Wide enough to read as ribbons rather than wires — the
   ray travels *through* the strip, so the strip has to be thick enough to hold
   it. Round caps make each one finish as a rounded band rather than a cut line. */
/* Thin, and coloured by the gradient each path carries as an attribute — blue
   at the hub running to ocean green at the badge.

   No stroke here on purpose. A stroke in CSS beats a presentation attribute, so
   setting one would paint over all six gradients; the resting and lit states
   are told apart by opacity instead, which leaves the colour alone. */
.sx-orbit__pipe{
    stroke-width:6;
    stroke-linecap:round;
    opacity:.55;
    transition:opacity .45s ease;
}

.sx-orbit__pipe.is-lit{ opacity:1; }

/* The travelling light, running inside the strip. Slightly narrower than the
   strip so a hairline of the strip stays visible either side and the ray reads
   as flowing along a channel rather than replacing it. One dash out of a
   normalised length of 1, moved hub-end to label-end. */
/* A ray, not a pill. One solid dash renders as a rounded block sliding along
   the strip; a real streak needs a bright head with a trail breaking up behind
   it. That is what the dash pattern below is: a long leading dash, then dashes
   of shrinking length separated by shrinking gaps, so the tail thins out into
   nothing. The whole pattern sums to just under the normalised path length of
   1, so it never repeats — there is one ray on the strip, not a dotted line. */
/* No stroke colour here on purpose: each path carries its own gradient as a
   presentation attribute, and a CSS stroke would override all six of them. */
.sx-orbit__pulse{
    /* Just under the strip, so a hairline of the strip stays visible either
       side of the ray. */
    stroke-width:18;
    stroke-linecap:round;
    stroke-dasharray:.46 .54;
    stroke-dashoffset:.46;
    opacity:0;
    filter:drop-shadow(0 0 16px rgba(47,158,107,.75));
}

.sx-orbit__pulse.is-firing{
    /* Eased out of the hub and into the label rather than linear, so the ray
       accelerates away and settles as it lands. */
    animation:sx-orbit-ray 1.1s cubic-bezier(.32,.5,.25,1) forwards;
}

@keyframes sx-orbit-ray{
    0%   { stroke-dashoffset:.46;  opacity:0; }
    10%  { opacity:1; }
    /* Held to the very end rather than faded out: the ray is meant to arrive at
       the card, not evaporate short of it. */
    92%  { opacity:1; }
    100% { stroke-dashoffset:-.54; opacity:0; }
}

/* --- hub --- */

.sx-orbit__hub{
    position:absolute;
    left:50%;
    top:50%;
    width:15%;
    aspect-ratio:1;
    transform:translate(-50%,-50%);
    display:grid;
    place-items:center;
}

.sx-orbit__halo{
    position:absolute;
    inset:-26%;
    border-radius:50%;
    background:radial-gradient(circle,
        rgba(47,158,107,.20) 0%,
        rgba(47,158,107,.09) 45%,
        transparent 70%);
    animation:sx-orbit-breathe 4.5s ease-in-out infinite;
}

@keyframes sx-orbit-breathe{
    0%,100%{ transform:scale(1);    opacity:.75; }
    50%    { transform:scale(1.09); opacity:1; }
}

/* The mark spins; the halo does not. Separate elements so the glow stays put
   while the artwork turns.

   Turned about Y with perspective, so it narrows to an edge and opens out
   again — a coin turning rather than a wheel spinning. rotate() about Z was
   carrying the artwork upside down through half of every turn.

   A run at making this a globe — a textured sphere, then a pre-rendered
   rotation — is gone: on a mark this size the coin reads more clearly than any
   of it, which is the whole job. */
.sx-orbit__mark{
    position:relative;
    width:100%;
    height:auto;
    border-radius:50%;
    box-shadow:0 14px 40px rgba(4,25,26,.28), 0 0 0 6px #fff;
    animation:sx-orbit-spin 22s linear infinite;
}

@keyframes sx-orbit-spin{
    from{ transform:perspective(680px) rotateY(0deg); }
    to  { transform:perspective(680px) rotateY(360deg); }
}

/* --- labels --- */

.sx-orbit__labels{
    list-style:none;
    margin:0;
    padding:0;
}

.sx-orbit__label{
    position:absolute;
    top:var(--top);
    width:27.5%;
    transform:translateY(-50%);
    transition:opacity .45s ease, transform .45s ease;
}

/* The arms end at 72.6% and 27.4% of the box; the labels start just beyond.
   Pulled in slightly and given padding, so the card sits over the point the
   strip arrives at rather than floating away from it. */
.sx-orbit__label--right{ left:73.5%;  text-align:left; }
.sx-orbit__label--left { right:73.5%; text-align:right; }

.sx-orbit__label h4{
    margin:0 0 .3rem;
    font-size:clamp(.95rem,.85rem + .35vw,1.1rem);
    line-height:1.25;
    font-weight:700;
    color:#0a2422;
    text-wrap:balance;
    transition:color .45s ease;
}

.sx-orbit__label p{
    margin:0;
    font-size:clamp(.8rem,.76rem + .18vw,.9rem);
    line-height:1.55;
    color:#5b7370;
    text-wrap:pretty;
    transition:color .55s ease;
}

/* Dimmed until its arm fires. Never hidden — a label that is invisible when the
   script does not run is content lost to decoration. */
.sx-orbit.is-ready:not(.is-static) .sx-orbit__label{ opacity:.62; }

.sx-orbit.is-ready .sx-orbit__label.is-lit{
    opacity:1;
    transform:translateY(-50%) scale(1.03);
}

.sx-orbit.is-ready .sx-orbit__label.is-lit h4{ color:#0d7d75; }

/* --- the lit card -------------------------------------------------------- */
/* Registering the angle is what makes it animatable: an unregistered custom
   property is only a string and cannot be interpolated. Browsers without
   @property still get the gradient, just not the rotation. Same mechanism the
   cookie banner uses, registered separately so the two never share a clock. */
@property --sx-orbit-angle{
    syntax:"<angle>";
    initial-value:0deg;
    inherits:false;
}

.sx-orbit__label{
    padding:.85rem 1.05rem;
    border-radius:16px;
    border:1px solid transparent;
    /* The fill layer sits at z-index -1. Without a stacking context here it
       would drop behind the section itself and never be seen; isolation keeps
       it behind the text but in front of the page. */
    isolation:isolate;
    transition:opacity .45s ease, transform .45s ease,
               border-color .45s ease, box-shadow .45s ease;
}

/* What the ray leaves behind: the card fills green into black, from the side
   the strip arrived on.

   The fill is on a pseudo-element whose opacity is animated, not on the card's
   own background. Gradients do not interpolate — transitioning background-image
   between two of them snaps rather than fades — so the only way to get a smooth
   fill is to cross-fade a layer that is already painted. */
.sx-orbit__label::after{
    content:"";
    position:absolute;
    inset:0;
    z-index:-1;
    border-radius:inherit;
    background:linear-gradient(115deg,
        #14503f 0%,
        #0b2f26 42%,
        #061a15 78%,
        #030d0b 100%);
    opacity:0;
    transition:opacity .55s ease;
}

.sx-orbit.is-ready .sx-orbit__label.is-lit::after{ opacity:1; }

/* Right-hand cards are entered from their left edge, left-hand cards from their
   right, so the gradient runs the way the ray was travelling. */
.sx-orbit__label--left::after{ background-image:linear-gradient(-115deg,
        #14503f 0%,
        #0b2f26 42%,
        #061a15 78%,
        #030d0b 100%); }

.sx-orbit.is-ready .sx-orbit__label.is-lit{
    border-color:transparent;
    box-shadow:0 18px 44px rgba(4,25,26,.30);
}

/* Text inverts onto the dark fill. Colour interpolates, so this crossfades with
   the panel underneath rather than switching at the end. */
.sx-orbit.is-ready .sx-orbit__label.is-lit h4{ color:#7fe9d4; }
.sx-orbit.is-ready .sx-orbit__label.is-lit p{ color:rgba(219,240,234,.86); }

/* The rotating border. A conic gradient painted into the padding box and
   masked to the 1px frame, so only the edge shows the colour running round. */
.sx-orbit.is-ready .sx-orbit__label.is-lit::before{
    content:"";
    position:absolute;
    inset:0;
    border-radius:inherit;
    padding:1px;
    background:conic-gradient(from var(--sx-orbit-angle),
        #2f9e6b, #32d9cb, #7fe9d4, #0d7d75, #2f9e6b);
    -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;
            mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite:exclude;
    pointer-events:none;
    animation:sx-orbit-border 4s linear infinite;
}

@keyframes sx-orbit-border{ to{ --sx-orbit-angle:360deg; } }

/* --- narrow screens ------------------------------------------------------ */
/* Six labels around a circle need horizontal room a phone has not got. Below
   992px the diagram becomes the mark above a plain list, which is the same
   markup read a different way. */
@media (max-width:991.98px){
    .sx-orbit__stage{
        aspect-ratio:auto;
        max-width:34rem;
        display:flex;
        flex-direction:column;
        align-items:center;
        gap:1.75rem;
    }

    .sx-orbit__svg{ display:none; }

    .sx-orbit__hub{
        position:static;
        transform:none;
        width:8.5rem;
    }

    .sx-orbit__labels{
        display:grid;
        gap:1.25rem;
        width:100%;
    }

    .sx-orbit__label,
    .sx-orbit__label--right,
    .sx-orbit__label--left{
        position:static;
        width:100%;
        left:auto;
        right:auto;
        top:auto;
        transform:none;
        text-align:left;
        padding-left:1rem;
        border-left:2px solid #d9eae5;
    }

    .sx-orbit.is-ready:not(.is-static) .sx-orbit__label{ opacity:1; }

    .sx-orbit.is-ready .sx-orbit__label.is-lit{
        transform:none;
        border-left-color:#2f9e6b;
        box-shadow:none;
        background:rgba(47,158,107,.06);
    }

    /* The rotating frame is anchored by the label's own positioning context.
       Here the labels are static, so the pseudo-element would resolve against
       the stage instead and paint a stray gradient across the section. */
    .sx-orbit .sx-orbit__label::before{ display:none; }

    /* Same reasoning for the fill: the list reads better as tinted rows than as
       five dark panels stacked down a white page. */
    .sx-orbit .sx-orbit__label::after{ display:none; }
    .sx-orbit.is-ready .sx-orbit__label.is-lit h4{ color:#0d7d75; }
    .sx-orbit.is-ready .sx-orbit__label.is-lit p{ color:#5b7370; }
}

@media (prefers-reduced-motion:reduce){
    .sx-orbit__mark,
    .sx-orbit__halo{ animation:none; }
    .sx-orbit__label::before{ animation:none; }
    .sx-orbit__pulse{ display:none; }
    .sx-orbit__label{ transition:none; }
}

/* --- about: mirrored wash + bigger diagram type --------------------------- */

/* Mirror of .sx-ha::before on the right-hand side, so the section is lit from
   both edges rather than fading out to plain white under the right-hand cards.
   Same geometry, same colour, flipped. */
.sx-ha__glow{
    content:"";
    position:absolute;
    z-index:0;
    pointer-events:none;
    right:-12%;
    top:-6%;
    width:58%;
    aspect-ratio:1;
    background:radial-gradient(circle at 58% 42%,
        rgba(50,217,203,.20) 0%,
        rgba(50,217,203,.07) 45%,
        rgba(50,217,203,0) 70%);
}

/* The label type was set for a 1440px laptop and stayed there. The root font
   size is not scaled above 1600px — see the compact-scale note at the top of
   this file — so a clamp that tops out at 1.1rem gives a 1.1rem heading on a
   2560px monitor. These are the two tiers the header already uses. */
.sx-orbit__label h4{ font-size:clamp(1rem,.88rem + .5vw,1.3rem); }
.sx-orbit__label p{ font-size:clamp(.85rem,.8rem + .3vw,1.02rem); }

@media (min-width:1600px){
    .sx-orbit__stage{ max-width:74rem; }
    .sx-orbit__label h4{ font-size:1.45rem; }
    .sx-orbit__label p{ font-size:1.08rem; line-height:1.6; }
    .sx-orbit__label{ padding:1.05rem 1.3rem; }
}

@media (min-width:1920px){
    .sx-orbit__stage{ max-width:82rem; }
    .sx-orbit__label h4{ font-size:1.6rem; }
    .sx-orbit__label p{ font-size:1.16rem; }
    .sx-orbit__label{ padding:1.2rem 1.5rem; }
}

/* --- about diagram: caption and numerals ---------------------------------- */

.sx-orbit__caption{
    margin:0 auto clamp(1.5rem,3vw,2.5rem);
    text-align:center;
    font-size:clamp(1.05rem,.95rem + .5vw,1.4rem);
    font-weight:700;
    line-height:1.25;
    letter-spacing:-.01em;
    color:#0a2422;
}


@media (min-width:1600px){
    .sx-orbit__caption{ font-size:1.6rem; }
}


/* --- about diagram: pipes, badges, cards ---------------------------------- */
/* The row used to be the card itself. It is now a two-part row — a circular
   badge sitting on the end of the pipe, and a bordered card beside it — so the
   card treatment moves off .sx-orbit__label and onto .sx-orbit__card. These
   come last in the file because they have to win over the earlier rules that
   still describe the row as a card. */

/* Back to the width they were, and coloured by the gradient the path carries as
   an attribute: blue at the hub running to ocean green at the badge.

   No stroke declared here. A stroke in CSS beats a presentation attribute, so
   one would paint over all six gradients — which is exactly what the flat
   #dcece7 that used to be on this rule was doing. Resting and lit are told
   apart by opacity instead, which leaves the colour alone.

   This is the rule that governs, not the one earlier in the file: same
   selector, same specificity, and this one comes last. */
.sx-orbit__pipe{
    stroke-width:26;
    stroke-linecap:round;
    opacity:.55;
    transition:opacity .45s ease;
}

.sx-orbit__pipe.is-lit{ opacity:1; }

/* --- the row --- */

/* Spans from 70% of the stage to its edge. The badge takes 18% of that, putting
   its centre at 70% + 9% = 72.7% — exactly the x each pipe is drawn to. Both
   figures are proportional, so they stay aligned at every width. */
.sx-orbit__label{
    display:flex;
    align-items:center;
    gap:4%;
    width:auto;
    padding:0;
    border:0;
    box-shadow:none;
}

.sx-orbit__label--right{ left:70%;  right:0;   flex-direction:row; }
.sx-orbit__label--left { right:70%; left:0;    flex-direction:row-reverse; }

/* The row is no longer the thing that gets a frame, so the old frame and fill
   pseudo-elements are switched off here and rebuilt on the card. */
.sx-orbit__label::before,
.sx-orbit__label::after{ display:none; }

.sx-orbit.is-ready .sx-orbit__label.is-lit{ box-shadow:none; }

/* --- the badge --- */

.sx-orbit__badge{
    flex:0 0 18%;
    aspect-ratio:1;
    display:grid;
    place-items:center;
    border-radius:50%;
    background:#fff;
    border:2px solid var(--c);
    color:var(--c);
    /* cqw would be cleaner but the stage is not a container; vw tracks the
       viewport closely enough for an icon glyph. */
    font-size:clamp(.95rem,.7rem + .7vw,1.5rem);
    box-shadow:0 8px 22px rgba(4,25,26,.16);
    position:relative;
    z-index:2;
    transition:background-color .5s ease, color .5s ease,
               border-color .5s ease, transform .5s ease;
}

.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge{
    background:var(--c);
    border-color:var(--c);
    color:#fff;
    transform:scale(1.08);
    box-shadow:0 10px 28px rgba(4,25,26,.28);
}

/* --- the card --- */

.sx-orbit__card{
    flex:1 1 auto;
    min-width:0;
    position:relative;
    isolation:isolate;
    padding:.8rem 1.05rem;
    border:1.5px solid color-mix(in srgb, var(--c) 45%, #ffffff);
    border-radius:16px;
    background:#fff;
    transition:border-color .5s ease, box-shadow .5s ease;
}

.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card{
    border-color:transparent;
    box-shadow:0 18px 44px rgba(4,25,26,.30);
}

/* The fill the ray leaves behind. On a pseudo-element whose opacity is
   cross-faded, because gradients do not interpolate — transitioning
   background-image between two of them snaps rather than fades. */
.sx-orbit__card::after{
    content:"";
    position:absolute;
    inset:0;
    z-index:-1;
    border-radius:inherit;
    background:linear-gradient(115deg, #14503f 0%, #0b2f26 42%, #061a15 78%, #030d0b 100%);
    opacity:0;
    transition:opacity .55s ease;
}

.sx-orbit__label--left .sx-orbit__card::after{
    background-image:linear-gradient(-115deg, #14503f 0%, #0b2f26 42%, #061a15 78%, #030d0b 100%);
}

.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card::after{ opacity:1; }

/* The rotating frame: a conic gradient painted into the padding box and masked
   to the 1px edge, so only the border shows the colour running round. */
.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card::before{
    content:"";
    position:absolute;
    inset:0;
    border-radius:inherit;
    padding:1.5px;
    background:conic-gradient(from var(--sx-orbit-angle),
        var(--c), #32d9cb, #7fe9d4, #0d7d75, var(--c));
    -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite:xor;
            mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite:exclude;
    pointer-events:none;
    animation:sx-orbit-border 4s linear infinite;
}

.sx-orbit__card h4{ margin:0 0 .25rem; }
.sx-orbit__card p{ margin:0; }

/* --- narrow screens ------------------------------------------------------ */
@media (max-width:991.98px){
    .sx-orbit__label,
    .sx-orbit__label--right,
    .sx-orbit__label--left{
        flex-direction:row;
        left:auto;
        right:auto;
        gap:.9rem;
        padding-left:0;
        border-left:0;
        text-align:left;
    }

    .sx-orbit__badge{ flex:0 0 2.9rem; }

    .sx-orbit__card{
        padding:.7rem .9rem;
        border-color:color-mix(in srgb, var(--c) 40%, #ffffff);
    }

    /* Five dark panels down a white page reads worse than tinted rows. */
    .sx-orbit__card::after{ display:none; }
    .sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card{
        border-color:var(--c);
        box-shadow:0 8px 22px rgba(4,25,26,.10);
    }
    .sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card::before{ display:none; }
}

@media (prefers-reduced-motion:reduce){
    .sx-orbit__badge,
    .sx-orbit__card{ transition:none; }
    .sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge{ transform:none; }
    .sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__card::before{ animation:none; }
}

/* --- about diagram: matching the reference connection --------------------- */
/* Three differences from the first pass, all in how the badge meets the card:
   the circle overlaps the card's inboard edge instead of standing off it, the
   card corners are far rounder, and the circle keeps a white face with a
   coloured ring rather than filling solid. */

/* No gap — the overlap is created by pulling the card under the badge, so the
   badge centre stays exactly where the pipes are drawn to. */
.sx-orbit__label{ gap:0; }

.sx-orbit__card{
    z-index:1;
    border-radius:28px;
    border-width:2px;
}

/* Pulled under the circle by roughly a third of its width, with the padding on
   that side increased by the same amount so the text still starts clear of it. */
.sx-orbit__label--right .sx-orbit__card{
    margin-left:-7%;
    padding-left:calc(7% + 1.1rem);
}

.sx-orbit__label--left .sx-orbit__card{
    margin-right:-7%;
    padding-right:calc(7% + 1.1rem);
}

/* White face, coloured ring, sitting over the card. The reference keeps every
   circle white — the colour is carried by the ring and the glyph, which is also
   what stops six filled discs competing with the hub. */
.sx-orbit__badge{
    border-width:3px;
    background:#fff;
    box-shadow:0 6px 18px rgba(4,25,26,.14),
               0 0 0 6px rgba(255,255,255,.9);
}

/* Lit: still white, but the ring brightens and picks up a halo in its own
   colour. */
.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge{
    background:#fff;
    color:var(--c);
    border-color:var(--c);
    transform:scale(1.1);
    box-shadow:0 8px 24px rgba(4,25,26,.22),
               0 0 0 6px rgba(255,255,255,.95),
               0 0 22px 2px color-mix(in srgb, var(--c) 45%, transparent);
}

@media (max-width:991.98px){
    /* Stacked rows have no inboard side to overlap, so the badge sits beside
       the card as a normal list marker would. */
    .sx-orbit__label{ gap:.9rem; }

    .sx-orbit__label--right .sx-orbit__card,
    .sx-orbit__label--left .sx-orbit__card{
        margin-left:0;
        margin-right:0;
        padding-left:.9rem;
        padding-right:.9rem;
    }

    .sx-orbit__card{ border-radius:20px; }
}

/* --- about diagram: the reference geometry, properly ----------------------
   Three things the previous pass got wrong, all geometric:

   1. The card was a rounded rectangle. It is a pill — radius equal to half its
      height, so each end is a true semicircle.
   2. The badge was an arbitrary size sitting near the card. Its diameter now
      equals the card's height, and it is centred on the centre of the card's
      inboard semicircular end — so the badge outline and the card's rounded end
      are the same circle, sharing one curve. That is what makes them read as
      one object rather than two overlapping ones.
   3. The pipe stopped at the badge. It now wraps the badge's outer half as a
      ring, so the connector holds the circle rather than merely touching it.

   Everything is proportional to the stage. The badge is 8.6% of stage width and
   the row is 13.87% of stage height — the same number of pixels, because the
   stage is locked to a 1000x620 ratio (8.6 / 0.62 = 13.87). Fixed rem sizes
   would drift out of the SVG's coordinate space as the stage resized. */

.sx-orbit__label{
    left:0;
    right:0;
    height:17.74%;
    display:block;
    gap:0;
}

/* --- the pill --- */

.sx-orbit__card{
    position:absolute;
    top:0;
    bottom:0;
    display:flex;
    flex-direction:column;
    justify-content:center;
    /* Half the height, so both ends are semicircles. */
    border-radius:999px;
    border:1.5px solid color-mix(in srgb, var(--c) 42%, #ffffff);
    background:#fff;
    margin:0;
}

/* Inboard edge starts half a badge before the pipe endpoint, putting the centre
   of its rounded end exactly on that endpoint. 72.7 - 4.3 = 68.4. */
.sx-orbit__label--right .sx-orbit__card{
    left:62.5%;
    right:0;
    margin:0;
    padding:.5rem 1.5rem .5rem 12.2%;
    text-align:left;
}

.sx-orbit__label--left .sx-orbit__card{
    right:62.5%;
    left:0;
    margin:0;
    padding:.5rem 12.2% .5rem 1.5rem;
    text-align:right;
}

/* --- the badge --- */

.sx-orbit__badge{
    position:absolute;
    top:50%;
    width:11%;
    aspect-ratio:1;
    transform:translate(-50%,-50%);
    border:1.5px solid color-mix(in srgb, var(--c) 42%, #ffffff);
    background:#fff;
    box-shadow:none;
    z-index:3;
}

.sx-orbit__label--right .sx-orbit__badge{ left:68%; }
.sx-orbit__label--left  .sx-orbit__badge{ left:32%; }

/* The pipe's grip. A ring around the badge's outer half — the side the pipe
   arrives from — so the connector wraps the circle instead of stopping at it.
   conic-gradient starts at twelve o'clock and runs clockwise, so `from 180deg`
   paints six o'clock round to twelve: the left half. The radial mask cuts the
   disc down to a ring. */
.sx-orbit__badge::before{
    content:"";
    position:absolute;
    inset:-16%;
    border-radius:50%;
    background:conic-gradient(from 180deg,
        color-mix(in srgb, var(--c) 30%, #dcece7) 0deg 180deg,
        transparent 180deg);
    -webkit-mask:radial-gradient(closest-side, transparent 74%, #000 74%);
            mask:radial-gradient(closest-side, transparent 74%, #000 74%);
    transition:background .5s ease;
    z-index:-1;
}

.sx-orbit__label--left .sx-orbit__badge::before{
    background:conic-gradient(from 0deg,
        color-mix(in srgb, var(--c) 30%, #dcece7) 0deg 180deg,
        transparent 180deg);
}

/* The grip takes the full colour when the ray lands. */
.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge::before{
    background:conic-gradient(from 180deg, var(--c) 0deg 180deg, transparent 180deg);
}

.sx-orbit.is-ready .sx-orbit__label--left.is-lit .sx-orbit__badge::before{
    background:conic-gradient(from 0deg, var(--c) 0deg 180deg, transparent 180deg);
}

.sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge{
    background:#fff;
    border-color:var(--c);
    border-width:2px;
    transform:translate(-50%,-50%) scale(1.04);
    box-shadow:none;
}

.sx-orbit__card h4{ margin:0 0 .15rem; line-height:1.2; }
.sx-orbit__card p{ line-height:1.45; }

/* --- narrow screens ------------------------------------------------------ */
@media (max-width:991.98px){
    .sx-orbit__label{
        position:static;
        height:auto;
        display:flex;
        align-items:center;
        gap:.9rem;
    }

    .sx-orbit__card{
        position:static;
        flex:1 1 auto;
        border-radius:999px;
        padding:.7rem 1.1rem !important;
        text-align:left !important;
    }

    .sx-orbit__badge{
        position:static;
        flex:0 0 3rem;
        width:3rem;
        transform:none;
    }

    .sx-orbit.is-ready .sx-orbit__label.is-lit .sx-orbit__badge{ transform:none; }
    .sx-orbit__badge::before{ display:none; }
}

/* --- home hero: left-aligned ----------------------------------------------
   Scoped to .sx-home, which only Views/Home/Index.cshtml sets. The hero is a
   shared partial, so an unscoped change here would rewrite /home-v2 as well —
   and that page is being kept as the untouched backup.

   The column starts at the container's left edge, which is the same x the
   header capsule starts at, so the hero text lines up with the header rather
   than floating independently of it. */

.sx-home .sx-hero__inner{
    text-align:left;
}

/* Each block gets its own measure rather than one wrapper, because they want
   different widths: a headline breaks best around 18 characters, a paragraph
   reads best around 50. A single wrapper would force one compromise on both. */
.sx-home .sx-hero__h1{
    max-width:19ch;
    margin-inline:0;
    text-wrap:balance;
}

.sx-home .sx-hero__slides{
    justify-items:start;
}

.sx-home .sx-hero__slide{
    align-items:flex-start;
    text-align:left;
}

.sx-home .sx-hero__slide-line{
    max-width:26ch;
}

.sx-home .sx-hero__slide-sub{
    max-width:48ch;
    margin-inline:0;
    text-align:left;
}

.sx-home .sx-hero__cta{
    justify-content:flex-start;
}

/* inline-flex keeps the panel only as wide as its three columns; the auto
   margins were what centred it. */
.sx-home .sx-hero__stats{
    margin-inline:0;
    justify-content:flex-start;
}

/* Phones get the centred treatment back. At that width a left column and a
   right gutter is just a narrower column, and centred type sits better under a
   centred logo. */
@media (max-width:575.98px){
    .sx-home .sx-hero__inner{ text-align:center; }
    .sx-home .sx-hero__h1{ margin-inline:auto; }
    .sx-home .sx-hero__slides{ justify-items:center; }
    .sx-home .sx-hero__slide{ align-items:center; text-align:center; }
    .sx-home .sx-hero__slide-sub{ margin-inline:auto; text-align:center; }
    .sx-home .sx-hero__cta{ justify-content:center; }
    .sx-home .sx-hero__stats{ margin-inline:auto; justify-content:center; }
}

/* --- home hero: tighter type ----------------------------------------------
   Smaller across the board, and every block sized so its line does not wrap.

   The three sizes step by a constant ratio rather than being picked
   independently — 2.6rem / 1.6rem / 1rem is roughly 1.6x between each, so the
   hierarchy reads as deliberate at every width instead of the gaps opening and
   closing as the viewport changes.

   Measures are wide enough that the copy sets on one line: the H1 is 28
   characters, the rotating line at most 27, and the descriptions at most 46. */

.sx-home .sx-hero__h1{
    font-size:clamp(1.75rem, 1.15rem + 2.1vw, 2.6rem);
    max-width:none;
    /* One line, so balancing has nothing to balance and only risks a break. */
    text-wrap:nowrap;
}

.sx-home .sx-hero__slide{
    font-size:clamp(1.15rem, .95rem + .75vw, 1.6rem);
}

.sx-home .sx-hero__slide-line{
    max-width:none;
    text-wrap:nowrap;
}

.sx-home .sx-hero__slide-sub{
    font-size:clamp(.9rem, .86rem + .18vw, 1rem);
    max-width:none;
    text-wrap:nowrap;
}

/* Below this the longest line stops fitting, so wrapping comes back on rather
   than letting the text run under the social rail or off the page. */
@media (max-width:767.98px){
    .sx-home .sx-hero__h1,
    .sx-home .sx-hero__slide-line,
    .sx-home .sx-hero__slide-sub{ text-wrap:balance; }

    .sx-home .sx-hero__slide-sub{ max-width:44ch; }
}

/* --- home hero: inset card ------------------------------------------------
   The hero stops being full-bleed and becomes a rounded panel with the page
   showing around it, so the header capsule sits on light ground rather than
   floating over the animation.

   Scoped to .sx-home. The hero is a shared partial and /home-v2 keeps the
   full-bleed version.

   The gutter is one custom property, used by the margin on three sides and by
   the top offset. Changing the inset is therefore one number, and the four
   sides cannot drift apart. */

/* The frame the card sits in — the strip down each side, the band the header
   capsule floats on, and the gap between the header and the hero.

   It was a flat #eef4f4. It now carries the same treatment as the About
   section: white, with a teal wash coming in from each upper corner. The
   numbers are that section's own — a circle 58% wide, rgba(50,217,203,.20)
   falling to nothing by 70% — so the two are the same background rather than
   two pale greens that nearly match.

   Sized and placed in vw, because the only part of this that is ever visible is
   the frame around the opening screen: everything below the hero is an opaque
   section painted over it.

   vw for the vertical offset too, not a percentage. A percentage there resolves
   against the background's painting area, which on <body> is the whole document
   — some sixteen screens tall — so "-12%" put the centre about 1900px above the
   page against a radius of 1100, and the wash rendered as nothing at all. */
.sx-home{
    background-color:#fff;
    background-image:
        radial-gradient(58vw 58vw at -8vw -10vw,
            rgba(50, 217, 203, .20) 0%,
            rgba(50, 217, 203, .07) 45%,
            rgba(50, 217, 203, 0) 70%),
        radial-gradient(58vw 58vw at calc(100% + 8vw) -10vw,
            rgba(50, 217, 203, .20) 0%,
            rgba(50, 217, 203, .07) 45%,
            rgba(50, 217, 203, 0) 70%);
    background-repeat:no-repeat;
}

/* The card treatment is gone: the hero is the full first screen again, exactly
   as it is on /home-v2 — artwork from y=0, edge to edge, square corners, with
   the capsule floating on it rather than above it.

   What that means rule by rule: no radius and no shadow, because there are no
   corners or edges to describe; no min-height of its own, so the 100vh the base
   rule sets is what applies; and no margins anywhere, which is what the deleted
   blocks further down handled. overflow stays — the canvas is inset:0 in here
   and still should not paint outside it. */
.sx-home .sx-hero{
    overflow:hidden;
}

/* The inner padding has to clear the header again. The card used to start below
   the capsule, so this was ordinary internal spacing; with the artwork running
   to the top the capsule floats over this box, and the top padding is what keeps
   the eyebrow out from under it. */
.sx-home .sx-hero__inner{
    padding-top:calc(var(--sx-header-height) + clamp(3rem, 7vh, 5.5rem));
    padding-bottom:clamp(3rem, 7vh, 5.5rem);
}


@media (max-width:991.98px){
    .sx-home .sx-hero__inner{
        padding-top:calc(var(--sx-header-height-mobile) + clamp(2.25rem, 6vh, 3.5rem));
        padding-bottom:clamp(2.25rem, 6vh, 3.5rem);
    }
}

/* --- one shell width for header and hero ----------------------------------
   The header sits in a Bootstrap .container; the hero card was using a fixed
   gutter. Two different measurements, so their left and right edges could not
   agree — which is the asymmetry.

   Both now read the same variable. The ladder below mirrors Bootstrap's own
   container breakpoints exactly (540/720/960/1140/1320, verified against
   bootstrap.min.css) and then continues into the two wide tiers this site
   added, so nothing changes at any existing width — it just becomes a single
   source both elements can share.

   --sx-shell-gap is the header's own padding-block. Using it for the space
   above the card as well makes three gaps identical by construction: viewport
   to header, header to card, card to the section below. */

:root{
    --sx-shell-gap:clamp(.6rem, 1.4vw, 1.1rem);
}


.sx-header{ padding-block:var(--sx-shell-gap); }

/* The inner is itself a .container, which would inset the text a second time
   and centre it in a box narrower than the card. It fills the card instead, and
   takes the same inline padding the header capsule gives its logo — so the
   headline starts at exactly the x the logo starts at. */
.sx-home .sx-hero__inner{
    max-width:100%;
    padding-inline:clamp(.9rem, 1.8vw, 1.5rem);
}

/* --- one inline padding for capsule and card ------------------------------
   The capsule's padding grows on wide screens; the hero card's did not, so the
   headline and the logo started at different x above 1600px — 116 against 124
   at 1920. One variable now feeds both, tiered the same way, so the two indents
   cannot drift again. */

:root{ --sx-shell-pad:clamp(.9rem, 1.8vw, 1.5rem); }

@media (min-width:1600px){ :root{ --sx-shell-pad:clamp(1.15rem, 1.5vw, 1.9rem); } }
@media (min-width:1920px){ :root{ --sx-shell-pad:clamp(1.4rem, 1.6vw, 2.2rem); } }

.sx-header__bar{ padding-inline:var(--sx-shell-pad); }
.sx-home .sx-hero__inner{ padding-inline:var(--sx-shell-pad); }

/* --- equal margins on every side ------------------------------------------
   The header and the hero card previously sat in a fixed-width container, which
   made their side margins (71px at 1440) many times their vertical gaps (17px).
   Both now span the viewport minus one gap, so all four margins are the same
   number and come from the same variable — reduce --sx-shell-gap and the whole
   frame tightens evenly.

   The container-width ladder this replaced has been deleted rather than left
   overridden; nothing reads it now. */

:root{
    /* Was clamp(.6rem, 1.4vw, 1.1rem). Tighter, and the vw term is gentler so
       the frame stays close to constant instead of opening up on wide screens. */
    --sx-shell-gap:clamp(.4rem, .7vw, .7rem);
}

/* Full width minus the gap, rather than a centred container. padding-inline
   rather than max-width, so the capsule's own edges land on the gap. */
.sx-header .container{
    max-width:none;
    width:100%;
    padding-inline:var(--sx-shell-gap);
}

/* --- home: social rail hidden ---------------------------------------------
   The rail is fixed to the viewport edge, so with the hero inset it floated
   over the light page rather than sitting on the dark artwork it was designed
   for. Hidden on this page only — the other pages still show it.
   !important because the markup carries Bootstrap's .d-lg-flex, which is
   itself !important. */
.sx-home .sx-social-rail{ display:none !important; }


/* --- home hero: the card is the first screen -------------------------------
   The card was content-height (min-height:auto), so it ended wherever the
   figures ended and the statistics band below it came into view underneath —
   two blocks sharing the opening screen. It now fills the screen exactly.

   Exactly, not roughly: the page above and around the card is built from three
   identical gaps and the fixed header, all of which are already variables, so
   the height is what is left after them —

       viewport to header   var(--sx-shell-gap)   ┐
       the header capsule   var(--sx-header-height) ├ the card's margin-top
       header to card       var(--sx-shell-gap)   ┘
       the card             what this rule sets
       card to next section var(--sx-shell-gap)     the card's margin-bottom

   so 100vh minus the capsule minus three gaps. --sx-header-height is itself
   re-declared at 1600px and at 1920px, which is what keeps this correct on a
   big desktop without a second rule: the taller capsule takes its height out
   of the card automatically.

   Desktop only. On a phone the same arithmetic would force a fixed-height box
   around copy that wraps to an unknown number of lines, and content would be
   cut off rather than the card growing to hold it. */

@media (min-width:992px){
    .sx-home .sx-hero{
        /* The whole screen, the way the base rule has it and the way /home-v2
           reads — not the screen less the capsule and three gaps, which is what
           the inset card had to be. */

        /* Was centre, which is what a flex row does to a single item that is
           shorter than the box. The inner has to be as tall as the hero before
           it can distribute anything inside itself. */
        align-items:stretch;
    }

    /* The inner fills the card and centres the split in it, which is what puts
       the copy on the middle line of the hero. The split keeps its own content
       height so the cards beside the copy can be measured from it. */
    .sx-home .sx-hero__inner{
        display:flex;
        flex-direction:column;
        justify-content:center;
    }

    /* The cookie banner drops the hero to align-items:flex-end so the figures
       finish just above it. That predates this layout: with the inner no longer
       stretched, every auto margin resolves to zero and the whole column falls
       to the bottom of a full-screen card. The banner's own reserve — the extra
       padding-bottom on .sx-hero__inner — already lifts the figures clear of it,
       so the card can stay stretched and keep its three zones while the banner
       is up.

       Both classes are put on <body> — sx-home by the view, sx-cookie-open by
       soulogix-cookie.js — so this is one compound selector, not a descendant
       one. */
    body.sx-cookie-open.sx-home .sx-hero{ align-items:stretch; }
}

/* --- a wider inset, and everything held to it ------------------------------
   The capsule and the card are now nearly the full width of the screen, but
   their contents still sat on a padding sized for the narrow container they
   used to live in — the logo was 35px from the capsule's edge at 1920 with
   almost 900px of unused space in the middle of the bar. The inset roughly
   doubles at every tier.

   All three tiers are restated here rather than edited in place at line 3900.
   A bare :root re-declaration would beat the earlier media-query tiers on
   source order alone and flatten the ladder, so the ladder has to be rebuilt in
   full, in order, wherever it is set last.

   --sx-shell-pad feeds .sx-header__bar and .sx-home .sx-hero__inner from one
   value, which is what keeps the headline starting at exactly the x the logo
   starts at. Widening the variable moves both together, so that alignment is
   preserved by construction rather than by matching two numbers.

   Doubled again on the second pass — the bar still had most of its width doing
   nothing. The vw term and the ceiling are what actually move on a desktop, so
   those are the two that doubled; the floor is left near where it was, because
   it only applies below about 530px where 90px of inset on each side of a phone
   would leave the logo nowhere to sit. */

:root{ --sx-shell-pad:clamp(1.25rem, 6vw, 5.2rem); }

@media (min-width:1600px){ :root{ --sx-shell-pad:clamp(4rem, 5.6vw, 6.4rem); } }
@media (min-width:1920px){ :root{ --sx-shell-pad:clamp(4.8rem, 4.8vw, 7.6rem); } }

/* --- the rotating block: room for a real sentence --------------------------
   The descriptions were written to fit on one line beside a narrow column and
   were cut to almost nothing to do it — "One codebase for Android and iOS."
   The fuller sentences are back (see StaticContentRepository), so the line has
   to be allowed to wrap.

   Wrapping cannot shift what is below it: every slide sits in the same grid
   cell, so the block is always as tall as the longest of them and a two-line
   description does not move the buttons when it rotates in.

   From 768px, not 992: below 768 the existing rule already turns wrapping back
   on, but between the two the line was still set to nowrap, and the longer
   sentences would have run off the side of the card there. */
@media (min-width:768px){
    .sx-home .sx-hero__slide-sub{
        text-wrap:balance;
        max-width:46ch;
        font-size:clamp(.95rem, .88rem + .28vw, 1.15rem);
    }
}


/* --- the hero: copy on the left, cards on the right ------------------------
   The clock and the platform ring are gone — markup, script, stylesheet and
   artwork. What replaces them is the arrangement in the reference: a column of
   copy on the left, a group of picture cards on the right, and a soft wash of
   the brand green behind them.

   The three promises are those cards. They were a strip of figures under the
   copy, which put them at the bottom of a full-screen card doing nothing for
   the right-hand half of it. */

:root{ --sx-hero-pad-block:clamp(2.5rem, 5.5vh, 4.5rem); }

.sx-home .sx-hero__inner{ padding-block:var(--sx-hero-pad-block); }

/* The wash. A lit pool behind the cards, the way the reference lights its grid
   — not a tint over the whole half. Two stops do the work: a bright core the
   size of the card group, and a long falloff that reaches the edges of the card
   without ever arriving at a visible boundary.

   In the same teal the buttons and the accent type already use, so it reads as
   this site's green rather than a second one. It sits under the content and
   over the canvas — z-index 1, the layer the vignette uses. */
.sx-home .sx-hero::before{
    content:"";
    position:absolute;
    inset:0;
    z-index:1;
    pointer-events:none;
    /* The colours are the statistics band's, stop for stop — #6cecc5 at the
       mint end through #32d9cb in the middle to #17a8bd at the deep end — so
       the pool is literally the same green as that container rather than a
       second one mixed by eye. What changes is the shape: a radial falloff
       instead of the band's diagonal sweep.

       The core is nearly opaque because it has to read against black at the
       band's own strength. Anything under about .8 and the black underneath
       drags it back to a tint — the whole complaint. */
    /* Measured off the mockup rather than described from it. Sampling a clean
       row of its background across the width gives:

           0%(0,1,1)  20%(1,5,7)  40%(0,9,11)  60%(1,16,22)
           80%(1,26,34)  90%(1,33,42)  95%(0,43,58)  100%(2,84,112)

       and down its right edge, (1,44,60) at the top, (2,79,109) at 40%, back to
       (0,42,54) at the foot. So it is not a green field: it is a deep cyan light
       standing just off the right edge, level with the cards, falling away to
       black — dark enough that the peak never passes 112 in blue. Blue leads
       green there, about 3:2, which is why it reads as cyan and not as the
       page's teal.

       Two layers do it. The radial is that light. The linear under it takes the
       left side down towards true black: the canvas paints its own (8,24,24)
       there, and against a right edge this dark, that much lift on the left
       shows up as grey.

       One layer, and it is transparent across most of the width.

       An earlier version matched the mockup's black by laying a black wash over
       the whole hero — .85 at the left. That did make the numbers agree, but a
       wash over the canvas dims the canvas: the animated floor grid is drawn
       there, and multiplying it by .15 took its brightest lines from (128,228,219)
       on /home-v2 down to (45,210,196) here, with the ground under them crushed
       from (7,27,27) to (2,8,9). The page looked black because everything on it
       had been dimmed, which is the opposite of contrast.

       So nothing is painted left of about two thirds now — the canvas is left
       to be as black and as bright as it is on /home-v2 — and the light only
       comes up over the last third, where the mockup has it. The right keeps
       its glow; the animation keeps its own. */
    background:
        linear-gradient(90deg,
            rgba(3, 112, 152, 0) 0%,
            rgba(3, 112, 152, 0) 66%,
            rgba(3, 112, 152, .02) 80%,
            rgba(3, 112, 152, .09) 90%,
            rgba(3, 112, 152, .22) 95%,
            rgba(3, 112, 152, .50) 100%);
}

/* The vignette drops below the wash on this page. It is the dark ellipse that
   keeps the headline legible, it is also z-index 1, and being a pseudo-element
   later in tree order it was painting on top: measured at the middle of the
   wash it was laying about 45% of rgba(9,23,23) over it, which is why the green
   kept coming out as a faint tint however far its own opacity was pushed. The
   same mistake the dial made against this exact rule.

   Below the wash it still does its job — the headline sits on the left, where
   the wash barely reaches. */
.sx-home .sx-hero::after{ z-index:0; }

/* --- the split --- */

.sx-hero__split{
    display:grid;
    gap:clamp(2rem, 4vw, 4rem);
    /* One column until there is room for two. Below that the cards fall under
       the copy rather than being squeezed beside it. */
    grid-template-columns:1fr;
    align-items:center;

    /* Deliberately not flex:1. Stretched to the card's full height, the grid
       row would be the card's height and the cards would stretch to that
       instead of to the copy. Left at its content height and centred by the
       parent, the row is the copy's height — which is what the cards match. */
}

@media (min-width:992px){
    .sx-hero__split{
        /* The cards take the smaller share. They are a group of small blocks
           beside the copy, not a second half of the page. */
        grid-template-columns:minmax(0, 1fr) minmax(0, 0.76fr);

        /* Stretch, so the card group can be told to match the height of the
           column beside it. */
        align-items:stretch;
    }

}

/* Vertically centred, and tighter than it was. The three blocks used to be
   spread across the whole card by auto margins; the heading now sits close
   enough to the line beneath it that the two read as one statement. */
.sx-hero__col{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    justify-content:center;
}

.sx-home .sx-hero__h1{ margin-bottom:clamp(1.1rem, 2vh, 1.6rem); }
.sx-home .sx-hero__slides{ margin-bottom:clamp(1.5rem, 3vh, 2.2rem); }
.sx-home .sx-hero__cta{ margin-bottom:0; }

/* --- the cards --- */

/* The three cards stand on one line, in the widths they have in the mockup —
   296:270:244. Bottoms aligned; because each image keeps its own aspect ratio
   and the widths step down, the tops step down with them. That descending run
   is the composition, and it comes out of the artwork's own proportions rather
   than being staged with offsets. */
.sx-hero__cards{
    list-style:none;
    margin:0;
    padding:0;
    display:grid;
    grid-template-columns:1fr .912fr .824fr;
    gap:clamp(.3rem, .5vw, .6rem);
    align-items:end;
}

/* No frame drawn here any more. The glass edge, the neon, the icon and the
   caption are all in the picture — anything this stylesheet added would be a
   second border outside the one already there. */
.sx-hero__card{
    position:relative;
    margin:0;
}

.sx-hero__card-art{
    display:block;
    width:100%;
    height:auto;

    /* The reflection under the glass, as in the mockup. box-reflect is a WebKit
       property — Chrome, Edge and Safari draw it, Firefox simply does not, and
       the cards stand without it there. It costs one line and no markup, which
       a mirrored copy of three images would not. */
    -webkit-box-reflect:below 1px
        linear-gradient(transparent 62%, rgba(255, 255, 255, .22) 100%);
}

/* Phones keep the three side by side rather than stacking them: these are tall
   cards, and one above another would push the copy off the screen entirely.
   Equal widths there, since the descending run needs more room than a phone
   has to read as anything but uneven. */
@media (max-width:575.98px){
    .sx-hero__cards{ grid-template-columns:repeat(3, 1fr); }
}

/* --- the group: bigger, and moved off the right edge ------------------------
   Two changes asked for together, and they pull against each other: the cards
   grow, and they move left. Growing them alone would only push them further
   into the corner, so the room comes from the split rather than from the gap —
   the copy gives up a little width and the cards take it.

   The size is a share of the viewport rather than a fixed width, so it steps
   with the screen instead of at breakpoints: --sx-cards-w below. The tiers are
   the four asked for, and the share rises with the screen because a card that
   is a third of a phone is a tenth of a large monitor at the same percentage. */

@media (min-width:992px){
    .sx-hero__split{
        /* Was 1fr / .76fr. The cards' column is wider now, which is what makes
           them bigger without changing the space between them. */
        grid-template-columns:minmax(0, 1fr) minmax(0, 1.02fr);
    }

    /* Off the right edge. The inset is the shell padding the header and the
       headline already use, plus a step of its own, so the group sits inboard
       of the line the "Book a Call" button keeps rather than level with it. */
    .sx-hero__cards{
        margin-right:clamp(1.5rem, 4vw, 5.5rem);
    }
}

/* Bigger on a tablet too, where the split is still one column and the cards sit
   under the copy with the full width to themselves. */
@media (min-width:576px) and (max-width:991.98px){
    .sx-hero__cards{
        width:min(100%, 34rem);
        margin-inline:auto;
    }
}

/* Large monitors: the copy stops growing at its measure, so without this the
   whole difference would go into empty middle. */
@media (min-width:1600px){
    .sx-hero__split{ grid-template-columns:minmax(0, 1fr) minmax(0, 1.14fr); }
}

@media (min-width:1920px){
    .sx-hero__split{ grid-template-columns:minmax(0, 1fr) minmax(0, 1.24fr); }
}

/* --- pure white through the section ---
   The description was rgba(226,240,238,.82) — a green-tinted white at 82%. On
   this hero that reads as grey beside the headline, which is #fff. Both are the
   same white now. */
.sx-home .sx-hero__slide-sub{ color:#fff; }

/* --- the social rail comes back ---
   It was hidden here when the hero became an inset card, because the rail is
   fixed to the viewport edge and floated over the light page beside it. The
   hero is dark to its right edge again, which is the ground it was drawn for,
   so it goes back to standing on the wall as it does on /home-v2.

   display:flex, not display:revert: the rule this overrides is !important
   because Bootstrap's own .d-lg-flex is, and revert would hand it back to the
   same !important declaration that hid it. */
@media (min-width:992px){
    .sx-home .sx-social-rail{ display:flex !important; }
}

/* --- About: onto one screen ------------------------------------------------
   The section ran past the fold and had to be scrolled through. The diagram is
   the largest part of it and its height follows its width — 1000:620 — so the
   width is what has to be capped, and capped against the viewport's height
   rather than a chosen number of rem, or a short laptop is back to scrolling.

   min(58rem, 100vh) gives a stage no taller than 62vh, which leaves the heading,
   the lead, the caption and the tags underneath about 260px on a 900px screen.
   The lead is narrower for the same reason: fewer lines, less height. */
@media (min-width:992px){
    .sx-home .sx-ha{ padding-block:clamp(1.6rem, 2.6vw, 2.4rem); }

    /* Driven by height rather than width. Everything else in the section — the
       heading, the lead, the caption, the tags, the two buttons and the padding
       — is roughly a fixed number of pixels, so the diagram gets what is left
       over: 100vh minus that overhead, and never more than 46vh. The width
       follows from the 1000:620 ratio.

       Capping the width instead could not do this. Width and viewport height
       are independent, so the same max-width that fits a 1080px screen is far
       too tall for a 670px one. */
    /* The stage's height and width, written once as variables so everything
       inside the diagram can be sized from the same two numbers.

       470px is the rest of the section measured on the page — padding, heading,
       lead, caption, tags and buttons come to about 440 — plus slack so a
       rounding difference does not put a scrollbar back. In px deliberately:
       the same figure in rem came out as 427 here, because the root font size
       on this site is 15px, so a rem allowance would be quietly 7% short of the
       pixels it is meant to be reserving.

       The width is the height times the 1000:620 ratio, held under the same two
       caps the stage itself uses, so the variable is what the stage actually
       measures rather than what it would measure uncapped.

       And a floor under all of it. Without one this arithmetic keeps giving the
       diagram whatever is left, however little that is: on a 700px window it
       came out 213px wide, on a 620px window 84px, with six cards piled on top
       of each other in the middle of the section. A diagram has a size below
       which it is not a diagram, and the fit has to give way at that point —
       so below roughly an 890px window the section scrolls a little instead. */
    .sx-home .sx-ha{
        --sx-stage-h:max(320px, min(46vh, calc(100vh - 470px)));
        --sx-stage-w:min(58rem, 90vw, calc(var(--sx-stage-h) * 1.613));
    }

    /* Full bleed to the header's own inset. The capsules are the outer 27.5% of
       the stage at each end, so the stage's edges are where they land: the left
       one under the start of the logo, the right one under the end of the
       "Book a Call" button. Both of those sit one shell gap plus one shell pad
       from the screen edge, which is exactly what this margin backs out to.

       -50vw + 50% is the standard way out of a container; the two variables put
       the inset back. .sx-ha already clips, so if a scrollbar makes 100vw a
       pixel wider than the page nothing spills. */
    .sx-home .sx-orbit__stage{
        width:auto;
        max-width:none;
        aspect-ratio:auto;
        height:var(--sx-stage-h);
        margin-inline:calc(-50vw + 50% + var(--sx-shell-gap) + var(--sx-shell-pad));
    }

    /* The type follows the stage, not the window. Everything in the diagram is
       placed as a percentage of the stage, but the type was sized in vw — so on
       a short, wide laptop the stage shrinks to fit the height while the words
       stay the size they are on a large monitor, and they run out of their
       cards.

       A fraction of --sx-stage-w rather than cqw: the container query needs the
       stage to be a size container, and making it one applies containment to a
       box whose contents deliberately hang outside it — the cards reach past
       the stage's own edge. This gets the same measurement with no containment.

       The ceilings are the sizes these had before — 1.3rem and 1.02rem. Left
       uncapped at .030 of the stage the heading reached 22px on a large screen,
       which is wider than the card's text column, so every title broke onto a
       second line and the capsules grew tall to hold it. */
    .sx-home .sx-orbit__label h4{
        font-size:clamp(.7rem, calc(var(--sx-stage-w) * .030), 1.05rem);
        line-height:1.2;
        margin:0 0 .12em;
    }
    .sx-home .sx-orbit__label p{
        font-size:clamp(.6rem, calc(var(--sx-stage-w) * .024), .88rem);
        line-height:1.3;
    }

    /* The pill sizes to its text. It was stretched top-to-bottom of the row,
       which fixed its height to the badge's — fine when the diagram was large
       and every description was one short line, but the pill cannot grow when
       the stage shrinks, so the words simply spilled out of it. Centred on the
       row instead, it takes the height it needs and the badge still lines up
       with its middle.

       The side padding is left alone: the inboard side is a percentage that
       clears the badge, and it is set per side by rules with two classes. Only
       the vertical padding is touched here, at the same specificity. */
    /* As tall as the badge, and taller if the words need it.

       min-height:100% is the row's height, which is the badge's diameter — so
       the pill is normally the v2 shape, exactly as deep as the circle on its
       end. height:auto is what stops the text spilling out of it: where a title
       breaks onto a second line the pill grows to hold it instead of clipping
       at the badge's height, which is what the pencil marks were correcting.

       Centred on the row, so it grows evenly above and below and the badge
       stays on its middle.

       One height for all six, so the row that wraps to two lines and the row
       that fits on one come out the same size. Left to size themselves they did
       not: "Small by Choice" is one line of title over one of description,
       "Independent Thinking" is two over two, and the pills differed by about
       30px down the column.

       24.5% of the stage's height, which is comfortably above the tallest of
       the six — measured, the most any of them needs is 90px against the 115
       this gives. Every pill therefore sits exactly on the minimum and they are
       all the same size, rather than each finding its own height.

       It was 30% for a moment, which did make them equal but at 141px each: the
       rows are only 32.3% of the stage apart, so that left 11px between one
       capsule and the next and they nearly touched. This leaves about 37.

       The max() keeps it at least as deep as the badge on its end, which is the
       v2 shape, and height:auto is the escape hatch: if a description ever ran
       longer than this allows, that pill would grow rather than clip the
       words. */
    .sx-home .sx-orbit__card{
        top:50%;
        bottom:auto;
        transform:translateY(-50%);
        height:auto;
        min-height:max(100%, calc(var(--sx-stage-h) * .245));
    }

    .sx-orbit__label--right .sx-orbit__card,
    .sx-home .sx-orbit__label--left .sx-orbit__card{
        padding-block:calc(var(--sx-stage-w) * .011);
    }
    .sx-home .sx-orbit__label{ padding:0; }

    /* --- the gap at the middle ---
       The mark shrinks and nothing else moves. The pipes are drawn from its edge
       to a fixed point inboard of each badge, so a smaller mark makes both the
       gap and the pipe longer on its own.

       The rows stay where they are. Moving them out looked like the same idea
       from the other end, but the capsule's width is what is left of the row
       after the badge, and taking 2.5% off the row took a third of the text
       column with it — the titles collapsed into one word per line.

       Sized off the stage's height, not its width. A percentage of the width was
       fine when the stage was 1000:620; now that it runs the full page the same
       12% would be nearly 200px across. Height is the dimension that stayed
       still, so the mark is a share of that and stays the size it looks.

       35% puts its edge at about the x the pipes start from, so they still
       disappear under it rather than stopping short. */
    .sx-home .sx-orbit__hub{
        width:auto;
        height:35%;
    }

    /* --- the capsule: home-v2's, narrower, pushed to the ends ---
       Every number in this diagram is a percentage of the stage, and the row
       spans the whole of it, so the capsule and the badge are placed by moving
       those percentages rather than by resizing anything.

       On /home-v2 the card runs from 62.5% to the edge — 37.5% — with an 11%
       badge centred on 68%, which is also where its pipe ends. That is the
       pattern to keep: pill, badge sitting on the pill's rounded end, pipe
       arriving under the badge.

       Here the card is 25% instead of 37.5%, which is 405px against v2's 444 at
       this width — a little smaller, as asked. Everything else follows it out:
       the badge to 79%, and the pipe ends in _AboutOrbit.cshtml to 790 and 210
       to meet it. The 12.5% the capsule gave up is the pipe's, on each side.

       The badge stays 8% — 130px here, the same circle v2 draws — because the
       capsule's height is the badge's diameter: the card is stretched between
       the row's top and bottom, and the badge is what makes the row that tall.
       Shrinking the badge would shrink the capsule with it. */
    /* 7%, not 8%. The pill is as deep as this circle, so the badge is what
       sets the floor under the capsule's height — at 8% that floor was 130px
       and the rows could not be given a decent gap without the section
       running past the fold. */
    .sx-home .sx-orbit__badge{ width:7%; }

    .sx-home .sx-orbit__label--right .sx-orbit__badge{ left:79%; }
    .sx-home .sx-orbit__label--left  .sx-orbit__badge{ left:21%; }

    /* The inboard padding clears the badge. It is a percentage of the stage, so
       it has to cover from the card's edge past the badge's far side: the badge
       spans 75% to 83% and the card starts at 75%, so 8% plus room to breathe. */
    .sx-home .sx-orbit__label--right .sx-orbit__card{
        left:75%;
        padding-left:10.5%;
    }

    .sx-home .sx-orbit__label--left .sx-orbit__card{
        right:75%;
        padding-right:10.5%;
    }

    /* Three rows of a 130px capsule need the height to keep them apart: at 48vh
       the rows sit about 152px apart on a 1080 screen, so there is roughly 20px
       between one capsule and the next and none of them touch. */
    .sx-home .sx-ha{ --sx-stage-h:clamp(440px, 48vh, 520px); }
    .sx-home .sx-ha__head{ margin-bottom:clamp(1rem, 2vw, 1.6rem); }
    .sx-home .sx-ha__lead{
        max-width:58ch;
        margin-inline:auto;
        font-size:clamp(.95rem, .9rem + .25vw, 1.05rem);
    }
    .sx-home .sx-orbit__caption{ margin-block:clamp(.5rem, 1vw, .9rem); }

    /* The cards shrink with the stage: a one-line description does not need the
       padding a three-line one did. */
    .sx-home .sx-orbit__label{ padding:.6rem .8rem; }
    .sx-home .sx-orbit__label p{ line-height:1.4; }
}



/* --- Contact -------------------------------------------------------------
   The supplied clip runs behind the band, re-encoded to a lazy animated WebP.
   It is a light clip — near-white with a grey dotted wave through the right
   side — so this is a light band: dark ink on it, and the two things that sit
   over it filled with the pale mint the header's "Book a call" button carries,
   #ffffff into #dcfbfb.

   Compact is still the rule. The address block beside the form, and the first
   two fields sharing a row, holds the whole thing to one screen. */
.sx-contact {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding-block: clamp(2.5rem, 5vw, 4rem);
    /* Painted immediately, at 6KB, so the band is never a blank rectangle
       waiting on the loop. The loop covers it once it arrives. */
    background: #fff url("../img/contact-bg-still.webp") center / cover no-repeat;
}

.sx-contact__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    pointer-events: none;
}
/* The element itself is what fills the band now, rather than an image inside a
   <picture>. Until the source is attached the poster is what shows, and
   object-fit governs that the same way it governs the frames. */
.sx-contact__bg {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* soulogix-contact.js dips this at the end of the clip so the wrap dissolves
       into the still underneath rather than cutting. */
    transition: opacity .55s ease;
}

/* What a hero video overlay does, inverted for a light clip: a white veil,
   heaviest where the words start and thinnest over the wave on the right, so
   the motion still reads but nothing has to compete with it. */
.sx-contact__scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(100deg,
        rgba(255, 255, 255, .88) 0%,
        rgba(255, 255, 255, .66) 42%,
        rgba(255, 255, 255, .34) 72%,
        rgba(255, 255, 255, .22) 100%);
}

.sx-contact__inner { position: relative; z-index: 2; }

/* Bigger than the section eyebrows elsewhere. Those sit above a heading in a
   band of their own; this one opens the last block on the page and was reading
   as a caption. */
.sx-contact__eyebrow {
    font-size: clamp(.95rem, .88rem + .32vw, 1.15rem);
    letter-spacing: .16em;
    margin-bottom: .7rem;
}

.sx-contact__head {
    max-width: 60ch;
    margin: 0 auto clamp(1.25rem, 2.5vw, 2rem);
    text-align: center;
}
.sx-contact__title {
    color: #0a2422;
    font-size: clamp(1.5rem, 1.1rem + 1.2vw, 2.1rem);
    line-height: 1.18;
    margin: 0 0 .6rem;
    text-wrap: balance;
}
.sx-contact__lede {
    margin: 0;
    color: #4a6664;
    font-size: clamp(.95rem, .92rem + .15vw, 1.02rem);
    line-height: 1.6;
}

/* The form takes the wider column: it is the thing being asked for, and the
   address block beside it is for people who would rather not use it. */
.sx-contact__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
    gap: clamp(1rem, 2vw, 1.75rem);
    /* Both columns run the full height of the row. The block on the left used to
       be centred against the form because it was so much shorter; it now carries
       enough to stand level, and the last thing in it is pushed to the bottom so
       the two finish on the same line whatever the form's height is. */
    align-items: stretch;
}

/* Both containers use the same brand teal as the contact CTA, so the pair reads
   as one contact surface rather than two pale cards over the video. */
.sx-contact__aside,
.sx-contact__panel {
    background: linear-gradient(100deg, #1fbfb2 0%, #32d9cb 100%);
    border: 1px solid rgba(0, 48, 44, .14);
    border-radius: 14px;
    box-shadow: 0 18px 44px rgba(4, 33, 31, .14);
    min-width: 0;
}

.sx-contact__aside {
    padding: clamp(1rem, 1.8vw, 1.4rem);
    display: flex;
    flex-direction: column;
}
.sx-contact__block { margin-top: 1rem; }
/* Sits on the bottom edge, which is what makes the two columns finish level. */
.sx-contact__block--last { margin-top: auto; padding-top: 1rem; }

.sx-contact__label {
    margin: 0 0 .55rem;
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .64rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: #0a4a47;
}

/* What the company does, as labels rather than links: the form is the only
   thing in this band that should be asking to be clicked. */
.sx-contact__chips {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}
.sx-contact__chips li {
    padding: .25rem .65rem;
    border: 1px solid rgba(0, 48, 44, .18);
    border-radius: 999px;
    background: rgba(255, 255, 255, .55);
    color: #06403d;
    font-size: .78rem;
    font-weight: 600;
}

.sx-contact__socials {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: .5rem;
}
.sx-contact__socials a {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .75);
    border: 1px solid rgba(0, 48, 44, .14);
    color: #06403d;
    font-size: .9rem;
    text-decoration: none;
    transition: background-color .25s ease, color .25s ease, transform .25s ease;
}
.sx-contact__socials a:hover,
.sx-contact__socials a:focus-visible {
    background: #000103;
    color: #32d9cb;
    transform: translateY(-2px);
    outline: none;
}
.sx-contact__panel { padding: clamp(1.1rem, 2vw, 1.6rem); }

.sx-contact__channels {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Rows inside the one container rather than a card each: the block is the
   container now, so a second border around every line would be two frames
   drawn around the same thing. */
.sx-contact__channel {
    display: flex;
    align-items: center;
    gap: .9rem;
    padding: .7rem 0;
}
.sx-contact__channel + .sx-contact__channel {
    border-top: 1px solid rgba(0, 48, 44, .18);
}

.sx-contact__icon {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: #000103;
    color: #32d9cb;
    font-size: .95rem;
}

.sx-contact__channel-body { min-width: 0; }
.sx-contact__channel-title {
    margin: 0 0 .1rem;
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .64rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    /* Darker than the grey these labels were: that was set for a near-white
       panel and does not carry on a tint this strong. */
    color: #0a4a47;
}
.sx-contact__channel-body a {
    color: #00302c;
    font-size: .95rem;
    font-weight: 600;
    text-decoration: none;
    overflow-wrap: anywhere;
}
.sx-contact__channel-body a:hover,
.sx-contact__channel-body a:focus-visible { color: #0d7d75; }

.sx-contact__promise {
    margin: .85rem 0 0;
    padding-top: .85rem;
    border-top: 1px solid rgba(0, 48, 44, .18);
    color: #0b3c3a;
    font-size: .88rem;
    line-height: 1.6;
}

.sx-contact__sent {
    margin: 0 0 1rem;
    padding: .8rem 1rem;
    border: 1px solid rgba(13, 125, 117, .4);
    border-radius: 10px;
    background: rgba(50, 217, 203, .16);
    color: #0a3d38;
    font-size: .92rem;
}

/* Two up, so name and email take one row rather than two, and phone and
   subject share the next — which is how the phone number was added without the
   panel growing a row taller.

   The panel is as tall as the block beside it, and that block now carries more
   than the form does; align-content spreads the rows into whatever is left over
   rather than stacking them at the top and leaving a hole under the button. */
.sx-contact__panel { display: flex; flex-direction: column; }

.sx-contact__form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .7rem;
    flex: 1;
    align-content: space-between;
}
.sx-field { min-width: 0; }
.sx-field--full { grid-column: 1 / -1; }

/* Every type the form uses, tel included — it was left out when the phone
   number was added, so that one field kept the browser's default box while the
   rest carried this. */
.sx-contact__form .sx-field input,
.sx-contact__form .sx-field textarea,
.sx-contact__form input[type="text"],
.sx-contact__form input[type="email"],
.sx-contact__form input[type="tel"],
.sx-contact__form textarea {
    width: 100%;
    padding: .72rem .9rem;
    border: 1px solid rgba(0, 48, 44, .2);
    border-radius: 10px;
    /* Plain white against the mint, so a field reads as cut into the container
       rather than as another panel laid on it. */
    background: #fff;
    color: #0a2422;
    font-size: .95rem;
    font-family: inherit;
    transition: border-color .25s ease, box-shadow .25s ease;
}
.sx-contact__form textarea { resize: vertical; min-height: 104px; }

.sx-contact__form ::placeholder { color: #7d9997; }

.sx-contact__form .sx-field input:focus,
.sx-contact__form .sx-field textarea:focus,
.sx-contact__form input[type="text"]:focus,
.sx-contact__form input[type="email"]:focus,
.sx-contact__form input[type="tel"]:focus,
.sx-contact__form textarea:focus {
    outline: none;
    border-color: rgba(13, 125, 117, .65);
    box-shadow: 0 0 0 3px rgba(50, 217, 203, .25);
}

.sx-field__error {
    display: block;
    margin-top: .3rem;
    color: #c0392b;
    font-size: .8rem;
}

.sx-contact__actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: .2rem;
}
.sx-contact__actions .sx-btn--primary {
    background: #000103;
    border-color: #000103;
    color: #32d9cb;
}
.sx-contact__actions .sx-btn--primary:hover,
.sx-contact__actions .sx-btn--primary:focus-visible {
    background: #091717;
    color: #5fe9dc;
}
.sx-contact__note {
    margin: 0;
    color: #0b3c3a;
    font-size: .82rem;
}

/* The widget draws itself at a fixed 300px; left to the grid it would be
   stretched by the cell and centred oddly on a wide panel. */
.sx-contact__captcha { display: flex; flex-direction: column; align-items: flex-start; }

/* One column below the two-up breakpoint. */
@media (max-width: 991.98px) {
    .sx-contact__grid { grid-template-columns: 1fr; }
}

@media (max-width: 575.98px) {
    .sx-contact__form { grid-template-columns: 1fr; }
    .sx-field { grid-column: 1 / -1; }
}


/* --- laptop scale ----------------------------------------------------------
   The site was drawn at big-desktop widths and reads as oversized on a laptop:
   at 100% a 1366 or 1536 screen gets the same type and spacing a 1920 one does,
   with a fifth of the room to put it in. Viewed at 80% browser zoom it comes
   right — which is the whole diagnosis, and it says what the fix is.

   So this is that zoom, applied by the page instead of by hand. zoom is the one
   property that does what the browser's own control does: the box is laid out at
   1/0.8 of the viewport and then drawn at 0.8, so a 1366 screen composes at 1707
   and lands on the tier the design was built for. transform: scale() cannot
   stand in for it — that scales the painting without re-laying anything out, so
   the page would keep its 1366 line breaks and gain a horizontal scrollbar.

   Bounded at both ends deliberately:

     under 992   untouched. Phones and tablets are laid out for their own width
                 already, and shrinking them would only make text smaller on the
                 screens that can least afford it.
     992-1799    scaled. 1280 composes at 1600, 1366 at 1707, 1536 at 1920.
     1800 and up untouched, because it already looks right there.

   Where a browser does not support zoom the page simply renders as it does
   today, which is the current behaviour and not a broken one. */
@media (min-width: 992px) and (max-width: 1799.98px) {
    :root { --sx-desktop-scale: .8; }

    body { zoom: var(--sx-desktop-scale); }

    /* The one thing zoom does not carry. Browser zoom grows the viewport, so
       100vh stays a screenful; CSS zoom scales a box that still measures the
       viewport in unscaled pixels, so 100vh would come out a fifth short and
       the hero would stop before the fold. Dividing by the scale is what makes
       it a screenful again. */
    .sx-hero {
        min-height: calc(100vh / var(--sx-desktop-scale));
        min-height: calc(100svh / var(--sx-desktop-scale));
    }
}


/* --- anchored sections ------------------------------------------------------
   The menu is six links and four of them are bands on this page. A jump lands
   the section's top edge on the top of the window, which is under the floating
   capsule — so each target reserves the capsule's height plus a little air. */
#about, #why-soulogix, #process, #services {
    scroll-margin-top: calc(var(--sx-header-height) + 1.25rem);
}
@media (max-width: 991.98px) {
    #about, #why-soulogix, #process, #services {
        scroll-margin-top: calc(var(--sx-header-height-mobile) + 1rem);
    }
}

/* --- phone service cards ----------------------------------------------------
   Desktop and tablet keep the bento treatment above. Phones need a denser,
   tap-first version: one card per row, smaller chrome, and details that open in
   flow without turning each service into a full screen of content. */
.sx-services__hint--tap { display: none; }

@media (hover: none) and (max-width: 575.98px) {
    .sx-services__hint--hover { display: none; }
    .sx-services__hint--tap { display: inline; }
}

@media (max-width: 575.98px) {
    .sx-services {
        padding-block: 2.25rem;
    }

    .sx-services__head {
        max-width: 100%;
        margin-bottom: 1.25rem;
    }

    .sx-services__eyebrow {
        padding: .28rem .7rem;
        font-size: .78rem;
        letter-spacing: .14em;
        margin-bottom: .65rem;
    }

    .sx-services__title {
        font-size: 1.45rem;
        line-height: 1.18;
        margin-bottom: .5rem;
    }

    .sx-services__lede {
        max-width: 34ch;
        margin-inline: auto;
        font-size: .9rem;
        line-height: 1.45;
    }

    .sx-bento {
        gap: .75rem;
        perspective: none;
    }

    .sx-tile {
        --sx-tile-pad: .95rem;
        border-radius: 10px;
        cursor: default;
        will-change: auto;
    }

    .sx-tile::before {
        box-shadow: 0 14px 30px rgba(0, 0, 0, .45);
    }

    .sx-tile__sheen,
    .sx-tile__edge {
        display: none;
    }

    .sx-tile__top {
        gap: .75rem;
        margin-bottom: .65rem;
    }

    .sx-tile__icon {
        font-size: 1.45rem;
    }

    .sx-tile__code {
        font-size: .6rem;
        letter-spacing: .1em;
    }

    .sx-tile__name {
        font-size: 1.08rem;
        line-height: 1.2;
        margin-bottom: .55rem;
    }

    .sx-tile__sum {
        display: -webkit-box;
        margin-bottom: .75rem;
        color: rgba(214, 230, 228, .82);
        font-size: .88rem;
        line-height: 1.45;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .sx-tile__meta {
        gap: .45rem;
        padding-top: .7rem;
    }

    .sx-tile__meta div {
        flex: 1 1 100%;
    }

    .sx-tile__meta dt {
        font-size: .58rem;
        letter-spacing: .1em;
    }

    .sx-tile__meta dd {
        font-size: .8rem;
    }

    .sx-tile__toggle {
        margin-top: .85rem;
        padding: .52rem .85rem;
        font-size: .8rem;
    }

    .sx-tile__caps {
        gap: .38rem;
    }

    .sx-tile__caps li {
        padding-left: 1rem;
        font-size: .8rem;
        line-height: 1.4;
    }

    .sx-tile__caps li::before {
        top: .55em;
        width: 5px;
        height: 5px;
    }

    .sx-tile__label {
        margin: .8rem 0 .4rem;
        font-size: .58rem;
        letter-spacing: .1em;
    }

    .sx-tile__chips,
    .sx-tile__children {
        gap: .3rem;
    }

    .sx-tile__chips span,
    .sx-tile__children a {
        padding: .18rem .48rem;
        font-size: .66rem;
        line-height: 1.35;
    }

    .sx-tile__link {
        margin-top: .8rem;
        font-size: .82rem;
    }

    .sx-tile.is-open .sx-tile__sum {
        display: block;
        overflow: visible;
    }
}

/* --- service page banner ----------------------------------------------------
   A service page opens on its own tile rather than on the photograph every
   other page shares: the same dark surface, the same teal icon, the same SVC
   code. Arriving from the tile then lands somewhere that plainly belongs to it.

   background-image rather than background, so the theme's own sizing keywords
   underneath are not thrown away with it. */
.page-header--service {
    background-image:
        radial-gradient(60% 90% at 78% 8%, rgba(50, 217, 203, .16) 0%, rgba(50, 217, 203, 0) 62%),
        linear-gradient(145deg, #235E54 0%, #18463F 26%, #103031 55%, #0B2124 80%, #081A1C 100%);
    background-color: var(--sx-black);
}

/* The tile's own top row — icon on the left, code on the right — centred here
   because a page header is centred where a tile is not. */
.page-header__mark {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin: 0 0 1.25rem;
}
.page-header__mark i {
    font-size: clamp(2rem, 1.4rem + 1.6vw, 2.75rem);
    color: #32d9cb;
    line-height: 1;
}
.page-header__code {
    font-family: "Cascadia Mono", Consolas, ui-monospace, monospace;
    font-size: .72rem;
    letter-spacing: .12em;
    color: rgba(50, 217, 203, .55);
}


/* --- mobile density ---------------------------------------------------------
   Everything below is bounded by `hover: none` or by a phone width, so no rule
   here can reach a desktop pointer. Measured on the home page at 390x844: the
   document was 9857px, and the four blocks below take about 1100px off it
   without shrinking a single line of body copy.
   -------------------------------------------------------------------------- */

/* 1. Services: the panel is an accordion where it opens on a tap.

   The two panes share one grid cell so hovering can swap them without moving
   anything, and where the panel drops out of flow that costs nothing. Where it
   does not — every touch device, which is the exact case the toggle button
   exists for — the cell is sized to the taller of the two, and the taller one
   is always the closed panel. So each card reserved the full height of content
   nobody had asked to see: 224px of dead space under "Engagement" on the first
   tile, 86 to 130 on the rest, and 646px across the section.

   Stacking the panes in two rows instead and collapsing the second to nothing
   sizes the card on what it is showing. grid-template-rows 0fr -> 1fr is what
   makes that animate rather than snap; browsers that will not interpolate it
   just open the panel instantly, which is the behaviour today.

   Keyed on `hover: none` deliberately — the same condition that swaps the cue
   for a real button further up. Wherever there is a button to press, the thing
   it opens now takes up room only once pressed. */
@media (hover: none) {
    /* Cards size to their own content. Stretched, a row is as tall as the tile
       currently open in it, so opening one card put six hundred pixels of empty
       surface inside the one beside it — the void this block exists to remove,
       moved one column across. */
    .sx-bento { align-items: start; }

    .sx-tile__panes {
        grid-template-rows: auto 0fr;
        transition: grid-template-rows .38s cubic-bezier(.16, 1, .3, 1);
        /* Not stretched to the card. Where a taller neighbour equalises the row
           the slack belongs at the bottom, under the button, rather than inside
           the panes box holding the two apart. */
        flex: 0 0 auto;
    }

    /* Out of the shared cell and into rows of their own. */
    .sx-tile__pane { grid-area: auto; }

    .sx-tile__pane--more {
        min-height: 0;
        overflow: hidden;
        transform: none;
    }

    /* The gap above the panel travels with it. Padding on the pane itself would
       survive the collapse — a zero-height row still paints its own padding —
       and show as a band under the summary in the closed state. */
    .sx-tile__pane--more > :first-child { margin-top: .9rem; }

    .sx-tile.is-open .sx-tile__panes { grid-template-rows: auto 1fr; }
    .sx-tile.is-open .sx-tile__pane--more { opacity: 1; }

    /* The summary stays where it is. Opening no longer replaces it — there is
       room below now — and :focus-within fires the instant the button inside
       the card takes focus, so without this the resting content faded out from
       under the thumb that pressed it. */
    .sx-tile:hover .sx-tile__pane--rest,
    .sx-tile:focus-within .sx-tile__pane--rest,
    .sx-tile.is-open .sx-tile__pane--rest {
        opacity: 1;
        transform: none;
        pointer-events: auto;
    }

    /* Hover and focus no longer open anything on their own; only the button
       does. Both still match on a touch screen — a tap leaves focus behind — and
       either one would otherwise reveal a panel the card has not made room for. */
    .sx-tile:hover .sx-tile__pane--more,
    .sx-tile:focus-within .sx-tile__pane--more { opacity: 0; }
    .sx-tile.is-open .sx-tile__pane--more { opacity: 1; }

    /* Pinned to the bottom edge, so two cards sharing a row have their buttons
       on one line instead of each floating under its own paragraph. */
    .sx-tile__toggle { margin-top: auto; }
}

/* 2. The process pipeline. Four stages of two paragraphs each ran to 1818px on
   a 390 screen, and a third of that was air: a 60px gutter for a 36px node, a
   36px gap between stages and 1.65 line-height on copy already set in a 300px
   column.

   The type is not touched. Body copy on a phone is the last thing that should
   pay for a long page, and the measure is what was costing the lines — a
   narrower gutter puts roughly two words back on every line, which is what
   actually removes them. */
@media (max-width: 575.98px) {
    .sx-process { padding-block: 2.5rem; }

    .sx-process__head { margin-bottom: 1.5rem; }

    .sx-path__list { gap: 1.75rem; }

    .sx-path__item {
        grid-template-columns: 2.25rem 1fr;
        column-gap: .75rem;
    }

    .sx-path__node {
        width: 1.9rem;
        height: 1.9rem;
        font-size: .78rem;
    }

    .sx-path__card h3 { margin-bottom: .4rem; }

    .sx-path__card p {
        line-height: 1.55;
        margin-bottom: .55rem;
    }
}

/* 3. About. The diagram degrades to a list of six rows on a phone, and the
   spacing was still the diagram's: a 28px gap under the hub and 20px between
   rows that are 66px tall. The two buttons underneath stacked full width for a
   combined 117px when both fit on one line. */
@media (max-width: 575.98px) {
    .sx-ha { padding-block: 2.25rem; }

    .sx-ha__head { margin-bottom: 1.25rem; }

    .sx-orbit__stage { gap: 1.1rem; }

    .sx-orbit__hub { width: 6.5rem; }

    .sx-orbit__labels { gap: .6rem; }

    .sx-ha__tags { gap: .35rem; }

    /* Side by side. Two full-width buttons stacked read as a form, and there is
       room for both on the narrowest phone this site supports. */
    .sx-ha__actions {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: .6rem;
    }

    .sx-ha__actions .sx-btn {
        flex: 1 1 auto;
        min-width: 0;
        padding-inline: 1rem;
        font-size: .85rem;
        white-space: nowrap;
    }
}

/* 4. Band padding. A section's vertical padding is a clamp whose middle term is
   in vw, so on a phone the viewport is too narrow for it to count and the band
   sits on its minimum — a minimum chosen against a desktop. The services band
   already had a phone tier of its own at 2.25rem and the contact band is on
   2.5rem already; the reasons band is the one still on a desktop figure. */
@media (max-width: 575.98px) {
    .sx-reasons { padding-block: 2.25rem; }
}


/* --- the collapsed menu ------------------------------------------------------
   Everything here is inside the breakpoint the toggle button itself lives in,
   so none of it can reach the desktop bar.

   What was wrong was the capsule being asked to be two things. Its background
   is a 95deg ramp from near-black to bright teal, drawn for a 66px pill where
   the whole ramp reads as one lit surface. Expanded, that same ramp painted a
   336px slab: the left half black, the right half bright teal, and six links
   centred across the seam — "Home", "Services" and "Contact Us" each sat half
   on one and half on the other. It was unreadable in the middle of its own
   menu.

   And the links were centred, content-width pills, because .navbar-nav is given
   align-items:center for the desktop row and the same rule applies when the
   list turns into a column. Six pills of six different widths, ragged down the
   middle, the widest 143px and the narrowest 71 in a 328px panel — so "Home"
   was a target a fifth of the width of the thing it sat in.
   -------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
    /* The panel gets a surface of its own and takes the capsule's full inner
       width, so the ramp behind it is covered rather than read through. The
       negative margin is the capsule's own padding-inline, backed out; the
       radius is its border-radius, so the two bottom corners agree. */
    .sx-header .navbar-collapse {
        margin-inline: calc(-1 * clamp(.9rem, 1.8vw, 1.5rem));
        padding-inline: clamp(.9rem, 1.8vw, 1.5rem);
        padding-top: .55rem;
        padding-bottom: .65rem;
        background: linear-gradient(180deg, #04201f 0%, #041a1a 100%);
        border-top: 1px solid rgba(50, 217, 203, .22);
        border-radius: 0 0 25px 25px;
    }

    /* The capsule goes dark for as long as the panel is open, which is what
       actually removes the ramp: backing the panel out by the padding leaves a
       strip of capsule down each side, and that strip was the bright end of the
       gradient. Doing it on the capsule instead means there is no width to get
       right and no seam to line up.

       The rule above still stands on its own where :has() is missing — the
       panel keeps its surface, and only the strip stays teal. */
    /* Flat #001a1a, which is the colour the ramp starts on and the colour baked
       into the logo PNG. Anything else here puts a faint rectangle round the
       wordmark — the reason the gradient's first 42% is flat to begin with. */
    .sx-header__bar:has(.navbar-collapse.show),
    .sx-header__bar:has(.navbar-collapse.collapsing) {
        background: #001a1a;
    }

    /* Full-width rows. align-items on the base rule is what shrank each link to
       its own text; stretch is what a column of them wants. */
    .sx-header .navbar-nav { align-items: stretch; }

    .sx-header .navbar-nav .nav-link {
        display: block;
        text-align: left;
        border-radius: 12px;
        padding: 11px 14px;
        font-size: .95rem;
    }

    /* The row that is already open reads as selected rather than as a stray
       highlight, now that it is the width of the panel. The tint carries that on
       its own; an inset rule down the left edge smeared along the top and bottom
       curves of the 12px radius and came out as an outline round the whole row. */
    .sx-header .navbar-nav .nav-link.active {
        background: rgba(50, 217, 203, .14);
    }

    /* Round, like everything else on the capsule, and a fixed square so the
       glyph inside is centred rather than sitting on the text baseline. */
    .sx-header .navbar-toggler {
        width: 44px;
        height: 44px;
        padding: 0;
        display: grid;
        place-items: center;
        border-radius: 999px;
    }

    /* The button says which way it goes. Bootstrap only swaps the class on the
       panel, so open and closed looked identical from the control. */
    .sx-header .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='%2399ffff' stroke-width='2.5' stroke-linecap='round' d='M7 7l16 16M23 7L7 23'/%3E%3C/svg%3E");
    }
}


/* --- footer: on the header's line -------------------------------------------
   The footer sat in a Bootstrap .container — centred, capped at 1320 — while
   the header capsule spans the viewport less one shell gap. Two different
   grids, so the two lockups could never agree: at 1874 the header's S was at
   117 and the footer's at 293.

   The footer takes the header's own geometry instead, written from the same two
   variables the capsule and the hero card read, so the three cannot drift
   apart. Bootstrap's row and column gutters already cancel each other exactly
   (-24 against +24 at 1920), which leaves the container's own inline padding as
   the only thing deciding where the first column's text begins.

   Note this widens the footer past the content bands above it, which keep the
   1320 container. That is the trade the alignment costs: the footer now agrees
   with the header rather than with the sections.
   -------------------------------------------------------------------------- */

:root{
    /* The artwork carries its own dark padding before the mark: the S begins
       21px into a 1269x452 file, so 1.65% of the width, which is 4.65% of the
       rendered height at the file's 2.8075:1 ratio.

       Measured from soulogix-logo.png — re-measure it if that file is ever
       regenerated, because nothing here can detect the change.

       It is invisible wherever it is applied: the colour baked behind the mark
       is #001a1a, which is the flat run at the start of the capsule's gradient
       and the footer's own background. */
    --sx-logo-ink: .0465;
}

/* The fluid wrapper adds a gutter of its own — 12px, unrelated to any of this
   — on top of whatever the inner container is given. The inset is one number
   now, and it is set below. */
.container-fluid.footer{ padding-inline: 0; }

.footer > .container{
    max-width: none;
    width: auto;
    /* One shell gap in from the viewport, exactly as the capsule sits. */
    margin-inline: var(--sx-shell-gap);
    /* Then what stands between the capsule's edge and the S inside it: its
       1px border, its inline padding, and the artwork's own indent. */
    padding-inline: calc(var(--sx-shell-pad) + 1px +
                         var(--sx-logo-height) * var(--sx-logo-ink));
}

/* The footer mark is set out by its own indent, so its S lands on the
   paragraph's edge instead of 3.6px right of it — the two now start on one
   line, and that line is the header's. */
.sx-lockup--footer{
    margin-left: calc(var(--sx-lockup-height) * var(--sx-logo-ink) * -1);
}


/* --- the legal page ---------------------------------------------------------
   Scoped to .sx-legal, which exists on the privacy notice and nowhere else.

   The theme's body size is set for marketing copy read in glances. This is the
   one page on the site somebody reads start to finish, usually because they
   want to know something specific about their own data, so it is set for
   reading: a larger base size, a looser line, and headings that separate the
   sections rather than merely labelling them.
   -------------------------------------------------------------------------- */
.sx-legal{
    color:#3f5654;
    font-size:1.02rem;
    line-height:1.75;
}

.sx-legal h2{
    color:#0a2422;
    font-size:clamp(1.35rem, 1.1rem + .8vw, 1.75rem);
    line-height:1.25;
}

/* Enough space above that a new section is obviously a new section, and a rule
   to make the break structural rather than a matter of judging whitespace. */
.sx-legal h2:not(:first-of-type){
    margin-top:3rem;
    padding-top:2rem;
    border-top:1px solid #e2edeb;
}

.sx-legal h3{
    color:#0d3b38;
    font-size:1.08rem;
    font-weight:600;
    letter-spacing:.01em;
}

.sx-legal p,
.sx-legal li{ max-width:70ch; }

.sx-legal ul{ padding-left:1.15rem; }
.sx-legal li{ margin-bottom:.5rem; }

/* The cookie and field names are the part a reader scans for. */
.sx-legal strong{ color:#0a2422; font-weight:600; }

.sx-legal a{
    color:#0d7d75;
    text-decoration:underline;
    text-underline-offset:2px;
}
.sx-legal a:hover,
.sx-legal a:focus-visible{ color:#0a5f59; }
