/* ==========================================================================
   Construction Software page — section styles

   Loaded only where a cn_* layout is placed (see tnb_construction_enqueue_assets),
   after tnb-components and tnb-responsive, so it lands last in the cascade and its
   rules win on source order without escalating specificity.

   THREE RULES THIS FILE KEEPS TO
   1. It never writes a rule for a bare shared selector — no .dt-h2, .dt-sub,
      .eyebrow, .container, .case-card. Those are consumed as-is, which is what makes
      this page inherit the site's type scale instead of restating it. Where a shared
      element needs adjusting, it is qualified by a cn- ancestor.
   2. Design tokens come from :root in components.css (--dt-ink, --dt-muted,
      --dt-line, --dt-red, --dt-dark, --container). Only tokens that exist nowhere
      else are declared here.
   3. One media query block per breakpoint, collected at the end of the file rather
      than scattered per section — see AI_CODING_POLICY.md.

   Values are the approved prototype's (construction.css + dedicated-teams.css from
   the design canvas). Where markup differs from the prototype the rule is adapted
   and the reason noted, rather than the markup being bent to fit a stale selector.
   ========================================================================== */

/* Page-scoped token. The prototype's deep navy is not part of the site palette, so it
   is declared here rather than added to the global :root. */
.cn-hero,
.cn-trust-sec,
.cn-types-sec,
.cn-answer,
.cn-abandon,
.cn-ai-sec,
.cn-banner {
  --cn-navy: #07111F;
}

/* In-page anchor links (#cn-cases, #cn-contact, etc.) had no compensation for the sticky
   header, so a jump landed the target partially underneath it. article.css already carries
   this same fix (.art-sec { scroll-margin-top: 96px; }) against the identical shared header. */
.dt-section[id],
.cn-answer[id],
.cn-banner[id] {
  scroll-margin-top: 96px;
}

/* The shared .case-* deck (components.css) reads --cs-red/--cs-navy/--cs-white/--cs-line/
   --cs-warmgray, and the only place those are defined is .section.cases on the homepage/case
   studies page. This section doesn't carry that class, so every var(--cs-*) here — including on
   the reused .case-deck-nav / .case-btn arrows — was invalid with no fallback and falling back
   to whatever it inherited, which is what broke both the deck's colours and the nav buttons.
   Values copied verbatim from that rule. */
.cn-cases-sec {
  --cs-red: #ec1c24;
  --cs-navy: #0c2340;
  --cs-white: #ffffff;
  --cs-line: #e8e5e0;
  --cs-warmgray: #4a4845;
  /* The shared .case-deck's side cards sit at translate3d(±720px, ...) inside a
     perspective + preserve-3d container, which visibly extends ~178px past the viewport at
     desktop widths and was adding real horizontal scroll to the whole page. Same fix as
     .cn-types-sec's own 100vw band: clip at the section, not the shared component. */
  overflow-x: clip;
}

/* .case-deck's shared 580px height is sized for that page's own cards. These four run
   403-465px tall (measured), so the fixed 580px was leaving ~115px of dead space between the
   card and the nav below it. 480px covers the tallest (RoofHyve, 465px) with a small margin
   instead of guessing at the shared value. */
.cn-cases-sec .case-deck {
  height: 480px;
}

/* .case-card is height: auto in the shared rule, sized to its own content — with four cards
   running 403-465px, each card was a different height as the deck cycled. Stretching every
   card to fill the now-fixed 480px deck keeps that constant across all four; .case-art-frame
   is already height: 100% of this row, so the photo grows into the extra space uniformly. */
.cn-cases-sec .case-card {
  height: 100%;
}

/* Same arrow both directions otherwise — .icon-flip on the homepage case deck (homepage.css)
   is the reference for this, reproduced here rather than depending on that stylesheet. */
.cn-cases-sec [data-cn-deck-prev] svg {
  transform: rotate(180deg);
}

/* .case-body's own overflow-y:auto (components.css) scrolls a card's copy column when its text
   exceeds the card height, with no colour of its own — same red-on-brand thumb already used for
   .so-cmp2 (components.css), reproduced here scoped to this section rather than restyling the
   shared .case-body rule every other .case-deck page also uses. */
.cn-cases-sec .case-body {
  scrollbar-width: thin;
  scrollbar-color: var(--dt-red) transparent;
  /* Shared rule's 36px right padding (components.css) put a wide empty gap between the copy
     text and the scrollbar sitting at the card's edge — tightened just for this section rather
     than the shared .case-body rule every other .case-deck page also uses. */
  padding-right: 18px;
}
.cn-cases-sec .case-body::-webkit-scrollbar {
  width: 6px;
}
.cn-cases-sec .case-body::-webkit-scrollbar-thumb {
  background-color: var(--dt-red);
  border-radius: 6px;
}

/* ── Motion ─────────────────────────────────────────────────────────────── */
@keyframes cnFloat {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-10px);
  }
}

/* ==========================================================================
   01 HERO
   Built on .dt-hero, so the h1, lead and action row are already styled and already
   in the site's heading and hero-sub groups. Only the photo layer is new.
   ========================================================================== */
/* Explicit 19px: matches the size the prototype and every other .dt-hero page ship,
   pinned here rather than left to the components.css cascade — two unscoped
   .dt-hero-lead rules already fight over 19px vs 20px there, and either outcome read
   as plain paragraph text next to this page's larger art-directed hero. */
.cn-hero .dt-hero-lead {
  font-size: 19px;
  max-width: 70%;
}

.cn-hero-lead-2 {
  margin-top: 16px;
}

/* The framed portrait treatment, used when the photo is a companion image. */
.cn-hero-photo {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 500px;
  margin-left: auto;
  aspect-ratio: 4 / 5;
  border-radius: 22px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 40px 90px -50px rgba(0, 0, 0, 0.9);
  animation: cnFloat 8s ease-in-out infinite;
}

/* Full-bleed treatment. The prototype switches to this whenever a hero photo is set,
   which is the approved look for this page: one column of copy over the photograph. */
.cn-hero-photo-bg .dt-hero-grid-layout {
  grid-template-columns: 1fr;
}

.cn-hero-photo-bg .dt-hero-content {
  max-width: unset;
}

.cn-hero-photo-bg .cn-hero-photo {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  animation: none;
  overflow: hidden;
}

/* The prototype used a custom <image-slot> element here; this build renders a real
   <img> so the photo gets srcset and an intrinsic size. Same fill behaviour. */
.cn-hero-photo-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cn-hero-photo-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(200deg, rgba(9, 13, 20, 0) 40%, rgba(9, 13, 20, 0.55) 100%);
}

/* Heavier scrim on the full-bleed variant: the copy sits directly over the photo, and
   the text has to keep its contrast ratio across the whole width. */
.cn-hero-photo-bg .cn-hero-photo-scrim {
  background: linear-gradient(
    90deg,
    rgba(6, 9, 14, 0.94) 0%,
    rgba(6, 9, 14, 0.82) 38%,
    rgba(6, 9, 14, 0.5) 70%,
    rgba(6, 9, 14, 0.65) 100%
  );
}

/* ==========================================================================
   02 ANSWER STRIP
   ========================================================================== */
.cn-answer {
  background: linear-gradient(100deg, rgba(236, 28, 36, 0.06), rgba(12, 35, 64, 0.05));
  border-top: 1px solid var(--dt-line);
  border-bottom: 1px solid var(--dt-line);
}

.cn-answer-inner {
  max-width: var(--container, 1280px);
  margin: 0 auto;
}

.cn-answer-oneline {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 26px 0;
  flex-wrap: nowrap;
}

.cn-answer-badge {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--dt-red);
  color: #fff;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
}

/* The question is a real <h2> here, not the prototype's <span> — the copy deck depends
   on the heading-then-paragraph pairing for extraction. Heading margins are reset so it
   still sits on the single line the design calls for. */
.cn-answer-q {
  flex-shrink: 0;
  margin: 0;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: normal;
  color: var(--dt-ink);
  white-space: nowrap;
}

.cn-answer-a {
  font-size: 16px;
  line-height: 1.5;
  color: var(--dt-muted);
  margin: 0;
}

/* ==========================================================================
   03 TRUST BENTO
   Four fixed footprints. The position classes come from the row index, so the grid
   placement below is what makes the layout, not the editor's ordering.
   ========================================================================== */
.cn-trust-sec {
  position: relative;
  overflow: hidden;
}

.cn-trust-sec .container {
  position: relative;
  z-index: 1;
}

/* Kept as a hook: the prototype ships it switched off, and the section reads correctly
   without it. Left in place so a backdrop can be introduced without new markup. */
.cn-trust-bg {
  display: none;
}

.cn-trust-ey {
  color: var(--dt-red);
}

/* Flex, not grid: A is one tall column beside a right-hand stack of (B + C side by
   side) over D — a shape flex can only reach with the two wrapper elements below, so
   Construction-trust.php nests cnt-cards b/c inside .cn-trust-right > .cn-trust-top
   and d inside .cn-trust-right, sitting after that row. */
.cn-trust-bento {
  margin-top: 52px;
  display: flex;
  gap: 20px;
}

/* flex-basis: 0 on all four keeps the split exactly ratio-driven (1.15 : 2, then 1 : 1
   inside the right column), matching the original grid's fr values instead of letting
   caption-length differences nudge the widths. This is safe ONLY while each pair's shared
   parent is flex-direction: row — the moment an ancestor switches that parent to column
   (.cn-trust-bento at 900px, .cn-trust-top at 560px), the now-vertical flex-basis: 0 combines
   with .cn-trust-card's overflow: hidden to disable the automatic min-height floor entirely,
   collapsing the card to 0px instead of sizing to its photo and copy. Both breakpoint blocks
   below switch the affected pair to flex-basis: auto at exactly the point their parent flips,
   which is what keeps them content-sized instead of erasing them. */
.cn-trust-a {
  flex: 1.15 1 0;
}

.cn-trust-right {
  flex: 2 1 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

.cn-trust-top {
  display: flex;
  gap: 20px;
}

.cn-trust-b,
.cn-trust-c {
  flex: 1 1 0;
  min-width: 0;
}

.cn-trust-d {
  flex-direction: row;
  align-items: stretch;
  min-height: 240px;
}

.cn-trust-card.cn-trust-d.dt-rev.in {
  display: flex;
  flex-direction: row;
}

.cn-trust-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: 24px;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--dt-line);
  box-shadow: 0 20px 48px -34px rgba(12, 35, 64, 0.28);
  transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.4s ease,
    border-color 0.4s ease;
}

.cn-trust-card:hover {
  transform: translateY(-6px);
  border-color: rgba(236, 28, 36, 0.28);
  box-shadow: 0 44px 80px -46px rgba(12, 35, 64, 0.42);
}

/* The card is both a reveal target and a hover target. While it is still revealing the
   transition has to describe opacity and transform; once revealed it hands transform
   back to the hover curve, or the lift would inherit the slow reveal easing. */
.cn-trust-card.dt-rev {
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.cn-trust-card.dt-rev.in {
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.4s ease;
}

.cn-trust-a.dt-rev {
  transition-delay: 0ms;
}

.cn-trust-b.dt-rev {
  transition-delay: 110ms;
}

.cn-trust-c.dt-rev {
  transition-delay: 220ms;
}

.cn-trust-d.dt-rev {
  transition-delay: 330ms;
}

/* The prototype painted these as CSS backgrounds. This build renders <img>, so the
   crop moves onto the image element — same result, but the photo carries srcset and
   lazy loading. Static: no pan-on-reveal, no hover zoom. */
.cn-trust-photo {
  position: relative;
  border-radius: 16px;
  margin: 14px 14px 0;
  overflow: hidden;
  flex: 1;
  min-height: 0;
}

.cn-trust-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

.cn-trust-card-body {
  padding: 22px 26px 26px;
}

.cn-trust-card-body h3 {
  font-family: "Outfit", system-ui, sans-serif;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.28;
  margin: 0;
  font-size: 20px;
}

.cn-trust-card-body h3 b {
  color: var(--dt-ink);
  font-weight: 700;
}

.cn-trust-card-body h3 span {
  color: var(--dt-muted);
  font-weight: 600;
}

.cn-trust-card-body p {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--dt-muted);
  margin: 8px 0 0;
}

.cn-trust-a .cn-trust-photo {
  min-height: 300px;
}

.cn-trust-a .cn-trust-card-body h3,
.cn-trust-d .cn-trust-card-body h3 {
  font-size: 25px;
  line-height: 1.24;
}

.cn-trust-c .cn-trust-photo {
  min-height: 178px;
}

.cn-trust-c .cn-trust-photo img {
  object-position: center 62%;
}

.cn-trust-c .cn-trust-card-body p {
  margin-top: 10px;
}

.cn-trust-stat-num {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 52px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--dt-ink);
}

.cn-trust-d .cn-trust-card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 34px 36px;
}

.cn-trust-d .cn-trust-photo {
  flex: 0 0 42%;
  margin: 14px;
  min-height: 0;
}

.cn-trust-cta {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  margin-top: 22px;
  padding: 6px 6px 6px 24px;
  background: var(--cn-navy);
  color: #fff;
  border-radius: 999px;
  border: 1.5px solid transparent;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

/* White on hover — needs the navy border, or a white pill disappears against this card's own
   white background. Text and the arrow circle invert with it so both stay readable. */
.cn-trust-cta:hover,
.cn-trust-cta:focus-visible {
  background: #fff;
  color: var(--cn-navy);
  border-color: var(--cn-navy);
}

.cn-trust-cta-arr {
  display: inline-grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #fff;
  color: var(--cn-navy);
  transition: background 0.25s ease, color 0.25s ease;
}

.cn-trust-cta:hover .cn-trust-cta-arr,
.cn-trust-cta:focus-visible .cn-trust-cta-arr {
  background: var(--cn-navy);
  color: #fff;
}

/* Sized here because the SVG carries no width or height attribute — an unsized SVG in
   an inline-grid wrapper collapses to 0x0. */
.cn-trust-cta-arr svg {
  width: 18px;
  height: 18px;
}

/* ==========================================================================
   04 TYPES GRID
   ========================================================================== */
.cn-types-grid {
  margin-top: 52px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.cn-type-card {
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 20px;
  padding: 28px 26px;
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.cn-type-card:hover {
  transform: translateY(-5px);
  border-color: rgba(236, 28, 36, 0.3);
  box-shadow: 0 26px 52px -34px rgba(12, 35, 64, 0.4);
}

.cn-type-ic {
  width: 48px;
  height: 48px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  color: var(--dt-red);
  background: rgba(236, 28, 36, 0.08);
  margin-bottom: 18px;
}

.cn-type-ic svg {
  width: 23px;
  height: 23px;
}

/* Uploaded override image, sized to the same footprint as the built-in SVGs so a custom
   icon sits in the swatch identically to the default set. */
.cn-type-ic img {
  width: 23px;
  height: 23px;
  object-fit: contain;
  display: block;
}

/* min-height keeps a one-line and a two-line card title on the same baseline, so the
   descriptions below them line up across a row. */
.cn-type-card h3 {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 19px;
  font-weight: 600;
  color: var(--dt-ink);
  letter-spacing: -0.01em;
  margin: 0 0 9px;
  min-height: 2.4em;
  display: flex;
  align-items: flex-end;
}

.cn-type-card p {
  font-size: 15px;
  line-height: 1.55;
  color: var(--dt-muted);
  margin: 0;
}

.cn-type-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.cn-type-card:hover .cn-type-link,
.cn-type-link:hover,
.cn-type-link:focus-visible {
  color: var(--dt-red);
  border-bottom-color: rgba(236, 28, 36, 0.4);
}

/* Full-bleed CTA band. The 100vw breakout is the approved treatment; it is paired with
   overflow-x: clip on the section because 100vw includes the scrollbar gutter and would
   otherwise scroll the page sideways by the scrollbar width. */
.cn-types-sec {
  overflow-x: clip;
}

/* This section's own 100vw full-bleed band already supplies its background and spacing, so the
   shared .dt-section.gray background (components.css) and the outer .dt-section padding-y just
   doubled up behind it on this page. */
.page-slug-construction-software-development-v2 section.dt-section.gray.cn-types-sec {
  background: unset;
  padding: 0px;
  padding-bottom: 50px;
}

/* -- Motion, second group ------------------------------------------------- */
@keyframes cnRoofPop {
  from { transform: translateY(6px) scale(0.985); }
  to   { transform: translateY(0) scale(1); }
}

@keyframes cnRoofMark {
  0%, 100% { transform: translateY(0); opacity: 1; }
  50%      { transform: translateY(-6px); opacity: 0.75; }
}

@keyframes cnStackFade {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@keyframes cnChipIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   05 CASE DECK
   The deck frame, cards and controls come from components.css (.case-*). Only the
   inner rows, the metric chips and the red-on-white accenting are added here.
   ========================================================================== */
.cn-case-deck .case-body {
  justify-content: flex-start;
  gap: 12px;
  overflow-y: auto;
}

.cn-case-deck .case-eyebrow {
  color: var(--dt-red);
}

.cn-case-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cn-case-k {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dt-red);
}

.cn-case-row p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--dt-muted);
  margin: 0;
}

/* margin-top:auto pins the chips to the bottom of the card, so cards with unequal copy
   length still line their metrics up. */
.cn-case-metrics {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--dt-line);
}

.cn-case-metric {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--dt-ink);
  background: linear-gradient(180deg, #fff, #fff5f5);
  border: 1px solid rgba(236, 28, 36, 0.28);
  border-radius: 8px;
  padding: 6px 12px;
  box-shadow: 0 8px 18px -12px rgba(236, 28, 36, 0.5);
}

.cn-case-metric svg {
  width: 13px;
  height: 13px;
  color: var(--dt-red);
  flex-shrink: 0;
}

.cn-case-deck .case-foot {
  margin-top: 8px;
}

.cn-case-deck .case-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: "Outfit", system-ui, sans-serif;
  font-weight: 600;
  font-size: 15px;
  color: var(--dt-red);
  text-decoration: none;
}

.cn-case-deck .case-link svg {
  width: 16px;
  height: 16px;
}

.cn-case-deck .case-link .arr {
  display: inline-flex;
  transition: transform 0.3s ease;
}

.cn-case-deck .case-link:hover .arr,
.cn-case-deck .case-link:focus-visible .arr {
  transform: translateX(4px);
}

/* The nav arrows carry no width or height attribute, so they need sizing here or they
   collapse to 0x0 inside their inline-flex button. */
.cn-cases-sec .case-btn svg {
  width: 16px;
  height: 16px;
}

/* ==========================================================================
   06 ROOFING
   ========================================================================== */
.cn-roof-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 48px;
  align-items: center;
  margin-top: 44px;
}

.cn-roof-lead {
  font-size: 17px;
  line-height: 1.6;
  color: var(--dt-muted);
  margin: 18px auto 0;
  max-width: 620px;
}

.cn-roof-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.cn-roof-list li {
  display: flex;
  gap: 14px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--dt-muted);
  transition: transform 0.3s ease;
}

.cn-roof-list li:hover {
  transform: translateX(4px);
}

.cn-roof-list li b {
  color: var(--dt-ink);
}

.cn-roof-dot {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(236, 28, 36, 0.1);
  color: var(--dt-red);
  transition: background 0.3s ease, color 0.3s ease;
}

.cn-roof-list li:hover .cn-roof-dot {
  background: var(--dt-red);
  color: #fff;
}

.cn-roof-dot svg {
  width: 14px;
  height: 14px;
}

/* The prototype declared its own opacity, transform and transition here, duplicating what
   .dt-rev in components.css already does to this element. Only the appearance and the
   settle animation are kept - re-declaring the reveal would fight it. */
.cn-roof-quote {
  position: relative;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 24px;
  padding: 44px 38px 38px;
  color: var(--dt-ink);
  overflow: hidden;
  box-shadow: 0 30px 70px -50px rgba(12, 35, 64, 0.35);
}

.cn-roof-quote.in {
  animation: cnRoofPop 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cn-roof-quote::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--dt-red), #ff6168);
}

.cn-roof-quote:hover {
  box-shadow: 0 44px 84px -46px rgba(236, 28, 36, 0.3);
  border-color: rgba(236, 28, 36, 0.28);
}

.cn-roof-quote-mark {
  position: absolute;
  top: 14px;
  left: 28px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 90px;
  line-height: 1;
  color: rgba(236, 28, 36, 0.16);
  animation: cnRoofMark 5s ease-in-out infinite;
}

.cn-roof-quote blockquote {
  position: relative;
  margin: 34px 0 0;
  font-size: 19px;
  line-height: 1.55;
  font-weight: 500;
  color: var(--dt-ink);
}

.cn-roof-quote-by {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--dt-line);
}

.cn-roof-quote-av {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 20%;
  border: 2px solid rgba(236, 28, 36, 0.5);
  flex-shrink: 0;
}

/* A <cite> here rather than the prototype's <span>, so the browser italic is reset. */
.cn-roof-quote-meta {
  display: flex;
  flex-direction: column;
  font-style: normal;
}

.cn-roof-quote-by b {
  display: block;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  color: var(--dt-ink);
}

.cn-roof-quote-by span {
  font-size: 13.5px;
  color: var(--dt-muted);
}

/* ==========================================================================
   07 + 18 TABBED PANELS - integrations wall and tech stack
   One block serves both: same markup, same behaviour, different content.
   ========================================================================== */
.cn-stack {
  margin-top: 48px;
}

.cn-stack-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  padding: 0 0 22px;
  border-bottom: 1px solid var(--dt-line);
}

.cn-stack-tab {
  padding: 11px 22px;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 999px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--dt-ink);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.cn-stack-tab:hover {
  color: var(--dt-red);
  border-color: rgba(236, 28, 36, 0.4);
  transform: translateY(-2px);
}

/* .is-active, not the prototype's .active - construction.js stamps the state class this
   theme uses everywhere else. */
.cn-stack-tab.is-active {
  background: var(--dt-red);
  border-color: var(--dt-red);
  color: #fff;
}

.cn-stack-panel {
  padding: 46px 40px 50px;
  min-height: 260px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  animation: cnStackFade 0.35s ease both;
}

/* Load-bearing, not tidiness. construction.js hides inactive panels with the hidden
   attribute, and the display:flex above is a class rule that outranks the UA sheet's
   [hidden] { display: none }. Without this, every panel would render at once. */
.cn-stack-panel[hidden] {
  display: none;
}

.cn-stack-cap {
  margin: 0 0 28px;
  font-size: 17px;
  line-height: 1.5;
  color: var(--dt-muted);
  max-width: 620px;
}

/* Flex, not a CSS-grid fixed-track row. Grid's auto-placement always fills tracks from the
   start, so a 4-item tab in a fixed-column grid left-anchors its chips against the empty
   trailing columns — centering the grid container just centers that mostly-empty box, not the
   items inside it. Flex's justify-content: center centers whatever's actually there. flex-basis
   is computed to divide the row into 4, so every tab's chips are the same size and a row of 6
   wraps to 4 + 2 (the second line centered) rather than shrinking to fit six across. */
.cn-stack-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
  /* .cn-stack-panel is align-items: center, so without this the row — itself a centred flex
     child — shrinks to its own content width instead of the panel's full width, and the basis
     calc() below would be computed against that shrunk width instead of the real row width. */
  width: 100%;
  align-self: stretch;
}

.cn-stack-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 26px 30px;
  flex: 0 0 calc((100% - 3 * 20px) / 4);
  min-width: 148px;
  border: 1px solid var(--dt-line);
  border-radius: 18px;
  background: #fff;
  font-size: 16px;
  font-weight: 600;
  color: var(--dt-ink);
  box-shadow: 0 20px 40px -38px rgba(12, 35, 64, 0.4);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), border-color 0.3s ease,
    box-shadow 0.3s ease;
  animation: cnChipIn 0.4s ease both;
  /* Stagger index arrives from the template as --cn-chip-i, so the curve stays here. */
  animation-delay: calc(var(--cn-chip-i, 0) * 55ms);
}

.cn-stack-chip:hover {
  transform: translateY(-5px);
  border-color: rgba(236, 28, 36, 0.4);
  box-shadow: 0 22px 40px -24px rgba(236, 28, 36, 0.45);
}

/* .cn-stack-chip is sometimes an <a> now (cns_item_link) — the class already sets its own
   color, so only the browser's default underline needs resetting. */
a.cn-stack-chip {
  text-decoration: none;
}

/* Tech stack wants more per row than Integrations — same shared chip, a section-scoped basis
   override. Repeated inside both breakpoints below at matching specificity, since a plain
   .cn-stack-chip rule inside a media query is otherwise weaker than this one and would lose
   the cascade even past the point it's supposed to apply. */
.cn-stack-sec .cn-stack-chip {
  flex-basis: calc((100% - 5 * 20px) / 6);
}

.cn-stack-logo {
  width: 52px;
  height: 52px;
  object-fit: contain;
  flex-shrink: 0;
}

.cn-stack-logo-txt {
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(236, 28, 36, 0.1);
  color: var(--dt-red);
  font-family: "Outfit", system-ui, sans-serif;
  font-weight: 700;
  font-size: 24px;
}

.cn-stack-chip-n {
  line-height: 1.3;
}

/* ==========================================================================
   08 DATA COST - cited stat bar
   ========================================================================== */
.cn-datacost-grid {
  margin-top: 52px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  border: 1px solid var(--dt-line);
  border-radius: 20px;
  overflow: hidden;
  background: #fff;
}

.cn-datacost-tile {
  padding: 34px 26px;
  border-right: 1px solid var(--dt-line);
}

.cn-datacost-tile:last-child {
  border-right: none;
}

.cn-datacost-v {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: clamp(34px, 3.4vw, 46px);
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--dt-red);
  line-height: 1;
}

.cn-datacost-l {
  margin-top: 14px;
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--dt-ink);
}

.cn-datacost-s {
  margin-top: 12px;
  font-size: 12px;
  color: var(--dt-muted);
}

/* Sources become links when a URL is supplied. Underlined deliberately: these cite
   third-party research, and a citation that does not look clickable gets missed. */
.cn-datacost-s a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: rgba(90, 100, 120, 0.45);
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.cn-datacost-s a:hover,
.cn-datacost-s a:focus-visible {
  color: var(--dt-red);
  text-decoration-color: var(--dt-red);
}

.cn-datacost-note {
  max-width: 960px;
  margin: 32px auto 0;
  text-align: center;
  font-size: 16px;
  line-height: 1.65;
  color: var(--dt-muted);
}

.cn-datacost-take {
  position: relative;
  max-width: 820px;
  margin: 26px auto 0;
  padding: 26px 30px 26px 34px;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-left: 4px solid var(--dt-red);
  border-radius: 14px;
  box-shadow: 0 24px 50px -40px rgba(12, 35, 64, 0.4);
  text-align: left;
}

.cn-datacost-take-tag {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dt-red);
  margin-bottom: 10px;
}

.cn-datacost-take p {
  margin: 0;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 19px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--dt-ink);
}

/* ==========================================================================
   08b FRAGMENTATION COST CALCULATOR
   Ported verbatim from construction-calc.jsx's own two-part stylesheet: a base ruleset
   (navy section, white module) immediately followed by a later "all-black theme" block
   that overrides the module/inputs/results/verdict to dark and the outer section to a
   light background with a faint cover-image overlay — both kept in this same source order
   so the cascade produces the same final look the reference design shows.
   ========================================================================== */
.cn-calc-sec { position: relative; background: var(--cn-navy); overflow: hidden; }
.cn-calc-sec::after { content: ""; position: absolute; inset: 0; opacity: 0.4; pointer-events: none; background-image: linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px); background-size: 46px 46px; -webkit-mask-image: radial-gradient(circle at 50% 40%, #000, transparent 78%); mask-image: radial-gradient(circle at 50% 40%, #000, transparent 78%); }
.cn-calc-sec > .container { position: relative; z-index: 1; }
.cn-calc-sec .eyebrow { color: #FF6168; }
.cn-calc-sec .dt-h2 { color: #fff; }
.cn-calc-sec .dt-sub { color: rgba(255,255,255,0.7); }
.cn-calc-module { position: relative; margin-top: 52px; border: 1px solid var(--dt-line); border-radius: 24px; overflow: hidden; background: #fff; box-shadow: 0 60px 120px -50px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06); }
.cn-calc-module::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--dt-red), #FF6168); z-index: 3; }
.cn-calc-shell { display: grid; grid-template-columns: 40% 60%; gap: 0; }
.cn-calc-inputs { padding: 40px 38px; background: var(--dt-gray); border-right: 1px solid var(--dt-line); display: flex; flex-direction: column; gap: 26px; }
.cn-calc-field { display: flex; flex-direction: column; }
.cn-calc-label { font-family: "Outfit", system-ui, sans-serif; font-size: 15px; font-weight: 600; color: var(--dt-ink); line-height: 1.35; }
.cn-calc-help { font-size: 12.5px; line-height: 1.45; color: var(--dt-muted); margin: 8px 0 0; }
.cn-calc-slider { margin-top: 14px; }
.cn-calc-slider-val { font-family: "Outfit", system-ui, sans-serif; font-size: 22px; font-weight: 700; color: var(--dt-red); letter-spacing: -0.02em; margin-bottom: 8px; }
.cn-calc-slider input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; border-radius: 6px; background: linear-gradient(90deg, var(--dt-red) var(--pct), #dcdfe4 var(--pct)); outline: none; }
.cn-calc-slider input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; border-radius: 50%; background: #fff; border: 3px solid var(--dt-red); cursor: pointer; box-shadow: 0 3px 8px rgba(12,35,64,0.25); }
.cn-calc-slider input[type="range"]::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: #fff; border: 3px solid var(--dt-red); cursor: pointer; }
.cn-calc-currency { margin-top: 14px; position: relative; display: flex; align-items: center; }
.cn-calc-cur-sign { position: absolute; left: 14px; font-family: "Outfit", system-ui, sans-serif; font-size: 16px; font-weight: 600; color: var(--dt-muted); }
.cn-calc-currency input { width: 100%; padding: 13px 14px 13px 30px; border: 1px solid var(--dt-line); border-radius: 11px; font-family: "Outfit", system-ui, sans-serif; font-size: 17px; font-weight: 600; color: var(--dt-ink); background: #fff; outline: none; transition: border-color .2s ease; }
.cn-calc-currency input:focus { border-color: var(--dt-red); }
.cn-calc-results { padding: 40px 38px; display: flex; flex-direction: column; justify-content: center; gap: 16px; background: #fff; }
.cn-calc-dash { color: #C7CBD1; }
.cn-calc-hero-card { background: var(--cn-navy); border-radius: 18px; padding: 28px 30px; color: #fff; }
.cn-calc-hero-label { font-size: 13.5px; color: rgba(255,255,255,0.65); }
.cn-calc-hero-val { display: block; font-family: "Outfit", system-ui, sans-serif; font-size: clamp(38px, 5vw, 54px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.05; margin: 8px 0; }
.cn-calc-hero-sub { display: block; font-size: 14px; line-height: 1.5; color: rgba(255,255,255,0.75); }
.cn-calc-tag { display: block; margin-top: 8px; font-size: 12px; font-style: normal; color: var(--dt-muted); text-align: left; }
.cn-calc-hero-card .cn-calc-tag { color: rgba(255,255,255,0.5); font-style: italic; }
.cn-calc-ab-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.cn-calc-card { border: 1px solid var(--dt-line); border-radius: 16px; padding: 22px 22px; display: flex; flex-direction: column; }
.cn-calc-card-label { font-size: 13px; color: var(--dt-muted); line-height: 1.35; }
.cn-calc-card-val { font-family: "Outfit", system-ui, sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.02em; color: var(--dt-ink); margin: 8px 0; }
.cn-calc-card-sub { font-size: 13px; line-height: 1.5; color: var(--dt-muted); }
.cn-calc-divider { height: 1px; background: var(--dt-line); }
.cn-calc-verdict { position: relative; z-index: 2; margin: 8px 22px 26px; padding: 34px 36px; background: linear-gradient(180deg, #fbfcfd 0%, #f3f5f7 100%); border-radius: 18px; border: 1px solid var(--dt-line); text-align: center; box-shadow: 0 30px 60px -40px rgba(12,35,64,0.5), inset 0 1px 0 #fff; }
.cn-calc-verdict.tier-2, .cn-calc-verdict.tier-3 { background: linear-gradient(180deg, #fff 0%, #fbf1f2 100%); border: 1px solid rgba(236,28,36,0.28); box-shadow: 0 34px 66px -34px rgba(236,28,36,0.35), inset 0 1px 0 #fff; }
.cn-calc-verdict::before { content: ""; position: absolute; inset: 0; border-radius: 18px; padding: 1px; background: linear-gradient(180deg, rgba(236,28,36,0.35), rgba(12,35,64,0.08) 45%, transparent); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; }
.cn-calc-verdict-flag { display: block; font-size: 12.5px; font-style: italic; color: #4a5563; margin-bottom: 16px; }
.cn-calc-verdict-body h3 { font-family: "Outfit", system-ui, sans-serif; font-size: 24px; font-weight: 600; letter-spacing: -0.02em; color: var(--dt-ink); margin: 0 0 12px; }
.cn-calc-verdict-body p { font-size: 15.5px; line-height: 1.6; color: var(--dt-muted); margin: 0 0 12px; }
.cn-calc-lead { margin-top: 22px; padding-top: 22px; border-top: 1px solid var(--dt-line); }
.cn-calc-lead-intro { font-size: 15px; line-height: 1.55; color: var(--dt-ink); margin: 0 auto 18px; }
.cn-calc-verdict .dt-btn { margin: 0 auto; }
@media (max-width: 940px) { .cn-calc-shell { grid-template-columns: 1fr; } .cn-calc-inputs { border-right: none; border-bottom: 1px solid var(--dt-line); } .cn-calc-ab-grid { grid-template-columns: 1fr; } }
/* ---------- calculator: all-black theme (overrides the block above, same source order) ---------- */
.cn-calc-sec { background: #EEF1F5; }
.cn-calc-sec .dt-h2 { color: var(--dt-ink); }
.cn-calc-sec .dt-sub { color: var(--dt-muted); }
/* An uploaded bg image sits at full strength (see .cn-calc-bg above), so the flat-background
   text colors two lines up no longer contrast — restore white/light text for that case only. */
.cn-calc-has-bg .dt-h2 { color: #fff; }
.cn-calc-has-bg .dt-sub { color: rgba(255,255,255,0.7); }
/* When an image is uploaded it is shown on its own, at full strength — no tinting/whitening layer
   on top — since the uploaded asset is expected to already carry whatever overlay it needs. The
   flat fallback colour above only ever shows when no image is set (the PHP template doesn't render
   this element at all in that case), so it is untouched. */
.cn-calc-bg { position: absolute; inset: 0; z-index: 0; background-image: var(--cn-calc-bg); background-size: cover; background-position: center; }
.cn-calc-module { background: #0b0b0d; border-color: rgba(255,255,255,0.08); box-shadow: 0 60px 120px -50px rgba(0,0,0,0.9), 0 0 0 1px rgba(255,255,255,0.05); }
.cn-calc-inputs { background: #121214; border-right-color: rgba(255,255,255,0.08); }
.cn-calc-results { background: #0b0b0d; }
.cn-calc-label, .cn-calc-card-val, .cn-calc-lead-intro { color: #fff; }
.cn-calc-help, .cn-calc-card-label, .cn-calc-card-sub, .cn-calc-tag { color: rgba(255,255,255,0.6); }
.cn-calc-currency input { background: #1a1a1d; color: #fff; border-color: rgba(255,255,255,0.14); }
/* The parent theme's global input[type="text"]:focus rule (style.css) sets color:#111 at higher
   specificity than a plain class selector, so it silently wins the moment these inputs are
   focused/typed into, leaving dark text on this dark-themed input — matching :focus specificity
   here so this rule's #fff wins while typing too, not just at rest. */
.cn-calc-currency input:focus { color: #fff; }
.cn-calc-cur-sign { color: rgba(255,255,255,0.55); }
.cn-calc-slider input[type="range"] { background: linear-gradient(90deg, var(--dt-red) var(--pct), #2a2a2e var(--pct)); }
.cn-calc-slider input[type="range"]::-webkit-slider-thumb { background: #0b0b0d; }
.cn-calc-slider input[type="range"]::-moz-range-thumb { background: #0b0b0d; }
.cn-calc-hero-card { background: #000; border: 1px solid rgba(255,255,255,0.1); }
.cn-calc-card { background: #141416; border-color: rgba(255,255,255,0.08); }
.cn-calc-dash, .cn-calc-divider, .cn-calc-lead { border-color: rgba(255,255,255,0.1); }
.cn-calc-divider { background: rgba(255,255,255,0.08); }
.cn-calc-verdict { background: linear-gradient(180deg, #141416 0%, #0d0d0f 100%); border-color: rgba(255,255,255,0.1); box-shadow: 0 30px 60px -40px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.05); }
.cn-calc-verdict.tier-2, .cn-calc-verdict.tier-3 { background: linear-gradient(180deg, #17090b 0%, #0d0d0f 100%); border-color: rgba(236,28,36,0.35); box-shadow: 0 34px 66px -34px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.05); }
.cn-calc-verdict-body h3 { color: #fff; }
.cn-calc-verdict-body p { color: rgba(255,255,255,0.68); }
.cn-calc-verdict-flag { color: rgba(255,255,255,0.55); }

/* ==========================================================================
   09 BUILD VS BUY
   The matrix itself is .so-cmp2 from components.css, reused whole. The prototype's own
   .cn-cmp* table is deliberately not ported - it would be a second implementation of a
   comparison grid this theme already has, including its mobile scroll behaviour.
   ========================================================================== */

/* .so-cmp2-head.lbl is shared with Software Outsourcing, which uses its own teal gradient for
   this header — not touched, since that's SO's live colour. The approved construction design
   calls for the dark slate gradient the prototype's own construction.css defines for this
   column instead, so it's overridden here, scoped to this section only. The tone-blue/tone-red
   headers already match the prototype's own values exactly and need no override. */
.cn-cmp-sec .so-cmp2-head.lbl {
  background: linear-gradient(135deg, #3a4658, #232c3a);
}

.cn-cmp-verdict {
  margin-top: 26px;
  background: linear-gradient(100deg, rgba(236, 28, 36, 0.06), rgba(12, 35, 64, 0.05));
  border: 1px solid rgba(236, 28, 36, 0.15);
  border-radius: 16px;
  padding: 24px 30px;
  font-size: 17px;
  line-height: 1.55;
  color: var(--dt-ink);
  font-weight: 500;
}

/* Inline links inside authored copy - the verdict, the cost lead-in, the AI note. */
.cn-inline-link {
  color: var(--dt-red);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid rgba(236, 28, 36, 0.35);
  transition: border-color 0.15s ease, color 0.15s ease;
}

.cn-inline-link:hover,
.cn-inline-link:focus-visible {
  color: #c8151c;
  border-bottom-color: var(--dt-red);
}

/* ==========================================================================
   12 ABANDONMENT - the risk section, dark by design
   The only section on the page with a dark ground, which is why the shared heading and
   description colours are overridden here. Both are qualified by .cn-abandon, so the
   override cannot reach .dt-h2 or .dt-sub anywhere else.
   ========================================================================== */
.cn-abandon {
  position: relative;
  padding: var(--dt-pad-y) 0;
  background: var(--cn-navy);
  overflow: hidden;
}

/* The backdrop URL arrives as --cn-abandon-bg from the template, so the stylesheet keeps
   control of the opacity and the gradient layered over it. With no image set the layer is
   simply empty and the navy ground shows through. */
.cn-abandon > .cn-abandon-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--cn-abandon-bg);
  background-size: cover;
  background-position: center;
  opacity: 0.42;
}

.cn-abandon > .cn-abandon-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(7, 17, 31, 0.55) 0%,
    rgba(7, 17, 31, 0.72) 45%,
    rgba(7, 17, 31, 0.9) 100%
  );
}

.cn-abandon > .container {
  position: relative;
  z-index: 1;
}

.cn-abandon .eyebrow {
  color: #ff6168;
}

.cn-abandon .dt-h2 {
  color: #fff;
}

.cn-abandon .dt-sub {
  color: rgba(255, 255, 255, 0.68);
}

.cn-abandon-list {
  margin-top: 40px;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 14px;
}

.cn-abandon-item {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 22px 20px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), border-color 0.3s ease,
    background 0.3s ease;
}

.cn-abandon-item:hover {
  transform: translateY(-6px);
  border-color: rgba(236, 28, 36, 0.5);
  background: rgba(255, 255, 255, 0.08);
}

.cn-abandon-ic {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  background: rgba(236, 28, 36, 0.16);
  color: #ff6168;
}

.cn-abandon-ic svg {
  width: 20px;
  height: 20px;
}

.cn-abandon-ic img {
  width: 20px;
  height: 20px;
  object-fit: contain;
  display: block;
}

.cn-abandon-item b {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15.5px;
  font-weight: 700;
  color: #fff;
  line-height: 1.25;
}

.cn-abandon-item p {
  font-size: 13.5px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.72);
  margin: 0;
}

.cn-abandon-test {
  margin-top: 30px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  padding: 22px 28px;
  font-size: 16px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.82);
}

.cn-abandon-test b {
  color: #fff;
}

/* ==========================================================================
   13 ENGINEER PROFILE
   ========================================================================== */
.cn-eng {
  margin-top: 44px;
  position: relative;
  display: flex;
  gap: 48px;
  align-items: center;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 24px;
  box-shadow: 0 30px 70px -50px rgba(12, 35, 64, 0.35);
  padding: 56px 60px;
  overflow: hidden;
}

/* Decorative inner rule with two gaps punched in it, top-left and bottom-right. The
   pseudo-elements are the gaps, painted in the card colour rather than cut out. */
.cn-eng-frame {
  position: absolute;
  inset: 18px;
  border: 1.5px solid rgba(236, 28, 36, 0.22);
  border-radius: 18px;
  pointer-events: none;
}

.cn-eng-frame::before,
.cn-eng-frame::after {
  content: "";
  position: absolute;
  width: 90px;
  height: 6px;
  background: #fff;
}

.cn-eng-frame::before {
  top: -3px;
  left: 44px;
}

.cn-eng-frame::after {
  bottom: -3px;
  right: 44px;
}

.cn-eng-photo {
  position: relative;
  flex-shrink: 0;
  width: 180px;
  height: 180px;
  border-radius: 50%;
  padding: 8px;
  background: rgba(236, 28, 36, 0.08);
  border: 2px solid rgba(236, 28, 36, 0.28);
}

/* object-position sits high on purpose: a centred crop of a head-and-shoulders portrait
   cuts the face in a circular frame. */
.cn-eng-photo img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 16%;
}

.cn-eng-body {
  flex: 1;
  min-width: 0;
  position: relative;
}

.cn-eng-quote {
  position: relative;
  margin: 0;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: clamp(19px, 1.7vw, 23px);
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--dt-ink);
  padding-left: 6px;
}

.cn-eng-qmark {
  position: absolute;
  top: -0.35em;
  left: -18px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 72px;
  line-height: 1;
  font-weight: 800;
  color: rgba(236, 28, 36, 0.18);
}

.cn-eng-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--dt-line);
}

/* A <cite> in this build, so the browser italic is reset and the two lines stack. */
.cn-eng-cite {
  display: flex;
  flex-direction: column;
  font-style: normal;
  min-width: 0;
}

.cn-eng-n {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 20px;
  font-weight: 700;
  color: var(--dt-ink);
  letter-spacing: -0.01em;
}

.cn-eng-role {
  font-size: 14px;
  color: var(--dt-muted);
  margin-top: 3px;
}

/* "Connect on" and the LinkedIn mark are one link (aria-label carries the full accessible
   name), but two visual pieces: a text pill and a separate circular icon badge, matching the
   .cn-trust-cta / .cn-trust-cta-arr pattern elsewhere on this page rather than running the
   label straight into the glyph inside a single pill. */
/* Plain container now, not a link — "Connect on" is label text and the <a> below is the icon
   circle alone, so only that circle is the clickable element and only it gets a hover state. */
.cn-eng-li {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
  padding: 4px 4px 4px 20px;
  border-radius: 999px;
  background: var(--dt-ink);
  color: #fff;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 14px;
  font-weight: 600;
}

.cn-eng-li-ic {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #fff;
  color: var(--dt-ink);
  text-decoration: none;
  transition: background 0.2s ease, color 0.2s ease;
}

.cn-eng-li-ic svg {
  width: 17px;
  height: 17px;
}

/* Colour inversion on the icon alone, no border — it isn't a filled pill against a page
   background anymore, just a circle sitting on the (already navy) pill behind it. */
.cn-eng-li-ic:hover,
.cn-eng-li-ic:focus-visible {
  background: var(--dt-ink);
  color: #fff;
}

/* ==========================================================================
   11 WHERE AI WORKS
   Three cited donuts plus a two-bar chart, then the use-case grid and a risk callout.
   ========================================================================== */

/* Registering the sweep variable is what makes the ring animate rather than jump.
   An unregistered custom property has no type, so a browser can only switch it
   discretely; declaring a <percentage> lets it interpolate. Where @property is not
   supported the ring simply appears at its final value, which is the prototype's own
   behaviour, so nothing is lost. */
@property --cn-a {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

@keyframes cnDonutFill {
  from {
    --cn-a: 0%;
  }
  to {
    --cn-a: var(--val, 0%);
  }
}

@keyframes cnBarGrow {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

.cn-ai-panel {
  margin-top: 52px;
}

.cn-ai-viz {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-items: stretch;
}

.cn-ai-donut {
  /* The ring colour is a token reference rather than an inline value, so the whole
     section can be re-toned from one place. */
  --c: var(--dt-red);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  border-right: 1px solid var(--dt-line);
  padding: 34px 26px;
}

/* The bar panel sits in the fourth column, so the third donut is the last bordered cell.
   Dropping the rule on the final child keeps a stray divider off the right edge when
   fewer than three donuts are entered. */
.cn-ai-donut:last-child {
  border-right: none;
}

.cn-ai-donut.dt-rev {
  transition-delay: calc(var(--cn-i, 0) * 90ms);
}

.cn-ai-donut-ring {
  position: relative;
  width: 148px;
  height: 148px;
  border-radius: 50%;
  background: conic-gradient(var(--c) var(--cn-a, 0%), #e9edf1 0);
  display: grid;
  place-items: center;
}

.cn-ai-donut.in .cn-ai-donut-ring {
  animation: cnDonutFill 1.15s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

/* Punches the centre out of the ring. */
.cn-ai-donut-ring::after {
  content: "";
  position: absolute;
  inset: 16px;
  border-radius: 50%;
  background: #fff;
  z-index: 0;
}

/* The figure is real text over the ring, not a label beside it: a conic-gradient conveys
   nothing to a screen reader, so the number has to be readable on its own. */
.cn-ai-donut-num {
  position: relative;
  z-index: 1;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 42px;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--dt-ink);
}

.cn-ai-donut-num i {
  font-size: 22px;
  font-style: normal;
  font-weight: 700;
  color: var(--c);
  margin-left: 1px;
}

.cn-ai-donut-cap b {
  display: block;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  color: var(--dt-ink);
}

.cn-ai-donut-from {
  display: block;
  margin-top: 6px;
  font-size: 13px;
  color: var(--dt-muted);
}

.cn-ai-donut-src {
  display: block;
  margin-top: 10px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--dt-muted);
  opacity: 0.85;
}

/* Citation links, same treatment as .cn-datacost-s: inherit the muted colour rather than
   default link blue, underline stays so it still reads as a link. */
.cn-ai-donut-src a,
.cn-ai-bars-src a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: rgba(90, 100, 120, 0.45);
}

.cn-ai-donut-src a:hover,
.cn-ai-donut-src a:focus-visible,
.cn-ai-bars-src a:hover,
.cn-ai-bars-src a:focus-visible {
  color: var(--dt-red);
  text-decoration-color: var(--dt-red);
}

.cn-ai-bars {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 13px;
  padding: 34px 26px;
}

.cn-ai-bars-t {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--dt-ink);
}

.cn-ai-bar {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 6px 10px;
}

.cn-ai-bar-l {
  font-size: 13px;
  color: var(--dt-muted);
  grid-column: 1 / -1;
}

.cn-ai-bar-track {
  height: 10px;
  border-radius: 999px;
  background: #e3e7ec;
  overflow: hidden;
}

/* Width is the target the template supplies as --w; the animation only scales it in, so
   the bar reads correctly even if the animation never runs. */
.cn-ai-bar-fill {
  display: block;
  width: var(--w, 0%);
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #ff6168, var(--dt-red));
  transform: scaleX(0);
  transform-origin: left;
}

.cn-ai-bars.in .cn-ai-bar-fill {
  animation: cnBarGrow 1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.cn-ai-bar-v {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--dt-red);
  text-align: right;
}

.cn-ai-bars-src {
  font-size: 12px;
  color: var(--dt-muted);
}

.cn-ai-read {
  max-width: 900px;
  margin: 26px auto 0;
  text-align: center;
  font-size: 16px;
  line-height: 1.6;
  color: var(--dt-muted);
}

.cn-ai-usehead {
  margin: 52px 0 24px;
  text-align: center;
}

.cn-ai-usehead .eyebrow {
  justify-content: center;
  color: var(--dt-red);
}

.cn-ai-usehead h3 {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: clamp(24px, 2.4vw, 32px);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--dt-ink);
  margin: 10px 0 0;
}

.cn-ai-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
}

.cn-ai-card {
  position: relative;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 16px;
  padding: 24px 20px 22px;
  overflow: hidden;
  box-shadow: 0 22px 44px -44px rgba(12, 35, 64, 0.4);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.cn-ai-card.dt-rev {
  transition-delay: calc(var(--cn-i, 0) * 55ms);
}

.cn-ai-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--dt-red), #ff6168);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.cn-ai-card::after {
  content: "";
  position: absolute;
  right: -40px;
  bottom: -40px;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(236, 28, 36, 0.1), transparent 70%);
  opacity: 0;
  transition: opacity 0.35s ease;
}

.cn-ai-card:hover {
  transform: translateY(-6px);
  border-color: rgba(236, 28, 36, 0.3);
  box-shadow: 0 34px 60px -38px rgba(236, 28, 36, 0.42);
}

.cn-ai-card:hover::before,
.cn-ai-card:hover::after,
.cn-ai-card:focus-within::before,
.cn-ai-card:focus-within::after {
  opacity: 1;
}

.cn-ai-card-ic {
  position: relative;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 11px;
  background: rgba(236, 28, 36, 0.09);
  color: var(--dt-red);
  margin-bottom: 14px;
}

.cn-ai-card-ic svg {
  width: 20px;
  height: 20px;
}

/* h4, not the prototype's h3: the section already has an h3 above this grid
   (.cn-ai-usehead h3), so the cards sit a level below it and the outline stays ordered.
   min-height keeps titles of one, two and three lines on a shared baseline. */
.cn-ai-card h4 {
  position: relative;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 20px;
  font-weight: 600;
  color: var(--dt-ink);
  margin: 0 0 10px;
  line-height: 1.3;
  min-height: unset;
}

.cn-ai-card p {
  position: relative;
  font-size: 13px;
  line-height: 1.5;
  color: var(--dt-muted);
  margin: 0;
}

.cn-ai-risk {
  margin-top: 30px;
  display: flex;
  align-items: flex-start;
  gap: 18px;
  background: var(--cn-navy);
  border-radius: 18px;
  padding: 28px 32px;
}

.cn-ai-risk-tag {
  flex-shrink: 0;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #fff;
  background: var(--dt-red);
  padding: 8px 14px;
  border-radius: 999px;
}

.cn-ai-risk p {
  font-size: 15.5px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.82);
  margin: 0;
}

.cn-ai-risk a {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ==========================================================================
   14 REVIEWS - a window of three
   Every review stays in the DOM and construction.js stamps is-l / is-c / is-r by offset.
   ========================================================================== */
.cn-rev-row {
  margin-top: 56px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  align-items: stretch;
}

.cn-rev-card {
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 22px;
  padding: 34px 32px 30px;
  display: flex;
  flex-direction: column;
  transition: transform 0.4s ease, box-shadow 0.4s ease, opacity 0.4s ease,
    border-color 0.4s ease;
}

/* Load-bearing. The prototype rendered only the visible three; this build keeps them all
   so focus and the reveal survive a move, which means the ones outside the window have to
   be taken out of the grid or all five would show at once. */
.cn-rev-card.is-far {
  display: none;
}

.cn-rev-card.is-c {
  border-color: rgba(236, 28, 36, 0.2);
  box-shadow: 0 30px 64px -34px rgba(12, 35, 64, 0.34);
  transform: translateY(-10px);
}

.cn-rev-card.is-l,
.cn-rev-card.is-r {
  opacity: 0.92;
}

.cn-rev-mark {
  color: var(--dt-red);
  opacity: 0.9;
  margin-bottom: 18px;
}

.cn-rev-mark svg {
  display: block;
  width: 30px;
  height: 30px;
}

.cn-rev-quote {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.55;
  color: var(--dt-ink);
  font-weight: 500;
  margin: 0;
  letter-spacing: -0.01em;
  flex: 1;
}

/* The design shows the quotation marks; they come from CSS so an editor pasting a
   verbatim Clutch review never has to add or strip them for the design to hold. */
.cn-rev-quote::before {
  content: open-quote;
}

.cn-rev-quote::after {
  content: close-quote;
}

.cn-rev-divider {
  height: 1px;
  background: var(--dt-line);
  margin: 24px 0 20px;
}

.cn-rev-foot {
  display: flex;
  align-items: center;
  gap: 14px;
}

.cn-rev-cite {
  flex: 1;
  min-width: 0;
  font-style: normal;
}

.cn-rev-name {
  display: block;
  font-size: 15px;
  font-weight: 600;
  color: var(--dt-ink);
}

.cn-rev-role {
  display: block;
  font-size: 13px;
  color: var(--dt-muted);
  margin-top: 2px;
}

.cn-rev-platform {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--dt-muted);
  flex-shrink: 0;
}

.cn-rev-star {
  color: #f5a623;
}

.cn-rev-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 40px;
}

.cn-rev-arrow {
  width: 48px;
  height: 48px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--dt-line);
  background: #fff;
  color: var(--dt-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.cn-rev-arrow svg {
  width: 16px;
  height: 16px;
}

.cn-rev-arrow:hover,
.cn-rev-arrow:focus-visible {
  background: var(--dt-red);
  color: #fff;
  border-color: var(--dt-red);
}

.cn-rev-dots {
  display: flex;
  gap: 8px;
}

.cn-rev-ddot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dt-line);
  border: none;
  cursor: pointer;
  padding: 0;
  transition: background 0.25s ease, width 0.25s ease, border-radius 0.25s ease;
}

.cn-rev-ddot.is-active {
  background: var(--dt-red);
  width: 24px;
  border-radius: 4px;
}

/* ==========================================================================
   15 COST DRIVERS - numbered, as an ordered list
   ========================================================================== */
.cn-drivers-grid {
  margin-top: 52px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  list-style: none;
  margin-left: 0;
  padding: 0;
}

.cn-driver {
  position: relative;
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 18px;
  padding: 30px 26px 26px;
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.cn-driver.dt-rev {
  transition-delay: calc(var(--cn-i, 0) * 60ms);
}

.cn-driver::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--dt-red), #ff6168);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s ease;
}

.cn-driver:hover {
  transform: translateY(-6px);
  border-color: rgba(236, 28, 36, 0.28);
  box-shadow: 0 30px 58px -36px rgba(12, 35, 64, 0.42);
}

.cn-driver:hover::before {
  transform: scaleX(1);
}

.cn-driver-ic {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 13px;
  background: rgba(236, 28, 36, 0.09);
  color: var(--dt-red);
  margin-bottom: 20px;
}

.cn-driver-ic svg {
  width: 23px;
  height: 23px;
}

.cn-driver-ic img {
  width: 23px;
  height: 23px;
  object-fit: contain;
  display: block;
}

.cn-driver b {
  display: block;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--dt-ink);
  margin-bottom: 9px;
}

.cn-driver p {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--dt-muted);
  margin: 0;
}

.cn-drivers-note {
  max-width: 960px;
  margin: 34px auto 0;
  text-align: center;
  font-size: 16px;
  line-height: 1.65;
  color: var(--dt-muted);
}

/* ==========================================================================
   16 PROCESS RAIL - also an ordered list
   ========================================================================== */
.cn-proc-layout {
  margin-top: 56px;
  display: grid;
  grid-template-columns: 0.92fr 1.08fr;
  gap: 72px;
  align-items: start;
}

.cn-proc-intro {
  position: sticky;
  top: 96px;
}

.cn-proc-intro .eyebrow {
  color: var(--dt-red);
}

/* The rail sits beside a left-aligned header, so the shared centred treatment is undone
   here. Qualified by .cn-proc-intro, so no other section's heading is affected. */
.cn-proc-intro .dt-h2 {
  text-align: left;
  margin: 0;
}

.cn-proc-intro .dt-sub {
  text-align: left;
  margin: 20px 0 0;
  max-width: none;
}

.cn-proc {
  position: relative;
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0;
}

.cn-proc-line {
  position: absolute;
  top: 22px;
  bottom: 30px;
  left: 21px;
  width: 2px;
  border-radius: 2px;
  background: repeating-linear-gradient(
    180deg,
    rgba(12, 35, 64, 0.18) 0 7px,
    transparent 7px 14px
  );
}

.cn-proc-fill {
  position: absolute;
  top: 22px;
  left: 21px;
  width: 2px;
  height: 0;
  border-radius: 2px;
  background: linear-gradient(180deg, #ff6168, var(--dt-red));
  box-shadow: 0 0 10px rgba(236, 28, 36, 0.5);
  z-index: 1;
  /* cnBuildLine alone reads as "run once and freeze": it ramps up, holds at full height for the
     last 15% of the cycle, then snaps back to 0 with no motion in between. The hammer masks that
     same snap with its always-on cnHammerTap wiggle; cnFillPulse gives the fill the same
     continuously-alive cue (same 0.5s cadence as cnHammerTap) so both loops read as running. */
  animation: cnBuildLine 6s cubic-bezier(0.5, 0, 0.5, 1) infinite,
    cnFillPulse 0.5s ease-in-out infinite;
}

.cn-proc-hammer {
  position: absolute;
  top: 0;
  left: -8px;
  width: 46px;
  height: 46px;
  margin-top: -6px;
  z-index: 3;
  transform-origin: 22% 82%;
  animation: cnHammerMove 6s cubic-bezier(0.5, 0, 0.5, 1) infinite,
    cnHammerTap 0.5s ease-in-out infinite;
}

.cn-proc-hammer img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 4px 6px rgba(12, 35, 64, 0.3));
}

.cn-proc-step {
  position: relative;
  display: grid;
  grid-template-columns: 44px 1fr;
  gap: 22px;
  align-items: start;
  padding-bottom: 38px;
  /* A <li> only auto-increments the list-item counter while its own display is list-item —
     switching it to grid for this layout silently disables that, which is why every node
     below was reading 00. counter-increment restores it manually. */
  counter-increment: list-item;
}

.cn-proc-step:last-child {
  padding-bottom: 0;
}

/* The step number is a counter too, zero-padded to match the approved "01" treatment.
   decimal-leading-zero is what gives the pad; the prototype did it in JS with padStart. */
.cn-proc-node {
  position: relative;
  z-index: 2;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #fff;
  border: 1.5px solid var(--dt-line);
  color: var(--dt-ink);
  font-family: "Outfit", system-ui, sans-serif;
  font-weight: 700;
  font-size: 14px;
  display: grid;
  place-items: center;
  box-shadow: 0 0 0 6px #fff;
  animation: cnNodeLight 6s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  /* --cnp-node-anim (set inline per node, see Construction-process.php) points at that node's own
     generated @keyframes so it stays in sync with the hammer/fill on every loop, not just the
     first; cnNodeLight + the linear --ni stagger only remain as the fallback shape/delay when
     markup never sets it. */
  animation-name: var(--cnp-node-anim, cnNodeLight);
  /* Must default to 0 whenever --cnp-node-anim is set — that keyframe already bakes its
     activation point in relative to a zero-delay start shared with the hammer/fill's own
     cycle; re-adding the linear per-node delay here would drift its reset point right back out
     of sync after the first loop, the exact bug this replaced. */
  animation-delay: var(--cnp-node-delay, calc(var(--ni, 0) * 0.95s));
}

.cn-proc-node::before {
  content: counter(list-item, decimal-leading-zero);
}

.cn-proc-tx {
  padding-top: 3px;
}

.cn-proc-step b {
  display: block;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--dt-ink);
  margin-bottom: 7px;
}

.cn-proc-step p {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--dt-muted);
  margin: 0;
  max-width: 460px;
}

/* ==========================================================================
   17 ENGAGEMENT MODELS
   ========================================================================== */
.cn-models-grid {
  margin-top: 52px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}

.cn-model-card {
  background: #fff;
  border: 1px solid var(--dt-line);
  border-radius: 22px;
  padding: 34px 32px;
  display: flex;
  flex-direction: column;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.cn-model-card:hover,
.cn-model-card:focus-within {
  transform: translateY(-5px);
  box-shadow: 0 30px 60px -40px rgba(12, 35, 64, 0.4);
}

.cn-model-card h3 {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 23px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--dt-ink);
  margin: 0 0 16px;
}

.cn-model-best {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dt-red);
  margin-bottom: 8px;
}

/* flex:1 on the copy pushes every card's link to the same baseline, so a short and a long
   description still line their CTAs up across the row. */
.cn-model-card p {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--dt-muted);
  margin: 0 0 24px;
  flex: 1;
}

.cn-model-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--dt-ink);
  text-decoration: none;
}

.cn-model-link:hover,
.cn-model-link:focus-visible {
  color: var(--dt-red);
}

.cn-model-link .arr svg {
  width: 16px;
  height: 16px;
}

/* ==========================================================================
   20 CLOSING CTA BANNER
   ========================================================================== */
.cn-banner {
  padding: var(--dt-pad-y) 0;
  background: radial-gradient(120% 140% at 50% 0%, #10233b 0%, var(--cn-navy) 60%);
}

/* Optional cnb_bg_image override — flat dark tint (not the default radial gradient) so the
   white heading/copy stay readable over an arbitrary photo. */
.cn-banner--has-bg {
  position: relative;
  background: var(--cnb-bg) center/cover no-repeat;
}

.cn-banner--has-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(6, 9, 14, 0.72);
}

.cn-banner--has-bg .container {
  position: relative;
  z-index: 1;
}

.cn-banner-inner {
  max-width: 860px;
  margin: 0 auto;
  text-align: center;
}

.cn-banner-inner h2 {
  font-family: "Outfit", system-ui, sans-serif;
  font-size: clamp(32px, 4vw, 52px);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: #fff;
  margin: 0;
}

.cn-banner-inner p {
  font-size: 17.5px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.72);
  margin: 22px auto 0;
  max-width: 680px;
}

/* Lifted off the body colour, so the closing line reads as emphasis. Specificity is
   enough on its own - the prototype's !important is not needed here. */
.cn-banner-inner .cn-banner-sub {
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
}

.cn-banner-actions {
  margin-top: 34px;
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

.cn-banner-ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.3);
}

.cn-banner-ghost:hover,
.cn-banner-ghost:focus-visible {
  background: #fff;
  color: var(--dt-ink);
}

/* ── Motion, third group ─────────────────────────────────────────────────── */
@keyframes cnBuildLine {
  0% {
    height: 0;
  }
  85%,
  100% {
    height: calc(100% - 52px);
  }
}

@keyframes cnFillPulse {
  0%,
  100% {
    box-shadow: 0 0 10px rgba(236, 28, 36, 0.5);
  }
  50% {
    box-shadow: 0 0 16px rgba(236, 28, 36, 0.85);
  }
}

@keyframes cnHammerMove {
  0% {
    top: 0;
  }
  85%,
  100% {
    top: calc(100% - 90px);
  }
}

@keyframes cnHammerTap {
  0%,
  100% {
    transform: rotate(-16deg) translateY(-2px);
  }
  50% {
    transform: rotate(4deg) translateY(2px);
  }
}

@keyframes cnNodeLight {
  0% {
    background: #fff;
    border-color: var(--dt-line);
    color: var(--dt-ink);
    box-shadow: 0 0 0 6px #fff;
  }
  3%,
  100% {
    background: var(--dt-red);
    border-color: var(--dt-red);
    color: #fff;
    box-shadow: 0 8px 18px -6px rgba(236, 28, 36, 0.55), 0 0 0 6px #fff;
  }
}

/* ── Late additions: elements the prototype styled but never rendered ────── */

/* Section CTA under the case deck. Optional, so it only ever appears when filled. */
.cn-cases-cta {
  margin-top: 40px;
  text-align: center;
}

.cn-cases-cta .arr svg {
  width: 17px;
  height: 17px;
}

/* Hand-off line after the process rail. */
.cn-proc-note {
  margin-top: 40px;
  text-align: center;
  font-size: 15px;
  color: var(--dt-muted);
}

/* The Clutch rating line under the review carousel. */
.cn-rev-rating {
  margin: 28px 0 0;
  text-align: center;
  font-size: 14.5px;
  color: var(--dt-muted);
}

.cn-rev-rating a {
  color: var(--dt-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cn-rev-rating a:hover,
.cn-rev-rating a:focus-visible {
  color: var(--dt-red);
}

.page-slug-construction-software-development-v2 .so-cmp2-head.lbl span {
    display: none;
}

.page-slug-construction-software-development-v2 a.dt-btn.dt-btn-primary:focus {
    color: white;
} 

.page-slug-construction-erp-software .art-pe-reviews .art-pe-rv-flag:nth-child(4) {
    display: none;
}

/* ==========================================================================
   RESPONSIVE
   One block per breakpoint, and they sit last in the file on purpose: a max-width
   rule has the same specificity as the base rule it overrides, so source order is
   what makes it win. Widest first, so narrower breakpoints override wider ones.
   ========================================================================== */

/* components.css's own .case-deck/.case-card already switch to natural, stacked-flow height at
   this exact breakpoint (height:auto, position:relative) — but .cn-cases-sec's own more-specific
   desktop height overrides below (unconditional) still win over that shared reset at any width,
   so without cancelling them here the cards keep the fixed desktop height and overflow into
   cn_roofing right after them once a card's wrapped text needs more room than that. */
@media (max-width: 1280px) {
  .cn-cases-sec .case-deck {
    height: auto;
  }
  .cn-cases-sec .case-card {
    height: auto;
  }
}

/* .dt-hero-content keeps its desktop max-width:600px here and just stretches edge-to-edge once
   components.css drops the hero grid to one column at this same breakpoint — never given a
   width/centering rule of its own for that state. */
@media (max-width: 1024px) {
  .cn-hero .dt-hero-content {
    max-width: 90%;
    margin: 0 auto;
    text-align: center;
  }
  /* text-align:center above only centers inline content — .dt-hero-points/.dt-hero-actions are
     flex containers whose rows stretch to the full (now-centered) content width and left-align
     their own icon+text/buttons inside that, which read as left-aligned against the centered
     heading/paragraph above them. Shrink the checklist to its own widest row and centre that one
     block (keeps every row's icon lined up in a straight column); centre the button row directly
     since it doesn't need the same width-shrink trick. */
  .cn-hero .dt-hero-points {
    width: fit-content;
    margin: 30px auto 0;
  }
  /* Inherited text-align:center re-centres each wrapped line inside a bullet's own text run,
     so a 2-line bullet loses its left edge against the icon on the second line. The row's icon
     already anchors the left edge (flex, align-items:center) — text just needs to read normally
     against it, the surrounding block handles the centering. */
  .cn-hero .dt-hero-point {
    text-align: left;
  }
  .cn-hero .dt-hero-actions {
    justify-content: center;
  }
  .cn-hero .dt-hero-lead {
    margin: auto;
    margin-top: 20px;
  }
  .cn-hero .dt-hero-grid-layout {
    padding: 10px 10px 30px 10px;
  }
}

@media (max-width: 980px) {
  .cn-ai-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .cn-ai-viz {
    grid-template-columns: 1fr 1fr;
  }
  .cn-ai-donut:nth-child(2n) {
    border-right: none;
  }
}

@media (max-width: 960px) {
  .cn-answer-oneline {
    flex-wrap: wrap;
    gap: 10px 14px;
    padding: 24px 0;
  }
  .cn-answer-q {
    white-space: normal;
  }
}

@media (max-width: 900px) {
  /* Same fixed-count logic as the base rule, just fewer per row so 6 148px+ chips don't
     force horizontal overflow at this width. Still every tab, same count and size. */
  .cn-stack-chip {
    flex-basis: calc((100% - 2 * 20px) / 3);
  }
  /* Tech stack's 6-per-row base override (above) has the same specificity, so it needs
     repeating here to actually drop to 3 per row at this width instead of overflowing. */
  .cn-stack-sec .cn-stack-chip {
    flex-basis: calc((100% - 2 * 20px) / 3);
  }
  .cn-trust-bento {
    flex-direction: column;
  }
  /* .cn-trust-bento just became a column, so A and the right group are now stacked on the
     vertical axis instead of side by side — flex-basis: auto so they size from content
     instead of collapsing (see the note on the base rules). */
  .cn-trust-a,
  .cn-trust-right {
    flex-basis: auto;
  }
  .cn-trust-a {
    flex-direction: row;
  }
  .cn-trust-a .cn-trust-photo {
    flex: 0 0 44%;
    min-height: 240px;
  }
  .cn-trust-a .cn-trust-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  /* Shrink-to-fit (base rule) leaves label and arrow bunched together — full width first so
     space-between has a row wide enough to actually distribute. */
  .cn-trust-cta {
    width: 100%;
    justify-content: space-between;
  }
  .cn-types-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .cn-abandon-list {
    grid-template-columns: repeat(2, 1fr);
  }
  .cn-rev-row {
    grid-template-columns: 1fr;
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
  }
  .cn-rev-card.is-l, .cn-rev-card.is-r {
    display: none;
  }
  .cn-rev-card.is-c {
    transform: none;
  }
  .cn-drivers-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 860px) {
  .cn-roof-grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  .cn-proc-layout {
    grid-template-columns: 1fr;
    gap: 40px;
  }
  .cn-proc-intro {
    position: static;
  }
  .cn-proc-intro .dt-h2 {
    text-align: left;
  }
  .cn-models-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 820px) {
  .cn-datacost-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .cn-datacost-tile:nth-child(2) {
    border-right: none;
  }
  .cn-datacost-tile:nth-child(1), .cn-datacost-tile:nth-child(2) {
    border-bottom: 1px solid var(--dt-line);
  }
}

@media (max-width: 720px) {
  .cn-ai-risk {
    flex-direction: column;
    gap: 14px;
  }
  .cn-eng {
    flex-direction: column;
    text-align: center;
    gap: 28px;
    padding: 44px 26px;
  }
  .cn-eng-qmark {
    position: static;
    display: block;
    margin-bottom: -18px;
  }
  .cn-eng-quote {
    padding-left: 0;
  }
  .cn-eng-foot {
    flex-direction: column;
  }
}

@media (max-width: 700px) {
  .cn-stack-panel {
    padding: 34px 22px 38px;
  }
}

@media (max-width: 560px) {
  .cn-stack-chip {
    flex-basis: calc((100% - 1 * 20px) / 2);
  }
  .cn-stack-sec .cn-stack-chip {
    flex-basis: calc((100% - 1 * 20px) / 2);
  }
  .cn-trust-top {
    flex-direction: column;
  }
  /* .cn-trust-top just became a column — B and C need flex-basis: auto for the same
     reason A does at 900px above. */
  .cn-trust-b,
  .cn-trust-c {
    flex-basis: auto;
  }
  .cn-trust-a {
    flex-direction: column;
    min-height: 0;
  }
  /* .cn-trust-card.cn-trust-d.dt-rev.in (base rule, unconditional) sets flex-direction:row at the
     same 4-class specificity — a plain .cn-trust-d selector here can never beat it, so this has to
     match that exact chain to actually win the tie via source order instead of silently losing to
     it, which is what was leaving this card's body flowed beside the photo and clipped invisible
     by the card's own overflow:hidden. */
  .cn-trust-card.cn-trust-d.dt-rev.in {
    flex-direction: column;
    min-height: 0;
  }
  .cn-trust-a .cn-trust-photo, .cn-trust-d .cn-trust-photo {
    flex: none;
    margin: 14px 14px 0;
    min-height: 200px;
  }
  /* Stacked photo-over-text now, not photo-beside-text, so the body no longer flex-grows
     to fill leftover row height and centre in it — that's what was pushing the copy down
     and leaving a blank gap under the photo. Top-aligned, sized to its own content. */
  .cn-trust-a .cn-trust-card-body,
  .cn-trust-d .cn-trust-card-body {
    flex: none;
    justify-content: flex-start;
  }
  .cn-trust-cta {
    width: 100%;
    justify-content: space-between;
  }
  .cn-types-grid {
    grid-template-columns: 1fr;
  }
  .cn-drivers-grid {
    grid-template-columns: 1fr;
  }
  .cn-hero .dt-hero-lead {
    font-size: 19px;
    max-width: 100%;
    margin: auto;
    margin-top: 20px;
  }
}

@media (max-width: 520px) {
  .cn-abandon-list {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .cn-datacost-grid {
    grid-template-columns: 1fr;
  }
  .cn-datacost-tile {
    border-right: none;
    border-bottom: 1px solid var(--dt-line);
  }
  .cn-datacost-tile:last-child {
    border-bottom: none;
  }
  .cn-ai-grid {
    grid-template-columns: 1fr;
  }
  .cn-ai-viz {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cn-ai-donut.in .cn-ai-donut-ring {
    animation: none;
    --cn-a: var(--val);
  }
  .cn-ai-bar-fill {
    transform: scaleX(1);
  }
  .cn-ai-bars.in .cn-ai-bar-fill {
    animation: none;
  }
  .cn-proc-fill {
    animation: none;
    height: calc(100% - 52px);
  }
  .cn-proc-hammer {
    display: none;
  }
  .cn-proc-node {
    animation: none;
    background: var(--dt-red);
    border-color: var(--dt-red);
    color: #fff;
  }
}
