/* ===========================================================================
   Sprio module library — presentation for modules.html
   ---------------------------------------------------------------------------
   The new modules are built from the same parts the service page already uses.
   Every value below was read off that page, not chosen here:

     section heading   clamp(40px, 4.35vw, 62px), weight 500, LEFT, in its own
                       grid column — never centred
     glyph             84px, weight 300, violet, no box around it
     card              1px solid rgba(5, 5, 7, 0.18) on white, NO shadow
     grid gap          16px between cards
     column gap        clamp(36px, 5vw, 80px) between heading and content
     body copy         18px / 1.45, --wf-muted
     corners           0, everywhere

   Modules 01-07 need nothing here: they are the service page's own markup and
   are styled by workflow-local.css exactly as they are on that page.
   =========================================================================== */

.modules-page {
  --wf-ink: #030307;
  --wf-paper: #faf9f7;
  --wf-muted: rgba(3, 3, 7, 0.58);
  --wf-line: rgba(5, 5, 7, 0.18);
  --wf-violet: #6904f2;
  --wf-violet-soft: #d9bdff;
  --wf-blue-soft: #a7ddfb;
  --wf-green-soft: #7bdd91;
  --wf-stack: min(1280px, calc(100vw - 96px));
  --wf-gutter: clamp(36px, 5vw, 80px);

  /* The gap between case-study cards, as the export sets it (and sets it with
     !important, in workflow-local.css). Named here so the rail can lay out to
     the same measure instead of a second one that happens to look similar. */
  --wf-cs-gap: clamp(40px, 4.8vw, 68px);

  /* The card arrow, drawn once. Every card that leads somewhere uses this
     same mark, at the same size, in the same corner. */
  --wf-arrow: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13 6l6 6-6 6'/%3E%3C/svg%3E");

  font-family: "Instrument Sans", sans-serif;
  color: var(--wf-ink);
}

.modules-page :is(h1, h2, h3, h4, h5, h6, p, a, span, strong, em, td, th, li, time) {
  font-family: "Instrument Sans", sans-serif;
}

/* Nothing WE add is ever round, and nothing floats on a shadow.
   Scoped to our own mod-* classes on purpose: the harvested modules must keep
   the live page's own treatment, including the deliberately circular orbit
   rings and play button inside the intro split. */
.modules-page [class^="mod-"],
.modules-page [class*=" mod-"] {
  border-radius: 0 !important;
  box-shadow: none !important;
}

/* ===========================================================================
   A module on a real page
   ---------------------------------------------------------------------------
   The library page supplies width, tokens and rhythm from its own wrappers.
   Dropped into a page built by the CMS a module has none of that, so every
   blueprint ships wrapped in .sprio-module, which supplies exactly the same
   context. One module then renders identically in the library and on a page.
   =========================================================================== */

.sprio-module {
  width: var(--wf-stack);
  margin: 0 auto;
  padding: clamp(64px, 6vw, 104px) 0;
}

/* Bands that run edge to edge carry their own padding. */
.sprio-module--bleed { width: 100%; padding: 0; }

/* The hero is the page's own top band: full width, and it owns its image. */
.sprio-module--hero-service {
  width: 100%;
  padding: 0;
  overflow: hidden;
  min-height: clamp(560px, 67vh, 700px);
  display: flex;
  background-color: #fff;
  background-image:
    linear-gradient(90deg, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0.96) 34%, rgba(255, 255, 255, 0.76) 58%, rgba(255, 255, 255, 0.06) 100%),
    url("/theme/sprio-photo-03.jpg");
  background-position: center, right center;
  background-repeat: no-repeat;
  background-size: cover, cover;
}

.sprio-module--hero-service .workflow-enterprise-hero { width: 100%; }

/* The hero's copy sits on the same left edge as every section below it. */
.sprio-module--hero-service .workflow-enterprise-copyblock {
  width: var(--wf-stack);
  margin: 0 auto;
}

/* Modules laid out inside the service page's stack fill the wrapper instead. */
.sprio-module > .workflow-ibm-intro,
.sprio-module > .workflow-ibm-capabilities,
.sprio-module > .workflow-ibm-usecases,
.sprio-module > .workflow-ibm-case-studies,
.sprio-module > .workflow-ibm-related,
.sprio-module > .workflow-ibm-resources { width: 100%; }

/* ------------------------------------------------------------ page framing */

.modules-intro,
.modules-note {
  width: var(--wf-stack);
  margin: clamp(64px, 6vw, 96px) auto clamp(32px, 3vw, 48px);
}

.modules-intro h1 {
  font-size: clamp(44px, 4.45vw, 64px);
  font-weight: 500;
  line-height: 1.08;
  margin: 0;
}

.modules-intro p {
  color: var(--wf-muted);
  font-size: 18px;
  line-height: 1.45;
  max-width: 820px;
  margin: 20px 0 0;
}

.modules-note {
  margin-top: clamp(80px, 8vw, 128px);
  border-bottom: 1px solid rgba(5, 5, 7, 0.35);
  padding-bottom: 14px;
}

.modules-note h2 {
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin: 0;
}

/* -------------------------------------------------------- the module label */

.mod {
  width: var(--wf-stack);
  margin: 0 auto clamp(84px, 8vw, 132px);
}

.mod--bleed .mod-body {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

.mod-label {
  display: flex;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 0;
  margin-bottom: 44px;
  border-top: 2px solid var(--wf-ink);
  border-bottom: 1px solid var(--wf-line);
}

.mod-label .mod-num {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--wf-violet);
}

.mod-label h2 { font-size: 22px; font-weight: 500; line-height: 1.2; margin: 0; flex: 1 1 auto; }

.mod-label code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 13px;
  color: var(--wf-muted);
  border: 1px solid var(--wf-line);
  padding: 4px 10px;
}

.mod-label .mod-use {
  flex-basis: 100%;
  font-size: 14px;
  color: var(--wf-muted);
  line-height: 1.45;
}

/* Harvested modules carry their own scroll offsets from the live page. */
.mod-body > [id] { scroll-margin-top: 0 !important; }

/* ------------------------------------------------------------ shared parts */

/* Section heading: left, in its own column, at the page's display size. */
.mod-body > div > h2 {
  color: var(--wf-ink);
  font-size: clamp(40px, 4.35vw, 62px);
  font-weight: 500;
  line-height: 1.1;
  margin: 0;
}

.mod-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }

.mod-tag {
  display: inline-block;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--wf-ink);
  background: rgba(3, 3, 7, 0.06);
}

.mod-tag.is-violet { background: var(--wf-violet-soft); }
.mod-tag.is-blue   { background: var(--wf-blue-soft); }
.mod-tag.is-green  { background: var(--wf-green-soft); }

.mod-source {
  display: inline-block;
  margin-top: 20px;
  color: var(--wf-violet);
  font-size: 15px;
}

/* ========================================================= 08 stat-band-dark */

.mod-statband { background: var(--wf-ink); padding: clamp(80px, 7vw, 120px) 0; }
.mod-statband .mod-inner { width: var(--wf-stack); margin: 0 auto; }

.mod-statband .mod-head { max-width: 940px; margin-bottom: clamp(56px, 5vw, 84px); }

.mod-statband .mod-head h3 {
  color: #fff;
  font-size: clamp(40px, 4.35vw, 62px);
  font-weight: 500;
  line-height: 1.1;
  margin: 0;
}

.mod-statband .mod-head p {
  color: rgba(255, 255, 255, 0.62);
  font-size: 18px;
  line-height: 1.45;
  margin: 22px 0 0;
  max-width: 720px;
}

.mod-statgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; }

.mod-statgrid article {
  padding: 0 clamp(24px, 2.4vw, 40px);
  border-left: 1px solid rgba(255, 255, 255, 0.22);
}

.mod-statgrid article:first-child { padding-left: 0; border-left: 0; }

.mod-statgrid strong {
  display: block;
  font-size: clamp(48px, 4.6vw, 68px);
  font-weight: 300;
  line-height: 1;
  color: var(--wf-violet-soft);
}

.mod-statgrid p {
  color: rgba(255, 255, 255, 0.62);
  font-size: 17px;
  line-height: 1.45;
  margin: 26px 0 0;
}

.mod-statgrid .mod-source { color: var(--wf-violet-soft); }

/* ====================================================== 09 capabilities-tagged
   Uses .workflow-ibm-capabilities itself; only the tag row is added.          */

/* ============================================================ 10 process-steps */

.mod-steps {
  display: grid;
  grid-template-columns: minmax(340px, 0.8fr) minmax(0, 3fr);
  gap: var(--wf-gutter);
  align-items: start;
}

/* Three steps was what the design was drawn with, but a process is however
   many steps it is: the track takes its column count from the content, so four
   sit in a row of four rather than three plus an orphan. */
.mod-steps-track {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: clamp(24px, 3vw, 48px);
  position: relative;
}

/* One line behind the numerals, from the first to the last. It runs through the
   centre of the discs, which each cover the length of line they sit on — so the
   line reads as threading them together rather than passing behind them. */
.mod-steps-track::before {
  content: "";
  position: absolute;
  top: 36px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--wf-violet);
}

.mod-steps-track article { position: relative; }

/* The step number is a disc, not a numeral on the page.

   72px across with its centre on the line at 36px, and the h3 below carries the
   difference (46px, against the numeral's old 34px) so the block is the same
   118px tall it always was and nothing under it moves.

   The fill is the brand violet — the colour the numerals and the line were
   already drawn in — so the discs belong to the same mark rather than
   introducing a second accent. On a dark or blue band it stays exactly as it
   is: a solid disc carries its own contrast and has nothing to invert.        */
/* Prefixed with .sprio-module and marked, deliberately: the page-wide flatten
   reset is `.modules-page [class^="mod-"] { border-radius: 0 !important }`, and
   an unprefixed .mod-steps .mod-step-num ties it on specificity and loses on
   source order — which is how the phone once rendered as a square silver box. */
.sprio-module .mod-steps .mod-step-num {
  position: relative;
  display: grid !important;
  place-items: center;
  width: 72px !important;
  height: 72px !important;
  padding: 0 !important;
  border-radius: 50% !important;
  background: var(--wf-violet) !important;
  color: #fff;
  font-size: 30px;
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.mod-steps h3 { font-size: 22px; font-weight: 500; line-height: 1.35; margin: 46px 0 0; }
.mod-steps p { color: var(--wf-muted); font-size: 17px; line-height: 1.5; margin: 16px 0 0; }

/* ========================================================= 11 capability-table */

.mod-table-block {
  display: grid;
  grid-template-columns: minmax(340px, 0.8fr) minmax(0, 3fr);
  gap: var(--wf-gutter);
  align-items: start;
}

.mod-table-wrap { overflow-x: auto; border-top: 1px solid rgba(5, 5, 7, 0.35); }
.mod-table { width: 100%; min-width: 860px; border-collapse: collapse; text-align: left; }

.mod-table thead th {
  padding: 22px 24px 22px 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--wf-muted);
  border-bottom: 1px solid var(--wf-line);
}

.mod-table td {
  padding: 26px 24px 26px 0;
  vertical-align: top;
  border-bottom: 1px solid var(--wf-line);
  font-size: 17px;
  line-height: 1.5;
  color: var(--wf-muted);
}

.mod-table td:first-child { color: var(--wf-ink); font-weight: 500; }

/* ========================================================= 12 integration-grid */

.mod-integrations {
  display: grid;
  grid-template-columns: minmax(340px, 0.8fr) minmax(0, 3fr);
  gap: var(--wf-gutter);
  align-items: start;
}

.mod-integration-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }

.mod-integration-grid article {
  border: 1px solid var(--wf-line);
  background: #fff;
  padding: 30px 28px 34px;
  min-height: 320px;
  display: flex;
  flex-direction: column;
}

.mod-integration-grid h3 { font-size: 19px; font-weight: 500; line-height: 1.35; margin: 20px 0 0; }
.mod-integration-grid p { color: var(--wf-muted); font-size: 16px; line-height: 1.5; margin: 14px 0 0; }

/* ============================================================= 13 stat-cards */

.mod-statcards {
  display: grid;
  grid-template-columns: minmax(340px, 0.8fr) minmax(0, 3fr);
  gap: var(--wf-gutter);
  align-items: start;
}

.mod-statcard-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }

.mod-statcard-grid article {
  border: 1px solid var(--wf-line);
  padding: 34px 30px 36px;
  background: #fff;
}

.mod-statcard-grid article:nth-child(1),
.mod-statcard-grid article:nth-child(6) { background: var(--wf-violet-soft); border-color: transparent; }
.mod-statcard-grid article:nth-child(2) { background: var(--wf-blue-soft); border-color: transparent; }
.mod-statcard-grid article:nth-child(4) { background: var(--wf-green-soft); border-color: transparent; }

.mod-statcard-grid strong {
  display: block;
  font-size: clamp(42px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1;
  color: var(--wf-ink);
}

.mod-statcard-grid h3 { font-size: 19px; font-weight: 500; line-height: 1.35; margin: 22px 0 0; }
.mod-statcard-grid p { color: var(--wf-muted); font-size: 16px; line-height: 1.5; margin: 12px 0 0; }
.mod-statcard-grid .mod-source { font-size: 14px; }

/* ============================================================== 14 split-chat */

.mod-sublabel {
  display: block;
  margin: 44px 0 0;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--wf-line);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--wf-ink);
}

.mod-checklist { list-style: none; margin: 0; padding: 0; }

.mod-checklist li { padding: 26px 0; border-bottom: 1px solid var(--wf-line); }
.mod-checklist h3 { font-size: 19px; font-weight: 500; line-height: 1.35; margin: 0; }
.mod-checklist p { color: var(--wf-muted); font-size: 16px; line-height: 1.5; margin: 10px 0 0; }

.mod-chat { border: 1px solid var(--wf-line); background: #faf8ff; }

.mod-chat-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 20px 24px;
  background: var(--wf-ink);
  color: #fff;
}

.mod-chat-head .mod-avatar {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--wf-violet);
  font-size: 15px;
  font-weight: 500;
}

.mod-chat-head strong { display: block; font-size: 16px; font-weight: 500; }
.mod-chat-head span { font-size: 13px; color: rgba(255, 255, 255, 0.62); }

.mod-chat-body { padding: 26px; display: flex; flex-direction: column; gap: 18px; }

.mod-bubble {
  max-width: 84%;
  padding: 16px 18px;
  font-size: 15px;
  line-height: 1.5;
  border: 1px solid var(--wf-line);
  background: #fff;
}

.mod-bubble.is-guest { align-self: flex-end; background: var(--wf-violet-soft); border-color: transparent; }
.mod-bubble time { display: block; margin-top: 10px; font-size: 12px; color: var(--wf-muted); }

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

@media (max-width: 1024px) {
  .mod-steps,
  .mod-table-block,
  .mod-integrations,
  .mod-statcards { grid-template-columns: 1fr; }
  .mod-integration-grid,
  .mod-statcard-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mod-statgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 48px; }
  .mod-statgrid article:nth-child(3) { padding-left: 0; border-left: 0; }
  .mod-steps-track { grid-template-columns: 1fr; }
  .mod-steps-track::before { display: none; }
}

@media (max-width: 767px) {
  .modules-page { --wf-stack: calc(100vw - 40px); }
  .mod-integration-grid,
  .mod-statcard-grid,
  .mod-statgrid { grid-template-columns: 1fr; }
  .mod-statgrid article { padding-left: 0; border-left: 0; }
  .mod-body > div > h2,
  .mod-statband .mod-head h3 { font-size: 34px; }
}

/* ============================================ 15 heading position, per section

   Where a section's heading sits is an editorial decision, so it is a setting
   in the admin rather than a line in this file: each section carries either
   opt-head-top or opt-head-side, and the two blocks below are what those mean.

   Above the content is the house default and is what an unset section gets, so
   a page picks it up without being touched. Beside the content restores the
   layout the sections came out of the export with.

   Two shapes to handle. The export's own sections make the heading the first
   cell of the same grid as the cards, so above means spanning every column.
   The library's sections keep the heading in a column of its own beside a
   wrapper, so above means collapsing to a single column.                     */

/* Three is what the design was drawn with, not a limit on the content: a
   compliance section with four items in a three-column grid leaves one card
   stranded on a row of its own.

   auto-fit was the obvious fix and the wrong one — it sizes tracks from the
   space, so three cards in a row wide enough for five came out narrow with a
   gap on the right. The count is what matters here, not the width, so the
   count is what the rule reads: four items get four columns; three, five and
   six all sit better in three. */
.sprio-module:not(.opt-head-side) .workflow-ibm-capabilities,
.sprio-module:not(.opt-head-side) .workflow-ibm-case-studies {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: 16px;
}

.sprio-module:not(.opt-head-side) .workflow-ibm-capabilities:has(article:nth-of-type(4)):not(:has(article:nth-of-type(5))),
.sprio-module:not(.opt-head-side) .workflow-ibm-case-studies:has(article:nth-of-type(4)):not(:has(article:nth-of-type(5))) {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.sprio-module:not(.opt-head-side) .workflow-ibm-capabilities > h2,
.sprio-module:not(.opt-head-side) .workflow-ibm-case-studies > h2 {
  grid-column: 1 / -1;
  margin-bottom: 0;
}

.sprio-module:not(.opt-head-side) .mod-steps,
.sprio-module:not(.opt-head-side) .mod-table-block,
.sprio-module:not(.opt-head-side) .mod-integrations,
.sprio-module:not(.opt-head-side) .mod-statcards {
  grid-template-columns: minmax(0, 1fr);
  row-gap: 38px;
}

/* Full width, a heading is no longer held to a narrow column — cap the measure
   or a short heading stretches into one thin line across the page. */
.sprio-module:not(.opt-head-side) .workflow-ibm-capabilities > h2,
.sprio-module:not(.opt-head-side) .workflow-ibm-case-studies > h2,
.sprio-module:not(.opt-head-side) .mod-steps > h2,
.sprio-module:not(.opt-head-side) .mod-table-block > h2,
.sprio-module:not(.opt-head-side) .mod-integrations > h2,
.sprio-module:not(.opt-head-side) .mod-statcards > h2 {
  max-width: 20ch;
}

/* Beside the content: the use-case cards are the one module whose heading was
   always on top, so this is the only place the side layout has to be built. */
.sprio-module.opt-head-side .workflow-ibm-usecases {
  display: grid;
  grid-template-columns: minmax(340px, 0.8fr) minmax(0, 3fr);
  gap: var(--wf-gutter);
  align-items: start;
}

.sprio-module.opt-head-side .workflow-ibm-usecases > h2 { margin-bottom: 0; }

/* One column on a phone — and marked important, which is the whole point.

   The four-item rule above is written with :has(), so it computes far higher
   than this one; a media query adds nothing to specificity. A section with
   exactly four cards therefore kept its four columns all the way down, and four
   capability cards on a 390px phone came out 58px wide — a title broken one
   word per line, one letter at a time. It was on the government and
   manufacturing pages as well, and had been since those pages were built.

   Fifth time a rule in this project has lost a fight it looked like it was
   winning. !important settles this one because there is nothing below a single
   column to disagree about. */
@media (max-width: 767px) {
  .sprio-module:not(.opt-head-side) .workflow-ibm-capabilities,
  .sprio-module:not(.opt-head-side) .workflow-ibm-case-studies,
  .sprio-module.opt-head-side .workflow-ibm-usecases {
    grid-template-columns: 1fr !important;
  }
}

/* Four cards do not fit across a tablet either. Between the phone breakpoint
   and 1024 the four-column rule gives 138px a card, so the same sections that
   were 58px wide on a phone were merely unreadable rather than absurd. Two
   columns there. Marked important for the same reason as the rule above: the
   four-item rule is written with :has() and outranks anything simpler. */
@media (min-width: 768px) and (max-width: 1023px) {
  .sprio-module:not(.opt-head-side) .workflow-ibm-capabilities:has(article:nth-of-type(4)):not(:has(article:nth-of-type(5))),
  .sprio-module:not(.opt-head-side) .workflow-ibm-case-studies:has(article:nth-of-type(4)):not(:has(article:nth-of-type(5))) {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}

/* ===================================================== 16 comparison table

   Module 11's table with one column fewer. Nothing about the type or the rules
   changes; the columns simply divide differently, and the two states being
   compared get equal width so neither reads as the answer before it is read. */

.mod-table--3 th:first-child,
.mod-table--3 td:first-child { width: 22%; }
.mod-table--3 th:not(:first-child),
.mod-table--3 td:not(:first-child) { width: 39%; }

/* ========================================================= 17 figure strip

   Module 08's figures without its band: same grid, same hairlines, on white.
   Six fit where the dark band takes four, so the columns halve and the rows
   gain the space the band's padding used to hold.                            */

.mod-figstrip { display: grid; row-gap: 38px; }

.mod-figstrip .mod-statgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--wf-gutter);
  row-gap: 48px;
}

.mod-figstrip .mod-statgrid article {
  padding-left: 28px;
  border-left: 1px solid rgba(5, 5, 7, 0.18);
}

.mod-figstrip .mod-statgrid strong {
  display: block;
  color: var(--wf-violet);
  font-size: clamp(38px, 3.4vw, 52px);
  font-weight: 400;
  line-height: 1;
}

.mod-figstrip .mod-statgrid p {
  margin: 14px 0 0;
  color: var(--wf-muted);
  font-size: 16px;
  line-height: 1.5;
}

@media (max-width: 1024px) {
  .mod-figstrip .mod-statgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767px) {
  .mod-figstrip .mod-statgrid { grid-template-columns: 1fr; }
  .mod-figstrip .mod-statgrid article { padding-left: 0; border-left: 0; }
}

/* ======================================================== 18 the icon set

   Drawings, not font glyphs. One geometric system on a 48-unit grid, stroked at
   a hairline and never filled, so an icon carries the same weight as the rules
   around it instead of sitting on the page like a bullet.

   The stroke is currentColor, which is what lets an icon invert with its card
   when the card turns violet on hover.                                        */

/* The glyph's own font rules must not size a drawing, and the colour is set on
   the SVG rather than inherited: the surrounding copy is muted grey, and an icon
   that inherits it disappears. */
.sprio-icon {
  width: 54px;
  height: 54px;
  display: block;
  margin: 0;
  overflow: visible;
  color: var(--wf-violet);
  stroke: currentColor;
}

.workflow-ibm-icon:has(.sprio-icon) {
  display: block;
  font-size: 0;
  line-height: 0;
  height: auto;
  min-height: 0;
}

/* ================================================== 19 reveal on hover

   A four-up grid where each card shows only its title, and gives up its
   explanation when the reader asks for it by pointing at it. The text is in the
   markup either way — hidden by opacity, never removed — so it is read by search
   engines and by a screen reader exactly as if it were visible.

   Touch has no hover. Rather than trap the copy behind a gesture that does not
   exist, anything without a fine pointer gets every card open, which is the
   layout this module has always had.                                          */

@media (hover: hover) and (pointer: fine) {
  .opt-reveal-on .mod-integration-grid article,
  .opt-reveal-on .workflow-ibm-capabilities article {
    position: relative;
    justify-content: flex-end;
    transition: background-color 220ms ease, border-color 220ms ease;
  }

  /* The title sits at the foot of the card and stays there when the body
     appears, so nothing jumps under the pointer. */
  .opt-reveal-on .mod-integration-grid article > h3,
  .opt-reveal-on .workflow-ibm-capabilities article > h3 {
    margin-top: auto;
    transition: color 220ms ease;
  }

  .opt-reveal-on .mod-integration-grid article > .workflow-ibm-icon,
  .opt-reveal-on .workflow-ibm-capabilities article > .workflow-ibm-icon {
    position: absolute;
    top: 30px;
    left: 28px;
    transition: color 220ms ease;
  }

  .opt-reveal-on .mod-integration-grid article > p,
  .opt-reveal-on .workflow-ibm-capabilities article > p {
    max-height: 0;
    opacity: 0;
    margin-top: 0;
    overflow: hidden;
    transition: max-height 260ms ease, opacity 180ms ease, margin-top 260ms ease;
  }

  .opt-reveal-on .mod-integration-grid article:hover,
  .opt-reveal-on .mod-integration-grid article:focus-within,
  .opt-reveal-on .workflow-ibm-capabilities article:hover,
  .opt-reveal-on .workflow-ibm-capabilities article:focus-within {
    background: var(--wf-violet);
    border-color: var(--wf-violet);
  }

  .opt-reveal-on .mod-integration-grid article:hover > *,
  .opt-reveal-on .mod-integration-grid article:focus-within > *,
  .opt-reveal-on .workflow-ibm-capabilities article:hover > *,
  .opt-reveal-on .workflow-ibm-capabilities article:focus-within > *,
  .opt-reveal-on .mod-integration-grid article:hover .sprio-icon,
  .opt-reveal-on .mod-integration-grid article:focus-within .sprio-icon,
  .opt-reveal-on .workflow-ibm-capabilities article:hover .sprio-icon,
  .opt-reveal-on .workflow-ibm-capabilities article:focus-within .sprio-icon {
    color: #fff;
  }

  .opt-reveal-on .mod-integration-grid article:hover > p,
  .opt-reveal-on .mod-integration-grid article:focus-within > p,
  .opt-reveal-on .workflow-ibm-capabilities article:hover > p,
  .opt-reveal-on .workflow-ibm-capabilities article:focus-within > p {
    max-height: 22em;
    opacity: 1;
    margin-top: 14px;
  }
}

/* ================================================== 20 open cards, no frame

   The figure cards were boxed and tinted — six filled rectangles in a row, which
   on a page that already stacks bordered grids reads as more furniture than
   content. Open is now the default: no border, no fill, and the space that was
   doing the separating comes from the gutter instead, so the columns are held
   apart by air rather than by a line.

   Nothing about the type changes. `frame="boxed"` puts the original back, per
   section, from the admin.                                                    */

.sprio-module:not(.opt-frame-boxed) .mod-statcard-grid {
  column-gap: var(--wf-gutter);
  row-gap: clamp(46px, 4.4vw, 68px);
}

.sprio-module:not(.opt-frame-boxed) .mod-statcard-grid article {
  border: 0;
  background: none;
  padding: 0;
}

/* The figure carried the card; without one it needs to lead, so it takes the
   violet the icons use and the title takes the weight the fill used to give. */
.sprio-module:not(.opt-frame-boxed) .mod-statcard-grid strong {
  color: var(--wf-violet);
  font-weight: 400;
}

.sprio-module:not(.opt-frame-boxed) .mod-statcard-grid h3 {
  margin-top: 20px;
  font-size: 20px;
  font-weight: 600;
}

.sprio-module:not(.opt-frame-boxed) .mod-statcard-grid p {
  margin-top: 10px;
  font-size: 17px;
  line-height: 1.5;
  max-width: 34ch;
}

/* The same treatment for the tile grids. A page of bordered rectangles reads as
   a spreadsheet; without the borders the columns are still columns, held by the
   gutter, and the icons carry the rhythm. A section can still ask to be boxed.

   A grid that reveals on hover keeps its card, deliberately: the violet fill
   needs a shape to fill, and a reader needs to see what is worth pointing at.
   Open and reveal are alternatives, not a combination.                        */

.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .mod-integration-grid,
.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .workflow-ibm-capabilities {
  column-gap: var(--wf-gutter);
  row-gap: clamp(46px, 4.4vw, 68px);
}

.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .mod-integration-grid article,
.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .workflow-ibm-capabilities article {
  border: 0;
  background: none;
  padding: 0;
  min-height: 0;
}

.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .mod-integration-grid h3,
.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .workflow-ibm-capabilities h3 {
  margin-top: 22px;
  font-size: 20px;
  font-weight: 600;
}

.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .mod-integration-grid p,
.sprio-module:not(.opt-frame-boxed):not(.opt-reveal-on) .workflow-ibm-capabilities p {
  margin-top: 10px;
  font-size: 17px;
  line-height: 1.5;
  max-width: 36ch;
}

/* ============================================ 21 use case cards, extended

   Four was the number the design was drawn with, and four is a poor fit for
   content that happens to have five or eight. The grid takes its columns from
   the space available, so any number wraps to a sensible row instead of
   overflowing one.

   The arrow is the same affordance the related-links cards already carry: it
   sits at the foot of the card, out of the copy's way, and covers the whole
   card so the entire tile is the target rather than a 20-pixel glyph.        */

/* One row, however many cards, moved by the prev/next pair.

   The row stays. What had to go was the reason the page seized up in the
   middle of it: the row was a native horizontal scroller lying across the full
   width of the window, and a trackpad flick is never perfectly vertical. Chrome
   locks a gesture to the first scroller that can take it, so a downward swipe
   with a few pixels of sideways drift latched onto the cards — measured at zero
   pixels of page movement and 140 of sideways card movement — and the reader
   felt the page hang.

   So on a mouse or trackpad the row is no longer wheel-scrollable at all: the
   arrows move it, and the wheel always belongs to the page. Touch keeps its
   swipe, where the browser picks an axis per gesture and gets it right. Both
   still reach every card; neither can trap the reader.                       */
.sprio-module--use-case-cards .workflow-ibm-card-grid {
  --uc-gap: clamp(16px, 1.5vw, 22px);
  --uc-per-view: 4;
  grid-template-columns: none;
  grid-auto-flow: column;
  /* The track, not the item, decides the width in a grid — a min on the article
     is ignored. Sizing the track as a share of the row rather than in pixels is
     what stops a card being sliced in half against the right-hand edge: a whole
     number of them fills the width at every window size, and the rest wait
     behind the arrows instead of hanging half out of the section. */
  grid-auto-columns: calc((100% - (var(--uc-per-view) - 1) * var(--uc-gap)) / var(--uc-per-view));
  align-items: stretch;
  gap: var(--uc-gap);
  overflow-x: auto;
  overflow-y: hidden;
  /* Nothing this row does may reach the page behind it. */
  overscroll-behavior: contain;
  scroll-snap-type: x proximity;
  scroll-padding-left: 0;
  padding-bottom: 4px;
  scrollbar-width: none;
}

.sprio-module--use-case-cards .workflow-ibm-card-grid article { scroll-snap-align: start; }

.sprio-module--use-case-cards .workflow-ibm-card-grid::-webkit-scrollbar { display: none; }

/* Three or fewer never scroll, so they share the row rather than leaving a
   quarter of it empty on the right. */
.sprio-module--use-case-cards .workflow-ibm-card-grid:has(> article:nth-child(-n + 3):last-child) {
  grid-auto-columns: minmax(0, 1fr);
}

/* A pointer that has a wheel is a pointer that can latch. Hidden overflow still
   scrolls under script, so the arrows lose nothing — and focus still drags the
   row along when a card is reached by keyboard. */
@media (hover: hover) and (pointer: fine) {
  .sprio-module--use-case-cards .workflow-ibm-card-grid { overflow-x: hidden; }
}

@media (max-width: 1199px) {
  .sprio-module--use-case-cards .workflow-ibm-card-grid { --uc-per-view: 3; }
}

@media (max-width: 899px) {
  .sprio-module--use-case-cards .workflow-ibm-card-grid { --uc-per-view: 2; }
}

/* On a phone the next card shows an edge of itself, which says swipe better
   than any arrow does. */
@media (max-width: 639px) {
  .sprio-module--use-case-cards .workflow-ibm-card-grid {
    grid-auto-columns: 78vw;
    scroll-snap-type: x mandatory;
  }
}

/* The card itself: picture, then copy, then the arrow on the foot rule. Laid
   out in flow rather than by absolute position, so the copy can never run
   under the arrow however long the sentence is, and every card in a row ends
   on the same line whatever it holds. */
.sprio-module--use-case-cards .workflow-ibm-card-grid article {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0 !important;
  overflow: hidden;
}

/* The picture was a fixed 240px whatever the column width, which is what put
   it and the title at odds. A ratio keeps the crop honest at every size. */
.sprio-module--use-case-cards .workflow-ibm-card-art {
  flex: none;
  height: auto !important;
  min-height: 0;
  aspect-ratio: 16 / 10;
  background-position: center;
  background-size: cover;
  position: relative;
}

/* A photograph can end on anything — a white wall, a face, a bright sky — and
   whatever it ends on sits directly above the title. Darkening the last third
   of the image gives the title a consistent foot to stand on without tinting
   the card, so it works over any picture and on any band. */
.sprio-module--use-case-cards .workflow-ibm-card-art::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 42%;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.34) 100%);
  pointer-events: none;
}

.sprio-module--use-case-cards .workflow-ibm-card-grid article h3 {
  margin: 24px 24px 0 !important;
  font-size: 20px;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.sprio-module--use-case-cards .workflow-ibm-card-grid article p {
  margin: 10px 24px 22px !important;
  padding-bottom: 0;
  font-size: 15.5px;
  line-height: 1.6;
}

/* The arrow sits on a hairline at the foot of the card, pushed there by the
   copy above it rather than pinned over it. */
.sprio-module--use-case-cards .workflow-ibm-card-go {
  position: relative;
  right: auto;
  bottom: auto;
  margin: auto 24px 0;
  padding: 16px 0 20px;
  width: auto;
  height: auto;
  min-height: 22px;
  border-top: 1px solid rgba(5, 5, 7, 0.14);
}

.sprio-module--use-case-cards .workflow-ibm-card-go::after {
  inset: auto 0 20px auto;
  width: 22px;
  height: 22px;
}

.workflow-ibm-card-go {
  position: absolute;
  right: 26px;
  bottom: 24px;
  width: 22px;
  height: 22px;
  font-size: 0;
  color: var(--wf-ink);
}

/* The whole card is the link; the glyph only says so. */
.workflow-ibm-card-go::after {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  -webkit-mask: no-repeat center/22px var(--wf-arrow);
  mask: no-repeat center/22px var(--wf-arrow);
}

.workflow-ibm-card-go::before {
  content: "";
  position: absolute;
  inset: auto;
  top: -100vh;
  right: -100vw;
  bottom: -100vh;
  left: -100vw;
}

/* Reached by keyboard the card has to say so; the arrow alone is 22 pixels of
   glyph in the corner of a 400-pixel target. */
.sprio-module--use-case-cards .workflow-ibm-card-grid article:focus-within {
  outline: 2px solid var(--wf-violet);
  outline-offset: 2px;
}

.sprio-module--use-case-cards .workflow-ibm-card-go:focus-visible { outline: none; }

/* The tints were written for exactly four cards, so a fifth onwards came out
   white. They repeat every four instead, which keeps the rhythm however many
   cards a section carries. */
.sprio-module--use-case-cards .workflow-ibm-card-grid article:nth-child(4n + 1) { background: #d9bdff; }
.sprio-module--use-case-cards .workflow-ibm-card-grid article:nth-child(4n + 2) { background: #a7ddfb; }
.sprio-module--use-case-cards .workflow-ibm-card-grid article:nth-child(4n + 3) { background: #7bdd91; }
.sprio-module--use-case-cards .workflow-ibm-card-grid article:nth-child(4n)     { background: #fff; }

/* =============================================== 22 typography, matched

   The family was already the home page's. The heading treatment was not: at
   this size Instrument Sans needs the negative tracking the home page gives it,
   or the words sit loose and read as a different typeface even though they are
   not. Measured off the home page: 500 weight, tight, tucked line height.     */

.sprio-module h2 {
  letter-spacing: -0.028em;
  line-height: 1.04;
}

.sprio-module h3 { letter-spacing: -0.012em; }

.sprio-module p,
.sprio-module td,
.sprio-module li { font-weight: 400; }

/* ================================================== 23 the rail's controls

   A scrollbar tells you there is more only once you have already found it. The
   pair of buttons and the count say so up front, and the buttons disable at
   each end rather than dead-ending silently.

   They are added by script, so a page without JavaScript keeps a rail that
   still scrolls by trackpad, swipe and keyboard — it simply has no buttons. */

.mod-rail-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  margin-top: 26px;
}

/* The theme styles every <button> on the page — black fill, violet fill, pill
   radius. These are not those buttons, so the reset is deliberate and forced. */
.sprio-module .mod-rail-nav .mod-rail-btn {
  width: 46px !important;
  height: 46px !important;
  min-width: 0 !important;
  min-height: 0 !important;
  display: grid !important;
  place-items: center;
  padding: 0 !important;
  margin: 0 !important;
  border: 1px solid var(--wf-line) !important;
  border-radius: 0 !important;
  background: #fff !important;
  background-image: none !important;
  box-shadow: none !important;
  color: var(--wf-ink) !important;
  cursor: pointer;
  transition: border-color 160ms ease, background-color 160ms ease, color 160ms ease;
}

.mod-rail-btn svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.sprio-module .mod-rail-nav .mod-rail-btn:hover:not(:disabled),
.sprio-module .mod-rail-nav .mod-rail-btn:focus-visible {
  border-color: var(--wf-violet) !important;
  color: var(--wf-violet) !important;
  outline: none;
}

.sprio-module .mod-rail-nav .mod-rail-btn:disabled {
  opacity: 0.32;
  cursor: default;
}

.sprio-module .mod-rail-nav .mod-rail-btn svg { width: 20px; height: 20px; }

.mod-rail-count {
  min-width: 52px;
  text-align: center;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--wf-muted);
}

/* ==================================================== 24 things that respond

   Restraint on purpose: a card lifts a little, a rule thickens, an arrow moves
   the distance it is pointing. Nothing scales, nothing shadows, nothing bounces
   — the design has no shadows and no round corners, and motion should not
   smuggle either back in.                                                    */

.sprio-module .workflow-ibm-card-grid article,
.sprio-module .mod-integration-grid article,
.sprio-module .workflow-ibm-capabilities article,
.sprio-module .mod-statcard-grid article,
.sprio-module .workflow-ibm-related article {
  transition: transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1), border-color 200ms ease;
}

.sprio-module .workflow-ibm-card-grid article:hover,
.sprio-module .workflow-ibm-related article:hover {
  transform: translateY(-4px);
}

.sprio-module .workflow-ibm-related article:hover { border-color: var(--wf-violet); }

.workflow-ibm-card-go,
.sprio-module .workflow-ibm-related a {
  transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1), color 180ms ease;
}

.sprio-module .workflow-ibm-card-grid article:hover .workflow-ibm-card-go,
.sprio-module .workflow-ibm-related article:hover a {
  transform: translateX(5px);
  color: var(--wf-violet);
}

/* A table row is a target too: the eye loses the line halfway across otherwise. */
.sprio-module .mod-table tbody tr { transition: background-color 160ms ease; }
.sprio-module .mod-table tbody tr:hover { background: rgba(105, 4, 242, 0.04); }

/* Figures and steps: the violet deepens rather than the card moving. */
.sprio-module .mod-statgrid article strong,
.sprio-module .mod-steps .mod-step-num { transition: color 200ms ease; }

.sprio-module .workflow-ibm-icon { transition: transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1); }
.sprio-module article:hover > .workflow-ibm-icon { transform: translateY(-3px); }

/* ===================================================== 25 arriving sections

   The hiding rule is written so it can only apply once the script has marked
   the document: no JavaScript, no hidden content. The same guard covers the
   moment before the script runs, and prefers-reduced-motion never gets here at
   all — the class is not added.                                              */

.sprio-motion .sprio-module [data-rise] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1) var(--rise-delay, 0ms),
    transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1) var(--rise-delay, 0ms);
}

.sprio-motion .sprio-module [data-rise].is-in {
  opacity: 1;
  transform: none;
}

/* A row of a table must not be transformed — it detaches from its borders. */
.sprio-motion .sprio-module tbody tr[data-rise] { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .sprio-module *,
  .sprio-module *::before,
  .sprio-module *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}

/* ============================================================== 26 the phone

   The conversation used to be a panel with a dark strip on top. It is a phone
   now, because that is what the reader is being asked to imagine: a customer
   messaging a business from the device in their hand.

   Everything is drawn — no photograph of a handset, so nothing to load, the
   frame takes the page's own colours, and it stays sharp at any size. The shell
   is the padding, the screen is the panels inside it, and the chrome (the
   island, the home bar) is pseudo-elements, which the reset at the top of this
   file cannot reach.

   Every radius and shadow here is !important on purpose. Section 02 flattens
   everything we add, deliberately — the design has no round corners. A device
   is the exception the rule was never written for, so it says so out loud
   rather than by weakening the rule for everything else.

   The status line is added by the script and the layout allows for it either
   way, so a browser that never runs it gets a phone with a taller header, not
   a hole.                                                                    */

.sprio-module .mod-chat {
  position: relative;
  width: min(354px, 100%);
  margin: 0 auto;
  padding: 12px;
  border: 0;
  /* A horizontal sweep, not a diagonal: machined metal catches the light in
     bands down its length, and that is the whole difference between a titanium
     rail and a grey border. */
  background: linear-gradient(
    96deg,
    #6d6d79 0%, #cfcfd8 5%, #f4f4f8 11%, #a2a2ae 26%,
    #52525d 48%, #a6a6b2 70%, #f1f1f5 88%, #777783 100%
  ) !important;
  border-radius: 54px !important;
  box-shadow:
    0 0 0 1px rgba(3, 3, 7, 0.4),
    0 46px 92px -34px rgba(3, 3, 7, 0.52),
    0 14px 32px -16px rgba(3, 3, 7, 0.34) !important;
}

/* The black gasket between glass and metal, drawn over both so the two
   surfaces read as one edge rather than as two things placed together. */
.sprio-module .mod-chat::before {
  content: '';
  position: absolute;
  inset: 10px;
  border-radius: 44px;
  box-shadow: 0 0 0 3px #07070c;
  pointer-events: none;
  z-index: 5;
}

/* The island. Near-black on a near-black header, so it needs the hairline to
   exist at all — which is also how it looks on the device. */
.sprio-module .mod-chat::after {
  content: '';
  position: absolute;
  top: 24px;
  left: 50%;
  width: 94px;
  height: 28px;
  transform: translateX(-50%);
  border-radius: 999px;
  background: #000;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.09);
  z-index: 6;
}

/* ---------------------------------------------------------------- the screen */

.sprio-module .mod-phone-status {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 52px;
  padding: 6px 28px 0;
  border-radius: 42px 42px 0 0 !important;
  background: var(--wf-ink);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.sprio-module .mod-phone-status .mod-phone-icons { display: inline-flex; align-items: center; gap: 6px; }
.sprio-module .mod-phone-status svg { display: block; height: 11px; width: auto; fill: currentColor; }

.sprio-module .mod-chat > .mod-chat-head {
  position: relative;
  border-radius: 42px 42px 0 0 !important;
  padding: 60px 20px 18px;
}

/* With the status line present the header is no longer the top of the screen. */
.sprio-module .mod-phone-status + .mod-chat-head { border-radius: 0 !important; padding-top: 14px; }

.sprio-module .mod-chat-head .mod-avatar {
  width: 40px;
  height: 40px;
  border-radius: 999px !important;
  font-size: 14px;
  color: #fff;
}

.sprio-module .mod-chat-head strong { font-size: 15px; }
.sprio-module .mod-chat-head div > span { font-size: 12px; }

/* A live line rather than the word alone: the dot is what says "now". Scoped to
   the span beside the name — the avatar is a span too. */
.sprio-module .mod-chat-head div > span::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 999px;
  background: #35d07f;
  vertical-align: middle;
}

.sprio-module .mod-chat-body {
  position: relative;
  padding: 18px 14px 34px;
  gap: 11px;
  border-radius: 0 0 42px 42px !important;
  background:
    radial-gradient(120% 55% at 50% 0%, rgba(105, 4, 242, 0.07), transparent 62%),
    #f5f3fb;
}

/* The home bar. */
.sprio-module .mod-chat-body::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 11px;
  width: 116px;
  height: 5px;
  transform: translateX(-50%);
  border-radius: 999px;
  background: rgba(3, 3, 7, 0.26);
}

.sprio-module .mod-chat .mod-bubble {
  max-width: 84%;
  padding: 9px 13px 7px;
  font-size: 14px;
  line-height: 1.42;
  border: 0;
  border-radius: 17px 17px 17px 5px !important;
  background: #fff;
  box-shadow: 0 1px 2px rgba(3, 3, 7, 0.12) !important;
}

.sprio-module .mod-chat .mod-bubble.is-guest {
  border-radius: 17px 17px 5px 17px !important;
  background: var(--wf-violet);
  color: #fff;
}

.sprio-module .mod-chat .mod-bubble time { margin-top: 4px; font-size: 11px; }
.sprio-module .mod-chat .mod-bubble.is-guest time { color: rgba(255, 255, 255, 0.74); }

@media (max-width: 767px) {
  .sprio-module .mod-chat { width: min(320px, 100%); }
}

/* ================================================= 27 case studies, as tiles

   A picture on top, the client's wordmark under it, then the story. The same
   shape the "featured work" strip uses, so a case study reads as a piece of
   work rather than as a paragraph in a box.

   The picture is the point, and a card without one is not a case study — so
   every card has one whether or not the content file supplies it. A file can
   set <img src> per card; a card left alone falls back to the site's own
   photography, a different frame per position, which is why the fallback lives
   here rather than in the blueprint (a rebuilt row copies row one, so three
   cards would otherwise share one photograph).                               */

.sprio-module--case-studies .workflow-ibm-case-studies article {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0 0 30px;
  border: 1px solid var(--wf-line);
  border-radius: 0;
  background: #fff;
  overflow: hidden;
  transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1), border-color 200ms ease;
}

.sprio-module--case-studies .workflow-ibm-case-studies article:hover {
  transform: translateY(-5px);
  border-color: rgba(5, 5, 7, 0.4);
}

/* The media band. A block in the flow, so the words sit under it rather than
   on top of it, and the card is as tall as its content. */
.sprio-module--case-studies .workflow-ibm-case-studies article::before {
  content: '';
  display: block;
  aspect-ratio: 16 / 10;
  background-color: #12121c;
  background-position: center;
  background-size: cover;
  background-image: var(--wf-cs-photo, none);
  margin-bottom: 26px;
}

.sprio-module--case-studies .workflow-ibm-case-studies article:nth-of-type(3n + 1) { --wf-cs-photo: url("/theme/sprio-photo-05.jpg"); }
.sprio-module--case-studies .workflow-ibm-case-studies article:nth-of-type(3n + 2) { --wf-cs-photo: url("/theme/sprio-photo-10.jpg"); }
.sprio-module--case-studies .workflow-ibm-case-studies article:nth-of-type(3n)     { --wf-cs-photo: url("/theme/sprio-photo-14.jpg"); }

/* A supplied picture covers the fallback rather than replacing the band, so a
   half-filled section has no holes in it. */
.sprio-module--case-studies article > .wf-cs-media {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.sprio-module--case-studies article > .wf-cs-media:not([src]),
.sprio-module--case-studies article > .wf-cs-media[src=''] { display: none; }

.sprio-module--case-studies article > :is(.workflow-ibm-logo, h3, p) { padding: 0 26px; }

.sprio-module--case-studies .workflow-ibm-logo {
  /* The export reserves 96px here for a client's logo artwork. With a wordmark
     set in type under a photograph that is just a hole in the card. */
  min-height: 0;
  color: var(--wf-ink) !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase;
  margin-bottom: 16px;
}

.sprio-module--case-studies article h3 {
  color: var(--wf-ink) !important;
  font-size: 20px !important;
  font-weight: 500 !important;
  line-height: 1.32 !important;
  margin: 0 0 12px;
}

.sprio-module--case-studies article p {
  color: var(--wf-muted) !important;
  font-size: 15px !important;
  line-height: 1.5 !important;
  margin: 0;
}

/* ============================================ 28 the field, used more widely

   The same slow field behind the dark band, at a fraction of the strength. A
   flat black section next to an animated card looks like the card is a mistake;
   this is what ties them together. It is decoration only — nothing here carries
   meaning, so it can be switched off wholesale below.                        */

.sprio-module .mod-statband { position: relative; overflow: hidden; isolation: isolate; }

.sprio-module .mod-statband::before {
  content: '';
  position: absolute;
  inset: -40%;
  z-index: 0;
  background:
    radial-gradient(30% 46% at 18% 26%, rgba(105, 4, 242, 0.5), transparent 70%),
    radial-gradient(34% 50% at 82% 74%, rgba(28, 86, 255, 0.4), transparent 72%);
  animation: sprio-drift 28s ease-in-out infinite alternate;
}

.sprio-module .mod-statband > .mod-inner { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .sprio-module--case-studies article::before,
  .sprio-module .mod-statband::before { animation: none; }
}

/* ================================================ 29 the arrow, everywhere

   The use-case cards put a drawn arrow in the bottom-right corner and made the
   whole tile the target. Three other card modules shipped the same idea as a
   literal "->" typed at the end of a link, which reads as a typo at card size
   and sits wherever the copy happens to end.

   Same mark, same corner, same size, on every card that leads somewhere. The
   link keeps its words for anyone who cannot see the glyph — the text is set
   to nothing, not removed, so a screen reader still announces "Learn more"
   rather than "link".                                                       */

.sprio-module--related-links .workflow-ibm-related article,
.sprio-module--resource-cards .workflow-ibm-resources article,
.sprio-module--case-studies .workflow-ibm-case-studies article { position: relative; }

/* Room for it, so the arrow never lands on the last line of the copy — and
   only on a card that has one. A card whose content file gave no link has no
   arrow, and reserving the corner anyway leaves it standing on empty space. */
.sprio-module--related-links .workflow-ibm-related article:has(> a),
.sprio-module--resource-cards .workflow-ibm-resources article:has(a) > div:last-child,
.sprio-module--case-studies .workflow-ibm-case-studies article:has(> a) { padding-bottom: 62px; }

.sprio-module--related-links .workflow-ibm-related article > a,
.sprio-module--resource-cards .workflow-ibm-resources article a,
.sprio-module--case-studies .workflow-ibm-case-studies article > a {
  position: absolute;
  right: 26px;
  bottom: 24px;
  width: 22px;
  height: 22px;
  margin: 0;
  padding: 0;
  font-size: 0;
  line-height: 0;
  color: var(--wf-ink);
}

.sprio-module--related-links .workflow-ibm-related article > a::after,
.sprio-module--resource-cards .workflow-ibm-resources article a::after,
.sprio-module--case-studies .workflow-ibm-case-studies article > a::after {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  -webkit-mask: no-repeat center/22px var(--wf-arrow);
  mask: no-repeat center/22px var(--wf-arrow);
}

/* The whole card is the link; the glyph only says so. */
.sprio-module--resource-cards .workflow-ibm-resources article a::before,
.sprio-module--case-studies .workflow-ibm-case-studies article > a::before {
  content: "";
  position: absolute;
  top: -100vh;
  right: -100vw;
  bottom: -100vh;
  left: -100vw;
}

/* It moves the distance it is pointing, like the rest of them. */
.sprio-module--related-links .workflow-ibm-related article > a,
.sprio-module--resource-cards .workflow-ibm-resources article a,
.sprio-module--case-studies .workflow-ibm-case-studies article > a {
  transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1), color 180ms ease;
}

.sprio-module--related-links .workflow-ibm-related article:hover > a,
.sprio-module--resource-cards .workflow-ibm-resources article:hover a,
.sprio-module--case-studies .workflow-ibm-case-studies article:hover > a {
  transform: translateX(5px);
}

/* ============================================== 30 nothing to say, nothing drawn

   A module ships with a fixed number of slots and a page rarely has exactly
   that many. A conversation of five messages, a case-study card with a headline
   and no standfirst: the missing field is blanked, and a blanked block element
   still paints — an empty bubble, a blank line holding a gap open. Neither is
   content, so neither is drawn.                                              */

.sprio-module .mod-chat .mod-bubble:empty,
.sprio-module--case-studies article p:empty,
.sprio-module--case-studies article .workflow-ibm-logo:empty { display: none; }


/* ==================================================== 31 back on brand

   Three values were drifting between the home page and everything built from
   the module library. All three are measurable, none is a matter of taste, and
   together they are why an inner page reads as a different site.

     ground      the home page is #faf9f7; the library was #ffffff
     heading     three colours were in play — #000, #030307 and violet — and
                 the tracking flipped between -0.028em and none
     display     46px here against 74px there, so the same typeface spoke in a
                 smaller, less certain voice

   Scoped away from .sprio-module--bleed on purpose. Those are the home page's
   own sections — the FAQ, the article strip, the contact band, the dark stat
   band — lifted whole. They are already on brand because they ARE the brand,
   and restyling them is how you break the thing you are trying to match.

   Named selectors rather than a blanket .sprio-module h2, because the lifted
   sections put their small uppercase kickers in an h2 as well: a blanket rule
   sets "COMMON QUESTIONS" at 58px, which is exactly what it did the first
   time I wrote this.                                                         */

.sprio-module:not(.sprio-module--bleed) > div > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-intro-copy h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-capabilities > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-usecases > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-case-studies > h2 {
  color: #000 !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important; /* measured off the home page: section headings are untracked */
  font-size: clamp(42px, 4vw, 58px) !important;
  line-height: 1.04 !important;
}

/* Panels are white ON the paper, which is what gives the home page its quiet
   depth. Open sections stay open — they just stop being invisible. */
.sprio-module .mod-table,
.sprio-module--case-studies .workflow-ibm-case-studies article,
.sprio-module .mod-chat-body,
.sprio-module .workflow-ibm-related article { background: #fff; }

/* The home page's dark is #000. The library's was #030307 — close enough to
   look like a mistake rather than a decision. */
.sprio-module .mod-statband { background: #000; }

/* The ground. It belongs to the page rather than to a module: a module is only
   as wide as the stack, so paper painted there leaves white margins down both
   sides. The class is set on <body> only for pages built from modules, so the
   home page — which paints its own sections — is untouched. */
:root { --wf-paper: #faf9f7; }

/* !important because the exported theme paints the body white from its own
   stylesheet, and this file loads alongside it rather than after it. */
body.sprio-modules { background: var(--wf-paper) !important; }

body.sprio-modules .sprio-module:not(.sprio-module--bleed):not(.sprio-module--hero-service):not(.opt-tone-dark):not(.opt-tone-blue) {
  background: transparent;
}

/* ============================================ 32 the bands, black and blue

   A section can sit on the page's own paper, on black, or on blue. The band
   runs edge to edge and carries a slow field of the brand's colour behind it,
   drifting on a long cycle — long enough that it reads as depth rather than as
   something moving, which is the difference between a brand band and a banner.

   The blue is the home page's own: sampled off the CTA band there, the family
   sits around #24246c with highlights toward #303cb4.

   How the bleed works: the module stops being a centred 1280px column and
   becomes a full-width block that re-creates the column with its own side
   padding. That keeps overflow:hidden usable, which is what lets the field
   drift inside the band instead of over the sections around it.             */

.sprio-module.opt-tone-dark,
.sprio-module.opt-tone-blue {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: 100%;
  padding-left: calc((100vw - var(--wf-stack)) / 2);
  padding-right: calc((100vw - var(--wf-stack)) / 2);
  color: #fff;
}

.sprio-module.opt-tone-dark { background: #000; }
.sprio-module.opt-tone-blue { background: #171d5e; }

.sprio-module.opt-tone-dark::before,
.sprio-module.opt-tone-blue::before {
  content: '';
  position: absolute;
  inset: -45%;
  z-index: 0;
  animation: sprio-drift 26s ease-in-out infinite alternate;
}

.sprio-module.opt-tone-dark::before {
  background:
    radial-gradient(32% 44% at 22% 24%, rgba(105, 4, 242, 0.55), transparent 70%),
    radial-gradient(36% 48% at 80% 74%, rgba(36, 60, 180, 0.45), transparent 72%);
}

.sprio-module.opt-tone-blue::before {
  background:
    radial-gradient(34% 46% at 26% 22%, rgba(105, 4, 242, 0.62), transparent 70%),
    radial-gradient(38% 50% at 78% 76%, rgba(48, 60, 180, 0.7), transparent 72%),
    radial-gradient(30% 38% at 62% 6%, rgba(0, 178, 220, 0.22), transparent 70%);
}

/* Every child sits above the field. */
.sprio-module.opt-tone-dark > *,
.sprio-module.opt-tone-blue > * { position: relative; z-index: 1; }

/* ------------------------------------------------- what a band does to type */

.sprio-module.opt-tone-dark :is(h2, h3, h4, strong, td, th, .workflow-ibm-logo),
.sprio-module.opt-tone-blue :is(h2, h3, h4, strong, td, th, .workflow-ibm-logo) {
  color: #fff !important;
}

.sprio-module.opt-tone-dark :is(p, li, time, small, span),
.sprio-module.opt-tone-blue :is(p, li, time, small, span) {
  color: rgba(255, 255, 255, 0.66) !important;
}

.sprio-module.opt-tone-dark a:not(.workflow-enterprise-button),
.sprio-module.opt-tone-blue a:not(.workflow-enterprise-button) { color: #fff !important; }

/* The figure is the loudest thing on a dark band, as it is on the stat band. */
.sprio-module.opt-tone-dark .mod-statcard-grid strong,
.sprio-module.opt-tone-blue .mod-statcard-grid strong,
.sprio-module.opt-tone-dark .mod-figstrip strong,
.sprio-module.opt-tone-blue .mod-figstrip strong {
  color: var(--wf-violet-soft) !important;
}

/* The step number is not in that list any more. It is a solid disc now, so it
   carries its own contrast and has nothing to invert — paling it on a band
   would put soft violet type on a violet fill. */
.sprio-module.opt-tone-dark .mod-step-num,
.sprio-module.opt-tone-blue .mod-step-num,
.sprio-module.opt-tone-image .mod-step-num { color: #fff !important; }

/* ------------------------------------------- and to rules, cards and glyphs */

.sprio-module.opt-tone-dark :is(article, li, tr, td, th, .mod-table, .mod-checklist li),
.sprio-module.opt-tone-blue :is(article, li, tr, td, th, .mod-table, .mod-checklist li) {
  border-color: rgba(255, 255, 255, 0.2) !important;
}

.sprio-module.opt-tone-dark .mod-table thead th,
.sprio-module.opt-tone-blue .mod-table thead th { border-bottom-color: rgba(255, 255, 255, 0.4) !important; }

.sprio-module.opt-tone-dark .mod-table tbody tr:hover,
.sprio-module.opt-tone-blue .mod-table tbody tr:hover { background: rgba(255, 255, 255, 0.06) !important; }

.sprio-module.opt-tone-dark .workflow-ibm-icon,
.sprio-module.opt-tone-blue .workflow-ibm-icon,
.sprio-module.opt-tone-dark .sprio-icon,
.sprio-module.opt-tone-blue .sprio-icon { color: #fff !important; }

/* Chips read as outlines on a band; a pastel fill on black looks like a sticker. */
.sprio-module.opt-tone-dark .mod-tag,
.sprio-module.opt-tone-blue .mod-tag {
  background: transparent !important;
  border: 1px solid rgba(255, 255, 255, 0.42);
  color: #fff !important;
}

/* Panels that were white on paper go glassy rather than staying a white slab. */
.sprio-module.opt-tone-dark :is(.mod-table, .workflow-ibm-related article),
.sprio-module.opt-tone-blue :is(.mod-table, .workflow-ibm-related article) {
  background: rgba(255, 255, 255, 0.04) !important;
}

/* A card that was open stays open; a boxed one gets a hairline, not a fill. */
.sprio-module.opt-tone-dark .workflow-ibm-card-grid article,
.sprio-module.opt-tone-blue .workflow-ibm-card-grid article { background: rgba(255, 255, 255, 0.06); }

@media (prefers-reduced-motion: reduce) {
  .sprio-module.opt-tone-dark::before,
  .sprio-module.opt-tone-blue::before { animation: none; }
}

/* The phone is its own screen and keeps its own colours. Inverting type inside
   it would put white timestamps on a white bubble — the band is behind the
   device, not inside it. */
.sprio-module.opt-tone-dark .mod-chat :is(p, li, time, small, span, strong, h3, h4),
.sprio-module.opt-tone-blue .mod-chat :is(p, li, time, small, span, strong, h3, h4) { color: inherit !important; }

.sprio-module.opt-tone-dark .mod-chat-body,
.sprio-module.opt-tone-blue .mod-chat-body { color: var(--wf-ink); }

.sprio-module.opt-tone-dark .mod-chat .mod-bubble.is-guest,
.sprio-module.opt-tone-blue .mod-chat .mod-bubble.is-guest { color: #fff !important; }

.sprio-module.opt-tone-dark .mod-chat .mod-bubble.is-guest time,
.sprio-module.opt-tone-blue .mod-chat .mod-bubble.is-guest time { color: rgba(255, 255, 255, 0.74) !important; }

/* The band is the section's background, so the module's own wrapper must stop
   painting one. Some harvested wrappers carry a white fill or a pale gradient
   from the export — left alone they sit on top of the band and the white type
   lands on white. Only the immediate child is cleared; panels nested deeper,
   the phone above all, keep their own surfaces. */
.sprio-module.opt-tone-dark > *,
.sprio-module.opt-tone-blue > * { background: transparent !important; }

/* Section 31 pins headings to black by name, which is right on paper and wrong
   on a band. Same selectors, same weight, later in the file. */
.sprio-module.opt-tone-dark > div > h2,
.sprio-module.opt-tone-blue > div > h2,
.sprio-module.opt-tone-dark .workflow-ibm-intro-copy h2,
.sprio-module.opt-tone-blue .workflow-ibm-intro-copy h2,
.sprio-module.opt-tone-dark .workflow-ibm-capabilities > h2,
.sprio-module.opt-tone-blue .workflow-ibm-capabilities > h2,
.sprio-module.opt-tone-dark .workflow-ibm-usecases > h2,
.sprio-module.opt-tone-blue .workflow-ibm-usecases > h2,
.sprio-module.opt-tone-dark .workflow-ibm-case-studies > h2,
.sprio-module.opt-tone-blue .workflow-ibm-case-studies > h2 { color: #fff !important; }

/* ================================================ 33 one type scale

   Measured off the inner page before this existed:

     H1  46px            one
     H2  58px            thirteen — bigger than the H1 above it
     H3  62 / 46 / 22 / 20w600 / 20w500 / 19px      six treatments
     P   20 / 18 / 17 / 16 / 14px                   five

   Measured off the home page, which is the brand:

     display   74px      the page title
     section   46px      a section heading
     card      20px w500 a card or list title
     lede      18px      a section standfirst
     body      16px      card copy, table cells
     meta      14px      captions, sources, timestamps
     kicker    12px      the small uppercase labels

   That is the scale below, and every step of it is one value. The ratio is
   what makes a hierarchy readable: 74 over 46 over 20 reads instantly, 46
   under 58 reads as a mistake.

   Scoped away from .sprio-module--bleed throughout — those are the home
   page's own sections and already measure exactly this.                     */

.modules-page {
  /* Down 20% from 46/5.1vw/74 at Karan's request — every stop scaled by the
     same 0.8 so the ramp keeps its shape across the whole viewport range, not
     just at the top end. The tracking is in em, so it follows on its own.
     This drives the inner-page hero only; the home page's own hero is a bleed
     section and is deliberately left where it is. */
  --t-display: clamp(37px, 4.08vw, 59px);
  --t-section: clamp(32px, 3.2vw, 46px);
  --t-card: 20px;
  --t-lede: 18px;
  --t-body: 16px;
  --t-meta: 14px;
  --t-figure: clamp(38px, 3.4vw, 48px);
  --t-figure-lg: clamp(44px, 4.2vw, 60px);
}

/* ---------------------------------------------------------------- display */

.sprio-module--hero-service .workflow-enterprise-title {
  font-size: var(--t-display) !important;
  font-weight: 500 !important;
  line-height: 1.10 !important;
  letter-spacing: -0.036em !important;
}

.sprio-module--hero-service .workflow-enterprise-copy {
  font-size: var(--t-lede) !important;
  font-weight: 400 !important;
  line-height: 1.5 !important;
}

/* ---------------------------------------------------------------- section */

.sprio-module:not(.sprio-module--bleed) > div > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-intro-copy h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-capabilities > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-usecases > h2,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-case-studies > h2,
.sprio-module .mod-statband .mod-head h3 {
  font-size: var(--t-section) !important;
  font-weight: 500 !important;
  line-height: 1.06 !important;
  letter-spacing: 0 !important;
}

/* ------------------------------------------------------- card and list title */

.sprio-module:not(.sprio-module--bleed) :is(article, li, .mod-chat-head, .workflow-ibm-thumb) :is(h3, h4),
.sprio-module:not(.sprio-module--bleed) .mod-checklist h3,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-card-grid h3,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-related h3 {
  font-size: var(--t-card) !important;
  font-weight: 500 !important;
  line-height: 1.34 !important;
  letter-spacing: 0 !important;
}

/* -------------------------------------------------------------------- copy */

.sprio-module:not(.sprio-module--bleed) :is(p, li, td) {
  font-size: var(--t-body) !important;
  font-weight: 400 !important;
  line-height: 1.52 !important;
}

/* The standfirst under a section heading is the one paragraph that leads. */
.sprio-module:not(.sprio-module--bleed) > div > p,
.sprio-module:not(.sprio-module--bleed) .workflow-ibm-intro-copy > p,
.sprio-module .mod-statband .mod-head p {
  font-size: var(--t-lede) !important;
  line-height: 1.5 !important;
}

.sprio-module:not(.sprio-module--bleed) :is(.mod-source, time, small, figcaption, .workflow-ibm-video small) {
  font-size: var(--t-meta) !important;
}

.sprio-module:not(.sprio-module--bleed) .mod-table th {
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------------ figures */

.sprio-module:not(.sprio-module--bleed) :is(.mod-statcard-grid, .mod-figstrip) strong {
  font-size: var(--t-figure) !important;
  font-weight: 300 !important;
  line-height: 1 !important;
  letter-spacing: -0.02em;
}

.sprio-module .mod-statgrid strong {
  font-size: var(--t-figure-lg) !important;
  font-weight: 300 !important;
  line-height: 1 !important;
}

/* The step number is out of the figure scale. It was a 84px numeral sitting on
   a line and it is now a 72px disc with the number inside it, which is a mark
   rather than a figure — sized by the disc, not by the page's type ramp. */
.sprio-module:not(.sprio-module--bleed) .mod-step-num {
  font-size: 30px !important;
  font-weight: 400 !important;
  line-height: 1 !important;
}

/* The phone runs at its own scale — it is a screen, not a column of the page. */
.sprio-module .mod-chat :is(p, li, td, h3, h4, strong, time, span) { font-size: inherit !important; }
.sprio-module .mod-chat .mod-bubble { font-size: 14px !important; line-height: 1.42 !important; }
.sprio-module .mod-chat .mod-bubble time { font-size: 11px !important; }
.sprio-module .mod-chat-head strong { font-size: 15px !important; }
.sprio-module .mod-chat-head div > span { font-size: 12px !important; }
.sprio-module .mod-phone-status { font-size: 13.5px !important; }

/* ============================================ 34 two quiet pieces of motion

   Restraint is the whole point. A page that moves everywhere is a page nobody
   can read, so this is two things and no more.

   The rule under a section heading draws itself across as the section is
   reached — 520ms, once, left to right. It is the only thing on the page that
   announces a section, and it costs one transform.

   The figures count up, which the script handles. Both are off entirely under
   prefers-reduced-motion, and both are decoration: the rule is a border, the
   figure is the real number the moment the count lands. */

.sprio-motion .sprio-module:not(.sprio-module--bleed) > div > h2 { position: relative; }

.sprio-motion .sprio-module:not(.sprio-module--bleed) > div > h2::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -22px;
  width: 84px;
  height: 2px;
  background: var(--wf-violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms cubic-bezier(0.22, 0.61, 0.36, 1) 120ms;
}

.sprio-motion .sprio-module:not(.sprio-module--bleed) > div > h2.is-in::after { transform: scaleX(1); }

.sprio-module.opt-tone-dark > div > h2::after,
.sprio-module.opt-tone-blue > div > h2::after { background: var(--wf-violet-soft); }

/* A photograph settles rather than snapping into place. */
.sprio-module :is(.workflow-ibm-card-grid article, .workflow-ibm-case-studies article) { overflow: hidden; }

.sprio-module :is(.workflow-ibm-card-art, .wf-cs-media) {
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.sprio-module article:hover :is(.workflow-ibm-card-art, .wf-cs-media) { transform: scale(1.04); }

@media (prefers-reduced-motion: reduce) {
  .sprio-module :is(.workflow-ibm-card-art, .wf-cs-media) { transition: none; }
}

/* ============================== 35 the kicker and the standfirst

   Every section now opens the way the home page's do: a small uppercase label,
   the heading, then one line saying what the section is for. Both are optional
   — a section that supplies neither renders exactly as before, because an
   empty one is not drawn (section 30). */

.sprio-module .mod-kicker {
  display: block;
  margin-bottom: 14px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wf-ink);
}

.sprio-module .mod-standfirst {
  margin: 22px 0 0;
  max-width: 62ch;
  font-size: var(--t-lede) !important;
  font-weight: 400 !important;
  line-height: 1.5 !important;
  color: var(--wf-muted) !important;
}

.sprio-module .mod-kicker:empty,
.sprio-module .mod-standfirst:empty { display: none; }

/* The rule that draws in sits under the standfirst, not under the heading, or
   it lands in the middle of the block. */
.sprio-motion .sprio-module:not(.sprio-module--bleed) > div > h2::after { bottom: -14px; }

.sprio-module .mod-statband .mod-kicker,
.sprio-module.opt-tone-dark .mod-kicker,
.sprio-module.opt-tone-blue .mod-kicker { color: rgba(255, 255, 255, 0.72) !important; }

.sprio-module.opt-tone-dark .mod-standfirst,
.sprio-module.opt-tone-blue .mod-standfirst { color: rgba(255, 255, 255, 0.66) !important; }

/* =========================== 36 the image band, with the panel floating

   A photograph is the section, and the content sits in a white panel laid on
   top of it with the image showing all the way around. The panel is where the
   type lives, so nothing inverts and nothing has to be checked for contrast —
   the page's own colours carry on inside it.

   The photograph drifts very slowly. Long enough that it reads as the picture
   breathing rather than as a slideshow, and it is transform-only, so it costs
   the compositor and not the main thread.                                    */

.sprio-module.opt-tone-image {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: 100%;
  padding:
    clamp(72px, 7vw, 118px)
    calc((100vw - var(--wf-stack)) / 2 + clamp(0px, 3.2vw, 60px));
  background: #0a0a12;
}

.sprio-module.opt-tone-image::before {
  content: '';
  position: absolute;
  inset: -8%;
  z-index: 0;
  background-image: var(--wf-band-photo, url("/theme/sprio-photo-09.jpg"));
  background-size: cover;
  background-position: center;
  animation: sprio-float 32s ease-in-out infinite alternate;
}

/* Different frame per band, so two image sections on one page are two pictures. */
/* Chosen deliberately: wide, dark, no faces. A portrait under a panel gets
   cropped to an eye and a chin, and a light photograph needs so much scrim to
   carry a white panel that it stops being a photograph. */
.sprio-module.opt-tone-image:nth-of-type(3n + 1)::before { --wf-band-photo: url("/theme/sprio-photo-09.jpg"); }
.sprio-module.opt-tone-image:nth-of-type(3n + 2)::before { --wf-band-photo: url("/theme/sprio-photo-12.jpg"); }
.sprio-module.opt-tone-image:nth-of-type(3n)::before     { --wf-band-photo: url("/theme/sprio-photo-08.jpg"); }

/* Enough scrim that the panel has something to sit on, not so much that the
   photograph stops being a photograph. */
.sprio-module.opt-tone-image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(5, 5, 12, 0.28), rgba(5, 5, 12, 0.5));
}

.sprio-module.opt-tone-image > * {
  position: relative;
  z-index: 2;
  background: #fff;
  padding: clamp(34px, 3.6vw, 60px);
  box-shadow: 0 48px 96px -44px rgba(3, 3, 7, 0.62);
}

@keyframes sprio-float {
  from { transform: scale(1.02) translate3d(-1%, -0.6%, 0); }
  to   { transform: scale(1.10) translate3d(1.4%, 1%, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .sprio-module.opt-tone-image::before { animation: none; }
}


/* ==================================== 38 the last two type strays

   Two sizes escaped the scale because they live in bleed sections, which
   section 33 deliberately leaves alone. The dark band's figure captions were
   rendering at 17px on a page whose body is 16 and whose lede is 18 — a size
   that exists nowhere else on the site. */

.sprio-module .mod-statgrid p { font-size: var(--t-body) !important; line-height: 1.52 !important; }
.sprio-module .mod-statband .mod-head p { font-size: var(--t-lede) !important; }

/* ============================== 39 the standfirst, and light panels on a band

   TWO FIXES, BOTH REGRESSIONS I INTRODUCED.

   1. The gaps inside the heading block.

   The kicker and the standfirst were added around each heading without touching
   the spacing that was already there, so both distances came out as whatever the
   module happened to be doing: 4px, 56px and 110px under one page's headings,
   and 18px above one heading against 84px above the next.

   Measured with the margins zeroed, the distance a module contributes is exactly
   its container's row-gap and nothing else — 0 in the block modules, 38 in the
   grids, 64 in the capability grid, 68 in the case studies. So the compensation
   is a short table keyed on that gap, and every line resolves to one distance:
   14px above the heading, 40px below it. 40 clears the violet rule that draws in
   under the heading at -14px.

   MEASURE THIS WITH MOTION OFF. Sections arrive by rising 18px into place, so a
   heading caught mid-animation reads 18px low and every gap around it is wrong
   by that much — which is how the first version of this table came to be
   calibrated against a moving target and landed 18px out across the board.      */

/* The block modules — the intro copy, the use-case rail, the stat band's head —
   settle it with margins, because margins are all there is between siblings. */

.sprio-module .mod-kicker:has(+ :is(h1, h2, h3)) { margin-bottom: 14px !important; }
.sprio-module .mod-kicker + :is(h1, h2, h3) { margin-top: 0 !important; }
.sprio-module :is(h2, h3):has(+ .mod-standfirst) { margin-bottom: 0 !important; }
.sprio-module :is(h2, h3) + .mod-standfirst { margin-top: 40px !important; }

/* The grid modules cannot be settled with margins at all.

   There the kicker, the heading, the standfirst and the content are four grid
   ITEMS on four rows, and the container's row-gap sits between them: 38 in the
   grids and the tables, 64 in the capability grid, 68 in the case studies. A
   negative margin looks like it should absorb that, and it does not — a grid
   track floors at zero, so pulling a 22px kicker up by 50 removes 22 and
   silently discards the rest. That is what left the kicker 42px above its
   heading while every other section had it at 14.

   So the gap is taken off the container and handed back to the content. Each of
   these containers holds exactly four children — kicker, heading, standfirst,
   one content block — which is what makes the exchange exact: the rows inside
   the heading block close to 14, and the content carries the module's own gap
   back as a margin. A section with no kicker and no standfirst is unaffected,
   because 14 + the margin is the gap it always had.                            */

.sprio-module :is(.mod-table-block, .mod-statcards, .mod-integrations, .mod-steps,
                  .mod-figstrip, .workflow-ibm-capabilities, .workflow-ibm-case-studies) {
  row-gap: 14px !important;
}
.sprio-module :is(.mod-table-block, .mod-statcards, .mod-integrations, .mod-steps,
                  .mod-figstrip, .workflow-ibm-capabilities, .workflow-ibm-case-studies)
  > :is(h2, h3) + .mod-standfirst { margin-top: 26px !important; }

/* Grid items do not collapse their margins, so the kicker's own 14px would be
   added to the row-gap rather than absorbed by it. The row-gap is the distance. */
.sprio-module :is(.mod-table-block, .mod-statcards, .mod-integrations, .mod-steps,
                  .mod-figstrip, .workflow-ibm-capabilities, .workflow-ibm-case-studies)
  > .mod-kicker { margin-bottom: 0 !important; }

/* row-gap was 38: the grids, the tables and the figure strip */
.sprio-module .mod-table-block > .mod-table-wrap,
.sprio-module .mod-statcards > .mod-statcard-grid,
.sprio-module .mod-integrations > .mod-integration-grid,
.sprio-module .mod-steps > .mod-steps-track,
.sprio-module .mod-figstrip > .mod-statgrid { margin-top: 24px !important; }
/* row-gap was 64: the capability grids */
.sprio-module .workflow-ibm-capabilities > article { margin-top: 50px !important; }
/* row-gap was 68: the case studies */
.sprio-module .workflow-ibm-case-studies > article,
.sprio-module .workflow-ibm-case-studies > .mod-cs-rail { margin-top: 54px !important; }

/*  2. A white panel on a coloured band.

   A band inverts its type to white, which is right for text sitting ON the
   band and wrong for text inside a panel sitting on it. The phone was already
   excepted; the case-study cards were not, so three white cards carried white
   text and read as empty boxes. Any light surface keeps the page's own ink. */

.sprio-module.opt-tone-dark :is(.mod-chat, .sprio-module--case-studies article, .workflow-ibm-case-studies article),
.sprio-module.opt-tone-blue :is(.mod-chat, .sprio-module--case-studies article, .workflow-ibm-case-studies article),
.sprio-module.opt-tone-image :is(.mod-chat, .sprio-module--case-studies article, .workflow-ibm-case-studies article) {
  color: var(--wf-ink);
}

.sprio-module.opt-tone-dark .workflow-ibm-case-studies article :is(h2, h3, h4, strong),
.sprio-module.opt-tone-blue .workflow-ibm-case-studies article :is(h2, h3, h4, strong),
.sprio-module.opt-tone-image .workflow-ibm-case-studies article :is(h2, h3, h4, strong) {
  color: var(--wf-ink) !important;
}

.sprio-module.opt-tone-dark .workflow-ibm-case-studies article :is(p, span, .workflow-ibm-logo),
.sprio-module.opt-tone-blue .workflow-ibm-case-studies article :is(p, span, .workflow-ibm-logo),
.sprio-module.opt-tone-image .workflow-ibm-case-studies article :is(p, span, .workflow-ibm-logo) {
  color: var(--wf-muted) !important;
}

.sprio-module.opt-tone-dark .workflow-ibm-case-studies article > a,
.sprio-module.opt-tone-blue .workflow-ibm-case-studies article > a,
.sprio-module.opt-tone-image .workflow-ibm-case-studies article > a { color: var(--wf-ink) !important; }

/* ================== 40 the heading block spans, like the heading always did

   The kicker and the standfirst were added as siblings of the heading, and in
   the grid modules that makes them grid ITEMS — so they took a card's cell.
   On a three-column case-study section that pushed two cards along and wrapped
   the third onto its own row. The heading already spanned the full width; its
   kicker and standfirst have to as well. */

.sprio-module :is(.workflow-ibm-capabilities, .workflow-ibm-case-studies, .workflow-ibm-usecases,
                  .mod-steps, .mod-table-block, .mod-integrations, .mod-statcards, .mod-figstrip)
  > :is(.mod-kicker, .mod-standfirst) {
  grid-column: 1 / -1;
}

/* ===================== 41 more than three case studies, on a rail

   Three fit across the page. A fourth used to make all four narrower, and a
   fifth wrapped onto a second row with two empty cells beside it — neither is
   what a set of proof points should do. So beyond three the cards become a
   rail, exactly like the use-case cards: three in view at full size, the rest
   a scroll away, with the same prev/next pair bottom right.

   The wrapper is added by script (see modules-local.js) rather than written
   into the module, so it reaches pages that were imported before this existed
   and, with JavaScript off, the cards simply wrap as they used to.            */

.sprio-module .mod-cs-rail {
  grid-column: 1 / -1;
  display: grid;
  grid-auto-flow: column;
  /* Exactly a third of the visible width, and never narrower than the copy can
     take. It has to be one fixed length rather than a minmax(): given a range,
     the grid fits every track inside the container instead of overflowing it —
     which came out as four three-quarter-width cards in a row that could not
     scroll and so never earned its buttons. The track decides the width in a
     grid, so this belongs here and not on the article.

     The gap is the export's own, taken from a variable rather than retyped: a
     railed section sits directly under an un-railed one on some pages, and a
     card that changes width because a fourth was added would be visible. */
  grid-auto-columns: max(272px, calc((100% - 2 * var(--wf-cs-gap)) / 3));
  column-gap: var(--wf-cs-gap);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: 4px;
  scrollbar-width: none;
}

.sprio-module .mod-cs-rail::-webkit-scrollbar { display: none; }
.sprio-module .mod-cs-rail > article { scroll-snap-align: start; margin-top: 0 !important; }

/* The buttons are a grid item too — without this they take one card's cell and
   sit in the middle of the row. */
.sprio-module .workflow-ibm-case-studies > .mod-rail-nav { grid-column: 1 / -1; }

/* A rail sets its own column count, so the four-across exception must not also
   apply — otherwise four cards are laid out twice, by two different rules. */
.sprio-module:not(.opt-head-side) .workflow-ibm-case-studies:has(> .mod-cs-rail) {
  grid-template-columns: minmax(0, 1fr);
}

/* One card at a time on a phone, where three would be 90px wide each. */
@media (max-width: 767px) {
  .sprio-module .mod-cs-rail { grid-auto-columns: minmax(0, 82%); }
}

/* On a band the buttons are the one light thing that should not stay light. */
.sprio-module.opt-tone-dark .mod-rail-nav .mod-rail-btn,
.sprio-module.opt-tone-blue .mod-rail-nav .mod-rail-btn {
  background: transparent !important;
  border-color: rgba(255, 255, 255, 0.38) !important;
  color: #fff !important;
}
.sprio-module.opt-tone-dark .mod-rail-nav .mod-rail-btn:hover:not(:disabled),
.sprio-module.opt-tone-blue .mod-rail-nav .mod-rail-btn:hover:not(:disabled) {
  border-color: #fff !important;
  background: rgba(255, 255, 255, 0.12) !important;
}
.sprio-module.opt-tone-dark .mod-rail-count,
.sprio-module.opt-tone-blue .mod-rail-count { color: rgba(255, 255, 255, 0.66) !important; }

/* ============================ 42 the orbit graphic, drifting

   The intro's illustration was a still: four ellipses and a sphere that looked
   like a diagram of something moving without moving. It now turns.

   Each ring keeps the tilt and stretch the export drew it with — those are
   stored as --r and --sx so a keyframe can spin the ring without flattening
   it, because `transform` is one property and a rotation written on its own
   would drop the scaleX and turn every ellipse back into a circle.

   Transform and opacity only, so it runs on the compositor: this sits behind
   copy people are reading and must never cost them a frame. And it is inside
   .sprio-motion, which the script only adds when the reader has not asked for
   less motion — so reduced-motion gets the still image, deliberately.

   The variant comes from the page slug (see document.ts), so pages differ from
   each other without anyone choosing.                                        */

.sprio-module .workflow-ibm-orbit::before { --r: 18deg;  --sx: 1.26; }
.sprio-module .workflow-ibm-orbit::after  { --r: -34deg; --sx: 1.18; }
.sprio-module .workflow-ibm-orbit i       { --r: 72deg;  --sx: 1.24; }
.sprio-module .workflow-ibm-orbit b       { --r: -8deg;  --sx: 0.68; }

@keyframes wf-orbit-spin {
  from { transform: rotate(var(--r)) scaleX(var(--sx)); }
  to   { transform: rotate(calc(var(--r) + 360deg)) scaleX(var(--sx)); }
}

/* A ring that leans rather than turning all the way round. */
@keyframes wf-orbit-sway {
  0%   { transform: rotate(calc(var(--r) - 9deg)) scaleX(var(--sx)); }
  50%  { transform: rotate(calc(var(--r) + 9deg)) scaleX(calc(var(--sx) * 1.06)); }
  100% { transform: rotate(calc(var(--r) - 9deg)) scaleX(var(--sx)); }
}

/* The sphere. It is the one lit object in the picture, so it breathes rather
   than travels — a moving highlight reads as alive, a moving ball reads as a
   loading spinner. */
@keyframes wf-orbit-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.07); }
}

@keyframes wf-orbit-drift {
  0%, 100% { transform: translate3d(0, -7px, 0); }
  50%      { transform: translate3d(0, 7px, 0); }
}

.sprio-motion .sprio-module .workflow-ibm-orbit::before,
.sprio-motion .sprio-module .workflow-ibm-orbit::after,
.sprio-motion .sprio-module .workflow-ibm-orbit i,
.sprio-motion .sprio-module .workflow-ibm-orbit b {
  animation: wf-orbit-spin var(--wf-orbit-dur, 48s) linear infinite;
  will-change: transform;
}

.sprio-motion .sprio-module .workflow-ibm-orbit span {
  animation: wf-orbit-breathe var(--wf-orb-dur, 7s) ease-in-out infinite;
  will-change: transform;
}

/* The rings are staggered so they never line up and never sit still together;
   the multipliers are prime-ish on purpose. */
.sprio-motion .sprio-module .workflow-ibm-orbit::before { animation-duration: calc(var(--wf-orbit-dur, 48s) * 1); }
.sprio-motion .sprio-module .workflow-ibm-orbit::after  { animation-duration: calc(var(--wf-orbit-dur, 48s) * 1.37); animation-direction: reverse; }
.sprio-motion .sprio-module .workflow-ibm-orbit i       { animation-duration: calc(var(--wf-orbit-dur, 48s) * 0.79); }
.sprio-motion .sprio-module .workflow-ibm-orbit b       { animation-duration: calc(var(--wf-orbit-dur, 48s) * 1.61); animation-direction: reverse; }

/* -------------------------------------- five graphics, one per page slug

   Not five speeds of the same picture — five different pictures. A page that
   only differs from the last one by how fast the same rings turn still reads as
   the same page, which was the point of doing this at all.

   All five are drawn from the SAME five elements the export ships: the orbit
   box's ::before and ::after, its <i>, its <b>, and the <span> that is the
   sphere. Nothing is added to the markup, so this reaches pages that were
   imported long before it existed, and a page with no illustration is
   unaffected.

   Shape rules sit outside .sprio-motion on purpose: a reader who has asked for
   less motion still gets their page's own picture, just a still one. Only the
   animations are inside it.

   Specificity is deliberate throughout. The base is `.workflow-ibm-orbit::before`
   in the theme's own sheet, and the shared animation above is three classes
   deep, so a variant has to out-rank both — hence the long prefixes rather than
   a pile of !important. */

/* 1 — ORBIT. Ellipses crossing, a lit sphere at the centre. The house default,
       and the one the export was drawn as. */
body[data-motion="1"] { --wf-orbit-dur: 48s; --wf-orb-dur: 7s; }

/* 2 — RIPPLE. Rings leaving the centre and fading, one after another: a call
       going out. Nothing rotates, so it reads as broadcast rather than orbit. */
body[data-motion="2"] { --wf-orb-dur: 4.4s; }

/* Still first, so a reader with motion turned off gets four concentric rings
   rather than nothing: the animated version starts every ring at opacity 0 and
   fades it in on its own delay, which off-screen means an empty grey box. */
body[data-motion="2"] .sprio-module .workflow-ibm-orbit::before,
body[data-motion="2"] .sprio-module .workflow-ibm-orbit::after,
body[data-motion="2"] .sprio-module .workflow-ibm-orbit i,
body[data-motion="2"] .sprio-module .workflow-ibm-orbit b {
  border-width: 1.5px;
  transform: none;
  opacity: 0.45;
}
body[data-motion="2"] .sprio-module .workflow-ibm-orbit::before { width: 108px; height: 108px; }
body[data-motion="2"] .sprio-module .workflow-ibm-orbit::after  { width: 172px; height: 172px; }
body[data-motion="2"] .sprio-module .workflow-ibm-orbit i       { width: 236px; height: 236px; }
body[data-motion="2"] .sprio-module .workflow-ibm-orbit b       { width: 300px; height: 300px; }

/* Animated, they are all one size and the ripple carries them outward. */
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit::before,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit::after,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit i,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit b {
  width: 132px;
  height: 132px;
  opacity: 0;
}

@keyframes wf-ripple {
  0%   { transform: scale(0.45); opacity: 0; }
  10%  { opacity: 0.9; }
  100% { transform: scale(2.5); opacity: 0; }
}

.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit::before,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit::after,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit i,
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit b {
  animation: wf-ripple 5.2s ease-out infinite;
}
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit::after { animation-delay: 1.3s; }
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit i      { animation-delay: 2.6s; }
.sprio-motion body[data-motion="2"] .sprio-module .workflow-ibm-orbit b      { animation-delay: 3.9s; }

/* 3 — ARCS. Three open arcs stacked outward from the sphere, lighting in
       sequence: signal leaving a transmitter. Only the top edge of each circle
       is drawn, which is what turns a ring into an arc. */
body[data-motion="3"] { --wf-orb-dur: 6s; }

body[data-motion="3"] .sprio-module .workflow-ibm-orbit::before,
body[data-motion="3"] .sprio-module .workflow-ibm-orbit::after,
body[data-motion="3"] .sprio-module .workflow-ibm-orbit i,
body[data-motion="3"] .sprio-module .workflow-ibm-orbit b {
  border-color: transparent;
  border-top-color: rgba(105, 4, 242, 0.5);
  border-width: 2.5px;
  transform: rotate(-45deg);
}
body[data-motion="3"] .sprio-module .workflow-ibm-orbit::before { width: 120px; height: 120px; }
body[data-motion="3"] .sprio-module .workflow-ibm-orbit::after  { width: 186px; height: 186px; }
body[data-motion="3"] .sprio-module .workflow-ibm-orbit i       { width: 252px; height: 252px; }
body[data-motion="3"] .sprio-module .workflow-ibm-orbit b       { width: 318px; height: 318px; }

@keyframes wf-arc {
  0%, 70%, 100% { opacity: 0.18; }
  20%           { opacity: 1; }
}

.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit::before,
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit::after,
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit i,
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit b {
  animation: wf-arc 3.6s ease-in-out infinite;
}
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit::after { animation-delay: 0.28s; }
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit i      { animation-delay: 0.56s; }
.sprio-motion body[data-motion="3"] .sprio-module .workflow-ibm-orbit b      { animation-delay: 0.84s; }

/* 4 — COLUMNS. Four bars rising and falling on their own cycles, the sphere
       small and steady above them: volume, not orbit. `border-radius` is set
       twice because the page-wide flatten reset would otherwise square the
       ends, the same rule that once made the phone a silver box. */
body[data-motion="4"] { --wf-orb-dur: 9s; }

body[data-motion="4"] .sprio-module .workflow-ibm-orbit::before,
body[data-motion="4"] .sprio-module .workflow-ibm-orbit::after,
body[data-motion="4"] .sprio-module .workflow-ibm-orbit i,
body[data-motion="4"] .sprio-module .workflow-ibm-orbit b {
  width: 26px;
  height: 150px;
  border: 0;
  border-radius: 14px !important;
  background: linear-gradient(180deg, rgba(105, 4, 242, 0.18), rgba(105, 4, 242, 0.62));
  transform-origin: 50% 100%;
  bottom: 26%;
  top: auto;
}
body[data-motion="4"] .sprio-module .workflow-ibm-orbit::before { margin-left: -117px; transform: scaleY(0.55); }
body[data-motion="4"] .sprio-module .workflow-ibm-orbit::after  { margin-left: -39px;  transform: scaleY(0.9); }
body[data-motion="4"] .sprio-module .workflow-ibm-orbit i       { margin-left: 39px;   transform: scaleY(0.68); }
body[data-motion="4"] .sprio-module .workflow-ibm-orbit b       { margin-left: 117px;  transform: scaleY(1); }

body[data-motion="4"] .sprio-module .workflow-ibm-orbit span {
  width: 46px;
  height: 46px;
  margin-bottom: 210px;
}

@keyframes wf-col {
  0%, 100% { transform: scaleY(0.4); }
  50%      { transform: scaleY(1); }
}

.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit::before,
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit::after,
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit i,
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit b {
  animation: wf-col 2.8s ease-in-out infinite;
}
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit::after { animation-duration: 3.7s; animation-delay: 0.4s; }
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit i      { animation-duration: 2.3s; animation-delay: 0.8s; }
.sprio-motion body[data-motion="4"] .sprio-module .workflow-ibm-orbit b      { animation-duration: 4.1s; animation-delay: 0.2s; }

/* 5 — CONSTELLATION. Four filled dots of different sizes drifting around a
       centred sphere. The only variant where the pieces move independently, so
       it reads as a system of parts rather than one mechanism. */
body[data-motion="5"] { --wf-orb-dur: 8s; }

body[data-motion="5"] .sprio-module .workflow-ibm-orbit::before,
body[data-motion="5"] .sprio-module .workflow-ibm-orbit::after,
body[data-motion="5"] .sprio-module .workflow-ibm-orbit i,
body[data-motion="5"] .sprio-module .workflow-ibm-orbit b {
  border: 0;
  background: rgba(105, 4, 242, 0.42);
  border-radius: 50% !important;
}
body[data-motion="5"] .sprio-module .workflow-ibm-orbit::before { width: 30px; height: 30px; margin: -128px 0 0 -152px; }
body[data-motion="5"] .sprio-module .workflow-ibm-orbit::after  { width: 54px; height: 54px; margin: 96px 0 0 138px; background: rgba(105, 4, 242, 0.26); }
body[data-motion="5"] .sprio-module .workflow-ibm-orbit i       { width: 20px; height: 20px; margin: 118px 0 0 -168px; background: rgba(105, 4, 242, 0.55); }
body[data-motion="5"] .sprio-module .workflow-ibm-orbit b       { width: 40px; height: 40px; margin: -104px 0 0 168px; background: rgba(105, 4, 242, 0.34); }

@keyframes wf-float-a { 0%, 100% { transform: translate3d(0, -12px, 0); } 50% { transform: translate3d(10px, 12px, 0); } }
@keyframes wf-float-b { 0%, 100% { transform: translate3d(8px, 10px, 0); } 50% { transform: translate3d(-10px, -14px, 0); } }

.sprio-motion body[data-motion="5"] .sprio-module .workflow-ibm-orbit::before { animation: wf-float-a 11s ease-in-out infinite; }
.sprio-motion body[data-motion="5"] .sprio-module .workflow-ibm-orbit::after  { animation: wf-float-b 14s ease-in-out infinite; }
.sprio-motion body[data-motion="5"] .sprio-module .workflow-ibm-orbit i       { animation: wf-float-b 9s  ease-in-out infinite; }
.sprio-motion body[data-motion="5"] .sprio-module .workflow-ibm-orbit b       { animation: wf-float-a 13s ease-in-out infinite; }
.sprio-motion body[data-motion="5"] .sprio-module .workflow-ibm-orbit span    { animation-name: wf-orbit-drift; }

/* ------------------------------------------------ and the play control

   It plays nothing. There is no video behind the illustration and never was —
   it is a still from a template, and a button that does nothing is worse than
   no button, because someone will click it. The picture moves on its own now,
   which is what it was pretending to promise. */

.sprio-module .workflow-ibm-video button { display: none !important; }

/* ------------------------------------------------ and the hero's own void

   The export pushes the hero paragraph down with `margin-top: clamp(150px,
   18vh, 220px)` — 162px at a laptop height. That is right for the hero it was
   drawn for, where the paragraph is 25-38px type under a 108px headline. Ours
   is an 18px lede under a headline that has just come down 20%, so the same
   spacer reads as a hole rather than a pause. Scaled to the type it now sits
   between. */

.sprio-module--hero-service .workflow-enterprise-copy {
  margin-top: clamp(40px, 6vh, 72px) !important;
}

/* ============== 43 the bleed sections, on a page that is not the home page

   The FAQ, the contact form and the article strip are lifted from the home
   page, where each one sits in a stack that supplies its own spacing. Dropped
   onto a service page they bring that assumption with them, and it is wrong
   twice.

   The FAQ has no padding at all — first text flush with the top edge, last
   text flush with the bottom — so it touches whatever band is above it. It
   gets the same room every other section on the page has.

   The contact form carries a 101px bottom margin, which is the gap before
   whatever follows it on the home page. On a service page it is the last
   thing, so that margin is a strip of dead space between the page and the
   footer. Only the LAST module loses it — a contact form in the middle of a
   page still needs its gap.                                                 */

.sprio-module--faq-accordion { padding: clamp(64px, 6vw, 104px) 0 !important; }

.sprio .sprio-module:last-child > * { margin-bottom: 0 !important; }

/* ==================== 45 the step rule stops at the last step

   The line was one full-width bar behind the discs, so it ran off past the last
   one and trailed into empty space — the row read as unfinished.

   It is drawn as segments now: each step draws a line from its own disc across
   the gap to the next one, and the last step draws nothing. That makes the rule
   start at 1 and end at 4 whatever the count, without anyone having to tell the
   CSS how many steps there are.

   `overflow: hidden` on the track is what makes it safe when the row wraps. At
   narrow widths auto-fit drops to three columns and the fourth step moves to a
   second row; the third step's segment then points at nothing, and clipping it
   at the track's edge is what removes it — the segment reaches into the gap to
   its right, which for a last-in-row step is outside the track.             */

.sprio-module .mod-steps-track {
  --wf-step-gap: clamp(24px, 3vw, 48px);
  gap: var(--wf-step-gap);
  overflow: hidden;
}

.sprio-module .mod-steps-track::before { content: none; }

/* The disc is centred over its own column, and the copy under it with it — a
   disc centred over left-aligned text reads as a mistake rather than a choice.
   Say the word and the text goes back to the left. */
.sprio-module .mod-steps-track article {
  display: grid;
  justify-items: center;
  text-align: center;
}

.sprio-module .mod-steps-track article :is(h3, p) { max-width: 34ch; }

/* With the discs centred, a segment runs from one disc's right edge to the next
   disc's left edge: out to the middle of this column plus the disc's radius,
   and on across the gap and half of the next column, less that radius again. */
.sprio-module .mod-steps-track article::after {
  content: "";
  position: absolute;
  top: 36px;
  left: calc(50% + 36px);
  right: calc(36px - 50% - var(--wf-step-gap));
  height: 1px;
  background: var(--wf-violet);
}

.sprio-module .mod-steps-track article:last-child::after { content: none; }

/* The steps stack into one column at 1024, not at 767 — the theme's own tablet
   breakpoint. Measured rather than assumed: a connector drawn between steps
   that are above and below each other is a long horizontal line pointing at
   nothing, which is how the first version of this looked at 900px. */
@media (max-width: 1024px) {
  .sprio-module .mod-steps-track article::after { content: none; }
}

/* ============== 46 the hero's two buttons trade places

   Book a Demo is the black one and See All Agents is the white one, until the
   reader reaches for the white one — at which point the two swap, so whichever
   button the reader is about to press is always the solid black one and the
   other steps back. The pair is only ever one strong button and one quiet one;
   what changes is which is which.

   Driven by :hover and :focus-visible rather than by a click. A click on either
   of these leaves the page, so a state that only appears on click is a state
   nobody ever sees. Focus is included so the swap happens for a reader using
   the keyboard too.

   :has() on the row is what lets pointing at ONE button restyle the OTHER. A
   browser without it still gets the sensible half — the button under the
   pointer turns black — and simply does not fade the other one out.         */

.sprio-module--hero-service .workflow-enterprise-button {
  border: 1px solid var(--wf-ink) !important;
  transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease,
    transform 180ms ease;
}

.sprio-module--hero-service .workflow-enterprise-button-primary {
  background: var(--wf-ink) !important;
  color: #fff !important;
}

.sprio-module--hero-service .workflow-enterprise-button-secondary {
  background: #fff !important;
  color: var(--wf-ink) !important;
}

/* Reaching for the second button makes it the solid one. */
.sprio-module--hero-service .workflow-enterprise-button-secondary:hover,
.sprio-module--hero-service .workflow-enterprise-button-secondary:focus-visible {
  background: var(--wf-ink) !important;
  color: #fff !important;
}

/* …and the first one steps back, keeping its text readable on white. */
.sprio-module--hero-service .workflow-enterprise-actions:has(.workflow-enterprise-button-secondary:hover)
  .workflow-enterprise-button-primary,
.sprio-module--hero-service .workflow-enterprise-actions:has(.workflow-enterprise-button-secondary:focus-visible)
  .workflow-enterprise-button-primary {
  background: #fff !important;
  color: var(--wf-ink) !important;
}

/* ================= 48 the ribbon is not drawn when there is nothing in it

   The violet strip is part of the hero, and its words are hero fields. A page
   that leaves them blank was still getting the band — a stripe of brand colour
   across the top of the page saying nothing. It is content, so it behaves like
   content: no words, no ribbon. */

.sprio-module--hero-service .workflow-enterprise-alert:not(:has(strong:not(:empty))):not(:has(span:not(:empty))) {
  display: none !important;
}

/* ============ 50 the heading beside the content, when there is room for it

   Two faults, found together when a page used the side heading on a module that
   also had a standfirst.

   The first: with opt-head-side these containers are a two-column grid — a
   heading column and a content column — and their children are flat: kicker,
   heading, standfirst, then the block of cards. Section 40 above makes the
   kicker and the standfirst span both columns, which is right when the heading
   is on top and wrong here. The span closes the row, so the block of cards is
   auto-placed onto the NEXT row, in the first column: eight integration cards
   sharing a 340px column at 31px each, stat cards at 65. Six of the eight
   modules that offer the option were unaffected, which is how it survived — it
   needs the side heading and a standfirst together.

   The second: between 768 and 1080 the split leaves the content column too
   narrow whatever is placed in it. Capability cards came out at 97px and case
   studies at 94px there, side heading or not. Below 768 the layout already
   stacked; it simply stacked 300px too late.

   So: side by side above 1080, stacked below it, and in side mode the heading
   parts sit in the first column with the content pinned to the second. The rows
   have to be named explicitly for `1 / -1` to mean anything — against implicit
   rows it resolves to a single row and the fix does nothing.                 */

@media (min-width: 1080px) {
  .sprio-module.opt-head-side :is(.mod-statcards, .mod-integrations) {
    grid-template-rows: auto auto 1fr;
  }

  .sprio-module.opt-head-side :is(.mod-statcards, .mod-integrations)
    > :is(.mod-kicker, .mod-standfirst) {
    grid-column: 1;
  }

  .sprio-module.opt-head-side .mod-statcards > .mod-statcard-grid,
  .sprio-module.opt-head-side .mod-integrations > .mod-integration-grid {
    grid-column: 2;
    grid-row: 1 / -1;
    /* The 24px in section 39 is the gap under a heading that sits above the
       content. Beside it, the content starts level with the heading. */
    margin-top: 0 !important;
  }

  /* Beside a heading there is roughly two-thirds of the page to work with, so
     these grids take fewer columns than they do at full width. Eight
     integration cards across four columns of a 590px content column is 111px
     each, which is a title broken one word per line. */
  .sprio-module.opt-head-side .mod-integration-grid,
  .sprio-module.opt-head-side .mod-statcard-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1280px) {
  .sprio-module.opt-head-side .mod-integration-grid,
  .sprio-module.opt-head-side .mod-statcard-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Below 1080 the heading goes back on top and the content takes the full width,
   which is what the narrow layout always did — it just did it 300px too late. */
@media (max-width: 1079px) {
  .sprio-module.opt-head-side :is(.workflow-ibm-capabilities, .workflow-ibm-case-studies,
                                  .workflow-ibm-usecases, .mod-steps, .mod-table-block,
                                  .mod-integrations, .mod-statcards, .mod-figstrip) {
    grid-template-columns: minmax(0, 1fr) !important;
  }

  .sprio-module.opt-head-side :is(.workflow-ibm-capabilities, .workflow-ibm-case-studies,
                                  .workflow-ibm-usecases, .mod-steps, .mod-table-block,
                                  .mod-integrations, .mod-statcards, .mod-figstrip) > * {
    grid-column: 1 / -1;
  }
}

/* ============================ 46 use case cards on a band, and their room

   The section reads as one plane: heading, a line of explanation, then the
   cards. What it was doing instead was pushing the first row of pictures up
   against the standfirst, so the sentence looked like a caption stuck to the
   photographs rather than an introduction to them. The rule below is the only
   thing standing between the two, so it has to be worth seeing.              */

.sprio-module--use-case-cards .workflow-ibm-card-grid {
  margin-top: clamp(20px, 2.2vw, 34px);
}

.sprio-module--use-case-cards .mod-standfirst {
  margin-bottom: 0;
  max-width: 62ch;
}

/* ---------------------------------------------------- the card on a band */

/* Glass, not a white slab: a fill this faint reads as a card without turning
   the row into six grey blocks on black. The hairline does the defining. */
.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-grid article,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-grid article {
  background: rgba(255, 255, 255, 0.045);
  border-color: rgba(255, 255, 255, 0.13) !important;
}

.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-grid article:hover,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-grid article:hover {
  background: rgba(255, 255, 255, 0.075);
  border-color: rgba(255, 255, 255, 0.3) !important;
}

.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-go,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-go {
  border-top-color: rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.72);
}

/* #6904f2 is a fine hover colour on paper and close to unreadable on black.
   On a band the arrow goes white and moves; the violet stays where it works. */
.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-grid article:hover .workflow-ibm-card-go,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-grid article:hover .workflow-ibm-card-go {
  color: #fff;
}

.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-grid article:hover h3,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-grid article:hover h3 {
  color: #fff !important;
}

.sprio-module--use-case-cards.opt-tone-dark .workflow-ibm-card-grid article:focus-within,
.sprio-module--use-case-cards.opt-tone-blue .workflow-ibm-card-grid article:focus-within {
  outline-color: #fff;
}

/* ------------------------------------------------------------ narrow screens */

/* The picture goes shallower as the card goes wider, so a phone-width card is
   a poster rather than a postcard with a caption. */
@media (max-width: 639px) {
  .sprio-module--use-case-cards .workflow-ibm-card-art { aspect-ratio: 2 / 1; }

  .sprio-module--use-case-cards .workflow-ibm-card-grid article h3 { margin-top: 20px !important; }
}
