/* ==========================================================================
   DaybookPro — inner pages (About / Solutions / Contact)
   Extends assets/css/style.css — same tokens, same component language.
   Sections: 0 Page hero · 1 Stats · 2 Values · 3 Team · 4 Cards
   5 Solution blocks · 6 Contact · 7 FAQ · 8 Responsive
   ========================================================================== */

/* ---------- 0. Page hero -------------------------------------------------- */
.page-hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(460px, 34vw, 650px);
  padding-block: 64px;
  background-color: var(--navy);
  background-repeat: no-repeat;
  background-position: right center;
  background-size: auto 100%;
  overflow: hidden;
}
/* "auto 100%" (height-fit, width following the photo's own aspect ratio)
   is deliberate at normal desktop widths — it shows the hero photo
   uncropped rather than "cover"'s more aggressive crop. But past a point,
   a wide-enough viewport needs more width than a height-fit image actually
   has, so it stops reaching the hero's own left edge — the plain
   background-color (var(--navy)) shows through as a hard vertical seam
   past wherever the image happened to end, since .page-hero::before's
   gradient stops are fixed percentages of the *container*, not of
   wherever the image itself stops covering. "cover" guarantees the image
   always spans full width (and height) with no gap possible, at the cost
   of cropping more of the photo the wider the viewport gets — an easy
   trade at this width, where there's already far more image than the
   gradient leaves visible anyway. */
@media (min-width: 1600px) {
  .page-hero { background-size: cover; }
}

/* Each page gets its own hero image/crop so they don't all look identical */
.page-hero--about { background-image: url("../img/about-hero.png"); background-position: right center; }
.page-hero--solutions { background-image: url("../img/Solutions-hero.png"); background-position: right center; }
.page-hero--contact { background-image: url("../img/contact-hero.png"); background-position: right center; }
.page-hero--testimonials { background-image: url("../img/cta-truck.webp"); background-position: right center; }
/* Roadmap doesn't use a photo — a decorative route-line SVG is rendered
   into .page-hero__route instead (see hero-page/render.php) */
.page-hero--roadmap { background-image: none; }
.page-hero--roadmap::before { background: none; }
.page-hero__route { position: absolute; inset: 0; z-index: 0; opacity: .6; }
.page-hero__route svg { width: 100%; height: 100%; }

.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    var(--navy) 0%,
    var(--navy) 34%,
    rgba(1, 15, 32, calc(var(--hero-overlay, 1) * .92)) 48%,
    rgba(1, 15, 32, calc(var(--hero-overlay, 1) * .55)) 66%,
    rgba(1, 15, 32, calc(var(--hero-overlay, 1) * .15)) 88%
  );
}

.page-hero__inner { position: relative; z-index: 1; max-width: 640px; }

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: .82rem;
  color: rgba(255, 255, 255, .58);
  margin-bottom: 18px;
}
.breadcrumb a:hover { color: #fff; }

.page-hero__title {
  font-size: clamp(1.9rem, 3.2vw, 2.8rem);
  font-weight: 800;
  color: #fff;
  letter-spacing: -.015em;
  line-height: 1.16;
}

.page-hero__lead {
  margin-top: 18px;
  max-width: 54ch;
  font-size: clamp(.98rem, 1.02vw, 1.1rem);
  line-height: 1.62;
  color: rgba(255, 255, 255, .85);
}

/* ---------- shared section rhythm ----------------------------------------- */
.page-section { padding-block: clamp(52px, 5.5vw, 88px); }
.page-section--alt { background: var(--grey-bg); }

.page-section__head {
  max-width: 620px;
  margin-inline: auto;
  text-align: center;
  margin-bottom: 48px;
}
.page-section__head p {
  margin-top: 12px;
  font-size: 1rem;
  color: var(--ink-soft);
}

.solutions-intro {
  max-width: 820px;
  margin-inline: auto;
  text-align: center;
}
.solutions-intro p {
  color: var(--ink-soft);
  font-size: .98rem;
  line-height: 1.75;
  margin-bottom: 18px;
}
.solutions-intro p:last-child { margin-bottom: 0; }
/* Same list treatment as .story-body's — this block can now render real
   <ul> markup (see blocks/text-block/render.php's bullet conversion),
   but nothing here styled a list before since the block was only ever
   used for short intro paragraphs. Left-aligned regardless of the
   block's own paragraph alignment (which can be centered) — centered
   bullet text reads badly, wrapping lines drift toward the middle
   instead of lining up under the bullet. */
.solutions-intro ul, .solutions-intro ol {
  margin: 0 0 18px;
  padding-left: 22px;
  text-align: left;
  color: var(--ink-soft);
  font-size: .98rem;
  line-height: 1.75;
}
.solutions-intro ul:last-child, .solutions-intro ol:last-child { margin-bottom: 0; }
.solutions-intro li { margin-bottom: 10px; }
.solutions-intro ul { list-style: disc; }
.solutions-intro ol { list-style: decimal; }

.eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--red);
  margin-bottom: 8px;
}

/* ---------- 1. Stats ------------------------------------------------------ */
.stat-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  text-align: center;
}
.stat-row .stat b {
  display: block;
  font-family: var(--font-display);
  font-size: 2.15rem;
  font-weight: 800;
  color: var(--ink);
}
.stat-row .stat span { font-size: .86rem; color: var(--ink-soft); }

/* ---------- 2. Values ------------------------------------------------------ */
.value-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px 40px;
}
.value-list--cards { grid-template-columns: repeat(3, 1fr); }
.value-item { display: flex; gap: 18px; }
.value-item .num {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.5rem;
  color: var(--red);
  flex: none;
  line-height: 1.3;
}
.value-item h3 { font-size: 1.02rem; font-weight: 700; margin-bottom: 6px; }
.value-item p { font-size: .9rem; color: var(--ink-soft); line-height: 1.6; }

/* ---------- 3. Team --------------------------------------------------------- */
.team-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
}
.team-card { text-align: center; }
.team-card__avatar {
  width: 84px; height: 84px;
  border-radius: 50%;
  margin: 0 auto 14px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, var(--ink-soft), var(--navy));
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
}
.team-card h3 { font-size: .98rem; font-weight: 700; margin-bottom: 2px; }
.team-card span { font-size: .82rem; color: var(--ink-soft); }

/* ---------- 4. Cards -------------------------------------------------------- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(var(--cg-cols, 5), 1fr);
  gap: 18px;
}
.card-grid--9 { grid-template-columns: repeat(3, 1fr); }
.info-card {
  display: block;
  padding: 26px 20px;
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  text-align: left;
  transition: box-shadow .2s var(--ease), transform .2s var(--ease), border-color .2s var(--ease);
}
.info-card:hover {
  box-shadow: var(--shadow-card);
  transform: translateY(-3px);
  border-color: transparent;
}
.info-card .icon-badge { margin-bottom: 14px; }
.info-card--image { padding: 0; overflow: hidden; }
.info-card--image img { width: 100%; height: 100%; min-height: 220px; object-fit: cover; display: block; }
.icon-grid__top-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-bottom: 24px;
}
.icon-grid__top-item { grid-column: 2; }
@media (max-width: 860px) {
  .icon-grid__top-row { grid-template-columns: repeat(2, 1fr); }
  .icon-grid__top-item { grid-column: 1 / -1; } /* no true middle column at 2 across - span both instead */
}
@media (max-width: 560px) {
  .icon-grid__top-row { grid-template-columns: 1fr; }
  .icon-grid__top-item { grid-column: 1; }
}
.info-card h3 { font-size: .96rem; font-weight: 700; }

.icon-badge {
  display: grid;
  place-items: center;
  width: 50px; height: 50px;
  border-radius: 50%;
  background: var(--grey-bg);
  color: var(--ink);
}
.icon-badge svg { width: 24px; height: 24px; }
.icon-badge--accent { background: var(--pink); color: var(--red); }

/* ---------- 5. Solution blocks ---------------------------------------------- */
.solution-block {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
  padding-block: 56px;
}
.solution-block:not(:last-child) { border-bottom: 1px solid var(--hairline); }
.solution-block.is-reverse .solution-block__copy { order: 2; }
.solution-block.is-reverse .solution-block__visual { order: 1; }

.solution-block__tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: .76rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--red);
  margin-bottom: 12px;
}
.solution-block__copy h3 {
  font-size: clamp(1.3rem, 2.2vw, 1.7rem);
  font-weight: 800;
}
.solution-block__copy > p { margin-top: 14px; font-size: .95rem; line-height: 1.7; color: var(--ink-soft); }
.solution-block__description { margin-top: 14px; }
.solution-block__description p { font-size: .95rem; line-height: 1.7; color: var(--ink-soft); margin-bottom: 14px; }
.solution-block__description p:last-child { margin-bottom: 0; }

/* Optional heading above a bullet list (e.g. "Feature Breakdown" /
   "Business Benefits" when a Solution has two separately-labelled lists) —
   sits right above .solution-list, so its own top margin is what actually
   separates it from whatever came before (the description, or the first
   list when this is the second one); .solution-list's own top margin would
   otherwise double up the gap directly underneath it, so that's zeroed via
   the adjacent-sibling selector rather than editing .solution-list itself,
   which still needs its normal top margin when no heading precedes it. */
.solution-list__heading { font-size: .82rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ink); margin: 22px 0 0; }
.solution-list__heading + .solution-list { margin-top: 12px; }
.solution-list { margin: 20px 0 26px; display: flex; flex-direction: column; gap: 11px; }
.solution-list li { display: flex; gap: 10px; align-items: flex-start; font-size: .92rem; }
.solution-list li svg { width: 16px; height: 16px; color: var(--red); margin-top: 4px; flex: none; }

.solution-block__visual {
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-card);
  background: linear-gradient(155deg, var(--navy) 0%, #132038 60%, var(--ink) 100%);
  display: flex; align-items: center; justify-content: center;
  position: relative;
  overflow: hidden;
}
.solution-block__visual::before {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(circle at 25% 20%, var(--red-tint-28), transparent 55%);
}
.solution-block__visual svg { width: 58%; height: auto; position: relative; z-index: 1; }
.solution-block__visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  position: relative;
  z-index: 1;
}

/* Placeholder state — used until a real photo is supplied */
.solution-block__visual--placeholder { background: var(--grey-bg); }
.solution-block__visual--placeholder::before { display: none; }
.visual-placeholder {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 100%;
  color: var(--ink-soft);
  border: 2px dashed var(--hairline);
  border-radius: var(--radius-card);
  justify-content: center;
}
.visual-placeholder svg { width: 34px; height: 34px; opacity: .7; }
.visual-placeholder span {
  font-family: var(--font-display);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* ---------- 6. Contact ------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: 44px;
  align-items: flex-start;
}

.contact-panel {
  background: var(--ink);
  color: #fff;
  border-radius: var(--radius-card);
  padding: 34px;
  position: sticky;
  top: calc(var(--header-h) + 24px);
}
.contact-panel h2 { color: #fff; font-size: 1.2rem; }
.contact-panel > p { margin-top: 10px; font-size: .9rem; color: rgba(255, 255, 255, .65); }

.contact-panel__list { margin-top: 28px; display: flex; flex-direction: column; gap: 20px; }
.contact-panel__list li { display: flex; gap: 14px; align-items: flex-start; }
.contact-panel__list .icon-badge { background: var(--red-tint-16); color: var(--red); width: 42px; height: 42px; flex: none; }
.contact-panel__list .icon-badge svg { width: 18px; height: 18px; }
.contact-panel__list b { display: block; font-size: .9rem; }
.contact-panel__list span { font-size: .84rem; color: rgba(255, 255, 255, .62); }
.contact-panel__list span a { color: inherit; transition: color .15s var(--ease); }
.contact-panel__list span a:hover { color: #fff; }

.form-card {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 34px;
}
.form-card h2 { font-size: 1.15rem; }
.form-card__lead { margin-top: 6px; font-size: .9rem; color: var(--ink-soft); margin-bottom: 26px; }

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { margin-bottom: 18px; }
.field label {
  display: block;
  font-family: var(--font-display);
  font-size: .84rem;
  font-weight: 700;
  margin-bottom: 7px;
  color: var(--ink);
}
.field input, .field select, .field textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1.5px solid var(--hairline);
  font-family: var(--font-body);
  font-size: .92rem;
  background: var(--grey-bg);
  transition: border-color .15s var(--ease), background-color .15s var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--red);
  background: #fff;
}
.field textarea { resize: vertical; min-height: 120px; }

.form-note { font-size: .8rem; color: var(--ink-soft); margin-top: 6px; }

.form-success {
  display: none;
  align-items: center;
  gap: 10px;
  background: #ecfdf3;
  color: #067647;
  border: 1px solid #abefc6;
  padding: 14px 16px;
  border-radius: var(--radius);
  font-size: .9rem;
  font-weight: 700;
  margin-top: 16px;
}
.form-success.is-visible { display: flex; }
.form-success svg { width: 18px; height: 18px; flex: none; }

/* ---------- 7. FAQ ------------------------------------------------------------ */
.faq-list { max-width: 760px; margin-inline: auto; }
.faq-item { border-bottom: 1px solid var(--hairline); padding-block: 20px; }
.faq-item__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--ink);
}
.faq-item__q svg { width: 18px; height: 18px; flex: none; color: var(--red); transition: transform .2s var(--ease); }
.faq-item.is-open .faq-item__q svg { transform: rotate(45deg); }
.faq-item__a { max-height: 0; overflow: hidden; transition: max-height .25s var(--ease); }
.faq-item__a-inner { padding-top: 12px; font-size: .92rem; line-height: 1.65; color: var(--ink-soft); }

/* ---------- 9. Testimonial detail pages ------------------------------------ */
.story-rating { color: var(--red); font-size: 1.3rem; letter-spacing: 3px; }
.story-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 16px;
  gap: 20px;
  margin-bottom: 40px;
  max-width: 720px;
  margin-inline: auto;
}
.story-head__group { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
/* flex-shrink is 0 (via "flex: none") on purpose — a company logo shouldn't
   get squashed thinner than its own configured width (up to 320px, set per
   testimonial via the Logo width slider). Without flex-wrap on .story-head
   above, that used to mean the logo just refused to shrink and pushed past
   the card's edge on narrow viewports instead; .story-head now wraps it
   onto its own line there instead of overflowing. */
.story-head__logo { flex: none; max-width: 100%; height: auto; object-fit: contain; }
.story-head__avatar {
  width: 72px; height: 72px;
  border-radius: 50%;
  flex: none;
  background: linear-gradient(150deg, var(--ink-soft), var(--navy));
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.3rem;
  overflow: hidden;
}
.story-head__avatar img { width: 100%; height: 100%; object-fit: cover; }
.story-head h2 { font-size: 1.4rem; margin-bottom: 2px; }
.story-head span { font-size: .9rem; color: var(--ink-soft); }

.story-quote {
  position: relative;
  background: var(--black);
  color: #fff;
  border-radius: var(--radius-card);
  padding: 40px 44px;
  margin-bottom: 40px;
  max-width: 720px;
  margin-inline: auto;
}
.story-quote__mark {
  font-family: var(--font-display);
  font-size: 5.5rem;
  font-weight: 700;
  color: rgba(255, 255, 255, .4);
  line-height: 1;
  margin-bottom: -6px;
}
.story-quote p { font-size: 1.05rem; line-height: 1.6; color: rgba(255, 255, 255, .92); margin-bottom: 16px; }
.story-quote p.story-quote__lede { font-size: 1.3rem; font-weight: 700; line-height: 1.5; color: #fff; }
.story-quote p.story-quote__closing { font-style: italic; }
.story-quote__attribution { margin-top: 20px; }
.story-quote__attribution strong { display: block; font-size: .98rem; color: #fff; }
.story-quote__attribution span { display: block; font-size: .86rem; color: rgba(255, 255, 255, .7); margin-top: 2px; }

/* Stacked eyebrow + heading, centered — used by blocks like Story Quote
   where the eyebrow and heading need to read as two clearly separate
   lines, unlike .roadmap-section__head which is a flex row for a
   pill-next-to-heading layout instead. */
.stacked-head { text-align: center; margin-bottom: 32px; }
.stacked-head .eyebrow { display: block; margin-bottom: 14px; }
.stacked-head h2 { margin: 0; }

/* Fixed 3-column card grid, used where a flexible auto-fit grid would
   produce an uneven row count (e.g. 6 items fitting 5-then-1 instead of
   a clean 3x2) at wide viewport widths. */
.grid-3col {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 860px) {
  .grid-3col { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .grid-3col { grid-template-columns: 1fr; }
}

/* Was max-width:720px — the same legacy narrow reading-column width used
   everywhere before the Overlap Card got its own Max Width control. The
   testimonial story page's width is now fixed at 1140px (matching the
   Overlap Card, which stays at 1140px on these pages), so any block
   added below the quote card lines up with it instead of the old narrow
   column. .story-nav below shares this same value so Back/Next stays
   aligned with it — keep both in sync if this ever changes. */
.story-body { max-width: 1140px; margin-inline: auto; }

/* Blocks like Platform Text and Stats, Icon Grid, Feature Card Grid etc.
   each carry their own top-level .page-section/.shell wrapping (built
   for being a full page section elsewhere on the site) — dropped into
   .story-body instead, that stacks its own padding-block on top of the
   surrounding .page-section's, and re-tries to cap .shell back up to
   1460px, wider than .story-body's own 1140px column. Same reasoning,
   same fix, as .overlap-card .page-section / .overlap-card .shell above
   — this is the .story-body equivalent so it applies to any such block
   landing here instead of just the Overlap Card.
   Their own "head" element (heading + lead text) is a separate, narrower
   readability cap on top of that (e.g. .platform-stats__head below,
   680px) — deliberate everywhere else these blocks are used as a full
   top-level section, but on this already-1140px-capped column it just
   reads as yet another restriction. Widened per block, here, as each
   one gets used on this page and reported — not blown open wholesale,
   since some of these "head" widths are sized against an image sitting
   next to them (Tech Banner, Featured Banner, Text Checklist + Image
   Split, Icon Intro Split), where forcing the text column wider would
   throw off the split instead of fixing anything. */
.story-body .page-section { padding-block: 28px; }
.story-body .shell { max-width: none; }
.story-body .platform-stats__head { max-width: none; }

.story-body p { color: var(--ink-soft); font-size: .98rem; line-height: 1.75; margin-bottom: 18px; }
.story-body strong, .story-body b { color: var(--ink); font-weight: 700; }
.story-body h2, .story-body h3, .story-body h4 {
  color: var(--ink);
  font-weight: 700;
  margin: 32px 0 14px;
  line-height: 1.35;
}
.story-body h2 { font-size: 1.3rem; }
.story-body h3 { font-size: 1.12rem; }
.story-body h4 { font-size: 1rem; }
.story-body ul, .story-body ol {
  margin: 0 0 18px;
  padding-left: 22px;
  color: var(--ink-soft);
  font-size: .98rem;
  line-height: 1.75;
}
.story-body li { margin-bottom: 10px; }
.story-body ul { list-style: disc; }
.story-body ol { list-style: decimal; }
.story-body a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }
.story-body .placeholder-note {
  display: inline-block;
  margin-top: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--pink);
  color: var(--red);
  font-family: var(--font-display);
  font-size: .76rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.story-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .92rem;
  color: var(--ink);
}
.story-back svg { width: 16px; height: 10px; transform: scaleX(-1); }
.story-back:hover { color: var(--red); }

.story-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 32px;
  max-width: 1140px; /* kept in sync with .story-body above */
  margin-inline: auto;
}
.story-next {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .92rem;
  color: var(--ink);
}
.story-next svg { width: 16px; height: 10px; }
.story-next:hover { color: var(--red); }


/* ---------- 10. Responsive ------------------------------------------------------ */
@media (max-width: 1080px) {
  .page-hero { background-size: cover; padding-block: 48px; }
  .page-hero::before {
    background: linear-gradient(90deg, rgba(1,15,32,.97) 0%, rgba(1,15,32,.88) 55%, rgba(1,15,32,.5) 100%);
  }
  .card-grid { grid-template-columns: repeat(3, 1fr); }
  .contact-grid { grid-template-columns: 1fr; }
  .contact-panel { position: static; }
}

@media (max-width: 860px) {
  .story-quote { padding: 28px 26px; }
  .stat-row { grid-template-columns: repeat(2, 1fr); gap: 30px; }
  .value-list { grid-template-columns: 1fr; }
  .team-grid { grid-template-columns: repeat(2, 1fr); }
  .card-grid { grid-template-columns: repeat(2, 1fr); }
  .solution-block { grid-template-columns: 1fr; padding-block: 40px; gap: 28px; }
  .solution-block.is-reverse .solution-block__copy { order: 1; }
  .solution-block.is-reverse .solution-block__visual { order: 2; }
  .form-row { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .stat-row { grid-template-columns: 1fr 1fr; }
  .team-grid { grid-template-columns: 1fr 1fr; }
  .card-grid { grid-template-columns: 1fr; }
  .story-head { justify-content: center; text-align: center; }
  .story-head__logo { max-width: 150px; }
}

/* ---------- Roadmap blocks (dbp/roadmap-section, dbp/roadmap-timeline) -- */
.roadmap-section { padding-block: 40px; }
.roadmap-section + .roadmap-section { border-top: 1px solid var(--hairline); }

.roadmap-section__head {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 32px;
}
.roadmap-section__head h2 { margin: 0; }
.roadmap-section__head p {
  flex-basis: 100%;
  margin: 4px 0 0;
  color: var(--ink-soft);
  font-size: .94rem;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 14px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
}
.status-pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.status-pill--shipped { background: color-mix(in srgb, #1a9c5c 15%, white); color: #178c53; }
.status-pill--progress { background: var(--pink); color: var(--red); }
.status-pill--planned { background: var(--grey-bg); color: var(--ink-soft); border: 1px solid var(--hairline); }
.status-pill--horizon { background: color-mix(in srgb, var(--navy) 10%, white); color: var(--navy); }

.roadmap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 24px;
}

.roadmap-card__text {
  margin: 6px 0 0;
  color: var(--ink-soft);
  font-size: .92rem;
  line-height: 1.55;
}

.roadmap-card__status {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--hairline);
  font-family: var(--font-display);
  font-size: .78rem;
  font-weight: 700;
  color: var(--ink-soft);
}
.roadmap-card__status .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.roadmap-card__status .dot--shipped { background: #1a9c5c; }
.roadmap-card__status .dot--progress { background: var(--red); }
.roadmap-card__status .dot--planned { background: #9aa3ad; }
.roadmap-card__status .dot--horizon { background: var(--navy); }

/* "Horizon" cards get a dashed, more provisional-looking treatment, and
   their date shows as a standalone pill rather than the dot+text row the
   other three statuses use — both driven automatically by statusType, not
   a separate setting to configure. */
.roadmap-card--dashed {
  border-style: dashed;
  border-color: #d7dbe6;
  background: var(--grey-bg);
  box-shadow: none;
}
.roadmap-card--dashed:hover {
  border-color: var(--navy);
  box-shadow: none;
  transform: none;
}
.roadmap-card--dashed .icon-badge { background: color-mix(in srgb, var(--navy) 8%, white); color: var(--navy); }

.roadmap-card__pill {
  display: inline-block;
  margin-top: 16px;
  padding: 5px 12px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--navy) 10%, white);
  color: var(--navy);
  font-family: var(--font-display);
  font-size: .74rem;
  font-weight: 800;
}

@media (max-width: 560px) {
  .roadmap-grid { grid-template-columns: 1fr; }
}

/* ---------- Roadmap timeline (dbp/roadmap-timeline) ---------------------- */
.roadmap-timeline { position: relative; max-width: 820px; margin: 0 auto; }
.roadmap-timeline::before {
  content: "";
  position: absolute;
  left: 21px;
  top: 22px;
  bottom: 22px;
  width: 2px;
  background: var(--hairline);
}

.timeline-item { position: relative; display: flex; gap: 24px; padding-bottom: 32px; }
.timeline-item:last-child { padding-bottom: 0; }

.timeline-item__marker {
  position: relative;
  z-index: 1;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #1a9c5c;
  display: grid;
  place-items: center;
}
.timeline-item__marker svg { width: 18px; height: 18px; }

.timeline-item__card {
  flex: 1;
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  padding: 22px 24px;
}
.timeline-item__quarter {
  display: inline-block;
  margin-bottom: 10px;
  padding: 4px 11px;
  border-radius: 999px;
  background: var(--grey-bg);
  color: var(--ink-soft);
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 700;
}
.timeline-item__card h3 { font-size: 1.02rem; margin: 0 0 8px; }
.timeline-item__card p { margin: 0; color: var(--ink-soft); font-size: .92rem; line-height: 1.55; }

@media (max-width: 560px) {
  .roadmap-timeline::before { left: 17px; }
  .timeline-item { gap: 16px; }
  .timeline-item__marker { width: 36px; height: 36px; }
  .timeline-item__marker svg { width: 15px; height: 15px; }
}

/* ---------- Testimonials grid page ---------------------------------------- */
.testimonial-grid-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.testimonial-grid-card__logo {
  max-height: 48px;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  object-position: left center;
  margin-bottom: 20px;
}
.testimonial-grid-card__quote {
  color: var(--ink);
  font-size: .96rem;
  line-height: 1.6;
  margin-bottom: 20px;
  flex: 1;
}
.testimonial-grid-card__meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 16px;
  border-top: 1px solid var(--hairline);
  margin-bottom: 16px;
}
.testimonial-grid-card__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--red);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .88rem;
  white-space: nowrap;
}
.testimonial-grid-card__link svg { width: 15px; height: 9px; }
.testimonial-grid-card__meta-right { display: flex; align-items: center; gap: 8px; }
.testimonial-grid-card__year { font-size: .8rem; color: var(--ink-soft); white-space: nowrap; }
.testimonial-grid-card__author { display: flex; align-items: center; gap: 12px; }
.testimonial-grid-card__avatar {
  width: 44px; height: 44px;
  border-radius: 50%;
  flex: none;
  overflow: hidden;
  background: linear-gradient(150deg, var(--ink-soft), var(--navy));
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .82rem;
}
.testimonial-grid-card__avatar img { width: 100%; height: 100%; object-fit: cover; }
.testimonial-grid-card__author h4 { margin: 0; font-size: .94rem; }
.testimonial-grid-card__author span { font-size: .82rem; color: var(--ink-soft); }

/* ---------- Resources page: tab filter bar ------------------------------- */
.resource-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-bottom: 40px;
}
.resource-tab {
  font-family: var(--font-display);
  font-size: .92rem;
  font-weight: 700;
  color: var(--ink);
  background: none;
  border: none;
  padding: 12px 22px;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}
.resource-tab:hover { background: var(--grey-bg); }
.resource-tab.is-active { background: var(--red); color: #fff; }
.resource-tab.is-active:hover { background: var(--red); }

/* ---------- Resources page: category-accented cards ---------------------- */
.resource-card {
  position: relative;
  padding-top: 30px;
  overflow: hidden;
}
.resource-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 5px;
  background: var(--ink);
  border-radius: var(--radius-card) var(--radius-card) 0 0;
}
.resource-card--accent::before { background: var(--red); }
.resource-card--accent .resource-card__eyebrow { color: var(--red); }
.resource-card__eyebrow {
  display: block;
  font-family: var(--font-display);
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 10px;
}
.resource-card h3 { font-size: 1.08rem; margin-bottom: 8px; }
.resource-card__text { color: var(--ink-soft); font-size: .92rem; line-height: 1.6; margin-bottom: 16px; }
.resource-card__link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-display);
  font-size: .88rem;
  font-weight: 700;
  color: var(--red);
}
.resource-card__link svg { width: 16px; height: 10px; transition: transform .15s var(--ease); }
.resource-card:hover .resource-card__link svg { transform: translateX(3px); }

.resource-card.is-hidden { display: none; }
#resource-empty.hidden { display: none; }

@media (max-width: 640px) {
  .resource-tabs { gap: 6px; }
  .resource-tab { padding: 9px 16px; font-size: .85rem; }
}

/* ---------- Case study page ------------------------------------------------ */
.cs-hero-image { display: block; width: 100%; height: auto; max-height: 480px; object-fit: cover; }

.cs-byline { color: var(--ink-soft); font-size: .92rem; margin-top: 6px; margin-bottom: 32px; }
.cs-byline strong { color: var(--ink); }

.divided-row {
  display: grid;
  grid-template-columns: repeat(var(--dr-cols, 4), 1fr);
  background: #fff;
}
.divided-row .benefit { border-left: 1px solid var(--hairline); }
.divided-row .benefit:first-child { border-left: 0; }

.cs-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}
.cs-split--reverse .cs-split__text { order: 2; }
.cs-split--reverse .cs-split__media { order: 1; }
.cs-split__media img { width: 100%; height: auto; border-radius: var(--radius-card); display: block; }
.cs-split__text h2 { margin-bottom: 14px; }
.cs-split__text p { color: var(--ink-soft); font-size: .96rem; line-height: 1.7; margin-bottom: 14px; }

.cs-download {
  position: relative;
  background: linear-gradient(120deg, var(--navy), #0d2440);
  background-size: cover;
  background-position: center;
  color: #fff;
  padding: 64px 24px;
  text-align: center;
  overflow: hidden;
}
.cs-download__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, rgba(1, 15, 32, .82), rgba(13, 36, 64, .7));
}
.cs-download--white.cs-download { background: #fff; color: var(--ink); }
.cs-download--white.cs-download h2 { color: var(--ink); }
.cs-download--white .cs-download-form button, .cs-download--white .cs-download-form__btn { background: var(--red); color: #fff; }
.cs-download--white .cs-download-form button:hover, .cs-download--white .cs-download-form__btn:hover { background: var(--red-dark); }
.cs-download--white .cs-download-form input[type="email"] { border: 1px solid var(--hairline); }
.cs-download h2 { color: #fff; margin-bottom: 28px; }
.cs-download-form {
  display: flex;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
  max-width: 480px;
  margin: 0 auto;
}
.cs-download-form input[type="email"] {
  flex: 1;
  min-width: 220px;
  padding: 13px 18px;
  border-radius: 999px;
  border: none;
  font-family: var(--font-body);
  font-size: .94rem;
}
.cs-download-form button, .cs-download-form__btn {
  flex: none;
  display: inline-block;
  padding: 13px 26px;
  border-radius: 999px;
  border: none;
  background: var(--ink);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .92rem;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .2s var(--ease);
}
.cs-download-form button:hover, .cs-download-form__btn:hover { background: var(--red); color: #fff; }
.cs-download-form__btn--standalone { margin-top: 28px; }

.cs-quote {
  text-align: center;
  max-width: 720px;
  margin: 0 auto;
}
.cs-quote__mark { font-family: var(--font-display); font-size: 2.6rem; font-weight: 700; color: var(--red); line-height: 1; margin-bottom: 12px; }
.cs-quote p { font-size: 1.1rem; line-height: 1.6; color: var(--ink); margin-bottom: 20px; }
.cs-quote strong { display: block; font-size: .96rem; color: var(--ink); }
.cs-quote span { font-size: .86rem; color: var(--ink-soft); }

.cs-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.cs-gallery img { width: 100%; height: 220px; object-fit: cover; border-radius: var(--radius-card); display: block; }

@media (max-width: 860px) {
  .divided-row { grid-template-columns: 1fr; }
  .divided-row .benefit { border-left: 0; border-top: 1px solid var(--hairline); }
  .divided-row .benefit:first-child { border-top: 0; }
  .cs-split { grid-template-columns: 1fr; gap: 28px; }
  .cs-split--reverse .cs-split__text { order: 1; }
  .cs-split--reverse .cs-split__media { order: 2; }
  .cs-gallery { grid-template-columns: 1fr; }
}

/* ---------- Platform Text and Stats block ---------------------------------- */
.platform-stats__head { max-width: 680px; margin-bottom: 44px; }
.platform-stats--photo {
  position: relative;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.platform-stats__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgba(0,0,0,.78) 35%, rgba(0,0,0,.4) 100%);
}
.platform-stats--photo .shell { position: relative; z-index: 1; }
.platform-stats--photo .section-title,
.platform-stats--photo .platform-stats__lead { color: #fff; }
.platform-stats--photo .text-red { color: var(--red); }
.platform-stats--photo .platform-stats__pill--lozenge {
  background: rgba(255, 255, 255, .1);
  border-color: rgba(255, 255, 255, .18);
  color: #fff;
}

.platform-stats__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ps-accent, var(--red));
  font-weight: 700;
  font-size: .92rem;
  margin-bottom: 14px;
}
.platform-stats__pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ps-accent, var(--red));
  flex: none;
}
.platform-stats__pill--lozenge {
  background: var(--grey-bg);
  border: 1px solid var(--hairline);
  padding: 6px 18px 6px 6px;
  border-radius: 999px;
  color: var(--ink);
  gap: 10px;
}
.platform-stats__pill--lozenge::before { content: none; } /* the icon badge replaces the dot */
.platform-stats__pill-icon {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--ps-accent, var(--red));
  color: #fff;
  display: grid;
  place-items: center;
}
.platform-stats__pill-icon svg, .platform-stats__pill-icon img { width: 14px; height: 14px; }
.platform-stats__lead { color: var(--ink-soft); font-size: 1rem; line-height: 1.6; margin-top: 12px; }

.platform-stats__grid {
  display: grid;
  grid-template-columns: repeat(var(--ps-cols, 4), 1fr);
  gap: 32px;
}
.platform-stats__item {
  text-align: center;
  padding: 24px 18px;
  border-radius: var(--radius-card);
  transition: box-shadow .2s var(--ease), transform .2s var(--ease);
}
.platform-stats__item:hover {
  box-shadow: var(--shadow-card);
  transform: translateY(-3px);
}
.platform-stats__item .icon-badge { margin: 0 auto 14px; }
.platform-stats__item h3 { font-size: 1rem; margin-bottom: 6px; }
.platform-stats__item p { font-size: .88rem; color: var(--ink-soft); line-height: 1.5; margin: 0; }

@media (max-width: 860px) {
  .platform-stats__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .platform-stats__grid { grid-template-columns: 1fr; }
}

/* ---------- Contact Hero block ---------------------------------------------- */
.contact-hero-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: 64px; align-items: start; }
/* The reused Contact Info Panel defaults to position:sticky for its
   original sidebar context — not wanted here, where it's just the right
   half of an ordinary two-column layout. */
.contact-hero-grid .contact-panel { position: static; }

.demo-benefits { display: flex; flex-direction: column; gap: 22px; margin-top: 32px; }
.demo-benefits li { display: flex; align-items: flex-start; gap: 14px; }
.demo-benefits__icon {
  flex: none;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  display: grid;
  place-items: center;
}
.demo-benefits__icon svg { width: 17px; height: 17px; }
.demo-benefits b { display: block; font-size: .98rem; }
.demo-benefits__text { display: block; font-size: .88rem; color: var(--ink-soft); margin-top: 2px; }

@media (max-width: 860px) {
  .contact-hero-grid { grid-template-columns: 1fr; gap: 40px; }
}

/* ---------- Direct Contact CTA block ----------------------------------------- */
.direct-contact { text-align: center; }
.direct-contact__actions { display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; margin-top: 28px; }
/* .btn--outline is shared with other blocks (its 999px pill shape is
   correct there, e.g. Tech Partnership Banner) - scoped override here
   instead of changing it globally, so this block's secondary button
   matches its own primary button's shape. */
.direct-contact__actions .btn--outline { border-radius: var(--radius); }
.btn--outline {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 13px 26px;
  border-radius: 999px;
  border: 1.5px solid var(--red);
  color: var(--red);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .94rem;
  background: #fff;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}
.btn--outline:hover { background: var(--red); color: #fff; }
.btn--outline svg { width: 16px; height: 16px; }

/* ---------- Stat Dashboard block --------------------------------------------- */
/* Base section/grid/number/label styling lives here; the glow icon badge and
   top "lip" gradient are further down, grouped with the shared glow CSS they
   reuse (search "Stat Dashboard glow badges"). */
.stat-dashboard__grid {
  display: grid;
  grid-template-columns: repeat(var(--sd-cols, 4), 1fr);
}
.stat-dashboard__item {
  text-align: center;
  padding-inline: 24px;
  border-left: 1px solid rgba(255, 255, 255, .14);
}
.stat-dashboard__item:first-child { border-left: 0; }
.stat-dashboard__number {
  font-family: var(--font-display);
  font-size: 2.2rem;
  font-weight: 800;
  color: #fff;
  line-height: 1;
  margin: 0;
}
.stat-dashboard__label { font-size: .92rem; color: rgba(255, 255, 255, .6); margin: 8px 0 0; }

@media (max-width: 860px) {
  .stat-dashboard__grid { grid-template-columns: 1fr 1fr; row-gap: 32px; }
  /* At 2 columns, the right-hand item in a row that also has a divider
     below it (i.e. not the last row) would otherwise have its vertical
     border-left run straight down into that horizontal border-bottom,
     visibly touching/crossing it at the corner. Swap the plain full-height
     border-left for a pseudo-element instead, so its length can be capped
     short of the bottom — leaving a clear gap above the horizontal line —
     without needing to touch the (also shared, full-height) desktop rule.
     The last row has no line below it to avoid, so it keeps a full-height
     divider via the second, more specific rule underneath. */
  .stat-dashboard__item { border-left: 0; position: relative; }
  .stat-dashboard__item:nth-child(2n)::before {
    content: ''; position: absolute; left: -1px; top: 0; bottom: 32px;
    width: 1px; background: rgba(255, 255, 255, .14);
  }
  .stat-dashboard__item:nth-child(2n):nth-last-child(-n+2)::before { bottom: 0; }
  /* The vertical dividers between columns are still meaningful in a 2-col
     layout, but dropping to 2 columns also creates a second *row* with no
     divider at all between it and the first — add a matching horizontal
     line under every item, then strip it back off the last row (the last
     2 items in DOM order, since there are 2 columns) so it doesn't dangle
     under the final row with nothing below it. */
  .stat-dashboard__item { padding-top: 36px; padding-bottom: 24px; border-bottom: 1px solid rgba(255, 255, 255, .14); }
  /* Row-gap already opens space above every row uniformly; adding padding-top
     here on top of that specifically widens the gap *below* each divider line
     (line-to-next-icon), while padding-bottom keeps the tighter, unchanged
     gap *above* it (label-to-line) — the line was sitting too close to the
     icon underneath it otherwise. First row has no line above it yet, so its
     own padding-top would just be dead space — stripped back off. */
  .stat-dashboard__item:nth-child(-n+2) { padding-top: 0; }
  .stat-dashboard__item:nth-last-child(-n+2) { border-bottom: 0; padding-bottom: 0; }
}
@media (max-width: 560px) {
  .stat-dashboard__grid { grid-template-columns: 1fr; row-gap: 28px; }
  /* Single column now, so "first row" is just the first item — the 860px
     rule above thinks in pairs (nth-child(-n+2)), which would wrongly also
     zero out the 2nd item's padding-top here even though it now sits under
     a divider of its own. Reset then re-strip it from just the true first. */
  .stat-dashboard__item { padding-top: 36px; }
  .stat-dashboard__item:first-child { padding-top: 0; }
  .stat-dashboard__item { border-left: 0; }
  /* Single column now, so "last row" is simply the last item. */
  .stat-dashboard__item:last-child { border-bottom: 0; padding-bottom: 0; }
}

/* ---------- Tech Partnership Banner block ------------------------------------ */
.tech-banner {
  position: relative;
  background-size: cover;
  background-position: center;
  background-color: var(--ink); /* fallback if no image is set yet */
  color: #fff;
  overflow: hidden;
}
.tech-banner__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgba(0,0,0,.8) 35%, rgba(0,0,0,.4) 100%);
}
.tech-banner__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
  padding-block: 80px;
}

.tech-banner__pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .16);
  padding: 6px 18px 6px 6px;
  border-radius: 999px;
  margin-bottom: 22px;
  font-size: .9rem;
  font-weight: 600;
}
.tech-banner__pill-icon {
  flex: none;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--tb-accent, var(--red));
  display: grid;
  place-items: center;
}
.tech-banner__pill-icon svg, .tech-banner__pill-icon img { width: 15px; height: 15px; }

.tech-banner__heading { font-size: clamp(1.6rem, 2.6vw, 2.1rem); font-weight: 800; line-height: 1.2; color: #fff; }
.tech-banner .text-red { color: var(--tb-accent, var(--red)); }
.tech-banner__lead { color: rgba(255, 255, 255, .78); font-size: .98rem; line-height: 1.65; margin-top: 16px; max-width: 480px; }

.tech-banner__logo { margin: 4px 0 18px; }
.tech-banner__logo img { max-height: 60px; width: auto; display: block; }

.tech-banner__icon-checklist { margin-top: 30px; display: flex; flex-direction: column; gap: 20px; }
.tech-banner__icon-checklist li { display: flex; align-items: flex-start; gap: 16px; }
.tech-banner__icon-checklist-icon {
  flex: none;
  width: 48px; height: 48px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .12);
  display: grid;
  place-items: center;
  color: var(--tb-accent, rgba(255, 255, 255, .85));
}
.tech-banner__icon-checklist-icon svg, .tech-banner__icon-checklist-icon img { width: 22px; height: 22px; }
.tech-banner__icon-checklist li strong { display: block; color: #fff; font-size: .98rem; margin-bottom: 4px; }
.tech-banner__icon-checklist-text { display: block; color: rgba(255, 255, 255, .65); font-size: .88rem; line-height: 1.5; }

.tech-banner__checklist { margin-top: 30px; display: flex; flex-direction: column; gap: 17px; }
.tech-banner__checklist li { display: flex; align-items: center; gap: 14px; font-size: .96rem; }
.tech-banner__check {
  flex: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--tb-accent, var(--red));
  display: grid;
  place-items: center;
}
.tech-banner__check svg { width: 10px; height: 10px; }

.tech-banner__quote {
  position: relative;
  border-radius: var(--radius-card);
  padding: 34px 38px;
}
.tech-banner__quote-mark { color: var(--tb-accent, var(--red)); font-family: var(--font-display); font-size: 2.4rem; font-weight: 700; line-height: 1; margin-bottom: 10px; }
.tech-banner__quote p { font-style: italic; font-size: 1.05rem; line-height: 1.6; color: rgba(255, 255, 255, .95); margin-bottom: 10px; }
.tech-banner__quote--light p { color: var(--ink-soft); }
.tech-banner__quote--light .tech-banner__quote-attribution strong { color: var(--ink); }
.tech-banner__quote--light .tech-banner__quote-role { color: var(--ink-soft); }
.tech-banner__quote-attribution { display: flex; align-items: center; gap: 14px; margin-top: 22px; }
.tech-banner__quote-avatar {
  flex: none;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--tb-accent, var(--red));
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .92rem;
  line-height: 1;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.tech-banner__quote-avatar img { width: 100%; height: 100%; object-fit: cover; }
.tech-banner__quote-attribution strong { display: block; font-size: .95rem; }
.tech-banner__quote-role { display: block; font-size: .84rem; color: rgba(255, 255, 255, .65); margin-top: 1px; }

@media (max-width: 900px) {
  .tech-banner__inner { grid-template-columns: 1fr; gap: 40px; padding-block: 56px; }
}

/* ---------- Icon Intro Split block ------------------------------------------- */
.icon-intro-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}
.icon-intro-split--reverse .icon-intro-split__text { order: 2; }
.icon-intro-split--reverse .icon-intro-split__media { order: 1; }
.icon-intro-split__icon {
  display: inline-grid;
  place-items: center;
  width: 52px; height: 52px;
  border-radius: 14px;
  background: var(--iis-accent, var(--red));
  color: #fff;
  margin-bottom: 18px;
}
.icon-intro-split__icon svg, .icon-intro-split__icon img { width: 26px; height: 26px; }
.icon-intro-split__text h2 { margin-bottom: 6px; }
.icon-intro-split__subheading { color: var(--iis-accent, var(--red)); font-weight: 700; font-size: .96rem; margin-bottom: 16px; }
.icon-intro-split__text p { color: var(--ink-soft); font-size: .96rem; line-height: 1.7; margin-bottom: 14px; }
.icon-intro-split__text p:last-child { margin-bottom: 0; }
.icon-intro-split__media img { width: 100%; height: auto; display: block; }

@media (max-width: 860px) {
  .icon-intro-split { grid-template-columns: 1fr; gap: 32px; }
  .icon-intro-split--reverse .icon-intro-split__text { order: 1; }
  .icon-intro-split--reverse .icon-intro-split__media { order: 2; }
}

/* ---------- Feature Card Grid block ------------------------------------------ */
.feature-card-grid__head { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; }
.feature-card-grid__head-icon { display: inline-flex; color: var(--fcg-accent, var(--red)); }
.feature-card-grid__head-icon svg, .feature-card-grid__head-icon img { width: 22px; height: 22px; }
.feature-card-grid__head h2 { font-size: 1.3rem; margin: 0; }

.feature-card-grid {
  display: grid;
  grid-template-columns: repeat(var(--fcg-cols, 3), 1fr);
  gap: 20px;
}
.feature-card-grid__item {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  padding: 24px;
}
.feature-card-grid__icon {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--fcg-accent, var(--red)) 14%, white);
  color: var(--fcg-accent, var(--red));
  margin-bottom: 14px;
}
.feature-card-grid__icon svg, .feature-card-grid__icon img { width: 20px; height: 20px; }
.feature-card-grid__item h3 { font-size: 1rem; margin-bottom: 8px; }
.feature-card-grid__item p { font-size: .92rem; color: var(--ink-soft); line-height: 1.6; margin: 0; }
.feature-card-grid__status {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  font-weight: 700;
  font-size: .88rem;
  color: var(--fcg-accent, var(--red));
}
.feature-card-grid__status-icon {
  flex: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--fcg-accent, var(--red));
  display: grid;
  place-items: center;
}
.feature-card-grid__status-icon svg { width: 10px; height: 10px; }

.feature-card-grid__item--featured { background: var(--fcg-accent, var(--red)); border-color: transparent; }
.feature-card-grid__item--featured h3, .feature-card-grid__item--featured p { color: #fff; }
.feature-card-grid__item--featured .feature-card-grid__icon { background: rgba(255, 255, 255, .2); color: #fff; }
.feature-card-grid__item--featured .feature-card-grid__status { color: #fff; }
.feature-card-grid__item--featured .feature-card-grid__status-icon { background: rgba(255, 255, 255, .25); }

@media (max-width: 860px) {
  .feature-card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .feature-card-grid { grid-template-columns: 1fr; }
}

/* ---------- Pill Checklist block ---------------------------------------------- */
.pill-checklist { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.pill-checklist--fixed {
  display: grid;
  grid-template-columns: repeat(var(--pc-max, 4), max-content);
  justify-content: center;
}
@media (max-width: 640px) {
  .pill-checklist--fixed { grid-template-columns: repeat(2, max-content); }
}
@media (max-width: 420px) {
  .pill-checklist--fixed { grid-template-columns: 1fr; justify-items: center; }
}
.pill-checklist__item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 10px 18px 10px 10px;
  font-size: .92rem;
  font-weight: 600;
  color: var(--ink);
}
.pill-checklist__check {
  flex: none;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--pc-accent, var(--red));
  display: grid;
  place-items: center;
}
.pill-checklist__check svg { width: 11px; height: 11px; }

/* ---------- Gradient Quote Band block ----------------------------------------- */
.gradient-quote-band { padding-block: 48px; }
.gradient-quote-band__inner { display: flex; align-items: center; gap: 28px; }
.gradient-quote-band__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  border-radius: 50%;
  background: #fff;
  color: var(--ink);
}
.gradient-quote-band__icon svg, .gradient-quote-band__icon img { width: 26px; height: 26px; }
.gradient-quote-band__text p {
  color: #fff;
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1.45;
  margin-bottom: 10px;
}
.gradient-quote-band__text p:last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .gradient-quote-band__inner { flex-direction: column; align-items: flex-start; gap: 18px; }
  .gradient-quote-band__text p { font-size: 1.05rem; }
}

/* ---------- Overlap Card block ------------------------------------------------ */
.overlap-card-section { position: relative; z-index: 2; padding-bottom: clamp(40px, 5vw, 72px); }
.overlap-card {
  position: relative;
  padding: clamp(28px, 4vw, 48px);
  box-shadow: var(--shadow-card);
}
/* Blocks like Icon Intro Split, Feature Card Grid, Platform Text and
   Stats etc. each carry their own page-section/.shell wrapping, built
   for being a top-level page section — full padding-block (52-88px) and
   its own side gutters. Nested inside this card, that stacks on top of
   the card's own padding, producing exactly the oversized gaps and
   inconsistent widths this rule set is here to prevent. Neutralising
   both here means nested content sits flush with the card's own padding
   instead, and a single --oc-gap controls the space between whatever
   ends up stacked, rather than each block's own mismatched padding. */
.overlap-card .page-section { padding-block: 28px; }
.overlap-card .shell { max-width: none; }
.overlap-card > * + * { margin-top: var(--oc-gap, 40px); }
@media (max-width: 640px) {
  .overlap-card-section { padding-bottom: 32px; }
}
/* Root cause of "no bullets/spacing" when core WordPress blocks
   (Heading/Paragraph/List) are dragged straight into this card, as the
   block's own placeholder invites: this card never had ANY default
   typography of its own — it was only ever built and tested with a
   Pull Quote block inside, which brings its own classed styles. Drop a
   plain List block in instead and it inherits nothing but the theme's
   site-wide `ul { list-style: none; margin: 0; padding: 0; }` reset —
   bullets, indent, and item spacing all vanish, with nothing here to
   re-enable them, while headings/paragraphs/bold text still looked
   basically fine because the theme's generic element styles cover
   those. :where() keeps all of this at zero specificity, so anything
   more specific already styling its own elements in here — Pull
   Quote's .story-quote__lede etc. — is completely unaffected and
   always wins; these are pure fallback defaults. No margin-top/bottom
   on the elements themselves — .overlap-card > * + * above already
   spaces top-level blocks apart via --oc-gap, so adding it here too
   would double up the gap between e.g. a Heading block and the
   Paragraph after it. */
:where(.overlap-card) p { color: var(--ink-soft); font-size: .98rem; line-height: 1.75; }
:where(.overlap-card) strong, :where(.overlap-card) b { color: var(--ink); font-weight: 700; }
:where(.overlap-card) h2, :where(.overlap-card) h3, :where(.overlap-card) h4 { color: var(--ink); font-weight: 700; line-height: 1.35; }
:where(.overlap-card) h2 { font-size: 1.3rem; }
:where(.overlap-card) h3 { font-size: 1.12rem; }
:where(.overlap-card) h4 { font-size: 1rem; }
:where(.overlap-card) ul, :where(.overlap-card) ol { padding-left: 22px; color: var(--ink-soft); font-size: .98rem; line-height: 1.75; }
:where(.overlap-card) li { margin-bottom: 10px; }
:where(.overlap-card) li:last-child { margin-bottom: 0; }
:where(.overlap-card) ul { list-style: disc; }
:where(.overlap-card) ol { list-style: decimal; }
:where(.overlap-card) a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- Text Checklist + Image Split block -------------------------------- */
.tcis { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.tcis--reverse .tcis__text { order: 2; }
.tcis--reverse .tcis__media { order: 1; }
.tcis .eyebrow { color: var(--tcis-accent, var(--red)); }
.tcis .text-red { color: var(--tcis-accent, var(--red)); }
.tcis__lead { color: var(--ink-soft); font-size: 1rem; line-height: 1.7; margin-bottom: 8px; }

.tcis__checklist { margin: 24px 0; display: flex; flex-direction: column; gap: 16px; }
.tcis__checklist li { display: flex; align-items: center; gap: 14px; }
.tcis__check { flex: none; border-radius: 50%; background: var(--tcis-accent, var(--red)); display: grid; place-items: center; }
.tcis__checklist--big .tcis__check { width: 32px; height: 32px; box-shadow: 0 4px 12px -2px rgba(0, 0, 0, .25); }
.tcis__checklist--big .tcis__check svg { width: 15px; height: 15px; }
.tcis__checklist--small .tcis__check { width: 20px; height: 20px; }
.tcis__checklist--small .tcis__check svg { width: 10px; height: 10px; }

/* .tech-banner__icon-checklist is reused directly for its structure, but
   it assumes a dark banner background (white text, translucent-white
   icon badges) - this block typically sits on a light background, so
   override those specifically here rather than changing the shared
   tech-banner styles themselves. */
.tcis__icon-checklist .tech-banner__icon-checklist-icon {
  background: color-mix(in srgb, var(--tcis-accent, var(--red)) 14%, white);
  border: none;
  color: var(--tcis-accent, var(--red));
}
.tcis__icon-checklist li strong { color: var(--ink); }
.tcis__icon-checklist .tech-banner__icon-checklist-text { color: var(--ink-soft); }

.tcis__actions { display: flex; gap: 14px; flex-wrap: wrap; }
/* .btn--outline is shared with other blocks (its 999px pill shape is
   correct there) - scoped overrides here instead of changing it globally,
   so this block's secondary button matches its own primary button's
   shape, and both pick up this block's own accent colour. */
.tcis__actions .btn--primary { background: var(--tcis-accent, var(--red)); }
.tcis__actions .btn--primary:hover { filter: brightness(0.9); }
.tcis__actions .btn--outline {
  border-radius: var(--radius);
  border-color: var(--tcis-accent, var(--red));
  color: var(--tcis-accent, var(--red));
}
.tcis__actions .btn--outline:hover { background: var(--tcis-accent, var(--red)); color: #fff; }

.tcis__media { position: relative; }
.tcis__media img { width: 100%; height: auto; border-radius: var(--radius-card); display: block; }

.tcis__stat {
  position: absolute;
  left: 24px; bottom: -24px;
  background: #fff;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 16px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.tcis__stat-icon { flex: none; color: var(--ink); }
.tcis__stat-icon svg, .tcis__stat-icon img { width: 22px; height: 22px; }
.tcis__stat strong { display: block; font-family: var(--font-display); font-size: 1.4rem; font-weight: 800; color: var(--ink); line-height: 1; }
.tcis__stat span { display: block; font-size: .85rem; color: var(--ink-soft); margin-top: 4px; }

@media (max-width: 860px) {
  .tcis { grid-template-columns: 1fr; gap: 32px; }
  .tcis--reverse .tcis__text { order: 1; }
  .tcis--reverse .tcis__media { order: 2; }
  .tcis__stat { position: static; margin-top: 16px; }
}

/* ---------- Customer Stats Grid block ------------------------------------------ */
.customer-stats-grid {
  display: grid;
  grid-template-columns: repeat(var(--csg-cols, 4), 1fr);
  gap: 24px;
}
.customer-stats-grid__item { padding: 28px 24px; text-align: center; }
.customer-stats-grid__item--featured {
  background: #fff;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.customer-stats-grid__icon {
  display: inline-grid;
  place-items: center;
  width: 56px; height: 56px;
  border-radius: 14px;
  background: var(--ink-soft);
  color: #fff;
  margin-bottom: 16px;
}
.customer-stats-grid__icon svg, .customer-stats-grid__icon img { width: 26px; height: 26px; }
.customer-stats-grid__icon--accent { background: var(--csg-accent, var(--red)); }
.customer-stats-grid__name { display: block; font-size: 1.05rem; }
.customer-stats-grid__role { display: block; font-size: .85rem; color: var(--ink-soft); margin-top: 2px; margin-bottom: 14px; }
.customer-stats-grid__stat {
  font-family: var(--font-display);
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--csg-accent, var(--red));
  margin: 0;
  line-height: 1;
}
.customer-stats-grid__stat-label { display: block; font-size: .88rem; color: var(--ink-soft); margin-top: 6px; margin-bottom: 14px; }
.customer-stats-grid__quote { font-style: italic; font-size: .9rem; color: var(--ink-soft); line-height: 1.5; margin: 0; }

@media (max-width: 860px) {
  .customer-stats-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .customer-stats-grid { grid-template-columns: 1fr; }
}

/* ---------- Testimonials Grid block -------------------------------------------- */
.testimonials-grid {
  display: grid;
  grid-template-columns: repeat(var(--tg-cols, 3), 1fr);
  gap: 24px;
}
@media (max-width: 860px) {
  .testimonials-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .testimonials-grid { grid-template-columns: 1fr; }
}

/* ---------- Featured Banner block ---------------------------------------------- */
/* Reuses .tech-banner's own overlay/pill/heading/lead/checklist classes
   directly (same section also carries the .tech-banner class) - only the
   inner layout (centered, single column, no quote) and a couple of
   Featured-Banner-specific pieces (plain pill text, logo) are new. */
.featured-banner__inner {
  position: relative;
  z-index: 1;
  text-align: center;
  max-width: 760px;
  margin-inline: auto;
}
.featured-banner__pill-plain {
  display: inline-block;
  color: var(--tb-accent, var(--red));
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  margin-bottom: 18px;
}
.featured-banner__logo { margin: 0 auto 24px; }
.featured-banner__logo img { width: 100%; height: auto; display: block; }
.featured-banner__heading { font-size: clamp(1.8rem, 3.2vw, 2.6rem); }
.featured-banner__lead { max-width: 560px; margin-inline: auto; }
.featured-banner__checklist { align-items: center; }
.featured-banner__checklist li { justify-content: center; }

/* ---------- Icon Grid: accent + photo background additions -------------------- */
.icon-grid-section .eyebrow { color: var(--ig-accent, var(--red)); }
.icon-grid-section .text-red { color: var(--ig-accent, var(--red)); }
/* .section-title already turns white automatically via the shared
   .platform-stats--photo rule (reused directly, not duplicated) - the
   lead paragraph has no equivalent shared class to hook into here, so
   it's covered explicitly instead, unless a textColor override already
   set an inline colour on it. */
.icon-grid-section.platform-stats--photo .stacked-head > p:not([style]) { color: rgba(255, 255, 255, .78); }

/* ---------- Icon Grid — Thumbnail block ----------------------------------------
   A separate block from Icon Grid (see its own block.json), not a variant of
   it — every card here always carries a photo, so this reuses .info-card's
   look (radius, border, shadow) rather than .info-card itself, since the
   layout underneath the padding is different enough (photo frame first,
   text padding starts partway down instead of at the top) to need its own
   rules rather than fighting .info-card's own padding/text spacing. */
.info-card--thumbnail {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
/* 15px inset on every side, so the white card shows as a frame around the
   photo instead of the photo running flush to the card's own edges.
   aspect-ratio keeps every photo at the same 3:2 (600x400) shape regardless
   of the column's actual rendered width, whatever the uploaded photo's own
   dimensions — object-fit: cover crops to fit rather than stretching. The
   frame is what clips the hover-zoom below (overflow: hidden + its own
   border-radius matching the card's) — the zoom lives on the photo one
   level in, so it can scale past the frame's inner edge without spilling
   out past the rounded corners. */
.info-card--thumbnail__frame { padding: 15px; }
.info-card--thumbnail__clip {
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-card);
  overflow: hidden;
}
.info-card--thumbnail__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .45s var(--ease);
}
.info-card--thumbnail:hover .info-card--thumbnail__photo { transform: scale(1.06); }
.info-card--thumbnail__body { padding: 4px 20px 26px; }
.info-card--thumbnail .icon-badge { margin-bottom: 14px; }
.info-card--thumbnail h3 { margin: 0 0 8px; font-size: .98rem; font-weight: 700; color: var(--ink); }
.info-card--thumbnail p { margin: 0; font-size: .9rem; line-height: 1.6; color: var(--ink-soft); }

/* ---------- Icon Grid — Thumbnail (Glow) block --------------------------------
   Reuses .info-card--thumbnail's card (frame, clip, photo zoom, body/h3/p)
   as-is via the shared class — everything below is additive, scoped under
   the --glow modifier so the plain Icon Grid — Thumbnail block is untouched.

   Ported from DaybookPro v2's Feature Grid White block: the icon badge sits
   overlaid on the photo (bottom-left) rather than in the body, as a
   squircle rather than a circle, and both the spin ring and the card-hover
   glow use the fixed Huly duotone (--iris / --ember, defined in style.css)
   rather than this site's own red/navy accent toggle — deliberately not
   tied to it, so this block always renders the same regardless of which
   item has "Red accent" set. */
.info-card--thumbnail--glow .info-card--thumbnail__clip { position: relative; }

.info-card--thumbnail--glow:hover {
  border-color: color-mix(in srgb, var(--ember) 55%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--ember) 15%, transparent) inset, 0 0 20px color-mix(in srgb, var(--ember) 40%, transparent);
}

/* Dark wash on the photo so the icon square stands off it — a tight
   radial patch behind the icon (bottom-left, ~15% of the shot) plus a
   uniform tint over the whole image. */
.info-card--thumbnail__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(circle at 18% 82%, rgba(0,0,0,.75) 0%, rgba(0,0,0,0) 15%),
    linear-gradient(rgba(9,10,12,.4), rgba(9,10,12,.5));
}
.info-card--thumbnail__grid {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.14) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.14) 1px, transparent 1px);
  background-size: 24px 24px;
}

/* Icon badge — squircle, overlaid bottom-left on the photo. Combined-class
   selector so this reliably beats the plain single-class .icon-badge rule
   regardless of source order. Falls back to sitting in the body (relative,
   centred like the plain block) whenever there's no photo to sit on. */
/* --glow-a/--glow-b default to the site's standard iris/ember pair but can
   be overridden per-instance (e.g. inline on a specific block's wrapper) —
   every existing glow card keeps rendering identically since the fallback
   chain reproduces the old hardcoded colours exactly. */
.icon-badge.icon-badge--glow {
  position: absolute; left: 16px; bottom: 16px; z-index: 1;
  width: 56px; height: 56px; border-radius: 18px;
  padding: 1px; margin-bottom: 0; overflow: hidden; isolation: isolate;
  background: none;
  border: 1px solid color-mix(in srgb, var(--glow-a, var(--iris)) 40%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--glow-a, var(--iris)) 15%, transparent) inset, 0 0 20px color-mix(in srgb, var(--glow-a, var(--iris)) 35%, transparent);
}
.info-card--thumbnail__body .icon-badge.icon-badge--glow {
  position: relative; left: auto; bottom: auto; margin-bottom: 14px;
}
.icon-badge__spin {
  content: '';
  position: absolute;
  inset: -70%;
  z-index: 0;
  pointer-events: none;
  background: conic-gradient(from 0deg,
    transparent 0deg, var(--glow-a, var(--iris)) 55deg, transparent 130deg,
    transparent 210deg, var(--glow-b, var(--ember)) 275deg, transparent 340deg, transparent 360deg);
  opacity: 0;
  animation: dbp-icon-spin 4s linear infinite;
  animation-play-state: paused;
  transition: opacity .4s var(--ease);
}
.info-card--thumbnail--glow:hover .icon-badge__spin { opacity: .9; animation-play-state: running; }
@keyframes dbp-icon-spin { to { transform: rotate(360deg); } }

.icon-badge__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border-radius: 17px;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--glow-a, var(--iris)) 55%, transparent), color-mix(in srgb, var(--navy) 50%, transparent) 75%),
    var(--navy);
  color: #fff;
}
.icon-badge__inner svg { width: 26px; height: 26px; }

/* ---------- Stat Dashboard glow badges (dbp/stat-dashboard) --------------------
   Reuses the .icon-badge--glow markup/CSS above (same square, ring and inner
   gradient as Icon Grid — Thumbnail (Glow)) but the ring runs continuously
   rather than waiting for a card hover — there's no "card" here to hover,
   just a stat sitting in a dark band, so the motion has to read as ambient. */
.stat-dashboard__icon { position: relative; display: inline-flex; margin-bottom: 18px; }
.stat-dashboard .icon-badge.icon-badge--glow { position: relative; left: auto; bottom: auto; }
.stat-dashboard .icon-badge__spin { opacity: .8; animation-play-state: running; }
.stat-dashboard .icon-badge__inner svg { width: 24px; height: 24px; }

/* The "lip" — a thin neon gradient band across the very top edge, so the
   section reads as its own distinct block instead of melting into a plain
   dark hero image sitting flush above it. --lip-a/--lip-b default to the
   same iris/ember pair as the icon glow, overridable independently via the
   block's own colour controls. */
.stat-dashboard { position: relative; background: var(--ink); padding-block: 56px; overflow: hidden; }
.stat-dashboard::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: var(--lip-height, 4px);
  background: linear-gradient(90deg, var(--lip-a, var(--iris)), var(--lip-b, var(--ember)));
  box-shadow: 0 0 24px 1px color-mix(in srgb, var(--lip-a, var(--iris)) 50%, transparent);
}

/* ---------- Customer Logos Carousel block -------------------------------------- */
/* overflow-x:clip + overflow-y:visible, not overflow:hidden, on both this and
   .logos-carousel__viewport below — still needed on the x-axis to stop the
   duplicated marquee track (double-width, for the seamless scroll loop) from
   widening the page, but plain "overflow: hidden" or "overflow-x: hidden"
   paired with "overflow-y: visible" both clip vertically too: per the CSS
   overflow spec, pairing a non-visible/non-clip value on one axis silently
   forces "visible" on the other axis to compute as "auto" instead, which
   still clips (confirmed in-browser via getComputedStyle — overflow-y read
   back as "auto", not "visible", and content was still cut off). "clip" is
   exempt from that forcing rule, so it's the only value that actually keeps
   the other axis unclipped. Needed because per-logo Vertical Position (see
   render.php) is a small transform:translateY() nudge, which — like the old
   Scale transform that caused the original crop bug — is paint-only and can
   still push a logo's visual box outside its own layout row at the extremes
   of its range. */
.logos-carousel { text-align: center; overflow-x: clip; overflow-y: visible; }

.logos-carousel__viewport {
  overflow-x: clip;
  overflow-y: visible;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.logos-carousel__track {
  display: flex;
  width: max-content;
  animation: logos-carousel-scroll var(--lc-speed, 30s) linear infinite;
}
.logos-carousel--reverse .logos-carousel__track { animation-direction: reverse; }
.logos-carousel:not(.logos-carousel--no-pause):hover .logos-carousel__track { animation-play-state: paused; }

.logos-carousel__group {
  display: flex;
  align-items: center;
  flex: none;
  gap: var(--lc-gap, 64px);
  padding-right: var(--lc-gap, 64px);
}
.logos-carousel__logo { display: block; flex: none; }
.logos-carousel__logo img {
  display: block;
  height: var(--lc-height, 40px);
  width: auto;
  max-width: none;
  object-fit: contain;
}
.logos-carousel--grayscale .logos-carousel__logo img {
  filter: grayscale(1);
  opacity: .55;
  transition: filter .2s var(--ease), opacity .2s var(--ease);
}
.logos-carousel--grayscale .logos-carousel__logo:hover img { filter: none; opacity: 1; }

@keyframes logos-carousel-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-100% / var(--lc-copies, 2))); }
}

@media (prefers-reduced-motion: reduce) {
  /* The global rule elsewhere forces animation-duration to .01ms, which
     would freeze this mid-loop at a near-random offset rather than a
     clean position. Explicitly settle it on the first logo set instead. */
  .logos-carousel__track { animation: none; transform: none; }
  /* The second group only exists to make the *animation* loop seamlessly -
     with no animation running, it serves no purpose and just looks like
     the logos are duplicated by mistake. */
  .logos-carousel__group[aria-hidden="true"] { display: none; }
}

/* ---------- Story Summary block (dbp/story-summary) ---------------------------- */
/* Its .shell (from the shared page-section wrapper) still carries the
   sitewide --gutter side padding even though .overlap-card .shell already
   zeroes out max-width — that's what was leaving these cards narrower than,
   and misaligned with, the Pull Quote card directly below them (which has
   no .shell at all, so it fills the overlap-card's own padding right up to
   its edge). Zeroing the gutter here too lines the two up. Scoped to this
   block's own section specifically, rather than to ".overlap-card .shell"
   generally, so it doesn't also widen every other .shell-based block that
   gets dragged into an Overlap Card elsewhere (e.g. the Roadmap page). */
.overlap-card .story-summary-section .shell { padding-inline: 0; }
/* Case Study Split gets the same treatment, but only when it's been dragged
   into an Overlap Card (the customer-story pages, alongside Pull Quote and
   Story Summary above) — scoped via its own .cs-split-section class rather
   than ".overlap-card .shell" generally, so its other, non-card placement
   (e.g. the standalone SpeedTech long-form case study page) keeps its
   original narrower, .shell-gutter-inset width untouched. */
.overlap-card .cs-split-section .shell { padding-inline: 0; }
.story-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.story-summary__card h3 { font-size: 1.05rem; font-weight: 700; color: var(--ink); margin-bottom: 18px; }
.story-summary__rows { display: flex; flex-direction: column; gap: 10px; }
.story-summary__row { display: flex; gap: 12px; font-size: .92rem; }
.story-summary__row dt { flex: 0 0 100px; font-weight: 600; color: var(--ink); }
.story-summary__row dd { margin: 0; color: var(--ink-soft); }
.story-summary__list { list-style: disc; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; }
.story-summary__list li { color: var(--ink-soft); font-size: .92rem; line-height: 1.6; }
.story-summary__list li strong, .story-summary__list li b { color: var(--ink); font-weight: 700; }
.story-summary__list li a { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 900px) {
  .story-summary { grid-template-columns: 1fr; }
}

/* ---------- Scroll Timeline block (dbp/timeline-scroll) ------------------------ */
/* The whole component sits at a fixed height (--ts-height, set inline per
   block instance); only .timeline-scroll__track scrolls internally, via its
   own overflow-y — the page itself never needs to be scroll-jacked to drive
   this. JS (assets/js/enhance.js) watches for an entry's top edge reaching
   the top of the track (where the year is pinned — see
   .timeline-scroll__year-col) and swaps .timeline-scroll__year's text to
   match, fading it between changes rather than snapping. Everything here
   still renders correctly with JS disabled — track just becomes an
   ordinary scrollable list, year stays on the first entry, .is-active
   marks the first dot. */
.timeline-scroll { position: relative; display: grid; grid-template-columns: 160px 1fr; gap: 48px; height: var(--ts-height, 560px); margin-top: 40px; }
/* Pinned at the top, matching .timeline-scroll__track's own top padding so
   the year lines up with wherever the "active" entry's top edge is — that's
   also literally where the trigger band in enhance.js sits, so this is the
   year the visitor is actually looking at, not just whatever's centred. */
.timeline-scroll__year-col { display: flex; align-items: flex-start; padding-top: 32px; }
.timeline-scroll__year {
  font-family: var(--font-display);
  font-size: 3rem;
  font-weight: 800;
  line-height: 1; /* a normal line-height leaves ~29px of space below the
    digits themselves, which read as the number "hanging" well above the
    dot/title row rather than sitting level with it — tight line-height
    keeps the glyphs themselves flush with padding-top, matching where the
    dot and title actually start. */
  color: var(--ink);
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.timeline-scroll__year.is-changing { opacity: 0; transform: translateY(-10px); }
/* Horizontal line from the year column across the grid gap up to the
   track's edge, right where the active dot sits (dot itself lives inside
   .timeline-scroll__track, which clips anything past its own edge, so this
   stops exactly there rather than needing to reach further and be hidden
   again — the effect reads as the line disappearing "behind" the dot).
   Box itself stays put at its full left:160px/width:49px footprint at all
   times — what animates is a scaleX transform, not width, so growth can be
   anchored at the *right* edge (transform-origin) without needing a fixed
   `right` value, which wouldn't track the dot correctly here anyway (the
   track column is 1fr, so the dot's x-position isn't a fixed distance from
   .timeline-scroll's own right edge the way it is from the left). Collapsed
   (scaleX(0)) it's a zero-width sliver sitting exactly at that right edge —
   at the dot — so growing out reads as the line emerging from behind the
   circle and extending left toward the year; shrinking reads as retreating
   back behind it. enhance.js toggles .is-linked on every scroll (hidden the
   instant it moves, whether or not that scroll actually reaches the next
   entry) and again once scrolling has been idle for a beat, so it's never
   shown mid-motion. top: 51px — see .timeline-scroll__entry's own
   padding-top below; the two are the same 8px shift for the same reason,
   keep them in sync. */
.timeline-scroll__connector {
  position: absolute; left: 160px; top: 55px;
  width: 49px; height: 2px;
  background: var(--ts-accent, var(--red));
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .25s var(--ease);
  pointer-events: none;
}
.timeline-scroll__connector.is-linked { transform: scaleX(1); }
@media (max-width: 640px) {
  .timeline-scroll__connector { left: 90px; width: 24px; }
}
.timeline-scroll__track {
  position: relative;
  height: 100%;
  overflow-y: auto;
  /* Bottom padding is deliberately huge, not symmetric with the top — it's
     scroll buffer, not visual spacing. Without enough room to keep
     scrolling after the last entry's own text ends, the track hits its
     max scrollTop before that entry's top can ever reach the trigger line
     the year label and scroll-snap are both keyed off (see enhance.js and
     scroll-padding-top below) — so the last one or two entries could never
     become "active" no matter how far you scrolled. Reserving close to a
     full track-height's worth of bottom padding guarantees enough travel
     for any last entry, regardless of how tall its own text happens to be. */
  padding: 32px 12px calc(var(--ts-height, 560px) - 100px) 40px;
  scrollbar-width: thin;
  /* Native scroll-snap does the "stop once aligned, a further scroll moves
     on" behaviour on its own — no JS needed for the snapping itself (the
     rAF scroll listener in enhance.js only drives the year/dot swap).
     scroll-padding-top shifts the snap point to match --top-offset below
     (kept in sync with enhance.js's own TOP_OFFSET) rather than snapping
     to the very top of the track, which would land 32px above the trigger
     line the year is actually keyed off. */
  scroll-snap-type: y mandatory;
  scroll-padding-top: 32px;
}
/* Purely a positioning context for .timeline-scroll__line below — no
   padding/sizing of its own, so it doesn't disturb the left-offset entries
   already get from .timeline-scroll__track's own padding-left. The reason
   it exists at all: .timeline-scroll__track has a *fixed* height (it's the
   scrolling viewport), so "top:0; bottom:0" on the line, positioned against
   track directly, only ever stretched to that fixed viewport height —
   correct-looking with 2-3 entries in view, but visibly cut short partway
   down a longer list. .inner has no set height of its own, so it sizes to
   its actual (much taller) content — all the stacked entries — and the
   line, positioned against *that*, now runs the full length instead. */
.timeline-scroll__inner { position: relative; }
/* left: -32px, not 8px — .timeline-scroll__inner sits 40px in from the
   track's own edge (it's a normal-flow child, so unlike an absolutely-
   positioned one it *does* get pushed over by track's own padding-left),
   but the dot's -39.5px is still measured against .timeline-scroll__entry,
   which only ever sat 0px into .inner. Landing the line back at the same
   absolute position as before (8px from track's own edge) now means
   8 - 40 = -32px from .inner's. */
.timeline-scroll__line { position: absolute; left: -32px; top: 0; bottom: 0; width: 1px; background: var(--hairline); }
/* padding-top: 8px pushes the title (normal flow) down to sit near the
   bottom of the year text — full year height is 48px (3rem, line-height:
   1), pulled back up 40px total from flush-with-the-bottom across two
   rounds of "still too far below the year" feedback. .timeline-scroll__dot's
   own "top" below needs
   the identical shift added by hand (see its own comment): an absolutely-
   positioned child's containing block is the ancestor's padding box, but
   that box's top edge sits at the ancestor's *border*, unmoved by the
   ancestor's own padding-top — only normal-flow content (the title) is
   actually pushed down by it, so dot and title don't move together for
   free here. scroll-snap-align and entries[i].offsetTop (enhance.js) are
   both untouched by this either way, since they key off the entry's
   border-box edge, which its own padding never moves. */
.timeline-scroll__entry { position: relative; padding-top: 12px; padding-bottom: 56px; scroll-snap-align: start; scroll-snap-stop: always; }
.timeline-scroll__entry:last-child { padding-bottom: 8px; }
/* left: -39.5px, not a round number — the dot's centre has to land exactly
   on .timeline-scroll__line's own centre (line sits at left:8px, 1px wide,
   so its centre is 8.5px from the track's edge; the entry box this dot is
   positioned against already starts 40px in via the track's own padding,
   so -39.5 is what closes that 8.5px gap for a 16px-wide dot). Any rounder
   number here visibly misses.
   top: 12px, not 4px — 4px was the dot's original offset when the title
   sat flush with the entry's own top; now that padding-top above pushes
   the title down 8px instead, the dot needs that same 8px added by hand
   to stay paired with it (padding doesn't move an absolute child's own
   reference point — see .timeline-scroll__entry's comment) — 4 + 8 = 12. */
.timeline-scroll__dot {
  position: absolute; left: -39.5px; top: 16px; z-index: 1;
  width: 16px; height: 16px; border-radius: 50%;
  border: 3px solid var(--ts-accent, var(--red));
  background: #fff;
  transition: background-color .25s var(--ease);
}
.timeline-scroll__entry.is-active .timeline-scroll__dot { background: var(--ts-accent, var(--red)); }
.timeline-scroll__title { font-size: 1.15rem; font-weight: 700; color: var(--ink); margin-bottom: 10px; }
.timeline-scroll__text { font-size: .95rem; line-height: 1.7; color: var(--ink-soft); }
@media (max-width: 640px) {
  .timeline-scroll { grid-template-columns: 90px 1fr; gap: 24px; height: min(var(--ts-height, 560px), 480px); }
  .timeline-scroll__year { font-size: 2rem; }
}
