/* =========================================================================
   SoftCircles — Home page visual refresh
   Scope: content areas of index.html only (hero, trusted-by, case studies,
   "who we are" / accordion, stats, testimonials, blog cards, footer CTA).
   Nothing here touches markup, links, or navigation — pure presentational
   layer that sits on top of assets/css/app.min-v=13.css.
   ========================================================================= */

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");

:root {
  --sc-teal: #008066;
  --sc-teal-dark: #045c48;
  --sc-dark: #1c252b;
  --sc-yellow: #fec527;
  --sc-blue: #9dceca;
  --sc-pink: #fea388;
  --sc-gray: #eceded;
  --sc-quote-bg: #f6f5f4;
  --sc-shadow-sm: 0 6px 20px rgba(28, 37, 43, 0.06);
  --sc-shadow-md: 0 14px 40px rgba(28, 37, 43, 0.12);
  --sc-shadow-lg: 0 24px 60px rgba(28, 37, 43, 0.16);
  --sc-ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Exact values pulled from the Figma dev-mode export */
  --sc-brand-blue: #3aadd9;
  --sc-border: #e7e8ec;
  --sc-ink: #0e0e12;
  --sc-text-muted: #4b4d57;
  --sc-star: #f4b335;
  --sc-tag-blue: #e3f5fb;
  --sc-tag-lavender: #eaedff;
  --sc-mint: #e8fffa;
  --sc-mint-pill: #cdf5ed;
  --sc-verified-bg: #e5fffe;
  --sc-band-1: #f9f9f9;
  --sc-band-2: #f4f5f7;
  --sc-band-3: #f3f3f3;
  --sc-btn-fill: #f5f6f7;
  --sc-green-bright: #12b76a;
  /* One ramp for every filled green button on the site -- the .btn-warning
     CTAs and the "View case study" link. They are styled by separate rules in
     separate parts of this file, so holding the value once is what keeps them
     from drifting apart. Left to right, light to dark; a plain 90deg ramp,
     deliberately not a two-way sweep that lightens through the middle and
     reads as a sheen. */
  --sc-btn-gradient: linear-gradient(
    90deg,
    var(--sc-green-bright) 0%,
    var(--sc-teal) 55%,
    var(--sc-teal-dark) 100%
  );
  --sc-font-body: "Inter", "Poppins", sans-serif;
}

/* Prevent the horizontal scrollbar that full-bleed sections (e.g. the
   trusted-by band) can introduce when their 100vw width slightly exceeds
   the visible viewport (scrollbar-width rounding). */
body {
  overflow-x: hidden;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

html {
  scroll-behavior: smooth;
}

::selection {
  background: var(--sc-teal);
  color: #fff;
}

/* -------------------------------------------------------------------------
   Hero
   ------------------------------------------------------------------------- */
main .container[data-background-change="#fff"] {
  position: relative;
}

.main-header {
  position: relative;
  z-index: 1;
  letter-spacing: -0.5px;
}

.main-header b {
  background: linear-gradient(100deg, var(--sc-teal) 0%, #04a37f 55%, var(--sc-teal-dark) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--sc-teal);
}

.btn {
  transition:
    transform 0.28s var(--sc-ease),
    box-shadow 0.28s var(--sc-ease),
    background-color 0.2s ease,
    /* The green CTAs carry a gradient, and background-image is not an
       animatable property -- their hover state dims with filter instead, so
       filter has to be in this list for that change to ease rather than
       snap. */ filter 0.2s ease,
    color 0.2s ease;
}

.btn.btn-warning,
.btn.btn-dark,
.btn.btn-outline-dark {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.btn.btn-warning::after,
.btn.btn-dark::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(120deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.35) 50%, rgba(255, 255, 255, 0) 100%);
  transform: translateX(-120%);
  transition: transform 0.6s var(--sc-ease);
}

.btn.btn-warning:hover,
.btn.btn-dark:hover,
.btn.btn-outline-dark:hover {
  transform: translateY(-3px);
  box-shadow: var(--sc-shadow-md);
}

.btn.btn-warning:hover::after,
.btn.btn-dark:hover::after {
  transform: translateX(120%);
}

.btn.btn-warning:active,
.btn.btn-dark:active,
.btn.btn-outline-dark:active {
  transform: translateY(-1px);
}

/* -------------------------------------------------------------------------
   Trusted-by band (two-column, divided)
   ------------------------------------------------------------------------- */
.sc-trustband {
  background: var(--sc-band-1);
  padding: 34px 0;
  /* Full-bleed: break out of the (narrower than viewport) page container
     so the band's background reaches both screen edges, while the
     nested .container inside keeps the text/logos aligned with the
     rest of the page content. */
  width: 100vw;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

.sc-trustband-col {
  padding: 6px 24px;
}

.sc-trustband-divider {
  border-left: 1px solid rgba(28, 37, 43, 0.12);
}

.sc-trustband-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: #70747a;
  margin-bottom: 16px;
}

.sc-trustband-label b {
  color: var(--sc-dark);
}

.sc-trustband-logos {
  display: flex;
  align-items: center;
  gap: 48px;
  flex-wrap: wrap;
}

.sc-trustband-logos img {
  /* One shared height cap for every logo. The sources are a mix of 26px,
     36px and 40px tall art, which is what made the rows read as a jumble;
     capping the height and letting the width follow puts them all on one
     centre line at the same visual size without squashing anything. The
     inline width/height attributes stay as they are -- they still reserve
     the box before the image loads, which is what keeps CLS down. */
  max-height: 32px;
  width: auto;
  object-fit: contain;
  flex: 0 0 auto;
  filter: grayscale(0) opacity(1);
  transition: filter 0.3s ease, transform 0.3s var(--sc-ease);
}

.sc-trustband-logos img:hover {
  filter: grayscale(0) opacity(1);
  transform: translateY(-2px);
}

@media (max-width: 991px) {
  .sc-trustband-divider {
    border-left: none;
    border-top: 1px solid rgba(28, 37, 43, 0.12);
    margin-top: 20px;
    padding-top: 20px;
  }
}

/* -------------------------------------------------------------------------
   Trust-band logo carousel (every breakpoint)
   Each logo row is a seamless auto-scrolling strip. The loop is a
   translateX(-50%), which only reads as seamless while the track is at
   least twice as wide as the window it scrolls inside -- otherwise the
   second half runs out mid-cycle and an empty gap rotates through. Two
   copies (one in the markup, one `aria-hidden` duplicate) are enough at
   phone widths but not on desktop, where a column is only ~520px and the
   awards row holds just three logos. home-redesign.js therefore clones the
   row until the track clears 2x its container, and sets
   --sc-trustband-duration from the measured width so a 5-logo strip and a
   3-logo strip travel at the same ~50px/s instead of sharing one fixed
   duration.
   ------------------------------------------------------------------------- */
.sc-trustband-scroller {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
}

.sc-trustband-track {
  display: flex;
  align-items: center;
  width: max-content;
}

.sc-trustband-track .sc-trustband-logos {
  flex-wrap: nowrap;
  flex-shrink: 0;
  /* Same as the row's gap, so the spacing across the loop seam matches the
     spacing between two logos inside a single copy. */
  padding-right: 48px;
}

/* Covers the text badges on the service pages too, not just the <img> logos. */
.sc-trustband-track .sc-trustband-logos > * {
  flex: 0 0 auto;
}

@media (max-width: 767px) {
  .sc-trustband-logos {
    gap: 32px;
  }

  .sc-trustband-track .sc-trustband-logos {
    padding-right: 32px;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .sc-trustband-track {
    animation: sc-trustband-marquee var(--sc-trustband-duration, 16s) linear infinite;
  }

  .sc-trustband-scroller:hover .sc-trustband-track {
    animation-play-state: paused;
  }
}

/* Reduced motion: nothing moves on its own -- a single static row the
   reader can scroll by hand. The duplicate copies only exist to feed the
   loop, so they come out. */
@media (prefers-reduced-motion: reduce) {
  .sc-trustband-scroller {
    overflow-x: auto;
  }

  .sc-trustband-track .sc-trustband-logos-dup {
    display: none;
  }

  .sc-trustband-track .sc-trustband-logos {
    padding-right: 0;
  }
}

/* -------------------------------------------------------------------------
   A column that does not scroll

   The service pages' "Recognized by" side is four short word-marks that fit
   their half of the row outright. A marquee there was motion for its own
   sake, and the scroller's edge mask kept clipping a badge mid-word. This
   modifier on the column drops the animation, the mask and the clipping, and
   lets the badges wrap if a narrow window needs them to.

   home-redesign.js skips any scroller inside this class, so no clone rows
   are added either.
   ------------------------------------------------------------------------- */
.sc-trustband-col.sc-trustband-static .sc-trustband-scroller {
  overflow: visible;
  -webkit-mask-image: none;
  mask-image: none;
}

.sc-trustband-col.sc-trustband-static .sc-trustband-track {
  width: auto;
  /* Beats the animation shorthand inside the prefers-reduced-motion block:
     three classes against one. */
  animation: none;
  flex-wrap: wrap;
}

.sc-trustband-col.sc-trustband-static .sc-trustband-logos {
  flex-wrap: wrap;
  /* The marquee rules pin this row at flex-shrink:0 so it can keep its
     max-content width and slide. Standing still it has to fit instead:
     without these two it stayed 502px wide inside a 342px phone column and
     pushed the badges off the screen. */
  flex-shrink: 1;
  min-width: 0;
  padding-right: 0;
}

@keyframes sc-trustband-marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* -------------------------------------------------------------------------
   Case study feature cards (SPEDPro / Real Madrid / Abloh)
   ------------------------------------------------------------------------- */
.zoom-img.color-reveal,
.zoom-img .color-reveal {
  box-shadow: var(--sc-shadow-sm);
  transition: box-shadow 0.4s var(--sc-ease), transform 0.4s var(--sc-ease);
}

a.link-article {
  display: block;
  color: inherit;
  text-decoration: none;
}

a.link-article:hover .color-reveal,
a.link-article:hover .zoom-img.color-reveal {
  box-shadow: var(--sc-shadow-lg);
  transform: translateY(-6px);
}

a.link-article .color-reveal::after {
  content: "\2197";
  position: absolute;
  right: 20px;
  bottom: 20px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #fff;
  color: var(--sc-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  opacity: 0;
  transform: translate(8px, 8px) scale(0.8);
  transition: opacity 0.35s ease, transform 0.35s var(--sc-ease);
  z-index: 101;
}

a.link-article:hover .color-reveal::after {
  opacity: 1;
  transform: translate(0, 0) scale(1);
}

a.link-article > strong {
  display: inline-block;
  margin-top: 18px;
  font-size: 1.05rem;
  transition: color 0.25s ease, transform 0.25s var(--sc-ease);
}

a.link-article:hover > strong {
  color: var(--sc-teal);
  transform: translateX(4px);
}

/* -------------------------------------------------------------------------
   Services accordion ("positions")
   ------------------------------------------------------------------------- */
.positions {
  background: transparent;
  box-shadow: none;
}

.position {
  border-bottom: 1px solid rgba(28, 37, 43, 0.08);
  padding: 2px 4px;
}

.position:last-child {
  border-bottom: none;
}

.position-header h5 {
  transition: color 0.25s ease;
}

.position-header[aria-expanded="true"] h5 {
  color: var(--sc-teal);
}

.sc-explore-btn {
  display: inline-block;
  margin-top: 14px;
  padding: 8px 18px;
  font-size: 0.85rem;
}

.position-header .plus {
  transition: transform 0.3s ease;
}

.position-content h6 {
  animation: sc-fade-in 0.5s ease both;
}

@keyframes sc-fade-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* -------------------------------------------------------------------------
   Stats intro ("Real projects. Real numbers.") + stats row
   ------------------------------------------------------------------------- */
.sc-stats-intro {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 30px;
}

.sc-stats-intro h2 {
  font-size: 3.25rem;
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.52px;
  color: var(--sc-dark);
}

.sc-stats-intro-right {
  max-width: 380px;
  padding-top: 6px;
}

.sc-stats-intro-right p {
  font-family: var(--sc-font-body);
  color: var(--sc-text-muted);
  margin-bottom: 14px;
}

.sc-link-arrow {
  display: inline-block;
  color: var(--sc-ink);
  font-family: var(--sc-font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  text-decoration: none;
  border-bottom: 2px solid var(--sc-ink);
  padding-bottom: 4px;
  transition: color 0.25s ease, border-color 0.25s ease, padding-right 0.25s ease;
}

.sc-link-arrow:hover {
  color: var(--sc-teal);
  border-color: var(--sc-teal);
  text-decoration: none;
  padding-right: 6px;
}

.sc-stats-row {
  display: flex;
  flex-wrap: wrap;
  border-top: 1px solid var(--sc-border);
  border-bottom: 1px solid var(--sc-border);
  margin-top: 40px;
}

.sc-stats-row-item {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 26px 24px;
  border-left: 1px solid var(--sc-border);
  transition: background-color 0.3s ease;
}

.sc-stats-row-item:first-child {
  border-left: none;
  padding-left: 0;
}

.sc-stats-row-item:hover {
  background-color: rgba(0, 128, 102, 0.04);
}

.sc-stats-row-item h2 {
  font-size: 1.625rem;
  line-height: 1.5;
  font-weight: 700;
  color: var(--sc-dark);
  margin: 0;
  white-space: nowrap;
}

.sc-stats-row-item span {
  font-family: var(--sc-font-body);
  color: var(--sc-text-muted);
  font-size: 0.84rem;
}

@media (max-width: 767px) {
  .sc-stats-row {
    flex-direction: column;
  }

  .sc-stats-row-item {
    border-left: none;
    border-top: 1px solid var(--sc-border);
    /* Desktop's horizontal padding (26px 24px) exists to space items apart
       side-by-side. Stacked vertically, that left padding is what was
       throwing the numbers out of alignment: `:first-child` resets its own
       padding-left to 0 for the desktop layout, but items 2 and 3 kept the
       24px left padding meant for a side-by-side row — so $10M sat flush
       left while 200+ and 1,000,000 sat indented under it. Reset every
       item's horizontal padding here so all three numbers share one left
       edge. */
    padding-left: 0;
    padding-right: 0;
  }

  .sc-stats-row-item:first-child {
    border-top: none;
  }
}

/* -------------------------------------------------------------------------
   Testimonials
   ------------------------------------------------------------------------- */
.random-quote {
  padding: 10px 0;
}

.random-quote .quote {
  position: relative;
  max-width: 900px;
  margin: 0 auto;
  padding: 46px 30px;
  border-radius: 18px;
  background: var(--sc-quote-bg);
  box-shadow: var(--sc-shadow-sm);
  transition: box-shadow 0.4s ease, transform 0.4s var(--sc-ease);
}

.random-quote .quote:hover {
  box-shadow: var(--sc-shadow-md);
  transform: translateY(-4px);
}

.random-quote .quote::before {
  content: "\201C";
  position: absolute;
  top: 4px;
  left: 26px;
  font-size: 84px;
  line-height: 1;
  font-family: Georgia, "Times New Roman", serif;
  color: var(--sc-teal);
  opacity: 0.25;
}

.quote-sm {
  background: transparent !important;
  padding: 0 !important;
  position: relative;
  z-index: 1;
}

/* -------------------------------------------------------------------------
   Blog / resources cards
   ------------------------------------------------------------------------- */
.resource-item .card {
  transition: transform 0.35s var(--sc-ease);
}

.resource-item .card:hover {
  transform: translateY(-6px);
}

.badge-blog {
  display: inline-block;
  color: var(--sc-teal) !important;
  font-weight: 600;
  letter-spacing: 0.2px;
}

.blog-card-title {
  transition: color 0.25s ease;
}

.resource-item .card:hover .blog-card-title {
  color: var(--sc-teal);
}

/* -------------------------------------------------------------------------
   Footer CTA banner ("Where there's smoke...")
   ------------------------------------------------------------------------- */
.bg-lightblue,
.bg-orange {
  position: relative;
}

.bg-lightblue h3,
.bg-orange h3 {
  letter-spacing: -0.4px;
}

.bg-lightblue .btn.btn-dark:hover {
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.28);
}

.bg-orange .btn.btn-outline-dark:hover {
  background-color: var(--sc-dark);
  color: #fff;
}

/* -------------------------------------------------------------------------
   Scroll-reveal utility (paired with home-redesign.js)
   ------------------------------------------------------------------------- */
.sc-reveal {
  opacity: 1;
  transform: none;
}

/* -------------------------------------------------------------------------
   Responsive tweaks
   ------------------------------------------------------------------------- */
@media (max-width: 991px) {
  main .container[data-background-change="#fff"]::before {
    width: 300px;
    height: 300px;
    top: -100px;
    right: -100px;
  }

  .sc-stats-intro h2 {
    font-size: 2rem;
  }

  .random-quote .quote {
    padding: 34px 20px;
  }
}

@media (max-width: 767px) {
  a.link-article .color-reveal::after {
    width: 36px;
    height: 36px;
    right: 12px;
    bottom: 12px;
    font-size: 16px;
  }
}

/* =========================================================================
   New Figma-aligned sections (real copy)
   ========================================================================= */

/* Trusted-by tweaks */
.sc-trust-title b {
  color: var(--sc-teal);
}

/* "Built for every stage of the journey" */
.sc-journey-band {
  background: var(--sc-gray);
  padding: 48px 40px;
}

.sc-journey-band h2 {
  font-weight: 700;
  font-size: 3.25rem;
  line-height: 0.9;
  letter-spacing: -0.42px;
  margin-bottom: 18px;
}

.sc-journey-band > .row > .col-lg-4 > p {
  color: var(--sc-text-muted);
  font-size: 0.97rem;
  line-height: 1.65;
  max-width: 420px;
}

.sc-journey-cards {
  display: flex;
  gap: 20px;
  height: 100%;
}

.sc-journey-card-item {
  flex: 1 1 0;
  border-radius: 20px;
  padding: 24px;
  min-height: 400px;
  /* Keep the card's portrait proportions (matches the ~267x400px it renders
     at in the normal 1264px container) as the container grows past 1685px,
     where .container switches to max-width:75vw and gets much wider — a
     fixed 400px height on that wider row made the cards look flat/short and
     the photos look "small". aspect-ratio scales height with width instead;
     min-height still floors it at narrower desktop widths (lg breakpoint). */
  aspect-ratio: 2 / 3;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  box-shadow: var(--sc-shadow-sm);
  transition: transform 0.35s var(--sc-ease), box-shadow 0.35s var(--sc-ease);
}

.sc-journey-card-item:hover {
  transform: translateY(-6px);
  box-shadow: var(--sc-shadow-md);
}

/* Photo only — no tint, no overlay. An earlier version darkened the bottom
   of each card to keep the white heading legible; that is deliberately gone,
   so the picture is shown exactly as it is. */
.sc-journey-card-item.sc-journey-light {
  background: url(../img/home/start-up.webp) center/cover no-repeat;
  color: #fff;
}

.sc-journey-card-item.sc-journey-dark-1 {
  background: url(../img/home/scale-up.webp) center/cover no-repeat;
  color: #fff;
}

.sc-journey-card-item.sc-journey-dark-2 {
  background: url(../img/home/journey-smbs.webp) center/cover no-repeat;
  color: #fff;
}

.sc-journey-icon {
  width: 42px;
  height: 42px;
  border-radius: 10px;
  background: #fff;
  color: var(--sc-teal);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  flex: 0 0 auto;
  transition: background-color 0.35s var(--sc-ease);
}

/* -------------------------------------------------------------------------
   Card face swap on hover

   At rest the card is the photograph: icon and heading sit together along
   the top, white on the picture, and nothing else. Hovering turns the whole
   card into a white panel -- the photo goes, the heading darkens, and the
   description appears underneath.

   The white face is a pseudo-element rather than a background swap, because
   a background-image cannot be transitioned away. It sits at z-index 0 and
   everything the card actually shows is lifted to 1, so the photo is covered
   but the content is not.

   It arrives as a wipe: parked one full card-height below at rest and slid
   up to cover on hover. transform is used (not top/height) so the browser
   composites it on the GPU instead of laying the card out on every frame.
   The card is already overflow:hidden with a 20px radius, so the panel is
   clipped to the rounded corners on the way up.
   ------------------------------------------------------------------------- */
.sc-journey-card-item::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #fff;
  transform: translateY(100%);
  /* Ease-out: quick off the bottom, settling gently at the top. */
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
  pointer-events: none;
  z-index: 0;
}

.sc-journey-card-item:hover::before {
  transform: translateY(0);
}

.sc-journey-head {
  display: flex;
  align-items: center;
  gap: 14px;
  position: relative;
  z-index: 1;
}

.sc-journey-card-item h5 {
  font-weight: 700;
  margin: 0;
  color: #fff;
  transition: color 0.2s ease;
}

/* The wipe covers the bottom of the card first and reaches the heading late,
   so the heading and its icon plate hold their on-photo look and then flip
   quickly, finishing just as the white edge arrives underneath them (~220ms
   in). Flipping any earlier puts dark text on the photograph; any later and
   the heading spends a moment as pale grey on white, which reads as a
   glitch. Coming back the top uncovers first, so no delay on the way out. */
.sc-journey-card-item:hover .sc-journey-icon,
.sc-journey-card-item:hover h5 {
  transition-duration: 0.08s;
  transition-delay: 0.14s;
}

.sc-journey-card-item:hover .sc-journey-icon {
  /* A white tile on a white card would vanish, so the plate goes grey and
     the glyph keeps its teal. */
  background: #f1f2f4;
}

.sc-journey-card-item:hover h5 {
  color: var(--sc-dark);
}

.sc-journey-text {
  margin-top: auto;
  position: relative;
  z-index: 1;
}

/* Only on the white face: at rest there is nothing here but photograph. */
.sc-journey-card-item p {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: #56595c;
  /* Lifts the text above the shade that the touch-size rules paint behind
     it -- an absolutely positioned ::before otherwise paints over static
     content, whatever the source order. */
  position: relative;
  z-index: 1;
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  transition: opacity 0.3s ease, max-height 0.35s var(--sc-ease);
}

.sc-journey-card-item:hover p {
  opacity: 1;
  max-height: 220px;
  /* Let the wipe clear the bottom of the card first, so the copy fades in
     onto white instead of onto the photograph. */
  transition-delay: 0.12s;
}

@media (max-width: 991px) {
  .sc-journey-band {
    padding: 30px 22px;
  }

  .sc-journey-band h2 {
    font-size: 2.4rem;
  }

  .sc-journey-cards {
    flex-direction: column;
  }

  .sc-journey-card-item {
    min-height: 260px;
    /* Cards stack full-width here — the 2:3 desktop aspect-ratio would make
       them absurdly tall, so go back to a fixed height like before. */
    aspect-ratio: auto;
  }

  /* There is no :hover on a touch screen, so the white face never arrives
     and the card stays the photograph. The description is shown anyway --
     it is the point of the card -- sitting on its own shade at the bottom,
     white on the picture like the heading above it. */
  .sc-journey-card-item p {
    opacity: 1;
    max-height: none;
    color: rgba(255, 255, 255, 0.92);
  }

  .sc-journey-text {
    /* Full-bleed: the negative margins cancel the card's 24px padding so the
       shade runs edge to edge and sits flush on the bottom, the way the old
       gradient band did. The card is overflow:hidden with a 20px radius, so
       the bottom corners are clipped for us. */
    margin: auto -24px -24px;
    padding: 16px 24px 18px;
  }

  .sc-journey-text::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
      180deg,
      rgba(8, 10, 14, 0) 0%,
      rgba(7, 9, 13, 0.58) 42%,
      rgba(6, 8, 12, 0.88) 100%
    );
    pointer-events: none;
  }
}

@media (max-width: 767px) {
  .sc-journey-band h2 {
    font-size: 1.9rem;
    line-height: 1.05;
  }
}

/* Case study badges (SPEDPro tags/rating) */
.sc-case-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}

.sc-case-meta .sc-case-stat {
  font-family: var(--sc-font-body);
  font-size: 0.9rem;
  color: var(--sc-text-muted);
  flex-basis: 100%;
  margin-bottom: 4px;
}

.sc-case-meta .sc-tag {
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid #ebebeb;
  background: transparent;
  font-family: var(--sc-font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: #9a9a9a;
}

/* First tag (EdTech) is filled, per Figma — the rest stay outlined/muted */
.sc-case-meta .sc-tag:first-of-type {
  border-color: transparent;
  background: var(--sc-tag-lavender);
  color: var(--sc-dark);
}

.sc-case-rating-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-basis: 100%;
  margin-top: 6px;
}

.sc-case-meta .sc-rating {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--sc-mint-pill);
  font-family: var(--sc-font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--sc-dark);
}

.sc-case-meta .sc-rating .fa {
  color: var(--sc-teal);
  font-size: 0.8rem;
}

.sc-case-meta .sc-case-stars .fa {
  color: var(--sc-star);
  font-size: 0.85rem;
  margin-right: 2px;
}

/* The image sits inside a.link-article (padding-bottom: 16px from the base
   framework) wrapping .color-reveal (margin-bottom: 16px) — 32px of space
   below the image before .sc-case-title-row's own margin-top even starts.
   .link-article is only used here on the page, so it's safe to zero both
   out and control the whole gap with margin-top below instead. */
.zoom-img > a.link-article {
  padding-bottom: 0;
}

.zoom-img > a.link-article .color-reveal {
  margin-bottom: 0;
}

/* Title row: SPEDPro heading (left) + "View case study" link (right) */
.sc-case-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin-top: 16px;
}

a.sc-case-title {
  display: inline-block;
  color: inherit;
  text-decoration: none;
  font-size: 1.05rem;
  transition: color 0.25s ease, transform 0.25s var(--sc-ease);
}

a.sc-case-title:hover {
  color: var(--sc-teal);
  transform: translateX(4px);
}

a.sc-case-view-link {
  flex-shrink: 0;
  display: inline-block;
  font-family: var(--sc-font-body);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: #fff;
  /* background-color stays as the fallback beneath the gradient. */
  background-color: var(--sc-teal);
  background-image: var(--sc-btn-gradient);
  /* The transparent 1.5px border below is still part of the painted area
     (background-clip defaults to border-box), but a background is *sized* to
     the padding box by default -- so the gradient stopped 1.5px short on each
     side and background-repeat tiled it into the gap. That put the ramp's
     dark end (#045c48) against the left edge and its light end against the
     right, which read as a black hairline down the left of the button.
     Sizing the gradient to the border box instead makes one ramp span the
     whole button, edge to edge, with nothing left over to repeat. */
  background-origin: border-box;
  /* Was a solid teal border, which cut a hard flat edge around the gradient.
     Kept at the same width but transparent so the button's box size (and so
     the title row's alignment) is unchanged. */
  border: 1.5px solid transparent;
  padding: 0.55rem 1.3rem;
  border-radius: 10px;
  text-decoration: none;
  white-space: nowrap;
  /* background-color cannot carry the hover change -- the gradient is a
     background-image and paints over it, and background-image is not an
     animatable property. brightness() moves the whole ramp at once and does
     transition. */
  transition: filter 0.25s ease, transform 0.25s var(--sc-ease), box-shadow 0.25s ease;
}

a.sc-case-view-link:hover {
  color: #fff;
  /* Darkens, matching the .btn-warning CTAs -- every green button on the page
     should react the same way. */
  filter: brightness(0.94);
  text-decoration: none;
  transform: translateY(-2px);
  box-shadow: var(--sc-shadow-md);
}

/* This link had no focus ring at all: it is an <a>, so it never picked up
   Bootstrap's .btn focus styling, and nothing here replaced it -- a keyboard
   user tabbing through the card had nothing to follow. Same green ring the
   .btn-warning CTAs now use. */
a.sc-case-view-link:focus {
  box-shadow: 0 0 0 0.2rem rgba(0, 128, 102, 0.35);
}

/* -------------------------------------------------------------------------
   Featured case-study carousel (home page)
   Bootstrap 4.3.1 drives it: one case study on screen, the next sliding in
   every 5 seconds, paused while hovered. bootstrap.bundle.min.js is already
   on the page, so no new library.

   Everything is scoped under .sc-case-carousel; the other seven pages that
   load this stylesheet still render their case study as a static .zoom-img.
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   The dots sit ON the banner, not above it

   The controls used to float in a row over the card, which left a wide empty
   band above the image and read as furniture that belonged to nothing. The
   dots now overlay the banner itself, centred along its bottom edge -- the
   shape people already expect from an image carousel. Prev/next arrows were
   dropped with the same reasoning: the carousel auto-advances and the dots
   already cover a manual jump.

   The overlay is sized to the banner, not to the whole slide: each slide
   also carries the title row and the meta line underneath, so a box
   stretched to the card's full height would drop the dots well below the
   picture. `top` matches .carousel-inner's padding-top and the box repeats
   the banner's own 2448:960 ratio, so it lands exactly over the image at
   every width with nothing measured in JS.

   The indicators keep their .carousel-indicators class and stay inside
   #scCaseCarousel: Carousel._setActiveIndicatorElement looks the container
   up from the carousel root and indexes its children to move .active.
   ------------------------------------------------------------------------- */
.sc-case-carousel {
  position: relative;
}

.sc-case-header {
  position: absolute;
  top: 16px;
  left: 0;
  right: 0;
  /* app.min gives .color-reveal .layer a z-index of 100. The layer is parked
     at left:100% and clipped, so it never shows -- but sitting above it
     costs nothing and removes the question. */
  z-index: 120;
  display: block;
  aspect-ratio: 2448 / 960;
  margin: 0;
  /* The banner underneath is a link to the case study. The overlay lets
     those clicks through; the two controls take theirs back below. */
  pointer-events: none;
}

.sc-case-controls {
  position: absolute;
  inset: 0;
  display: block;
  margin: 0;
}

.sc-case-header .sc-case-dots {
  position: absolute;
  left: 50%;
  /* Bootstrap's .carousel-indicators pins right:0 as well; left alone the
     pill would stretch from the centre to the banner's right edge. */
  right: auto;
  bottom: 18px;
  transform: translateX(-50%);
  pointer-events: auto;
  /* A translucent pill keeps the dots legible whatever is behind them -- the
     three banners run from a pale mock-up to a dark dashboard screenshot. */
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 14, 18, 0.38);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.sc-case-header .sc-case-dots button {
  background: rgba(255, 255, 255, 0.55);
}

.sc-case-header .sc-case-dots button.active {
  background: #fff;
}

.sc-case-carousel .carousel-inner {
  /* The slide transition translates items by +/-100%, so the overflow has to
     be clipped. That also cuts the card's shadow and its 6px hover lift,
     hence the vertical padding to give them somewhere to land. */
  overflow: hidden;
  padding: 16px 0 34px;
  /* Bootstrap sizes .carousel-inner from whichever slide is active, and
     slide 1 carries a client rating row the other two have no rating data
     for -- so each advance shifted the rest of the page by ~43px. Stacking
     all three in one grid cell makes the box as tall as its tallest slide
     and the height stops moving. Grid does not disturb the transition:
     Bootstrap animates transform, which applies to grid items unchanged. */
  display: grid;
}

/* Bootstrap's float clearfix would become a grid item of its own here and
   add an empty row under the card. */
.sc-case-carousel .carousel-inner::after {
  display: none;
}

.sc-case-carousel .carousel-item {
  grid-area: 1 / 1;
  /* Hiding MUST stay `display: none` -- Bootstrap's own mechanism.

     Carousel._slide() primes the incoming slide like this:

         next.classList.add('carousel-item-next')   -> translateX(100%)
         Util.reflow(next)                          -> next.offsetHeight
         next.classList.add('carousel-item-left')   -> translateX(0), animate

     The transition only runs if the browser commits translateX(100%) as the
     start value during that reflow. Going from `display: none` to a rendered
     box guarantees that: the box's very first computed style already carries
     the 100% offset.

     Hiding with `visibility: hidden` instead leaves the slide laid out the
     whole time with `transform: none` already committed, so both class
     changes coalesce into a single none -> none update, no start value is
     recorded, and the incoming card never slides -- it just appears while the
     outgoing one leaves. That read as a stall on every advance and was most
     obvious wrapping 3 -> 1. Verified in Chromium: incoming translateX peaked
     at 0px with visibility, 1234px with display.

     `display: none` also keeps off-screen slides out of the tab order and the
     accessibility tree, which is what visibility was reached for. */
  display: none;
}

.sc-case-carousel .carousel-item.active,
.sc-case-carousel .carousel-item.carousel-item-next,
.sc-case-carousel .carousel-item.carousel-item-prev {
  display: block;
}

/* app.min-v=13.css:13677 carries a bare `.active { background:#1c252b;
   color:#fff }` -- written for the blog pagination dots, but unscoped, so it
   also matched whichever slide Bootstrap marks active and painted the whole
   card navy with white text. */
.sc-case-carousel .carousel-item.active {
  background: transparent;
  color: inherit;
}

/* Bootstrap absolutely positions .carousel-indicators across the bottom of
   the slide. These sit in the control row above the card instead, so the
   positioning and the 15% side margins come off -- but the class itself has
   to stay, because Carousel._setActiveIndicatorElement finds the container
   by `.carousel-indicators` and indexes its children to move .active. */
.sc-case-dots {
  position: static;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sc-case-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #c9cbd0;
  cursor: pointer;
  transition: width 0.25s var(--sc-ease), background-color 0.25s ease;
}

/* Beats the bare `.active` above on specificity, so the dot reads as teal
   rather than picking up the pagination rule's navy. */
.sc-case-dots button.active {
  width: 24px;
  border-radius: 999px;
  background: var(--sc-teal);
}

.sc-case-dots button:focus-visible {
  outline: 2px solid var(--sc-teal);
  outline-offset: 2px;
}

/* All three banners are 2448x960. Pinning the ratio keeps every slide the
   same height before the lazy images have loaded, so the carousel does not
   resize as it advances. (Slide 1's markup carries width="600" height="600"
   on its fallback <img>, which would otherwise reserve a square box.) */
.sc-case-carousel .color-reveal img {
  width: 100%;
  aspect-ratio: 2448 / 960;
  object-fit: cover;
}

/* Belt-and-braces for the reveal layer: the markup no longer ships
   "show-color", and this makes sure a slide can never be left behind a flat
   colour block even if that class comes back. Higher specificity than
   app.min's `.color-reveal .layer.show-color { left: 0 }`. */
.sc-case-carousel .color-reveal .layer.show-color {
  left: 100%;
}

@media (max-width: 767px) {
  .sc-case-carousel .carousel-inner {
    padding: 12px 0 24px;
  }

  .sc-case-header {
    /* Follows the reduced .carousel-inner padding-top above. */
    top: 12px;
  }

  .sc-case-header .sc-case-dots {
    bottom: 10px;
    padding: 6px 10px;
  }
}

/* Hiring / staff-aug cards ("Skip the hiring bottleneck") */
.sc-hiring-card {
  border-radius: 18px;
  padding: 14px 22px;
  height: 100%;
  box-shadow: 0px 20px 40px -20px rgba(14, 14, 18, 0.25);
  transition: transform 0.35s var(--sc-ease), box-shadow 0.35s var(--sc-ease);
}

.sc-hiring-card:hover {
  transform: translateY(-6px);
}

.sc-hiring-card.sc-hiring-dark {
  background: var(--sc-ink);
  color: #fff;
}

.sc-hiring-card.sc-hiring-light {
  background: #fff;
  border: 1px solid var(--sc-border);
}

.sc-hiring-card h5 {
  font-weight: 700;
  letter-spacing: -0.15px;
  margin-bottom: 2px;
}

.sc-hiring-card .sc-hiring-exp {
  font-family: var(--sc-font-body);
  font-size: 0.75rem;
  opacity: 0.65;
  margin-bottom: 6px;
  display: block;
}

.sc-hiring-card.sc-hiring-light .sc-hiring-exp {
  color: var(--sc-text-muted);
  opacity: 1;
}

.sc-hiring-card .sc-tag {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  font-family: var(--sc-font-body);
  font-size: 0.69rem;
  font-weight: 600;
  margin: 0 6px 6px 0;
}

.sc-hiring-card.sc-hiring-dark .sc-tag {
  background: var(--sc-tag-blue);
  color: var(--sc-ink);
}

.sc-hiring-card.sc-hiring-light .sc-tag {
  background: var(--sc-tag-blue);
  color: var(--sc-ink);
}

.sc-hiring-card .sc-available {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--sc-font-body);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--sc-green-bright);
  margin-top: 4px;
}

.sc-hiring-card .sc-available .fa {
  color: var(--sc-green-bright);
  font-size: 0.5rem;
}

/* Blue banner card wrapping the "Skip the hiring bottleneck" copy */
.sc-hiring-banner {
  background: var(--sc-brand-blue);
  color: #fff;
  padding: 44px 40px;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.sc-hiring-banner h2,
.sc-hiring-banner h3 {
  font-weight: 700;
  font-size: 2rem;
  line-height: 1.125;
  letter-spacing: -0.32px;
  color: #fff;
  margin-bottom: 16px;
}

.sc-hiring-banner p {
  color: rgba(255, 255, 255, 0.9);
  margin-bottom: 20px;
}

/* Stacked hiring cards, with a peeking third card for visual depth.
   Padded and centered within its column so the cards sit inset from both
   the blue banner and the outer edge, instead of touching either. */
.sc-hiring-stack {
  position: relative;
  padding: 0 40px;
}

.sc-hiring-stack .row {
  position: relative;
  z-index: 2;
}

.sc-hiring-peek {
  position: relative;
  z-index: 1;
  width: 58%;
  max-width: 320px;
  margin: -30px auto 0;
  box-shadow: var(--sc-shadow-sm);
}

@media (max-width: 991px) {
  .sc-hiring-stack {
    padding: 0 20px;
  }
}

@media (max-width: 767px) {
  .sc-hiring-stack {
    /* The blue banner sits directly above this column (zero gap by
       design on desktop) and the green process card sits directly below
       — on mobile, once everything stacks into one column, that left
       both edges of the card stack touching their neighbors with no
       breathing room. Give it some vertical padding of its own. */
    padding: 24px 0;
  }

  /* The "peek" card was a desktop-only visual trick (a third card
     partially overlapping the row above it, offset with a negative
     margin, for depth). On mobile that just hid the card entirely —
     show it as a normal full-width stacked card instead, matching the
     other two. */
  .sc-hiring-peek {
    display: block;
    position: static;
    width: 100%;
    max-width: none;
    margin: 16px 0 0;
  }
}

/* 4-step process list ("How we turn ideas into shipped software") */
.sc-step-list {
  margin: 22px 0 0;
}

.sc-step-item {
  display: flex;
  gap: 18px;
  padding: 16px 0;
  border-bottom: 1px solid rgba(28, 37, 43, 0.08);
}

.sc-step-item:last-child {
  border-bottom: none;
}

.sc-step-num {
  flex: 0 0 auto;
  font-weight: 700;
  color: var(--sc-teal);
  font-size: 0.9rem;
  min-width: 28px;
}

.sc-step-item h5 {
  font-weight: 700;
  margin-bottom: 2px;
}

.sc-step-item p {
  color: #56595c;
  margin: 0;
  font-size: 0.92rem;
}

/* Timeline variant: bordered card rows with a connecting line and a circular number badge.
   Padded so the cards sit inset from both the outer edge and the green
   process card, instead of touching either. */
.sc-step-list-timeline {
  position: relative;
  padding: 0 40px;
}

@media (max-width: 991px) {
  .sc-step-list-timeline {
    padding: 0 20px;
  }
}

@media (max-width: 767px) {
  .sc-step-list-timeline {
    padding: 0;
  }
}

.sc-step-list-timeline .sc-step-item {
  border: 1px solid rgba(28, 37, 43, 0.1);
  border-radius: 14px;
  padding: 18px 20px;
  margin-bottom: 22px;
  background: #fff;
  align-items: flex-start;
}

.sc-step-list-timeline .sc-step-item:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 33px;
  width: 1px;
  height: 22px;
  background: rgba(28, 37, 43, 0.15);
  transform: translateY(100%);
}

.sc-step-list-timeline .sc-step-num {
  width: 34px;
  height: 34px;
  min-width: 34px;
  border-radius: 50%;
  background: var(--sc-mint);
  color: var(--sc-teal);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.8rem;
}

.sc-step-list-timeline .sc-step-item {
  border-color: var(--sc-border);
}

.sc-step-list-timeline .sc-step-item:not(:last-child)::after {
  background: var(--sc-border);
}

.sc-step-item h5 {
  font-family: var(--sc-font-body);
  font-weight: 600;
  color: var(--sc-ink);
}

.sc-step-item p {
  font-family: var(--sc-font-body);
  color: var(--sc-text-muted);
}

/* Light CTA banner (Launch Your Next AI Project) */
.sc-cta-light {
  background: linear-gradient(135deg, #f4f4f4 0%, #eef4f2 100%);
  padding: 46px 40px;
}

.sc-cta-light h2 {
  margin-bottom: 12px;
}

.sc-cta-light p {
  color: #56595c;
  max-width: 520px;
  margin-bottom: 20px;
}

.sc-cta-light .sc-trust-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 22px;
}

.sc-cta-light .sc-trust-badges span {
  font-size: 0.82rem;
  color: var(--sc-dark);
  font-weight: 500;
}

.sc-cta-light .sc-trust-badges .fa {
  color: var(--sc-teal);
  margin-right: 6px;
}

/* -------------------------------------------------------------------------
   Home CTA panel: badges and buttons share one bottom line

   The two buttons used to sit in a col-lg-4 next to the copy, stacked and
   vertically centred, so they floated in the middle of the panel with nothing
   to line up against. They now sit side by side on the same line as the trust
   badges, along the bottom of the panel.

   A grid column could not hold them: the pair needs about 525px and a
   col-lg-4 here is about 355px wide. So the grid row was dropped for a
   full-width flex line -- badges left, buttons right.

   Everything below is scoped to .sc-cta-split. The six AI service pages share
   .sc-cta-light but keep their own col-lg-7 / col-lg-5 split, and nothing
   here reaches them.
   ------------------------------------------------------------------------- */
.sc-cta-split h2 {
  /* Without the old column the heading has the full panel width and collapses
     onto one line. This holds the "Lucky for you, we will." break. */
  max-width: 770px;
}

.sc-cta-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 32px;
  margin-top: 26px;
}

.sc-cta-split .sc-trust-badges {
  /* The footer's own margin-top now provides the gap. */
  margin-top: 0;
}

.sc-cta-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.sc-cta-actions .btn {
  margin-bottom: 0;
}

@media (max-width: 767px) {
  /* Stacked, and both buttons the same full width: the primary label wraps to
     two lines at this size, and a narrower secondary sitting beside it read
     as an afterthought. */
  .sc-cta-footer {
    display: block;
  }

  .sc-cta-split .sc-trust-badges {
    margin-bottom: 26px;
  }

  .sc-cta-actions {
    display: grid;
    gap: 12px;
  }

  .sc-cta-actions .btn {
    width: 100%;
  }
}

/* Section heading + left/right scroll-nav buttons, shared by horizontal
   scrollers (industry cards, etc.) */
.sc-section-header-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px 24px;
  margin-bottom: 32px;
}

.sc-scroll-nav {
  gap: 10px;
  flex-shrink: 0;
  margin-left: auto;
}

.sc-scroll-btn {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid rgba(27, 35, 46, 0.18);
  background: #fff;
  color: var(--sc-dark);
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.sc-scroll-nav .sc-scroll-btn {
  display: flex;
}

.sc-scroll-btn:hover {
  background: var(--sc-dark);
  color: #fff;
  border-color: var(--sc-dark);
}

.sc-scroll-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

/* -------------------------------------------------------------------------
   Two-line section heading

   The frame breaks this heading after "In" and bolds the second line, so on
   a desktop the break is part of the design rather than wherever the text
   happens to wrap. Each half becomes its own block, and `nowrap` stops a
   half from splitting.
   ------------------------------------------------------------------------- */
@media (min-width: 992px) {
  .sc-split-heading .sc-heading-line {
    display: block;
    white-space: nowrap;
  }
}

/* Below that the forced break stops helping: holding two unbreakable lines
   on a phone means shrinking the type until it is smaller than the body
   copy under it. So the halves go back to being inline and the heading
   simply flows and wraps wherever it fits, at the normal size. The bold
   still starts at "High", which is the part that carries the emphasis. */
@media (max-width: 991px) {
  .sc-split-heading .sc-heading-line {
    display: inline;
    white-space: normal;
  }
}

/* Horizontal single-row scroller for industry cards */
.sc-industry-scroller {
  display: flex;
  gap: 28px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  /* extra top padding so the hover lift (translateY) has room and the
     card's rounded top corners don't get clipped by the scroller */
  padding: 14px 4px 18px;
  -webkit-overflow-scrolling: touch;
  /* Hide the visible scrollbar/slider — dragging still works, and the
     left/right nav buttons cover the rest. */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* old Edge / IE */
}

.sc-industry-scroller::-webkit-scrollbar {
  display: none; /* Chrome, Safari, new Edge */
  height: 0;
}

/* Three and a half cards in view: the half tells you the row keeps going,
   which is the whole job the arrows used to do. Width is derived from the
   container rather than pinned at 320px so the half stays a clean half at
   every width -- 84px is the three full 28px gaps that sit between the 3.5
   cards. (At 1440 this works out to the same 320px the fixed rule gave.) */
.sc-industry-scroller .sc-industry-card {
  flex: 0 0 calc((100% - 84px) / 3.5);
  scroll-snap-align: start;
}

@media (max-width: 991px) {
  /* Two and a half on a tablet: two full gaps instead of three. */
  .sc-industry-scroller .sc-industry-card {
    flex-basis: calc((100% - 56px) / 2.5);
  }
}

@media (max-width: 767px) {
  /* One card at a time, with the next one's edge showing so it is obvious
     the row scrolls. */
  .sc-industry-scroller .sc-industry-card {
    flex-basis: calc(100% - 56px);
  }
}

/* -------------------------------------------------------------------------
   Pagination dots for horizontal card scrollers

   The industry row used to be driven by a pair of arrows in the section
   header. Dots read better here: they say how much row there is as well as
   how to move through it, and they match the case-study carousel, so the two
   scrollers on this page now behave the same way.

   One dot per screenful, not per card -- eight dots for eight cards would be
   noise when three and a half of them are already visible. home-redesign.js
   works out how many that is and writes the buttons, since the count depends
   on the viewport.
   ------------------------------------------------------------------------- */
.sc-scroll-dots {
  display: flex;
  /* Right-aligned, where the arrows used to be, rather than centred under
     the row: that corner is the end the row scrolls towards, and it keeps
     the section's controls in the same place they have always been. */
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-top: 28px;
}

/* display:flex would otherwise beat the hidden attribute. */
.sc-scroll-dots[hidden] {
  display: none;
}

.sc-scroll-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #c9cbd0;
  cursor: pointer;
  transition: width 0.25s var(--sc-ease), background-color 0.25s ease;
}

/* app.min-v=13.css:13677 has a bare `.active { background:#1c252b }` meant
   for the blog pagination. Two classes plus the element name clear it. */
.sc-scroll-dots button.active {
  width: 24px;
  border-radius: 999px;
  background: var(--sc-teal);
}

.sc-scroll-dots button:focus-visible {
  outline: 2px solid var(--sc-teal);
  outline-offset: 2px;
}

/* Industry / domain-expertise cards */
.sc-industry-card {
  position: relative;
  border-radius: 20px;
  padding: 32px 28px;
  min-height: 340px;
  background: #f4f4f4;
  color: var(--sc-dark);
  overflow: hidden;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  transition: transform 0.35s var(--sc-ease), box-shadow 0.35s var(--sc-ease),
    background-color 0.35s ease, color 0.35s ease;
  box-shadow: var(--sc-shadow-sm);
}

.sc-industry-card:hover {
  background: #000;
  color: #fff;
  transform: translateY(-6px);
  box-shadow: var(--sc-shadow-md);
  text-decoration: none;
}

.sc-industry-card .sc-eyebrow {
  display: block;
  font-family: var(--sc-font-body);
  font-size: 0.72rem;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  opacity: 0.55;
  margin-bottom: 34px;
}

.sc-industry-card h4 {
  font-weight: 600;
  font-size: 1.6rem;
  letter-spacing: -0.32px;
  /* pinned to the bottom of the card by default; hovering reveals the
     paragraph above it, which pushes the heading upward */
  margin-top: auto;
  margin-bottom: 0;
}

.sc-industry-card p {
  font-family: var(--sc-font-body);
  font-size: 0.9rem;
  line-height: 1.55;
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  margin: 0;
  transition: opacity 0.3s ease, max-height 0.3s ease, margin-bottom 0.3s ease;
}

.sc-industry-card:hover p {
  opacity: 0.85;
  max-height: 140px;
  margin-bottom: 12px;
}

/* Touch devices have no :hover, so the desktop hover-reveal above would
   leave the paragraph permanently invisible — show it by default and let
   the card grow past its min-height instead of relying on the hover
   trigger. */
@media (max-width: 991px) {
  .sc-industry-card h4 {
    margin-top: 0;
  }

  .sc-industry-card p {
    opacity: 1;
    max-height: none;
    margin-bottom: 12px;
  }
}

@media (max-width: 767px) {
  .sc-industry-card {
    min-height: 0;
    padding: 20px;
  }

  .sc-industry-card h4 {
    font-size: 1.15rem;
  }

  .sc-industry-card p {
    font-size: 0.82rem;
  }
}

/* Testimonial grid (Our Clients' Success Stories) — light band contained to
   the same width as the rest of the page content (not full-bleed), 3-column
   staggered masonry, per Figma dev-mode export. */
.sc-testimonials-band {
  background: var(--sc-band-3);
  padding: 48px 40px;
}

.sc-testimonial-kicker {
  font-family: var(--sc-font-body);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--sc-text-muted);
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
}

.sc-testimonials-band h2 {
  font-weight: 700;
  font-size: 3rem;
  letter-spacing: -0.4px;
}

/* "success stories" highlighted in teal, on its own line (forced with a
   <br> in the markup per the Figma layout) rather than relying on
   .main h2 b, which would also draw the swipe-in underline used
   elsewhere — this heading just needs the color, no underline. */
.sc-testimonial-highlight {
  color: var(--sc-teal);
}

/* The shared .sc-case-meta .sc-rating .fa rule colors icons teal (correct
   for the SPEDPro case study's checkmark badge) — but here .sc-rating
   wraps 5 star icons directly, which should read as gold/yellow like every
   other star rating on the page (--sc-star), not teal. Scoped to this band
   only so the SPEDPro badge is untouched. */
.sc-testimonials-band .sc-rating .fa {
  color: var(--sc-star);
}

@media (max-width: 767px) {
  .sc-testimonials-band h2 {
    font-size: 2.1rem;
  }
}

@media (max-width: 991px) {
  .sc-testimonials-band {
    padding: 34px 22px;
  }
}

.sc-testimonial-grid {
  display: flex;
  align-items: flex-start;
  gap: 28px;
  /* The three columns had no width cap, so they simply split whatever the
     band was wide: past ~1200px every card stretched into a squat, wide
     rectangle, while the mockup's cards are taller than they are wide.
     Capping the row and centring it fixes the card width from 1180px up,
     so the card keeps its proportions on any monitor. */
  max-width: 1180px;
  margin-inline: auto;
  /* The quote and the company line under the name are one tone in the
     mockup -- the client's name is the only dark text on the card. They
     live in different subtrees (.quote-sm vs the attribution .d-flex) so
     neither can inherit from the other; holding the value here keeps them
     from drifting apart the way they did when only the quote was lightened.
     #70747a is the soft grey this stylesheet already uses for muted labels
     (.sc-trustband-label) and clears WCAG AA at 4.7:1 on white. */
  --sc-testimonial-body: #70747a;
}

.sc-testimonial-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.sc-testimonial-col-offset {
  padding-top: 56px;
}

.sc-testimonial-grid .random-quote {
  display: block !important;
  margin: 0 !important;
}

.sc-testimonial-grid .quote {
  height: auto;
  max-width: none;
  margin: 0;
  padding: 26px 24px;
  text-align: left;
  background: #fff;
}

/* The shared .random-quote .quote::before absolutely-positions the
   decorative quote mark into a top corner, so here it landed on the same
   line as the verified badge and stars and read as clutter. In the mockup
   the mark is not decoration behind the content: it sits in the flow, on
   its own line under the badge row, and pushes the message down. Remove
   the absolute one outright and rebuild it as a static block below. */
.sc-testimonial-grid .quote::before {
  content: none;
}

/* .quote-sm holds the badge row first and then the message as a bare text
   node. Making it a flex column lets ::before be a real block in the flow
   rather than an overlay; `order` on the badge row then lifts it back to
   the top, so the painted order is badge row -> quote mark -> message
   without restructuring the markup of six cards. */
.sc-testimonial-grid .quote-sm {
  display: flex;
  flex-direction: column;
  text-align: left !important;
  font-size: 0.95rem !important;
  line-height: 1.6;
  /* Was inheriting --sc-dark, the same near-black as the bold client name
     below it, so a five-line quote read as a heavy slab. */
  color: var(--sc-testimonial-body);
  padding: 0 !important;
}

.sc-testimonial-grid .quote-sm::before {
  /* The supplied artwork rather than Georgia's typographic quote. Drawn at
     30x22 and shipped at 4x (120x88, 796 bytes, lossless) so it stays
     sharp on high-DPI screens; the teal is baked into the file and is the
     same #008066 as --sc-teal. An empty ::before with a background sizes
     itself from width/height, so the block occupies exactly the ink -- no
     dead line-box space under it the way the glyph had. */
  content: "";
  display: block;
  width: 30px;
  height: 22px;
  background-image: url(../img/home/quote-mark.webp);
  background-repeat: no-repeat;
  background-position: left top;
  background-size: 30px 22px;
  margin-bottom: 12px;
}

.sc-testimonial-grid .sc-quote-header {
  order: -1;
  margin-bottom: 14px;
}

.sc-testimonial-grid .quote .d-flex {
  justify-content: flex-start !important;
  /* The client photo is the row's first item; centring keeps the circle on
     the optical middle of the two-line name/company block. */
  align-items: center;
  gap: 12px;
  /* The markup's py-4 py-lg-5 utilities are !important, and at lg they put
     48px above the attribution -- far more air than the mockup, which
     tucks the name close under the message. */
  padding: 14px 0 0 !important;
}

/* -------------------------------------------------------------------------
   Client photo on the testimonial attribution line

   A fixed circle in front of the name and company. flex-basis is pinned so
   the circle never squashes when a long job title wraps -- the text block
   beside it takes the shrinking instead.

   The supplied files are 1254x1254 and about 1.3MB each. They are shipped
   here at 120x120 (~2KB) under a "-sm" name: six of these at full size
   would have added roughly 5MB to the home page for circles rendered at
   46px.

   Two of the six clients have no photo yet, so those fall back to their
   initials in the same circle rather than leaving a gap in the row.
   ------------------------------------------------------------------------- */
.sc-quote-avatar {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Also the resting colour behind a photo that has not decoded yet, so the
     row never jumps or flashes white. */
  background: var(--sc-verified-bg);
}

.sc-quote-avatar img {
  width: 100%;
  height: 100%;
  /* The source files are square, but cover keeps the crop honest if a later
     photo is not. */
  object-fit: cover;
  display: block;
  border-radius: 50%;
}

.sc-quote-avatar-initials {
  font-family: var(--sc-font-body);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--sc-teal);
}

/* Attribution. Both lines were running at the base .text-18/.text-14
   sizes, much larger than the mockup: the name reads there as a small
   uppercase label and the company as muted support beneath it. The
   markup's inline style="font-weight: 500" was removed from index.html so
   this weight applies without needing !important to out-rank it. */
.sc-testimonial-grid .quote .text-18 {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--sc-dark);
  margin-top: 0 !important;
}

.sc-testimonial-grid .quote .text-14 {
  font-size: 0.75rem;
  color: var(--sc-testimonial-body);
  margin-top: 2px;
}

.sc-quote-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.sc-verified-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--sc-verified-bg);
  font-family: var(--sc-font-body);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--sc-dark);
  margin-bottom: 0;
}

.sc-verified-badge .fa {
  color: var(--sc-teal);
}

.sc-quote-stars .fa {
  color: var(--sc-star);
  font-size: 0.8rem;
  margin-right: 1px;
}

/* Dark video-testimonial placeholder cards */
.sc-video-card {
  position: relative;
  min-height: 260px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: linear-gradient(150deg, #232a46 0%, #14172a 100%);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 24px 26px;
}

.sc-video-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--sc-teal);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 8px rgba(44, 75, 255, 0.18);
}

.sc-video-play .fa {
  color: #fff;
  font-size: 0.95rem;
  margin-left: 2px;
}

.sc-video-caption {
  position: relative;
  z-index: 1;
}

.sc-video-caption .text-18,
.sc-video-caption .text-14 {
  color: #fff;
}

/* Below lg the three columns get too narrow to hold a testimonial: at
   768px each card was only ~197px wide, so a message ran to eight or nine
   lines and the card turned into a tall ribbon. Two columns across the
   tablet range keeps the card near the ~310px width it has on a phone and
   the ~366px it has on desktop. */
@media (min-width: 768px) and (max-width: 991px) {
  .sc-testimonial-grid {
    flex-wrap: wrap;
  }

  .sc-testimonial-col {
    flex: 0 1 calc(50% - 14px);
  }

  /* Columns wrap as whole units, so with columns 1 and 2 filling the first
     row the third would drop underneath at half width and leave the right
     half of that row empty. Give it the full row instead and turn it on
     its side, so its two cards sit beside each other at the same ~310px
     as the four above them and the block reads as an even 2x3. */
  .sc-testimonial-col:nth-child(3) {
    flex-basis: 100%;
    flex-direction: row;
  }

  .sc-testimonial-col:nth-child(3) > .random-quote {
    flex: 1 1 0;
    min-width: 0;
  }

  .sc-testimonial-col-offset {
    padding-top: 0;
  }
}

@media (max-width: 767px) {
  .sc-testimonial-grid {
    flex-direction: column;
  }

  .sc-testimonial-col-offset {
    padding-top: 0;
  }
}

/* Blog section header row */
.sc-blog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

.sc-blog-header p {
  margin: 0;
  max-width: 560px;
}

/* Green process card ("How we turn ideas into shipped software") */
.sc-process-card {
  background: var(--sc-teal);
  padding: 40px 34px;
  color: #fff;
  height: 100%;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.sc-process-card h3,
.sc-process-card h2 {
  color: #fff;
  font-weight: 700;
  font-size: 2rem;
  line-height: 1.125;
  letter-spacing: -0.32px;
  position: relative;
  z-index: 1;
  margin-bottom: 16px;
}

.sc-process-card p {
  color: rgba(255, 255, 255, 0.85);
  position: relative;
  z-index: 1;
  margin-bottom: 20px;
}

.sc-process-card .btn {
  position: relative;
  z-index: 1;
}

@media (max-width: 767px) {
  .sc-cta-light,
  .sc-process-card {
    padding: 34px 22px;
  }
}

/* =========================================================================
   Button parity pass — exact Figma button treatment
   (white-fill / black-border uppercase pills, and the one filled-gray
   secondary button). Scoped to `main` so nothing outside the home page
   content area is touched.
   ========================================================================= */

/* White pill, black border, uppercase 15px/600 — the repeated secondary CTA
   used across "Explore the service", "See more/past projects",
   "Hire AI Experts", "Read our blogs". */
main .btn.btn-outline-dark {
  background: #fff;
  border: 1px solid var(--sc-ink);
  border-radius: 9px;
  color: var(--sc-ink);
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

main .btn.btn-outline-dark:hover {
  background: var(--sc-ink);
  border-color: var(--sc-ink);
  color: #fff;
}

/* White pill on a colored/dark card background — "Get a Free Quote",
   "Talk to an AI Specialist". */
main .sc-hiring-banner .btn.btn-light,
main .sc-process-card .btn.btn-light {
  background: #fff;
  border: 1px solid #fff;
  border-radius: 9px;
  color: #000;
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

main .sc-hiring-banner .btn.btn-light:hover,
main .sc-process-card .btn.btn-light:hover {
  background: transparent;
  color: #fff;
}

/* Filled light-gray secondary button — "Connect with our experts" is the
   one CTA that isn't an uppercase pill in the Figma spec. */
main .sc-journey-band .btn.btn-outline-dark {
  background: var(--sc-btn-fill);
  border: 1px solid #000;
  border-radius: 10px;
  color: var(--sc-ink);
  font-family: var(--sc-font-body);
  font-weight: 600;
  font-size: 0.906rem;
  text-transform: none;
  letter-spacing: normal;
}

main .sc-journey-band .btn.btn-outline-dark:hover {
  background: #000;
  color: #fff;
}

/* Primary teal CTA ("Let's talk!", "Schedule a Free Consultation").

   The colour lives in app.min-v=13.css, which the whole site shares and which
   is versioned in its filename, so every correction has to be an override
   here rather than an edit there:
     :5027   .btn-warning        background-color / border-color  #008066
     :5037   .btn-warning:focus  box-shadow rgba(222,170,12,.5)   <- yellow ring
     :12428  .btn-warning:hover  background / border-color #1c252b <- navy hover

   All fifteen of these buttons sit inside <main> on all eight pages, so the
   `main` scope below reaches every one of them and keeps the specificity
   (0,3,1) comfortably above app.min's (0,2,0) state rules.

   The gradient was already overriding the flat fill, but on a 100deg axis
   running mid-teal -> lighter -> dark, which read as a sheen across the
   middle rather than a ramp. It now uses the shared --sc-btn-gradient: a
   straight 90deg run, light on the left to dark on the right. */
main .btn.btn-warning {
  background-color: var(--sc-teal);
  background-image: var(--sc-btn-gradient);
  /* .btn carries a transparent 1.5px border. That border area still gets
     painted (background-clip defaults to border-box) but a background is
     *sized* to the padding box, so the gradient fell 1.5px short on each side
     and background-repeat tiled it into the gap: the ramp's dark end
     (#045c48) landed against the left edge and its light end against the
     right, which read as a black hairline down the left of the button.
     Sizing to the border box makes one ramp cover the whole button. */
  background-origin: border-box;
  border-color: transparent;
  border-radius: 9px;
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

/* app.min paints the button #1c252b on both :hover and :focus. Overriding it
   with a second, reversed gradient used to put the light end on the right,
   which read as the button flipping rather than reacting -- brightness()
   dims the ramp as a whole and keeps its direction. The border is repeated
   here because app.min's rule sets border-color alongside the background.
   The translateY(-3px) lift, the shadow and the ::after shine sweep all stay
   with the rules near the top of this file. */
main .btn.btn-warning:hover,
main .btn.btn-warning:focus {
  background-color: var(--sc-teal);
  background-image: var(--sc-btn-gradient);
  /* Repeated from the base rule: app.min sets `background` (the shorthand) on
     these states, and any shorthand resets background-origin back to
     padding-box -- which would bring the tiled dark hairline back on hover. */
  background-origin: border-box;
  border-color: transparent;
}

/* Only :hover dims. app.min's navy applies to :focus as well, so :focus has
   to be in the rule above to hold the gradient -- but a button that is merely
   focused has not been pointed at, and darkening it there would leave it
   dimmed after a click until something else takes focus. */
main .btn.btn-warning:hover {
  filter: brightness(0.94);
}

/* The ring is kept and only recoloured -- it is the one thing telling a
   keyboard user where they are, and the inherited yellow is left over from
   Bootstrap's original warning palette, which this button no longer uses. */
main .btn.btn-warning:focus,
main .btn.btn-warning.focus {
  box-shadow: 0 0 0 0.2rem rgba(0, 128, 102, 0.35);
}

main .sc-explore-btn {
  padding: 8px 20px;
  font-size: 0.82rem;
}

/* =========================================================================
   Section spacing — a little vertical breathing room between every
   top-level content block on the home page. CSS-only, targets each
   section by its exact direct-child relationship to its container so
   nothing inside a section (cards, rows of columns, the footer CTA
   banner) is affected.
   ========================================================================= */
:root {
  /* Was 100px, derived from the Figma "Home page" frame (1920px wide):
     the gap between the last visible element of one section and the first
     of the next (SPEDPro tags row bottom @3307 -> hiring banner top @3422
     = 115px; process card bottom @4269 -> next section top @4369.5 =
     ~100px; testimonials band bottom @7460 -> "Latest insights" heading
     @7560 = 100px) consistently landed around 100px.

     Now 40px, because in the built page 100px read as far too much empty
     space between sections. 40px is the rhythm the trust band already had
     above and below itself, so the rest of the page is pulled down to
     match it -- which is also what makes the old .sc-trustband-flush
     override redundant (it existed purely to cancel this gap back to
     40px, and is removed below).

     This is a :root variable, so the change is deliberately global: the
     six AI service pages and services.html load this file too, and their
     section joins move from 100px to 40px with it. Those pages keep their
     own 56px .sc-svc-section rhythm for everything else.

     The hiring banner -> process card transition stays the one documented
     exception below, where Figma has them flush (0px). */
  --sc-section-gap: 40px;
}

main > .container > section.row,
main > .container > .sc-trustband,
main > .container > .row,
main > .container > .sc-journey-band,
main > .container > .sc-stats-intro,
main > .container > .sc-hiring-row,
main > .container > .sc-testimonials-band,
main > .container > .sc-blog-header,
main > .container > .container > .row,
main > .container > .container > .sc-cta-light {
  margin-top: var(--sc-section-gap);
  margin-bottom: var(--sc-section-gap);
}

/* "Real projects. Real numbers." heading + the $10M/200+/1,000,000 stat
   row + the SPEDPro case study are one visual section (per Figma), not
   three stacked sections — give them a small shared internal rhythm
   instead of the full section gap, and only push the *outer* edges
   (heading's top, case study's bottom) out to the normal section gap. */
main > .container > .sc-stats-intro {
  margin-bottom: 0;
}

main > .container > .sc-stats-row {
  /* Was 40px. That used to be the "tighter than a section break" value
     back when the section gap was 100px -- but the section gap is now 40px
     itself, so keeping 40px here would leave this group with no internal
     rhythm at all and it would read as three separate sections instead of
     one. 24px restores the distinction. */
  margin-top: 24px;
  margin-bottom: 24px;
}

/* The case-study block used to be a bare `main > .container > .zoom-img`.
   It is now three .zoom-img slides inside .sc-case-carousel, so that
   selector no longer matches anything and the section's top/bottom spacing
   would have collapsed. The carousel wrapper inherits the rule; the
   .zoom-img selector stays alongside it so the other pages, where the block
   is still a direct child, are unaffected. */
main > .container > .zoom-img,
main > .container > .sc-case-carousel {
  margin-top: 0;
  margin-bottom: var(--sc-section-gap);
}

/* The hiring row (blue banner + job cards) and the process row (steps +
   green card) sit directly on top of one another with zero gap, so the
   blue banner's bottom-right corner touches the green card's top-left
   corner — overrides the generic section-gap margin above. */
main > .container > .sc-hiring-row {
  margin-bottom: 0;
}

main > .container > .sc-process-row {
  margin-top: 0;
}

/* Below the lg breakpoint the two columns stack — DOM order puts the
   checklist (steps) above the green "From napkin sketch to app store"
   card. On mobile it should read the other way: the green summary card
   first, the supporting checklist underneath it. `.row` is already
   `display:flex` (Bootstrap), so a plain `order` swap reverses the visual
   stacking order without touching the markup. */
@media (max-width: 991px) {
  .sc-process-row > .col-lg-6:first-child {
    order: 2;
  }

  .sc-process-row > .col-lg-6:last-child {
    order: 1;
  }
}

/* Hero sits right under the nav — keep it snug up top, just add room below it. */
main > .container > section.row {
  margin-top: 0;
}

/* The blue/yellow footer CTA banner is a full-bleed block that sits directly
   under <main>, outside any .container — give it room from the section above. */
main > div[style*="linear-gradient"] {
  margin-top: var(--sc-section-gap);
}

/* ===========================================================================
   Large-screen cap — the base framework grows .container to max-width:75vw
   past 1685px viewport width, with NO upper bound. On a big monitor (or a
   normal monitor zoomed out, which is CSS-equivalent to a wider viewport)
   that lets the container keep expanding forever — 2600px viewport => a
   1950px-wide container — while text, icons, and card padding stay at their
   fixed rem/px sizes. The page doesn't get "more responsive", it just gets
   sparser: the same small type and small cards floating in far too much
   width. Capping the container's growth keeps every section's proportions
   (type size vs. whitespace) consistent from a laptop up through an
   ultra-wide/zoomed-out display, instead of only working within one range.
   =========================================================================== */
@media (min-width: 1685px) {
  .container {
    max-width: min(75vw, 1600px);
  }
}

@media (max-width: 767px) {
  :root {
    /* Figma export only covers the 1920px desktop frame, so there's no
       mobile spec to measure. The old pair was 100px/64px (a 0.64 ratio);
       at the new 40px base that same ratio would give ~26px, which is too
       tight to read as a section break at all, so mobile holds at 32px. */
    --sc-section-gap: 32px;
  }
}

/* =========================================================================
   Contact CTA — "Where there's smoke..." (blue / light-gray split)
   Shared by index.html and services.html — both link this stylesheet.
   ========================================================================= */
.sc-svc-contact {
  width: 100vw;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

/* Root cause of a height mismatch: Bootstrap's `.row` is display:flex,
   which SHOULD stretch both columns to equal height by default — but that
   only works reliably when both columns are plain flex items with no
   competing height rules. Rather than fight flex-stretch edge cases,
   force the row onto CSS Grid instead: grid items stretch to fill their
   row's height unconditionally, so the blue column and the form column
   are guaranteed to be exactly the same height, no matter which one has
   more content. */
.sc-svc-contact .row {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* The gap-in-the-middle-with-half-width-columns bug: the columns still
   carry Bootstrap's ".col-lg-6" class, which sets `max-width: 50%` (and a
   flex-basis) meant for a *flex* row. Percentage max-width on a grid item
   resolves against its own grid cell — which is already 50% of the row —
   so 50% of 50% left each column at just 25% of the row, with a blank gap
   where the unused space collapsed into the middle. Neutralize those
   leftover flex-column sizing properties now that the parent is a grid. */
.sc-svc-contact .row > [class*="col-"] {
  max-width: 100%;
  width: 100%;
  flex: none;
}

@media (max-width: 991px) {
  .sc-svc-contact .row {
    grid-template-columns: 1fr;
  }
}

.sc-svc-contact-left {
  background: var(--sc-brand-blue, #3aadd9);
  color: #fff;
  padding: 70px 50px;
  display: flex;
  /* Center the whole text block as a unit — both axes — while the text
     inside that block stays left-aligned (so the heading, paragraph, and
     button all share the same left edge, instead of each line centering
     independently with ragged edges). */
  align-items: center;
  justify-content: center;
}

.sc-svc-contact-inner {
  max-width: 460px;
  width: 100%;
  text-align: left;
}

.sc-svc-contact-left h2 {
  color: var(--sc-dark);
  font-weight: 700;
  font-size: 2.6rem;
  margin-bottom: 20px;
}

.sc-svc-contact-left p {
  color: rgba(14, 14, 18, 0.72);
  margin-bottom: 28px;
}

@media (max-width: 991px) {
  .sc-svc-contact-left {
    padding: 50px 26px;
  }

  .sc-svc-contact-left h2 {
    font-size: 2.1rem;
  }
}

/* -------------------------------------------------------------------------
   Sticky left column — one side stays in place while the other side
   scrolls past it. Shared by the "What you get, beyond the build" section
   on services.html and the "It's not rocket science" section on index.html.
   ------------------------------------------------------------------------- */
.sc-value-sticky {
  position: sticky;
  top: 170px;
}

@media (max-width: 991px) {
  .sc-value-sticky {
    position: static;
  }
}

/* "Why SoftCircles" / "Our Processes" button pair. Previously the second
   button used an inline `margin-left: 30px` to space it from the first —
   fine side-by-side on desktop, but once the two buttons wrap onto
   separate lines on a narrow screen, that left margin just shifted the
   second button in from the shared left edge instead of the first. A flex
   row with `gap` spaces them consistently whether they sit side-by-side or
   wrap, so both always share the same left edge. */
.sc-value-btn-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 48px;
}

/* -------------------------------------------------------------------------
   Nav "Contact" link — same text size as the other nav-links, just with a
   thin outline/pill border around it so it still reads as a CTA.
   ------------------------------------------------------------------------- */
.navbar-home .nav-link.sc-nav-contact {
  border: 1px solid rgba(28, 37, 43, 0.35);
  border-radius: 8px;
  padding-left: 16px;
  padding-right: 16px;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.navbar-home .nav-link.sc-nav-contact:hover {
  border-color: #1c252b;
}


/* -------------------------------------------------------------------------
   Trust band top gap on very small screens

   The .sc-trustband-flush override used to live here: it cancelled the
   then-100px section gap back down to 40px on the home page. The section
   gap is now 40px everywhere, so that rule did nothing but restate the
   default -- it was removed, along with the class in index.html.

   It was masking one thing, though. index.html stacks five
   .negative-bottom-space-mobile spacers directly above the band, and the
   base framework gives those margin-bottom:-10px !important below 450px.
   A collapsed margin is the largest positive plus the smallest negative,
   so that -10px eats into the band's top gap: it lands at 22px while every
   other join on the page is 32px. The old rule's -24px happened to win the
   negative slot and hid this; at the smaller values it shows. So add the
   10px back and the band sits on the same rhythm as everything else.

   The adjacent-sibling selector keeps this to the one place those spacers
   actually exist -- no other page loading this file has them.
   ------------------------------------------------------------------------- */
@media (max-width: 450px) {
  main > .container > .negative-bottom-space-mobile + .sc-trustband {
    margin-top: calc(var(--sc-section-gap) + 10px);
  }
}
