/* ==========================================================================
   Kore: page & component styles (home, product template, industries, misc)
   ========================================================================== */

/* ==========================================================================
   HOME: hero
   ========================================================================== */
/* Centred, like every other hero on the site: copy, then the full shot. */
.home-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(44px, 5vw, 84px) 0 0;
  background: linear-gradient(180deg, #f7fbff 0%, #ffffff 44%);
  padding-bottom: 65px;
}
.home-hero__head {
  position: relative;
  z-index: 2;
  max-width: 900px;
  margin-inline: auto;
  text-align: center;
}

.home-hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 8px 7px 7px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-1);
  font-size: 0.82rem;
  color: var(--ink-2);
  margin-bottom: 24px;
}
/* It opens the chat now, so it has to look pressable and stop inheriting the
   browser's button styling. */
.home-hero__badge {
  cursor: pointer;
  font-family: inherit;
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.home-hero__badge:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-2);
  border-color: color-mix(in srgb, var(--blue) 34%, var(--line-2));
}
.home-hero__badge:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}
/* No uppercase here: "KORE AI" set in caps at 0.74rem reads as an acronym
   nobody has heard of, where the product name reads as a name. */
.home-hero__badge b {
  background: var(--ink);
  color: #fff;
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.home-hero__badge span {
  padding-right: 8px;
}

.home-hero__title {
  font-size: clamp(2.45rem, 5.4vw, 4.5rem);
  line-height: 1.02;
  letter-spacing: -0.038em;
  text-wrap: balance;
}
.home-hero__lede {
  margin: 24px auto 0;
  font-size: clamp(1.02rem, 1.25vw, 1rem);
  color: var(--muted);
  max-width: 62ch;
}
.home-hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 18px;
}
.home-hero__trust {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px 26px;
  margin-top: 30px;
  font-size: 0.86rem;
  color: var(--muted);
}
.home-hero__trust li {
  display: flex;
  align-items: center;
  gap: 7px;
}
.home-hero__trust .k-icon {
  color: var(--cyan);
}

.home-hero__shot {
  display: block;
  width: 100%;
  height: auto;
}

.h-card {
  position: absolute;
  z-index: 3;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 14px 16px;
  min-width: 208px;
}
.h-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.h-card__title {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.01em;
}
.h-card__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.16);
}
.h-card__value {
  font-family: var(--font-display);
  font-size: 1.62rem;
  font-weight: 700;
  letter-spacing: -0.03em;
}
.h-card__meta {
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 2px;
}
.h-card__meta b {
  color: #16a34a;
}
.h-card--a {
  top: 10%;
  left: -2%;
}
.h-card--b {
  top: 30%;
  right: -2%;
}
.h-card--c {
  bottom: 22%;
  left: 3%;
}

.h-check {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.h-check li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.83rem;
  color: var(--ink-2);
}
.h-check i {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  flex: none;
  border: 1.5px solid var(--line-2);
  display: grid;
  place-items: center;
  transition:
    background-color 0.4s var(--ease),
    border-color 0.4s var(--ease);
}
.h-check i::after {
  content: "";
  width: 7px;
  height: 4px;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-45deg) scale(0);
  transition: transform 0.3s var(--ease);
}
.h-check li.is-on i {
  background: var(--cyan);
  border-color: var(--cyan);
}
.h-check li.is-on i::after {
  transform: rotate(-45deg) scale(1);
}
.h-check li.is-on {
  color: var(--muted-2);
  text-decoration: line-through;
}

.h-avatars {
  display: flex;
}
.h-avatars img {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2px solid #fff;
  object-fit: cover;
  margin-left: -9px;
}
.h-avatars img:first-child {
  margin-left: 0;
}

/* ==========================================================================
   HOME: partners marquee
   ========================================================================== */
.home-logos {
  padding: 34px 0 8px;
  border-top: 1px solid var(--line);
}
.home-logos__label {
  text-align: center;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: 26px;
}
.home-logos .k-marquee__track {
  gap: 62px;
}
/* Each mark carries its own fitted width and height, so nothing is forced to
   a single dimension here: the caps are only a guard against a file that is
   dropped in without going through the list. */
.home-logos img {
  max-height: 30px;
  max-width: 142px;
  height: auto;
  width: auto;
  object-fit: contain;
  opacity: 0.52;
  filter: grayscale(1);
  transition:
    opacity var(--t) var(--ease),
    filter var(--t) var(--ease);
}
.home-logos li:hover img {
  opacity: 1;
  filter: none;
}
/* The same rail inside a section that already has its own heading, so it drops
   the top rule and the label spacing. */
.home-logos--inline {
  border-top: 0;
  padding: 6px 0 0;
  margin-top: 34px;
}

/* ==========================================================================
   HOME, the "one platform" bento
   ========================================================================== */
.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 18px;
}
.bento__cell {
  position: relative;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 28px;
  display: flex;
  flex-direction: column;
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.bento__cell:hover {
  transform: translateY(-5px);
  box-shadow: var(--sh-3);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
}
.bento__cell--2 {
  grid-column: span 2;
}
.bento__cell--3 {
  grid-column: span 3;
}
.bento__cell--4 {
  grid-column: span 4;
}
.bento__cell--6 {
  grid-column: span 6;
}
.bento__cell--dark {
  background: radial-gradient(120% 130% at 10% 0%, #14405f, #0b1524 60%);
  color: #fff;
  border-color: transparent;
}
.bento__cell--dark .bento__title {
  color: #fff;
}
.bento__cell--dark .bento__text {
  color: rgba(255, 255, 255, 0.66);
}
.bento__icon {
  width: 46px;
  height: 46px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, #fff);
  margin-bottom: 18px;
}
.bento__cell--dark .bento__icon {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.16);
  color: var(--cyan-soft);
}
.bento__title {
  font-family: var(--font-display);
  font-size: 1.22rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 9px;
}
.bento__text {
  color: var(--muted);
  font-size: 0.94rem;
}
.bento__media {
  margin-top: auto;
  padding-top: 22px;
}
/* Fixed ratio + cover, so a portrait source cannot stretch its row and leave
   the other cards in that row with a gap above their image. --focal moves the
   crop when the subject is not in the middle. */
.bento__media img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  border-radius: var(--r);
  border: 1px solid var(--line);
}
.bento__cell--dark .bento__media img {
  border-color: rgba(255, 255, 255, 0.12);
}
.bento__stat {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 3.6vw, 3.2rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
}
.bento__stat-label {
  font-size: 0.88rem;
  color: var(--muted);
  margin-top: 8px;
}

/* ==========================================================================
   HOME: ecosystem tabs
   ========================================================================== */
.eco__tabs {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 5px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  width: fit-content;
  margin: 0 auto clamp(34px, 4vw, 54px);
}
.eco__ink {
  position: absolute;
  top: 5px;
  bottom: 5px;
  left: 0;
  border-radius: 999px;
  background: #fff;
  box-shadow: var(--sh-1);
  transition:
    transform 0.42s var(--ease),
    width 0.42s var(--ease);
  z-index: 0;
}
.eco__tab {
  position: relative;
  z-index: 1;
  cursor: pointer;
  padding: 11px 22px;
  border-radius: 999px;
  border: 0;
  background: none;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
  transition: color var(--t) var(--ease);
}
.eco__tab.is-active {
  color: var(--ink);
  font-weight: 600;
}

.eco__panel {
  display: none;
}
.eco__panel.is-active {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: center;
  animation: ecoIn 0.55s var(--ease) both;
}
@keyframes ecoIn {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.eco__heading {
  font-size: clamp(1.7rem, 2.8vw, 2.5rem);
  line-height: 1.1;
  margin-bottom: 16px;
}
.eco__lede {
  color: var(--muted);
  margin-bottom: 26px;
}
.eco__list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.eco__item {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 18px;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.eco__item:hover {
  transform: translateX(5px);
  box-shadow: var(--sh-2);
  border-color: color-mix(in srgb, var(--accent) 34%, var(--line));
}
.eco__item-icon {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
}
/* Same neutral frame the menu and the product cards give a brand mark. */
.eco__item-icon--logo {
  background: #fff;
  border: 1px solid var(--line);
  padding: 5px;
}
.eco__item-icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.eco__item-name {
  display: block;
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
}
.eco__item-text {
  display: block;
  font-size: 0.85rem;
  color: var(--muted);
  margin-top: 1px;
}
.eco__item-go {
  color: var(--muted-2);
  transition:
    transform var(--t) var(--ease),
    color var(--t) var(--ease);
}
.eco__item:hover .eco__item-go {
  color: var(--accent);
  transform: translateX(3px);
}

.eco__visual {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--sh-3);
  background: #fff;
}
/* A fixed ratio is what stops the section jumping height every time a tab is
   switched, every panel has to agree on one shape. The default matches the
   2160x1248 product screenshots the industry pages use; a section whose shots
   are a different shape overrides the two numbers inline, so `cover` fills the
   panel exactly instead of cropping the artwork. */
.eco__visual {
  --ar-w: 2160;
  --ar-h: 1248;
  aspect-ratio: var(--ar-w) / var(--ar-h);
}
.eco__visual img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
}
.eco__visual::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(11, 21, 36, 0.35));
  pointer-events: none;
}
.eco__badge {
  position: absolute;
  z-index: 2;
  left: 20px;
  bottom: 20px;
  right: 20px;
  background: #fff;
  border-radius: 16px;
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  border: 1px solid var(--line);
}
.eco__badge b {
  font-family: var(--font-display);
  font-size: 1.3rem;
}
.eco__badge span {
  font-size: 0.85rem;
  color: var(--muted);
}

/* ==========================================================================
   Product / service card grid (used on index pages & related strips)
   ========================================================================== */
.pgrid {
  display: grid;
  /* min() rather than a flat 300px: auto-fill will not shrink a track below
     its minimum, so on a 305px screen one column still wanted 300 and pushed
     the page sideways. This lets the last column give way instead. */
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  gap: 20px;
}
.pcard {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 28px;
  border-radius: var(--r-lg);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.pcard::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(
    90deg,
    var(--accent),
    color-mix(in srgb, var(--accent) 30%, var(--cyan))
  );
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.45s var(--ease);
}
.pcard:hover {
  transform: translateY(-6px);
  box-shadow: var(--sh-3);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
}
.pcard:hover::before {
  transform: scaleX(1);
}
.pcard.is-hidden {
  display: none;
}
.pcard__icon {
  width: 50px;
  height: 50px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, #fff);
  margin-bottom: 20px;
  transition:
    transform var(--t) var(--ease),
    background-color var(--t) var(--ease),
    color var(--t) var(--ease);
}
.pcard:hover .pcard__icon {
  background: var(--accent);
  color: #fff;
  transform: rotate(-7deg) scale(1.06);
}
/* Same rule as the menu tiles: a brand mark cannot be flooded with white on
   hover or tilted, so the logo card holds a neutral face and answers with its
   border instead. */
.pcard__icon--logo {
  background: #fff;
  border-color: var(--line);
  padding: 6px;
}
.pcard__icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.pcard:hover .pcard__icon--logo {
  background: #fff;
  border-color: color-mix(in srgb, var(--accent) 45%, #fff);
  box-shadow: 0 3px 12px color-mix(in srgb, var(--accent) 16%, transparent);
  transform: scale(1.06);
}
.pcard__name {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.pcard__text {
  color: var(--muted);
  font-size: 0.93rem;
  margin-top: 9px;
  flex: 1;
}
.pcard__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 16px;
}
.pcard__tag {
  font-size: 0.74rem;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--muted);
  border: 1px solid var(--line);
}
.pcard__go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 20px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--accent);
}
.pcard__go .k-icon {
  transition: transform var(--t) var(--ease);
}
.pcard--more {
  background: var(--paper-2);
}
.pcard:hover .pcard__go .k-icon {
  transform: translateX(4px);
}

/* Filter bar */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 30px;
}
.filters button {
  padding: 9px 18px;
  border-radius: 999px;
  cursor: pointer;
  background: #fff;
  border: 1px solid var(--line-2);
  color: var(--muted);
  font-size: 0.89rem;
  font-weight: 500;
  transition: all var(--t) var(--ease);
}
.filters button:hover {
  border-color: var(--ink);
  color: var(--ink);
}
.filters button.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

/* ==========================================================================
   HOME: industries
   ========================================================================== */
/* Six-column base so five cards tile without a hole: 3 across, then 2 wide. */
.ind-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 20px;
}
.ind-card {
  grid-column: span 2;
}
.ind-grid > :nth-child(4),
.ind-grid > :nth-child(5) {
  grid-column: span 3;
}
.ind-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  min-height: 430px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 28px;
  color: #fff;
  isolation: isolate;
  /* Grows from the top edge, so the lift below never pulls the bottom of
     the card up past where it started. See the hover rule. */
  transform-origin: 50% 0;
  transition: transform 0.5s var(--ease-out-soft);
}
/* The lift, and why it is not a lift on its own.

   A plain translateY(-6px) moves the card out from under a cursor sitting
   in the bottom six pixels of it. Hover is lost, the card drops back, the
   cursor is inside again, and it oscillates for as long as the pointer
   rests there: the card visibly shakes.

   Any hover transform that can shrink the box away from the pointer does
   this. The cure is to make the hovered box always contain the resting one,
   and then the loop cannot start. Growing from the top by 2 percent adds
   8.6px to a 430px card, which is more than the 6px it rises, so the bottom
   edge ends up 2.6px lower than it began. min-height keeps that card 430px
   at every breakpoint, so the margin holds everywhere.

   Two percent is small enough to read as the same lift and large enough to
   pay for it. Do not raise the translate without raising the scale. */
.ind-card:hover {
  transform: translateY(-6px) scale(1.02);
}
.ind-card img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease-out-soft);
}
.ind-card:hover img {
  transform: scale(1.06);
}
/* The scrim deepens as the list appears, so the extra lines stay readable
   whatever the photo behind them is doing. */
.ind-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    180deg,
    rgba(11, 21, 36, 0.05) 20%,
    rgba(11, 21, 36, 0.78) 74%,
    rgba(7, 16, 25, 0.94)
  );
  transition: opacity 0.55s var(--ease-out-soft);
}
.ind-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: linear-gradient(
    180deg,
    rgba(11, 21, 36, 0.3) 0%,
    rgba(11, 21, 36, 0.86) 60%,
    rgba(7, 16, 25, 0.96)
  );
  transition: opacity 0.55s var(--ease-out-soft);
}
.ind-card:hover::before {
  opacity: 1;
}
.ind-card__title {
  color: #fff;
  font-size: 1.5rem;
  margin-bottom: 8px;
}
.ind-card__text {
  color: rgba(255, 255, 255, 0.76);
  font-size: 0.92rem;
}

/* grid-template-rows animates to the content's real height: max-height had to
   guess an upper bound, and the transition spent half its time crossing empty
   space, which is what made it feel abrupt. */
.ind-card__reveal {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.6s var(--ease-out-soft);
}
.ind-card:hover .ind-card__reveal,
.ind-card:focus-within .ind-card__reveal {
  grid-template-rows: 1fr;
}
.ind-card__list {
  overflow: hidden;
  min-height: 0;
  display: grid;
  gap: 7px;
}
.ind-card__list li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.87rem;
  color: rgba(255, 255, 255, 0.9);
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 0.45s var(--ease-out-soft),
    transform 0.45s var(--ease-out-soft);
}
.ind-card__list li:first-child {
  margin-top: 16px;
}
/* Each line follows the one above it, so the list unfolds rather than blinking. */
.ind-card:hover .ind-card__list li,
.ind-card:focus-within .ind-card__list li {
  opacity: 1;
  transform: none;
}
.ind-card:hover .ind-card__list li:nth-child(1) {
  transition-delay: 0.1s;
}
.ind-card:hover .ind-card__list li:nth-child(2) {
  transition-delay: 0.16s;
}
.ind-card:hover .ind-card__list li:nth-child(3) {
  transition-delay: 0.22s;
}
.ind-card:hover .ind-card__list li:nth-child(4) {
  transition-delay: 0.28s;
}
.ind-card:hover .ind-card__list li:nth-child(5) {
  transition-delay: 0.34s;
}
.ind-card:hover .ind-card__list li:nth-child(6) {
  transition-delay: 0.4s;
}
.ind-card__list .k-icon {
  color: var(--cyan);
  flex: none;
}
.ind-card__go {
  margin-top: 18px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 0.92rem;
  color: #fff;
}
.ind-card__go .k-icon {
  transition: transform var(--t) var(--ease);
}
.ind-card:hover .ind-card__go .k-icon {
  transform: translateX(4px);
}

/* ==========================================================================
   Stats strip
   ========================================================================== */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.stats__cell {
  background: #fff;
  padding: clamp(24px, 3vw, 40px);
  text-align: center;
  transition: background-color var(--t) var(--ease);
}
.stats__cell:hover {
  background: var(--paper);
}
.stats__num {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.4vw, 3rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  background: linear-gradient(120deg, var(--blue), var(--cyan));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stats__label {
  margin-top: 10px;
  font-size: 0.89rem;
  color: var(--muted);
}
.stats--dark {
  background: rgba(255, 255, 255, 0.12);
  border-color: transparent;
}
.stats--dark .stats__cell {
  background: transparent;
}
.stats--dark .stats__cell:hover {
  background: rgba(255, 255, 255, 0.04);
}
.stats--dark .stats__label {
  color: rgba(255, 255, 255, 0.6);
}

/* ==========================================================================
   Testimonials & stories sliders
   ========================================================================== */
.slider {
  position: relative;
}
.slider__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(320px, 1fr);
  gap: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  cursor: grab;
  /* overflow-x:auto also clips vertically, so the cards' hover lift needs
     headroom inside the scroller, the negative margin keeps the section
     spacing exactly where it was. */
  padding: 10px 0 14px;
  margin-top: -10px;
}
.slider__track::-webkit-scrollbar {
  display: none;
}
.slider__track.is-grabbing {
  cursor: grabbing;
  scroll-snap-type: none;
}
.slider__track > * {
  scroll-snap-align: start;
}
.slider__nav {
  display: flex;
  gap: 10px;
  margin-top: 26px;
}
.slider__btn {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  cursor: pointer;
  background: #fff;
  border: 1px solid var(--line-2);
  color: var(--ink);
  display: grid;
  place-items: center;
  transition: all var(--t) var(--ease);
}
.slider__btn:hover:not(:disabled) {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
}
.slider__btn:disabled {
  opacity: 0.32;
  cursor: default;
}
.slider__dots {
  display: flex;
  gap: 7px;
  align-items: center;
  margin-left: auto;
}
.slider__dots button {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line-2);
  cursor: pointer;
  transition: all var(--t) var(--ease);
}
.slider__dots button.is-on {
  width: 22px;
  border-radius: 999px;
  background: var(--ink);
}

.story {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: #fff;
  display: flex;
  flex-direction: column;
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.story:hover {
  transform: translateY(-5px);
  box-shadow: var(--sh-3);
}
.story__img {
  height: 220px;
  overflow: hidden;
}
.story__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease);
}
.story:hover .story__img img {
  transform: scale(1.06);
}
.story__body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  flex: 1;
}
.story__tag {
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
}
.story__title {
  font-family: var(--font-display);
  font-size: 1.14rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
  margin: 10px 0 18px;
}
.story__stats {
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.story__stat b {
  display: block;
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--blue);
  letter-spacing: -0.03em;
}
.story__stat span {
  font-size: 0.78rem;
  color: var(--muted);
}

.quote {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 30px;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.quote:hover {
  transform: translateY(-5px);
  box-shadow: var(--sh-3);
  border-color: var(--line-2);
}
.quote__mark {
  font-family: var(--font-display);
  font-size: 5rem;
  line-height: 0.7;
  color: var(--line-2);
  margin-bottom: 6px;
}
.quote__text {
  color: var(--ink-2);
  font-size: 0.97rem;
  line-height: 1.62;
  flex: 1;
}
.quote__stars {
  display: flex;
  gap: 3px;
  color: var(--yellow);
  margin-top: 20px;
}
.quote__stars svg {
  fill: currentColor;
  stroke: none;
}
.quote__who {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-top: 16px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.quote__who img {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
}
/* Both blocks with their own line-height rather than two inline spans split
   by a <br>: the break inherited the card line-height, which is set for body
   copy and left far too much air between the name and the role. */
.quote__name {
  display: block;
  font-weight: 700;
  font-size: 12px;
  line-height: 1.25;
}
.quote__role {
  display: block;
  font-size: 11px;
  line-height: 1.3;
  margin-top: 2px;
  color: var(--muted);
}

/* ==========================================================================
   FAQ accordion
   ========================================================================== */
.faq {
  display: grid;
  gap: 10px;
}
.faq__item {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  overflow: hidden;
  transition:
    border-color var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.faq__item.is-open {
  border-color: color-mix(in srgb, var(--accent) 34%, var(--line));
  box-shadow: var(--sh-1);
}
.faq__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 24px;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-display);
  font-size: 1.04rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.faq__icon {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--line-2);
  display: grid;
  place-items: center;
  transition: all var(--t) var(--ease);
}
.faq__icon::before,
.faq__icon::after {
  content: "";
  position: absolute;
  width: 11px;
  height: 1.8px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--t) var(--ease);
}
.faq__icon {
  position: relative;
}
.faq__icon::after {
  transform: rotate(90deg);
}
.faq__item.is-open .faq__icon {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.faq__item.is-open .faq__icon::after {
  transform: rotate(0deg);
}
.faq__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.42s var(--ease);
}
.faq__item.is-open .faq__panel {
  grid-template-rows: 1fr;
}
.faq__inner {
  overflow: hidden;
}
.faq__inner p {
  padding: 0 24px 22px;
  color: var(--muted);
  max-width: 78ch;
}

/* ==========================================================================
   PRODUCT PAGE TEMPLATE
   ========================================================================== */
/* Centered hero: the copy block, then the product shot below it at full size.
   The shots are 2160x1248 with a pure-white background baked in, so the hero
   gradient resolves to white well before the image starts and the mockup sits
   on the page seamlessly: nothing cropped, nothing framed. */
.p-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(40px, 4.6vw, 72px) 0 0;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--accent) 7%, #fff) 0%,
    #fff 42%
  );
}
.p-hero__head {
  position: relative;
  z-index: 2;
  max-width: 880px;
  margin-inline: auto;
  text-align: center;
}
.p-hero__crumbs {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  color: var(--muted);
  margin-bottom: 20px;
}
.p-hero__crumbs a:hover {
  color: var(--accent);
}
.p-hero__crumbs span {
  color: var(--muted-2);
}
.p-hero__title {
  font-size: clamp(2.3rem, 5vw, 4rem);
  line-height: 1.03;
  letter-spacing: -0.035em;
  margin: 18px 0 0;
  text-wrap: balance;
}
.p-hero__lede {
  margin: 20px auto 0;
  font-size: clamp(1.02rem, 1.25vw, 1.2rem);
  color: var(--muted);
  max-width: 62ch;
}
.p-hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 30px;
}
.p-hero__points {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 26px;
  margin-top: 26px;
  font-size: 0.87rem;
  color: var(--muted);
}

/* Wrapped onto three lines these read as a ragged block, because a centred row
   restarts each line at a different x. Stacking them and letting the list size
   to its own content keeps the group centred while every tick lines up. */
@media (max-width: 760px) {
  .p-hero__points {
    flex-direction: column;
    align-items: flex-start;
    gap: 11px;
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
    text-align: left;
  }
}
.p-hero__points li {
  display: flex;
  align-items: center;
  gap: 7px;
}
.p-hero__points .k-icon {
  color: var(--accent);
}

.p-hero__media {
  position: relative;
  z-index: 2;
  max-width: 1220px;
  margin: clamp(34px, 4vw, 60px) auto 0;
}

/* Service and industry heroes lead with a photograph, which sat flush against
   the sticky sub-nav below it. Application heroes are UI screenshots that are
   meant to run into that edge, so they keep the original flush treatment: hence the modifier rather than a change to .p-hero itself. */
.p-hero--spaced {
  padding-bottom: clamp(32px, 3.4vw, 50px);
}
.p-hero--spaced .p-hero__shot {
  border-bottom-right-radius: 8px;
  border-bottom-left-radius: 8px;
}
/* Full image, never cropped. */
.p-hero__shot {
  display: block;
  width: 100%;
  height: auto;
  border-top-right-radius: 8px;
  border-top-left-radius: 8px;
}
.p-hero__halo {
  position: absolute;
  inset: 6% 4% 14%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--accent) 20%, transparent),
    transparent 64%
  );
  filter: blur(60px);
  z-index: -1;
}
.p-hero__chip {
  position: absolute;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 10px 18px;
  font-size: 0.88rem;
  font-weight: 600;
  white-space: nowrap;
}
.p-hero__chip .k-icon {
  color: var(--accent);
}
.p-hero__chip--1 {
  top: 12%;
  left: -1%;
}
.p-hero__chip--2 {
  bottom: 20%;
  right: -1%;
}

/* Sticky in-page nav */
.p-nav {
  position: sticky;
  top: var(--sticky-top);
  transition: top 0.42s var(--ease);
  z-index: 60;
  background: rgba(255, 255, 255, 0.88);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-block: 1px solid var(--line);
}
.p-nav__inner {
  display: flex;
  align-items: center;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 10px 0;
}
.p-nav__inner::-webkit-scrollbar {
  display: none;
}
.p-nav__inner > a {
  padding: 8px 15px;
  border-radius: 999px;
  font-size: 0.88rem;
  color: var(--muted);
  white-space: nowrap;
  transition: all var(--t) var(--ease);
}
.p-nav__inner > a:hover {
  color: var(--ink);
  background: var(--paper-2);
}
.p-nav__inner > a.is-on {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
.p-nav__cta {
  margin-left: auto;
  padding-left: 16px;
}

/* Sticky step story */
/* .steps is a scroll track whose height JS sets from the step count; the stage
   pins inside it so the list stays put and only the shot changes. Falls back
   to a plain two-column block if JS never runs or the stage is too tall to pin
   (see initSteps), which is why the grid lives on the stage, not the track. */
.steps {
  position: relative;
}
.steps__stage {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(30px, 5vw, 78px);
  align-items: center;
}
.steps.is-pinned .steps__stage {
  /* Clears the header *and* the sticky sub-nav above it: --subnav-h is
     measured by initSteps, since CSS cannot read the nav's height. */
  position: sticky;
  top: calc(var(--sticky-top) + var(--subnav-h, 0px) + 20px);
  transition: top 0.42s var(--ease);
}
.steps__list {
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 1vw, 14px);
}
.steps__item {
  /* A button now, so a step can be jumped to directly. */
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  position: relative;
  padding: 18px 24px 18px 28px;
  border-radius: var(--r-lg);
  border: 1px solid transparent;
  background: transparent;
  transition:
    background-color 0.5s var(--ease),
    border-color 0.5s var(--ease),
    transform 0.5s var(--ease);
}
.steps__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 16px;
  bottom: 16px;
  width: 3px;
  border-radius: 3px;
  background: var(--line-2);
  transition: background-color 0.5s var(--ease);
}
/* Inactive steps recede so the current one carries the eye, now that all four
   are on screen together rather than scrolling past one at a time. */
.steps.is-pinned .steps__item {
  opacity: 0.5;
  transition:
    opacity 0.45s var(--ease),
    background-color 0.5s var(--ease),
    border-color 0.5s var(--ease);
}
.steps.is-pinned .steps__item.is-active {
  opacity: 1;
}
.steps.is-pinned .steps__item:hover {
  opacity: 0.8;
}
.steps.is-pinned .steps__item.is-active:hover {
  opacity: 1;
}
.steps__item:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.steps__item.is-active {
  background: #fff;
  border-color: var(--line);
  box-shadow: var(--sh-2);
}
.steps__item.is-active::before {
  background: var(--accent);
}
.steps__num {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-2);
  transition: color 0.5s var(--ease);
}
.steps__item.is-active .steps__num {
  color: var(--accent);
}
.steps__num i {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--paper-2);
  font-style: normal;
  font-size: 0.78rem;
  color: var(--muted);
  transition: all 0.5s var(--ease);
}
.steps__item.is-active .steps__num i {
  background: var(--accent);
  color: #fff;
}
.steps__title {
  font-family: var(--font-display);
  font-size: 1.24rem;
  font-weight: 700;
  letter-spacing: -0.022em;
  margin: 8px 0 7px;
}
.steps__text {
  color: var(--muted);
  font-size: 0.95rem;
}
.steps__media {
  align-self: center;
}

/* Laptop-height fallback: the list is too tall to pin the whole stage, so the
   shot pins on its own and the list scrolls past it. `align-self: start` is
   required, a centred grid item has no free space to stick within. */
.steps.is-mediapin .steps__media {
  position: sticky;
  top: calc(var(--sticky-top) + var(--subnav-h, 0px) + 20px);
  align-self: start;
  transition: top 0.42s var(--ease);
}
/* A sticky item can only travel inside its own column's box, and that box ends
   with the last step, so without this the shot lets go exactly as the final
   step comes up to be read. The tail gives it enough runway to hold. */
.steps.is-mediapin .steps__list {
  padding-bottom: clamp(140px, 28vh, 280px);
}
.steps__frame {
  /* Ratio comes in as two numbers rather than one `aspect-ratio` value, so the
     height cap below can be derived from it. templates/product.php overrides
     them per journey; 4:3 is the default for older, wider shots. */
  --ar-w: 4;
  --ar-h: 3;
  position: relative;
  width: 100%;
  margin-inline: auto;
  aspect-ratio: var(--ar-w) / var(--ar-h);
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--paper);
  box-shadow: var(--sh-3);
}

/* Once the stage pins, the shot has to fit between the sticky offset and the
   bottom of the viewport: otherwise on a laptop you scroll to step 4 and the
   image for it is already off the screen. Capping the *width* (the usable
   height, converted through the shot's own ratio) shrinks the frame to fit
   instead of cropping it, so the whole shot stays visible. Tall screens never
   reach the cap and are unaffected. */
@media (min-width: 1025px) {
  .steps__frame {
    /* --header-h, not --sticky-top: the latter flips to 0 when the header
       slides away, which would let the frame grow mid-scroll, overrun its
       sticky container and drop out of view, the exact bug this cap exists
       to fix. 48px covers the stage's 20px offset plus breathing room. */
    max-width: calc(
      (100vh - var(--header-h) - var(--subnav-h, 0px) - 48px) * var(--ar-w) /
        var(--ar-h)
    );
    max-width: calc(
      (100svh - var(--header-h) - var(--subnav-h, 0px) - 48px) * var(--ar-w) /
        var(--ar-h)
    );
  }
}
.steps__shot {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(1.03);
  transition:
    opacity 0.6s var(--ease),
    transform 0.8s var(--ease);
}
.steps__shot.is-active {
  opacity: 1;
  transform: none;
}
.steps__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}

/* Feature grid */
.fgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(268px, 100%), 1fr));
  gap: 16px;
}
.fcard {
  padding: 26px;
  border-radius: var(--r-lg);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.fcard:hover {
  transform: translateY(-4px);
  box-shadow: var(--sh-2);
  border-color: color-mix(in srgb, var(--accent) 28%, var(--line));
}
.fcard__icon {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
  margin-bottom: 16px;
  transition: all var(--t) var(--ease);
}
.fcard:hover .fcard__icon {
  background: var(--accent);
  color: #fff;
  transform: rotate(-6deg);
}
.fcard__title {
  font-family: var(--font-display);
  font-size: 1.04rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin-bottom: 8px;
}
.fcard__text {
  color: var(--muted);
  font-size: 0.9rem;
}
/* Only on the cards that link somewhere. */
.fcard__go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 16px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--accent);
  transition: gap var(--t) var(--ease);
}
.fcard__go .k-icon {
  transition: transform var(--t) var(--ease);
}
.fcard:hover .fcard__go {
  gap: 11px;
}
.fcard:hover .fcard__go .k-icon {
  transform: translateX(3px);
}

/* Compact list of everything the platform replaces. Three columns of chips
   rather than full cards. These are labels with a destination, not features
   that need explaining. */
.toolgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: 10px;
}
.toolgrid__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.toolgrid__item:hover {
  transform: translateX(4px);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
}
.toolgrid__icon {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 10px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, #fff);
  transition:
    background var(--t) var(--ease),
    color var(--t) var(--ease);
}
.toolgrid__item:hover .toolgrid__icon {
  background: var(--accent);
  color: #fff;
}
/* After the base rule, or the accent fill above would win on source order and
   the logo would sit on a coloured tile. */
.toolgrid__icon--logo,
.toolgrid__item:hover .toolgrid__icon--logo {
  background: #fff;
  border: 1px solid var(--line);
  padding: 4px;
}
.toolgrid__icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.toolgrid__label {
  font-size: 0.93rem;
  font-weight: 600;
  color: var(--ink-2);
}
.toolgrid__go {
  margin-left: auto;
  color: var(--muted-2);
  opacity: 0;
  transform: translateX(-4px);
  transition:
    opacity var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.toolgrid__item:hover .toolgrid__go {
  opacity: 1;
  transform: none;
  color: var(--accent);
}

/* Alternating showcase rows */
.show-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4.5vw, 72px);
  align-items: center;
}
.show-row + .show-row {
  margin-top: clamp(52px, 6vw, 104px);
}
.show-row:nth-child(even) .show-row__media {
  order: -1;
}
.show-row__title {
  font-size: clamp(1.55rem, 2.5vw, 2.2rem);
  line-height: 1.12;
  margin: 16px 0 14px;
}
.show-row__text {
  color: var(--muted);
}
.show-row__list {
  margin-top: 22px;
  display: grid;
  gap: 11px;
}
.show-row__list li {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 0.94rem;
  color: var(--ink-2);
}
.show-row__list .k-icon {
  color: var(--accent);
  flex: none;
  margin-top: 3px;
}
.show-row__media {
  position: relative;
}
.show-row__frame {
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--sh-3);
  background: #fff;
}
/* The photo here is portrait (1984x2976), so at full column width it stood
   almost twice as tall as the text beside it and set the height of the whole
   row. A square crop brings it back in line and still scales with the column,
   rather than a fixed pixel cap that would over-crop on a narrow screen. */
.show-row__frame img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  display: block;
}
.show-row__blob {
  position: absolute;
  inset: 8% 4%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--accent) 22%, transparent),
    transparent 64%
  );
  filter: blur(40px);
  z-index: -1;
}

/* Split feature: dark panel + checklist */
/* Editorial, not a dark marketing slab. The previous version was a navy
   gradient split exactly in half with a column of identical cyan ticks, the
   shape every generated landing page arrives in. This one is on paper, the
   columns are uneven, the list is set with rules rather than repeated icons,
   and the photo carries a caption that says where it was taken. */
.splitband {
  border-radius: var(--r-xl);
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
}
.splitband__body {
  padding: clamp(30px, 3.6vw, 56px);
  align-self: center;
}
.splitband__eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-2);
}
/* A drawn rule instead of a pill, a typographic mark, not a badge. */
.splitband__eyebrow::after {
  content: "";
  height: 1px;
  width: 46px;
  background: var(--line-2);
}
.splitband__title {
  font-size: clamp(1.7rem, 2.8vw, 2.4rem);
  line-height: 1.1;
  margin: 18px 0 14px;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.splitband__text {
  color: var(--muted);
  max-width: 46ch;
}
.splitband__list {
  margin-top: 28px;
  display: grid;
}
.splitband__list li {
  display: block;
  padding: 12px 0 12px 20px;
  position: relative;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 0.93rem;
}
.splitband__list li:last-child {
  border-bottom: 1px solid var(--line);
}
/* A short dash, set on the baseline: quieter than a filled tick, and it
   does not repeat the same glyph five times down the column. */
.splitband__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.6em;
  width: 9px;
  height: 1.5px;
  background: var(--accent);
  border-radius: 2px;
}
.splitband__media {
  position: relative;
  min-height: 340px;
}
.splitband__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.splitband__caption {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--ink-2);
}
.splitband__caption .k-icon {
  color: var(--accent);
}

/* Comparison table */
.ctable {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #fff;
}
.ctable th,
.ctable td {
  padding: 16px 20px;
  text-align: left;
  font-size: 0.93rem;
  border-bottom: 1px solid var(--line);
}
.ctable thead th {
  background: var(--paper);
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: -0.01em;
}
.ctable tbody tr:last-child td {
  border-bottom: 0;
}
.ctable tbody tr:hover {
  background: var(--paper);
}
.ctable td:first-child {
  font-weight: 600;
  color: var(--ink);
}
.ctable .yes {
  color: #16a34a;
  font-weight: 600;
}
.ctable .no {
  color: var(--muted-2);
}
.ctable-wrap {
  overflow-x: auto;
}

/* Pricing */
.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 18px;
  align-items: stretch;
}
.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 30px;
  border-radius: var(--r-lg);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.plan:hover {
  transform: translateY(-5px);
  box-shadow: var(--sh-3);
}
/* The thicker border would push this card's content down 1px against its
   neighbours; trim the padding by the same 1px so every row still lines up. */
.plan--best {
  border-color: var(--accent);
  border-width: 2px;
  padding: 29px;
}
.plan__flag {
  position: absolute;
  top: -12px;
  left: 30px;
  background: var(--accent);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 13px;
  border-radius: 999px;
}
.plan__name {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
}
.plan__desc {
  color: var(--muted);
  font-size: 0.9rem;
  margin-top: 7px;
  min-height: 42px;
}
.plan__price {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 20px 0 4px;
}
.plan__price b {
  font-family: var(--font-display);
  font-size: 2.6rem;
  letter-spacing: -0.04em;
  line-height: 1;
}
.plan__price span {
  color: var(--muted);
  font-size: 0.88rem;
}
.plan__note {
  font-size: 0.82rem;
  color: var(--muted-2);
}
/* The pitch line under the button, as restaurants.kore.co sets it: quoted,
   small and bold. Cards are a flex column with the button pushed to the floor
   by the list above, so this needs its own gap rather than a margin collapse. */
.plan__tagline {
  margin-top: 14px;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink-2);
  text-align: center;
}
/* `flex: 1` pushes the button to the card floor; `align-content: start` stops
   a short list from spreading its rows to fill the space it just claimed. */
.plan__list {
  margin: 24px 0;
  display: grid;
  gap: 11px;
  flex: 1;
  align-content: start;
}
.plan__list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 0.91rem;
  color: var(--ink-2);
}
.plan__list .k-icon {
  color: var(--accent);
  flex: none;
  margin-top: 3px;
}
/* The smaller qualifying line the source sets beneath certain features: "Collect and manage reviews / Includes web platform and mobile apps". */
.plan__linesub {
  display: block;
  margin-top: 2px;
  font-style: normal;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--muted);
}
/* The managed tier closes with a short explanation and a footnote. */
.plan__blurb {
  margin: 0 0 14px;
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--muted);
}
.plan__foot {
  margin: 0 0 16px;
  font-size: 0.78rem;
  color: var(--muted-2);
}

/* Related products strip */
.related {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
}
.related__item {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 17px 19px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.related__item:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-2);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
}
.related__icon {
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
  flex: none;
}
/* Same neutral frame every other product mark gets. */
.related__icon--logo {
  background: #fff;
  border: 1px solid var(--line);
  padding: 4px;
}
.related__icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.related__name {
  font-weight: 600;
  font-size: 0.94rem;
}
.related__blurb {
  font-size: 0.81rem;
  color: var(--muted);
}

/* ==========================================================================
   INDUSTRY PAGE

   The hero, the sticky sub-nav and the section rhythm are the shared .p-hero
   set that applications and services use, so an industry page reads the same
   way as the rest of the site. Only the case study below is industry-only.
   ========================================================================== */

/* Case study block */
.casestudy {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #fff;
  box-shadow: var(--sh-2);
}
.casestudy__media {
  position: relative;
  min-height: 380px;
}
.casestudy__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease);
}
.casestudy:hover .casestudy__media img {
  transform: scale(1.04);
}
.casestudy__body {
  padding: clamp(28px, 3.6vw, 56px);
  align-self: center;
}
.casestudy__title {
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
  line-height: 1.12;
  margin: 18px 0 14px;
}
.casestudy__text {
  color: var(--muted);
}
.casestudy__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 40px;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.casestudy__stats b {
  display: block;
  font-family: var(--font-display);
  font-size: 1.9rem;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--accent);
}
.casestudy__stats span {
  font-size: 0.82rem;
  color: var(--muted);
}

@media (max-width: 1024px) {
  .casestudy {
    grid-template-columns: 1fr;
  }
  .casestudy__media {
    min-height: 260px;
  }
}

/* ==========================================================================
   Page hero (simple, for company / contact / blog / legal)
   ========================================================================== */
/* Centred by default so every hero on the site reads the same way. */
/* Trimmed at both ends: the old top of 96px pushed the headline down the
   screen, and the bottom stacked on top of the next section's own padding to
   leave 107px of nothing between the button and the first row of content. */
.s-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(40px, 4.4vw, 64px) 0 clamp(26px, 2.8vw, 42px);
  background: linear-gradient(180deg, #f6fbff, #fff 78%);
}
.s-hero__inner {
  position: relative;
  z-index: 2;
  max-width: 880px;
  margin-inline: auto;
  text-align: center;
}
.s-hero__title {
  font-size: clamp(2.2rem, 4.6vw, 3.8rem);
  line-height: 1.04;
  letter-spacing: -0.035em;
  margin: 18px 0 0;
  text-wrap: balance;
}
.s-hero__lede {
  margin: 20px auto 0;
}
.s-hero .home-hero__actions,
.s-hero .k-pill {
  justify-content: center;
}
.s-hero .home-hero__actions {
  display: flex;
  justify-content: center;
}
/* Article heroes put their content straight in the container rather than an
   __inner, so centre that too, and the byline row with it. */
.s-hero .k-container--narrow {
  text-align: center;
}
.s-hero .article__byline {
  justify-content: center;
}
.s-hero .article__share {
  margin-left: 0;
}

/* ==========================================================================
   Company page
   ========================================================================== */
.timeline {
  position: relative;
  display: grid;
  gap: 4px;
}
.timeline::before {
  content: "";
  position: absolute;
  left: 15px;
  top: 10px;
  bottom: 10px;
  width: 2px;
  background: linear-gradient(180deg, var(--cyan), var(--line) 85%);
}
.tl-item {
  position: relative;
  padding: 20px 0 20px 54px;
}
.tl-item::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 26px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--cyan);
  box-shadow: 0 0 0 5px rgba(0, 180, 229, 0.12);
}
.tl-year {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--blue);
}
.tl-title {
  font-weight: 600;
  margin: 6px 0 6px;
}
.tl-text {
  color: var(--muted);
  font-size: 0.94rem;
  max-width: 62ch;
}

/* From tablet up the line moves to the middle and entries alternate sides.
   A single left-hand column left half the section empty. Each item gets its
   own row (--row, set inline) so entries stagger rather than pairing up. */
@media (min-width: 900px) {
  .timeline {
    grid-template-columns: minmax(0, 1fr) 2px minmax(0, 1fr);
    column-gap: 0;
    row-gap: 0;
  }
  .timeline::before {
    left: 50%;
    margin-left: -1px;
  }

  .tl-item {
    grid-row: var(--row);
    grid-column: 1;
    padding: 18px 56px 18px 0;
    text-align: right;
  }
  .tl-item::before {
    left: auto;
    right: -7px;
  }
  .tl-item .tl-text {
    margin-left: auto;
  }

  .tl-item:nth-child(even) {
    grid-column: 3;
    padding: 18px 0 18px 56px;
    text-align: left;
  }
  .tl-item:nth-child(even)::before {
    left: -7px;
    right: auto;
  }
  .tl-item:nth-child(even) .tl-text {
    margin-left: 0;
    margin-right: auto;
  }
}

.team {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 18px;
}
.team__card {
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #fff;
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.team__card:hover {
  transform: translateY(-5px);
  box-shadow: var(--sh-3);
}
/* A card with no bio written yet opens nothing, so it does not lift and does
   not take a pointer. It keeps the same body as every other card, Read bio
   included: without that line it sat a head shorter than its neighbours and
   the row stopped reading as one set. So it looks identical at rest and does
   nothing when you reach for it, which is the whole intent.

   Qualified by the grid because .team__card sets cursor: pointer again lower
   down the file, and at equal weight the later rule would win. */
.team .team__card--flat {
  cursor: default;
}
.team .team__card--flat:hover {
  transform: none;
  box-shadow: none;
}
.team .team__card--flat:hover .team__more {
  color: var(--muted-2);
  gap: 6px;
}
/* The portraits are 220px studio cut-outs with a wide white margin, so at card
   width the head floats in a field of nothing. Zooming past the margin fills
   the frame; the tint behind means any edge that does show is not raw white
   against a white card. */
.team__photo {
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--paper-2);
}
.team__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1);
  transform-origin: 50% 34%;
  transition: transform 0.7s var(--ease);
}
.team__card:hover .team__photo img {
  transform: scale(1.1);
}
.team__card--flat:hover .team__photo img {
  transform: scale(1);
}
.team__body {
  padding: 18px 20px 22px;
}
.team__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.02rem;
}
.team__role {
  font-size: 0.85rem;
  color: var(--muted);
  margin-top: 3px;
}
/* The card is a <button>, so it has to be told to stop looking like one.
   Deliberately display:block and not a flex container: Safari refuses to
   make a <button> one, wrapping the children in an anonymous shrink-to-fit
   box instead, which collapsed the photo to the image's intrinsic width and
   left the rest of the card empty. The column lives on .team__inner. */
.team__card {
  display: block;
  width: 100%;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.team__inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}
/* Spans now, so they need to be told to behave like the divs they replaced. */
.team__photo,
.team__body,
.team__name,
.team__role {
  display: block;
}
.team__body {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.team__card:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}
/* Always on, and pinned to the card floor by the auto margin. Revealing it on
   hover left a blank line sitting under every name, and cards in a row stretch
   to the tallest, so the gap has to belong to something. */
.team__more {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 14px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted-2);
  transition:
    color var(--t) var(--ease),
    gap var(--t) var(--ease);
}
.team__card:hover .team__more,
.team__card:focus-visible .team__more {
  color: var(--blue);
  gap: 10px;
}

/* ---------------- Biography dialog ---------------- */
.tmodal {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: grid;
  place-items: center;
  padding: 20px;
  pointer-events: none;
}
body.is-bio .tmodal {
  pointer-events: auto;
}
.tmodal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(11, 21, 36, 0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
body.is-bio .tmodal__scrim {
  opacity: 1;
}
.tmodal__dialog {
  position: relative;
  width: min(560px, 100%);
  max-height: min(88vh, 620px);
  background: #fff;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
  overflow: hidden;
  opacity: 0;
  transform: translateY(14px) scale(0.98);
  transition:
    opacity 0.3s var(--ease),
    transform 0.4s var(--ease-out-soft);
}
body.is-bio .tmodal__dialog {
  opacity: 1;
  transform: none;
}
.tmodal__body {
  padding: clamp(26px, 3vw, 38px);
  max-height: inherit;
  overflow-y: auto;
}
.tmodal__head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 14px;
}
/* Shown at 84px from a 220px file, so it stays sharp. Cropped like the cards
   are, or the face sits small in the middle of the studio margin. */
.tmodal__avatar {
  flex: none;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper-2);
  border: 1px solid var(--line);
}
.tmodal__avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.22);
  transform-origin: 50% 34%;
}
.tmodal__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.tmodal__name {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.tmodal__role {
  color: var(--blue);
  font-weight: 600;
  font-size: 0.92rem;
  margin-top: 4px;
}
.tmodal__text {
  margin-top: 18px;
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.72;
  white-space: pre-line;
}
.tmodal__x {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #fff;
  color: var(--ink);
  cursor: pointer;
  transition:
    background-color var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.tmodal__x:hover {
  background: var(--paper-2);
  transform: rotate(90deg);
}

@media (max-width: 700px) {
  .tmodal__dialog {
    max-height: 90vh;
  }
  .tmodal__avatar {
    width: 68px;
    height: 68px;
  }
  .tmodal__name {
    font-size: 1.3rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tmodal__dialog {
    transition-duration: 0.01ms;
    transform: none;
  }
  .team__more {
    transition: none;
  }
}

.values {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: 18px;
}
.value {
  padding: 28px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: #fff;
  position: relative;
  overflow: hidden;
}
/* Solid, not outlined, an outline at this weight reads as a rendering fault
   at small sizes and disappears entirely on low-contrast screens. */
.value__n {
  font-family: var(--font-display);
  font-size: 3.4rem;
  font-weight: 900;
  line-height: 1;
  color: var(--line-2);
  margin-bottom: 14px;
}
.value h3 {
  font-size: 1.1rem;
  margin-bottom: 9px;
}
.value p {
  color: var(--muted);
  font-size: 0.93rem;
}

.jobs {
  display: grid;
  gap: 10px;
}
.job {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  padding: 20px 24px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.job:hover {
  transform: translateX(5px);
  box-shadow: var(--sh-2);
  border-color: var(--cyan);
}
.job__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
}
.job__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.job__go {
  margin-left: auto;
  color: var(--blue);
  font-weight: 600;
  font-size: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* ==========================================================================
   Blog / news
   ========================================================================== */
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 22px;
}
.post {
  display: flex;
  flex-direction: column;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.post:hover {
  transform: translateY(-6px);
  box-shadow: var(--sh-3);
}
.post.is-hidden {
  display: none;
}
.post__img {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--paper-2);
}
.post__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease);
}
.post:hover .post__img img {
  transform: scale(1.06);
}
.post__body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  flex: 1;
}
.post__meta {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.78rem;
  color: var(--muted-2);
}
.post__cat {
  color: var(--blue);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.post__title {
  font-family: var(--font-display);
  font-size: 1.16rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
  margin: 12px 0 10px;
}
.post__excerpt {
  color: var(--muted);
  font-size: 0.92rem;
  flex: 1;
}
/* "Read it", the arrow slides out and a rule draws under the label on hover,
   so the whole card reads as one target rather than a static caption. */
.post__go {
  margin-top: 18px;
  font-size: 0.89rem;
  font-weight: 600;
  color: var(--blue);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  position: relative;
  align-self: flex-start;
  transition: gap var(--t) var(--ease);
}
.post__go::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -3px;
  height: 1.5px;
  width: calc(100% - 22px);
  background: currentColor;
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.38s var(--ease);
}
.post__go .k-icon {
  transition: transform 0.38s var(--ease);
}
.post:hover .post__go {
  gap: 11px;
}
.post:hover .post__go::after {
  transform: scaleX(1);
}
.post:hover .post__go .k-icon {
  transform: translateX(3px);
}

.post--feature {
  grid-column: 1 / -1;
  flex-direction: row;
}
.post--feature .post__img {
  aspect-ratio: auto;
  flex: 1 1 52%;
  min-height: 340px;
}
.post--feature .post__body {
  flex: 1 1 48%;
  padding: clamp(28px, 3.4vw, 52px);
  justify-content: center;
}
.post--feature .post__title {
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
}

/* ==========================================================================
   Blog listing: API-backed, with search, Load more and infinite scroll
   ========================================================================== */
.blog-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
  margin-bottom: 26px;
}
.blog-search {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 18px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line-2);
  flex: 1 1 320px;
  max-width: 420px;
  transition: border-color var(--t) var(--ease);
}
.blog-search:focus-within {
  border-color: var(--cyan);
}
.blog-search .k-icon {
  color: var(--muted-2);
  flex: none;
}
.blog-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--ink);
}
.blog-search input:focus {
  outline: none;
}
.blog-toolbar__count {
  font-size: 0.88rem;
  color: var(--muted);
}

.blog-state {
  text-align: center;
  color: var(--muted);
  padding: 48px 0;
}
.blog-state--error {
  color: #c02626;
}

.blog-more {
  display: flex;
  justify-content: center;
  margin-top: 40px;
  position: relative;
}
/* Watched by the infinite scroll; sits above the button so loading starts
   before the visitor actually reaches the bottom. */
.blog-more__sentinel {
  position: absolute;
  top: -600px;
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.blog-more__end {
  text-align: center;
  color: var(--muted-2);
  font-size: 0.88rem;
  margin-top: 40px;
}

/* Appended cards fade up rather than snapping into the grid. */
.post.is-fresh {
  opacity: 0;
  transform: translateY(16px);
}
.post {
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    opacity 0.6s var(--ease-out-soft);
}

/* Placeholders while a page is in flight. */
.post--skeleton {
  pointer-events: none;
  border-color: var(--line);
}
.post--skeleton .post__img {
  background: var(--paper-2);
  aspect-ratio: 16 / 10;
}
.sk {
  display: block;
  border-radius: 6px;
  background: var(--paper-2);
}
.sk--meta {
  width: 45%;
  height: 11px;
  margin-bottom: 14px;
}
.sk--title {
  width: 85%;
  height: 18px;
  margin-bottom: 14px;
}
.sk--line {
  width: 100%;
  height: 11px;
  margin-bottom: 8px;
}
.sk--short {
  width: 60%;
}
.post--skeleton .post__img,
.sk {
  animation: skPulse 1.4s ease-in-out infinite;
}
@keyframes skPulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

/* Article body coming from the API: it ships its own tags, so the shared
   .article rules are extended rather than replaced. */
.article--api img {
  max-width: 100%;
  height: auto;
  border-radius: var(--r-lg);
  margin: 28px 0;
}
.article--api h1 {
  font-size: 1.9rem;
  margin: 40px 0 16px;
}
.article--api table {
  width: 100%;
  border-collapse: collapse;
  margin: 26px 0;
}
.article--api td,
.article--api th {
  border: 1px solid var(--line);
  padding: 10px 14px;
  text-align: left;
}
.article--api ul,
.article--api ol {
  padding-left: 0;
}
.article--api ol {
  list-style: decimal;
  padding-left: 22px;
}
.article--api ol li {
  display: list-item;
  color: var(--ink-2);
  margin-bottom: 8px;
}
.article--api ol li::before {
  content: none;
}
.article--api iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  border: 0;
  border-radius: var(--r-lg);
  margin: 28px 0;
}

/* Article byline + hero */
.article__byline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.article__author {
  display: flex;
  align-items: center;
  gap: 12px;
}
.article__author img {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
}
.article__author b {
  display: block;
  font-size: 0.94rem;
}
.article__author em {
  display: block;
  font-style: normal;
  font-size: 0.82rem;
  color: var(--muted);
}
.article__meta {
  font-size: 0.86rem;
  color: var(--muted);
}

/* ---------- Share row ---------- */
.share {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
  position: relative;
}
.share__copy {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 15px;
  border-radius: 999px;
  cursor: pointer;
  background: #fff;
  border: 1px solid var(--line-2);
  color: var(--ink-2);
  font-family: inherit;
  font-size: 0.84rem;
  font-weight: 600;
  white-space: nowrap;
  transition:
    border-color var(--t) var(--ease),
    color var(--t) var(--ease),
    background-color var(--t) var(--ease);
}
.share__copy:hover {
  border-color: var(--ink);
  color: var(--ink);
}
.share__copy .k-icon {
  transition: transform var(--t) var(--ease);
}
.share__copy:hover .k-icon {
  transform: translateY(-1px);
}
.share__copy.is-copied {
  border-color: #57b894;
  color: #2f8f6b;
  background: #f2fbf7;
}
.share__copy.is-copied .k-icon {
  transform: none;
}

.share__links {
  display: flex;
  align-items: center;
  gap: 8px;
}
.share__net {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  background: #fff;
  color: var(--ink-2);
  transition:
    border-color var(--t) var(--ease),
    transform var(--t) var(--ease),
    color var(--t) var(--ease);
}
.share__net:hover {
  border-color: var(--ink);
  color: var(--ink);
  transform: translateY(-2px);
}
.share__net img,
.share__net svg {
  transition: transform var(--t) var(--ease);
}
.share__net:hover img,
.share__net:hover svg {
  transform: scale(1.08);
}
/* Announced to screen readers; sighted users get the button's label change. */
.share__toast {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

@media (max-width: 560px) {
  .share {
    width: 100%;
    margin-left: 0;
    justify-content: space-between;
  }
  .share__links {
    gap: 6px;
  }
  .share__net {
    width: 32px;
    height: 32px;
  }
}
.article__hero {
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--sh-2);
  margin-top: 34px;
}
.article__hero img {
  width: 100%;
  max-height: 480px;
  object-fit: cover;
}
.article__end {
  margin-top: 44px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}
.article__end a {
  color: var(--blue);
  font-weight: 600;
}

/* Article body: width comes from .k-container--narrow, so text lines up with
   the hero image and any figures. */
.article {
  max-width: 780px;
  margin-inline: auto;
}
.article figure {
  margin: 32px 0;
}
.article figure img {
  margin: 0;
}
.article figcaption {
  font-size: 0.84rem;
  color: var(--muted);
  margin-top: 10px;
  text-align: center;
}
.article blockquote cite {
  display: block;
  font-style: normal;
  font-size: 0.85rem;
  color: var(--muted);
  margin-top: 12px;
}
.article a {
  color: var(--blue);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--blue) 35%, transparent);
  text-underline-offset: 3px;
}
.article a:hover {
  text-decoration-color: var(--blue);
}
.article strong {
  color: var(--ink);
  font-weight: 600;
}
.article p {
  color: var(--ink-2);
  margin-bottom: 22px;
}
.article h2 {
  font-size: 1.7rem;
  margin: 42px 0 16px;
}
.article h3 {
  font-size: 1.24rem;
  margin: 32px 0 12px;
}
.article ul {
  display: grid;
  gap: 10px;
  margin-bottom: 24px;
}
.article ul li {
  display: flex;
  gap: 11px;
  color: var(--ink-2);
}
.article ul li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cyan);
  flex: none;
  margin-top: 10px;
}
.article blockquote {
  margin: 32px 0;
  padding: 24px 28px;
  border-left: 3px solid var(--cyan);
  background: var(--paper);
  border-radius: 0 var(--r) var(--r) 0;
  font-size: 1.06rem;
  color: var(--ink);
}
.article img {
  border-radius: var(--r-lg);
  margin: 32px 0;
  border: 1px solid var(--line);
}

/* ==========================================================================
   Legal pages: sticky section index beside the body
   ========================================================================== */
.legal {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: clamp(30px, 5vw, 76px);
  align-items: start;
}
.legal__toc {
  position: sticky;
  top: calc(var(--sticky-top) + 28px);
  transition: top 0.42s var(--ease);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.legal__toc-title {
  font-size: 0.74rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
  margin-bottom: 12px;
}
.legal__toc > a {
  padding: 8px 12px;
  border-radius: 9px;
  font-size: 0.88rem;
  color: var(--muted);
  border-left: 2px solid var(--line);
  transition: all var(--t) var(--ease);
}
.legal__toc > a:hover {
  color: var(--ink);
  background: var(--paper-2);
}
.legal__toc > a.is-on {
  color: var(--blue);
  border-left-color: var(--blue);
  font-weight: 600;
  background: var(--paper-2);
}
.legal__toc-cta {
  margin-top: 24px;
  padding: 18px;
  border-radius: var(--r);
  background: var(--paper-2);
  border: 1px solid var(--line);
}
.legal__toc-cta p {
  margin-bottom: 8px;
}
.legal__body {
  max-width: 780px;
  margin-inline: 0;
}
.legal__body > section {
  scroll-margin-top: calc(var(--header-h) + 28px);
}
.legal__body > section + section {
  margin-top: 46px;
  padding-top: 40px;
  border-top: 1px solid var(--line);
}
.legal__body h2:first-child {
  margin-top: 0;
}

@media (max-width: 980px) {
  .legal {
    grid-template-columns: 1fr;
  }
  .legal__toc {
    position: relative;
    top: 0;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    padding-bottom: 22px;
    border-bottom: 1px solid var(--line);
  }
  .legal__toc-title {
    width: 100%;
    margin-bottom: 6px;
  }
  .legal__toc > a {
    border-left: 0;
    border: 1px solid var(--line-2);
    border-radius: 999px;
    font-size: 0.82rem;
  }
  .legal__toc > a.is-on {
    border-color: var(--blue);
  }
  .legal__toc-cta {
    width: 100%;
    margin-top: 12px;
  }
}

/* ==========================================================================
   Contact
   ========================================================================== */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
  gap: clamp(28px, 4vw, 60px);
  align-items: start;
}
.cform {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: clamp(26px, 3vw, 42px);
  box-shadow: var(--sh-2);
}
.cform__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
/* reCAPTCHA v3's floating badge, hidden because it lands exactly on the chat
   orb in the bottom-right corner. Google allows this only if the page carries
   the attribution instead, which the note under the form does: see the
   privacy line in contact.php and templates/rep.php. visibility, not display:
   the badge is also the iframe reCAPTCHA works in, and display:none stops it
   scoring. */
.grecaptcha-badge {
  visibility: hidden;
}
/* Honeypot. Off-canvas rather than display:none, which some bots read as a
   field they are meant to skip. Same technique as .aform__hp in careers.css. */
.cform__hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- Submit result (contact form and rep form) ----------

   A notice, not a line of prose. Unstyled it sat between the dark button and
   the grey small print and read as more small print, so the one thing the
   visitor is waiting for was the least visible thing on the form.

   Collapsed rather than display:none when empty: the element carries
   role="status" aria-live="polite", and a live region that is inserted and
   filled in the same frame is announced unreliably. This way it is always in
   the accessibility tree and only costs space once there is something in it. */
.cform__status {
  margin: 0;
  padding: 0;
  border: 0 solid transparent;
  border-radius: var(--r-sm);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  font-size: 0.9rem;
  line-height: 1.55;
  font-weight: 500;
}
.cform__status.is-ok,
.cform__status.is-error {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  max-height: none;
  overflow: visible;
  opacity: 1;
  margin: 18px 0 2px;
  padding: 14px 16px;
  border-width: 1px;
  animation: statusIn 0.34s var(--ease) both;
}
/* The tick and the alert mark are pseudo-elements: the JS sets the text with
   .text(), which would wipe a real child node on every update. */
.cform__status.is-ok::before,
.cform__status.is-error::before {
  content: "";
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 20px 20px;
}
.cform__status.is-ok {
  color: #1f6b52;
  background: #f1f9f5;
  border-color: #c9e7d8;
}
.cform__status.is-ok::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232f7f63' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M8 12.4l2.6 2.6L16 9.6'/%3E%3C/svg%3E");
}
.cform__status.is-error {
  color: #a81f1f;
  background: #fdf3f3;
  border-color: #f4d4d4;
}
.cform__status.is-error::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c02626' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.8v4.6'/%3E%3Cpath d='M12 16.2h.01'/%3E%3C/svg%3E");
}
@keyframes statusIn {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .cform__status.is-ok,
  .cform__status.is-error {
    animation: none;
  }
}
.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin-bottom: 16px;
}
.field label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-2);
}
.field input,
.field select,
.field textarea {
  padding: 13px 16px;
  border-radius: 12px;
  border: 1px solid var(--line-2);
  background: #fff;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--ink);
  width: 100%;
  transition:
    border-color var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.field textarea {
  min-height: 130px;
  resize: vertical;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: none;
}
.field__err {
  font-size: 0.8rem;
  color: #c02626;
  display: none;
}
.field.is-bad input,
.field.is-bad textarea,
.field.is-bad select {
  border-color: #e0796f;
}
.field.is-bad .field__err {
  display: block;
}

/* Valid state + a short shake so a rejected field is impossible to miss. */
.field.is-good input,
.field.is-good textarea {
  border-color: #57b894;
}
@keyframes fieldShake {
  0%,
  100% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(-5px);
  }
  40% {
    transform: translateX(4px);
  }
  60% {
    transform: translateX(-3px);
  }
  80% {
    transform: translateX(2px);
  }
}
.field.is-shaking {
  animation: fieldShake 0.4s var(--ease-soft);
}

/* ==========================================================================
   intl-tel-input skin, the library's own CSS loads first; this makes the
   country selector read as part of our field rather than a bolted-on widget.
   ========================================================================== */
.iti {
  width: 100%;
  display: block;
}
/* The country selector is a tab inside the field: it follows the field's
   rounded left corners rather than sitting in it as a square block, and keeps
   clear of the number with a divider and real breathing room after the code. */
.iti__selected-country,
.iti__selected-flag {
  background: var(--paper-2) !important;
  padding: 0 12px 0 14px !important;
  border-right: 1px solid var(--line);
  border-radius: 11px 0 0 11px !important;
}
/* No hover tint: it darkened a corner of the field for no useful signal.
   The plugin paints it on the inner .iti__selected-country-primary through
   its own --iti-hover-color variable, behind a long :has() selector that is
   awkward to out-specify, so the variable is redefined instead: nothing to
   paint means nothing to override. Keyboard focus still needs a visible
   mark, so that one stays. */
.iti {
  --iti-hover-color: transparent;
}
.iti__selected-country:focus-visible {
  outline: none;
  background: #eaf0f7 !important;
}
.iti--separate-dial-code .iti__selected-dial-code {
  margin-left: 7px;
  margin-right: 2px;
  font-size: 0.93rem;
  color: var(--ink-2);
}
/* Keeps the selector tucked inside the field's own 1px border. */
.iti__country-container {
  padding: 1px 0 1px 1px;
}
.iti__arrow {
  border-top-color: var(--muted-2);
  margin-left: 6px;
}

.iti__dropdown-content,
.iti__country-list {
  border: 1px solid var(--line-2) !important;
  border-radius: 14px !important;
  box-shadow: none !important;
  padding: 6px !important;
  font-family: inherit;
}
/* Only the outer panel hides its overflow, to keep the rounded corners. The
   list inside it must scroll: with overflow hidden on both, four of the 244
   countries were reachable and the wheel did nothing. */
.iti__dropdown-content {
  overflow: hidden;
}
.iti__country-list {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* !important because the plugin writes an inline max-height of its own,
     measured before the modal has settled, which came out at 185px. */
  max-height: min(300px, 42vh) !important;
  overscroll-behavior: contain;
}
.iti__dropdown-content .iti__country-list {
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
}
.iti__search-input {
  height: 40px;
  margin-bottom: 6px;
  padding: 0 12px;
  font-family: inherit;
  font-size: 0.9rem;
  width: 100%;
  background: var(--paper-2);
  border: 1px solid transparent !important;
  border-radius: 10px !important;
}
.iti__search-input:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan) !important;
}
.iti__country {
  padding: 9px 11px;
  border-radius: 9px;
  font-size: 0.9rem;
  color: var(--ink-2);
}
.iti__country.iti__highlight,
.iti__country:hover {
  background: var(--paper-2) !important;
  color: var(--ink);
}
.iti__country.iti__active {
  background: color-mix(in srgb, var(--cyan) 12%, #fff) !important;
}
.iti__divider {
  border-bottom-color: var(--line);
  margin: 5px 0;
}
.iti__dial-code {
  color: var(--muted);
}

/* ==========================================================================
   Custom select: replaces the native dropdown, which cannot be styled and
   renders as an OS menu. Progressive enhancement: the real <select> stays in
   the DOM (hidden) so the form still submits and validates normally.
   ========================================================================== */
.ksel {
  position: relative;
}
.ksel__native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.ksel__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 13px 16px;
  border-radius: 12px;
  border: 1px solid var(--line-2);
  background: #fff;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t) var(--ease);
}
.ksel__btn:hover {
  border-color: var(--muted-2);
}
.ksel.is-open .ksel__btn {
  border-color: var(--cyan);
}
.field.is-bad .ksel__btn {
  border-color: #e0796f;
}
.ksel__value {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ksel__value.is-placeholder {
  color: var(--muted-2);
}
.ksel__chev {
  flex: none;
  color: var(--muted);
  transition: transform var(--t) var(--ease);
}
.ksel.is-open .ksel__chev {
  transform: rotate(180deg);
  color: var(--cyan);
}

.ksel__menu {
  position: absolute;
  z-index: 40;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  background: #fff;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  padding: 6px;
  max-height: 292px;
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity 0.18s var(--ease),
    transform 0.22s var(--ease),
    visibility 0.18s;
}
.ksel.is-open .ksel__menu {
  opacity: 1;
  visibility: visible;
  transform: none;
}
/* Flip above the button when there is no room below (last field on a form). */
.ksel.is-up .ksel__menu {
  top: auto;
  bottom: calc(100% + 6px);
  transform: translateY(6px);
}
.ksel.is-up.is-open .ksel__menu {
  transform: none;
}

.ksel__opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 11px 13px;
  border-radius: 9px;
  font-size: 0.94rem;
  color: var(--ink-2);
  cursor: pointer;
  transition:
    background-color 0.12s var(--ease),
    color 0.12s var(--ease);
}
.ksel__opt:hover {
  background: var(--paper-2);
  color: var(--ink);
}
.ksel__opt.is-active {
  background: var(--paper-2);
  color: var(--ink);
}
.ksel__opt.is-selected {
  color: var(--blue);
  font-weight: 600;
}
.ksel__opt .ksel__tick {
  flex: none;
  opacity: 0;
  color: var(--blue);
  transition: opacity 0.12s var(--ease);
}
.ksel__opt.is-selected .ksel__tick {
  opacity: 1;
}
.ksel__menu::-webkit-scrollbar {
  width: 10px;
}
.ksel__menu::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: 99px;
  border: 3px solid #fff;
}

/* The map is a sibling of the info cards, not one of them, so the column owns
   the rhythm, one value spaces the cards and the map alike, instead of the
   map carrying its own margin that drifted out of step. */
.cside {
  --cside-gap: 12px;
  display: grid;
  gap: var(--cside-gap);
  align-content: start;
}
.cinfo {
  display: grid;
  gap: var(--cside-gap, 12px);
}
.cinfo__item {
  display: flex;
  gap: 15px;
  padding: 20px 22px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.cinfo__item:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-2);
}
.cinfo__icon {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  color: var(--blue);
  background: rgba(16, 83, 126, 0.08);
  flex: none;
}
.cinfo__label {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
}
.cinfo__value {
  display: block;
  font-weight: 600;
  margin-top: 3px;
}
.cinfo__value a:hover {
  color: var(--blue);
}
.cinfo__note {
  display: block;
  font-size: 0.86rem;
  color: var(--muted);
  margin-top: 4px;
}
.cmap {
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
}
.cmap img {
  width: 100%;
  height: 220px;
  object-fit: cover;
}

/* ==========================================================================
   Numbered benefit cards: 01..06
   ========================================================================== */
.numcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.numcard {
  background: #fff;
  padding: clamp(26px, 3vw, 40px);
  position: relative;
  transition: background-color var(--t) var(--ease);
}
.numcard:hover {
  background: var(--paper);
}
.numcard__n {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}
.numcard__n::after {
  content: "";
  width: 34px;
  height: 1px;
  background: color-mix(in srgb, var(--accent) 40%, var(--line));
  transition: width 0.45s var(--ease);
}
.numcard:hover .numcard__n::after {
  width: 62px;
}
.numcard h3 {
  font-size: 1.14rem;
  margin-bottom: 10px;
  letter-spacing: -0.02em;
}
.numcard p {
  color: var(--muted);
  font-size: 0.93rem;
}

/* ==========================================================================
   Metric callouts, the big quantified proof numbers
   ========================================================================== */
.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(20px, 3vw, 44px);
}
.metric {
  position: relative;
  padding-top: 26px;
  border-top: 2px solid var(--line);
  transition: border-color var(--t) var(--ease);
}
.metric:hover {
  border-top-color: var(--accent);
}
.metric__num {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: -0.05em;
  font-size: clamp(2.8rem, 5.4vw, 4.6rem);
  background: linear-gradient(
    115deg,
    var(--ink) 8%,
    var(--blue) 52%,
    var(--cyan) 96%
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.metric__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  margin: 14px 0 8px;
  letter-spacing: -0.015em;
}
.metric__text {
  color: var(--muted);
  font-size: 0.92rem;
  max-width: 34ch;
}

/* ==========================================================================
   "Works with the tools you already use": integration grid
   ========================================================================== */
/* Two marquees running against each other, the same component the homepage
   uses, so partners read the same way wherever they appear. */

.integration {
  background: #fff;
  min-height: 108px;
  display: grid;
  place-items: center;
  padding: 22px;
  transition:
    background-color var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.integration img {
  max-height: 28px;
  width: auto;
  filter: grayscale(1);
  opacity: 0.55;
  transition:
    filter var(--t) var(--ease),
    opacity var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.integration:hover {
  background: var(--paper);
}
.integration:hover img {
  filter: none;
  opacity: 1;
  transform: scale(1.06);
}
.integration__more {
  background: var(--paper);
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--blue);
  text-align: center;
}

/* ==========================================================================
   How it works, three steps with a connecting line
   ========================================================================== */
.howto {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: clamp(22px, 3vw, 40px);
}
.howto::before {
  content: "";
  position: absolute;
  top: 33px;
  left: 8%;
  right: 8%;
  height: 2px;
  background: repeating-linear-gradient(
    90deg,
    var(--line-2) 0 8px,
    transparent 8px 16px
  );
  z-index: 0;
}
.howto__step {
  position: relative;
  z-index: 1;
  text-align: center;
}
.howto__badge {
  width: 66px;
  height: 66px;
  margin: 0 auto 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: #fff;
  border: 2px solid var(--line-2);
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  transition: all var(--t) var(--ease);
}
.howto__step:hover .howto__badge {
  border-color: var(--accent);
  background: var(--accent);
  color: #fff;
  transform: translateY(-4px) scale(1.05);
}
.howto__title {
  font-family: var(--font-display);
  font-size: 1.16rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 10px;
}
.howto__text {
  color: var(--muted);
  font-size: 0.93rem;
  max-width: 34ch;
  margin-inline: auto;
}

/* ==========================================================================
   Ratings / trust badges row
   ========================================================================== */
.ratings {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}
.rating {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 15px 22px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.rating:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-2);
}
.rating__score {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.03em;
}
.rating__stars {
  display: flex;
  gap: 2px;
  color: var(--yellow);
}
.rating__stars svg {
  fill: currentColor;
  stroke: none;
}
.rating__src {
  font-size: 0.8rem;
  color: var(--muted);
}

@media (max-width: 1024px) {
  .howto::before {
    display: none;
  }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1180px) {
  .bento {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .bento__cell--3,
  .bento__cell--4 {
    grid-column: span 4;
  }
  .bento__cell--2 {
    grid-column: span 2;
  }
  .bento__cell--6 {
    grid-column: span 4;
  }
}

@media (max-width: 1024px) {
  .eco__panel.is-active,
  .steps__stage,
  .show-row,
  .splitband,
  .contact-grid {
    grid-template-columns: 1fr;
  }
  .show-row:nth-child(even) .show-row__media {
    order: 0;
  }
  /* Stacked, the shot leads and nothing pins, a pinned stage would sit on top
     of the very text it illustrates. JS clears the track height to match. */
  .steps__media {
    order: -1;
  }
  .steps__list {
    gap: clamp(24px, 3vw, 42px);
  }
  .steps.is-pinned .steps__stage {
    position: static;
  }
  .steps.is-pinned .steps__item {
    opacity: 1;
  }
  .h-card--a {
    top: 5%;
    left: 1%;
  }
  .h-card--b {
    top: 28%;
    right: 1%;
  }
  .h-card--c {
    bottom: 18%;
    left: 2%;
  }
  .k-head--split {
    grid-template-columns: 1fr;
  }
  .post--feature {
    flex-direction: column;
  }

  /* Keep the chips over the shot once there is no room beside it. */
  .p-hero__chip--1 {
    top: 6%;
    left: 2%;
  }
  .p-hero__chip--2 {
    bottom: 12%;
    right: 2%;
  }
  .h-card--a {
    top: 4%;
    left: 1%;
  }
  .h-card--b {
    top: 26%;
    right: 1%;
  }
  .h-card--c {
    bottom: 14%;
    left: 1%;
  }
  /* Once the feature card stacks, its picture is as wide as the card and a
     forced height turns into a sideways crop. The news artwork carries its
     caption baked into the bottom left corner, so that crop was eating the
     name off the front of the page. Let the picture keep its own shape
     instead, capped so a tall one cannot take over the screen. */
  .post--feature .post__img {
    /* flex-basis is a height once the card is a column, so the 52% from the
       side-by-side layout has to go too or it sizes the pane instead of the
       picture. */
    flex: 0 0 auto;
    min-height: 0;
    aspect-ratio: auto;
  }
  .post--feature .post__img img {
    height: auto;
    max-height: 56vh;
    /* Only bites at the cap, and letterboxes rather than crops when it does. */
    object-fit: contain;
  }
  /* The zoom would crop the caption back off again, and there is no hover on
     the devices this applies to anyway. */
  .post--feature:hover .post__img img {
    transform: none;
  }
}

@media (max-width: 1024px) {
  .ind-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .ind-card,
  .ind-grid > :nth-child(4),
  .ind-grid > :nth-child(5) {
    grid-column: span 2;
  }
}

@media (max-width: 820px) {
  .bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .bento__cell,
  .bento__cell--2,
  .bento__cell--3,
  .bento__cell--4,
  .bento__cell--6 {
    grid-column: span 2;
  }
  .eco__tabs {
    width: 100%;
    overflow-x: auto;
    flex-wrap: nowrap;
    justify-content: flex-start;
    border-radius: var(--r);
  }
  .eco__ink {
    border-radius: var(--r);
  }
  .eco__tab {
    border-radius: var(--r);
  }
  .splitband__media {
    min-height: 240px;
  }
  .cform__row {
    grid-template-columns: 1fr;
    gap: 0;
  }
}

@media (max-width: 640px) {
  .ind-grid {
    grid-template-columns: 1fr;
  }
  .ind-card,
  .ind-grid > :nth-child(4),
  .ind-grid > :nth-child(5) {
    grid-column: span 1;
  }
  .bento {
    grid-template-columns: 1fr;
  }
  .bento__cell,
  .bento__cell--2,
  .bento__cell--3,
  .bento__cell--4,
  .bento__cell--6 {
    grid-column: span 1;
  }
  /* Give the shot the full screen width, and drop the floating overlays: at
     this size they cover more of the UI than they add, and everything they
     say is already in the hero bullets and the metrics row.

     Only the product hero, which is still one photograph. The home hero is a
     grid of cards now, and bleeding that to the edges left the tiles hard
     against the screen while every other block on the page kept its gutter. */
  .p-hero__media {
    width: calc(100% + var(--gutter) * 2);
    margin-inline: calc(var(--gutter) * -1);
  }
  .h-card,
  .p-hero__chip {
    display: none;
  }
  .home-hero__title {
    font-size: clamp(2.1rem, 9vw, 2.8rem);
  }
  .slider__track {
    grid-auto-columns: minmax(84%, 1fr);
  }
  .stats {
    grid-template-columns: 1fr 1fr;
  }
  .p-nav__cta {
    display: none;
  }
  .article blockquote {
    padding: 18px 20px;
  }
}

/* ==========================================================================
   Stacked button pairs, phones only

   Every action row is a flex row of pills, so once it wraps to one per line
   each button is shrink-to-fit and the longer label makes a visibly wider
   button. Stacking them full width makes the pair match.

   .reservations-features__actions is qualified by its section because
   feature-explorer.css loads after this file and would otherwise win the
   align-items declaration on equal specificity.
   ========================================================================== */
@media (max-width: 560px) {
  .home-hero__actions,
  .p-hero__actions,
  .k-cta__actions,
  .jobs__emptyacts,
  .adone__acts,
  .reservations-features .reservations-features__actions {
    flex-direction: column;
    align-items: stretch;
  }
  .home-hero__actions > .k-btn,
  .p-hero__actions > .k-btn,
  .k-cta__actions > .k-btn,
  .jobs__emptyacts > .k-btn,
  .adone__acts > .k-btn,
  .reservations-features .reservations-features__actions > .k-btn {
    width: 100%;
  }
}

/* ==========================================================================
   Pricing calculator (iReview)

   The published price depends on location count and contract length, so the
   page carries the same controls the live site does rather than printing one
   number and hoping it applies.
   ========================================================================== */
.calc__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px 20px;
  margin-bottom: 30px;
}
.calc__locs {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 16px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line-2);
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink-2);
}
.calc__locs input {
  width: 56px;
  padding: 8px 4px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  text-align: center;
  color: var(--ink);
  /* The native spinner is too small to hit and looks nothing like the rest
     of the UI: we ship our own -/+ buttons instead. */
  -moz-appearance: textfield;
  appearance: textfield;
}
.calc__locs input::-webkit-outer-spin-button,
.calc__locs input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.calc__locs input:focus {
  outline: none;
}
.calc__locs:focus-within {
  border-color: var(--accent);
}
.calc__step {
  width: 32px;
  height: 32px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: var(--paper);
  color: var(--ink-2);
  cursor: pointer;
  padding: 0;
  transition:
    background var(--t) var(--ease),
    color var(--t) var(--ease),
    border-color var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.calc__step:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.calc__step:active {
  transform: scale(0.9);
}
.calc__step:disabled {
  opacity: 0.38;
  cursor: not-allowed;
  background: var(--paper);
  border-color: var(--line-2);
  color: var(--ink-2);
  transform: none;
}

.calc__terms {
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--line);
}
.calc__term {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  background: none;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--muted);
  transition:
    background var(--t) var(--ease),
    color var(--t) var(--ease);
}
.calc__term i {
  font-style: normal;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 12%, #fff);
  color: var(--accent);
}
.calc__term:hover {
  color: var(--ink);
}
.calc__term.is-active {
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line);
  padding: 8px 15px;
}
.calc__band {
  width: 100%;
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted-2);
  margin: 0;
}

/* One tier name runs to two lines. Reserve the second line on every card so
   the descriptions and prices sit on one row across the four columns. */
@media (min-width: 720px) {
  .calc .plan__name {
    min-height: 2.4em;
  }
}

/* À la carte column: the price is whatever is ticked. `flex: 1` matches
   .plan__list so this card's button lands on the same line as the others. */
.calc__opts {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  display: grid;
  gap: 2px;
  align-content: start;
  flex: 1;
}
/* Unless the included-features list follows it, which takes the growth
   instead so both cards' buttons still land on the same line. */
.calc__opts:has(+ .plan__list) {
  flex: none;
  margin-bottom: 0;
}
.calc__opt {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 10px;
  border-radius: 11px;
  cursor: pointer;
  transition: background var(--t) var(--ease);
}
.calc__opt:hover {
  background: var(--paper-2);
}
.calc__opt input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.calc__box {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  flex: none;
  border: 1.5px solid var(--line-2);
  background: #fff;
  display: grid;
  place-items: center;
  color: #fff;
  transition:
    background var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.calc__box svg {
  opacity: 0;
  transform: scale(0.6);
  transition:
    opacity 0.18s var(--ease),
    transform 0.24s var(--ease);
}
.calc__opt input:checked + .calc__box {
  background: var(--accent);
  border-color: var(--accent);
}
.calc__opt input:checked + .calc__box svg {
  opacity: 1;
  transform: none;
}
.calc__opt input:focus-visible + .calc__box {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.calc__optname {
  flex: 1 1 auto;
  font-size: 0.9rem;
  color: var(--ink-2);
}
.calc__optprice {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}

/* The single plan sits beside the calculator that sizes it, so this pair wants
   more width each than the four-up grids get. */
.plans--pair {
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  max-width: 880px;
  margin-inline: auto;
}
.calc__locs--wide {
  width: 100%;
  justify-content: space-between;
  margin-bottom: 12px;
}
.calc__locs--wide label {
  margin-right: auto;
}
.calc__locs--wide input {
  width: 72px;
}
.plan--calc .calc__band {
  text-align: left;
  flex: 1;
  margin: 0 0 24px;
  font-size: 0.82rem;
}
.calc__foot {
  margin: 18px 0 0;
  text-align: center;
  font-size: 0.98rem;
  color: var(--muted-2);
}

/* An optional line the buyer can switch off, which changes the price above. */
.plan__ai {
  align-items: center;
}
.plan__ai .k-icon {
  color: var(--accent);
  flex: none;
}
.plan__ai > span:last-child {
  transition: color var(--t) var(--ease);
}
.plan__ai:not(.is-on) > span:last-child {
  color: var(--muted-2);
  text-decoration: line-through;
}
.plan__ai:not(.is-on) .k-icon {
  color: var(--muted-2);
}

/* Standing charge shown on every card, an advisory, not a feature. */
.plan__info {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  margin: 0 0 20px;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--muted-2);
}
.plan__info .k-icon {
  color: var(--accent);
  flex: none;
  margin-top: 1px;
}

.aiswitch {
  position: relative;
  display: inline-flex;
  flex: none;
  cursor: pointer;
  margin-top: 1px;
}
.aiswitch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.aiswitch__track {
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--line-2);
  transition: background var(--t) var(--ease);
}
.aiswitch__track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  transition: transform var(--t) var(--ease);
}
.aiswitch input:checked + .aiswitch__track {
  background: var(--accent);
}
.aiswitch input:checked + .aiswitch__track::after {
  transform: translateX(14px);
}
.aiswitch input:focus-visible + .aiswitch__track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Headline-price-only cards: nothing between the price and the button, so the
   button needs its own breathing room and the card its own floor. */
.plans--simple .plan > .k-btn {
  margin-top: 26px;
}
.plans--simple .plan__note {
  margin-bottom: 0;
}

/* --------------------------------------------------------------------------
   Term-priced plans (Designed.co)

   The source sells design time in measured quantities, hours, projects,
   priorities, so each row is a figure over the thing it measures rather than
   a tick and a sentence.
   -------------------------------------------------------------------------- */
.plans--4 {
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
}

.plan__specs {
  list-style: none;
  margin: 22px 0 24px;
  padding: 0;
  display: grid;
  gap: 0;
  flex: 1;
  align-content: start;
}
.plan__specs li {
  display: grid;
  gap: 1px;
  padding: 11px 0;
  border-top: 1px solid var(--line);
}
.plan__specs li:first-child {
  border-top: 0;
  padding-top: 0;
}
.plan__specs b {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ink);
}
.plan__specs span {
  font-size: 0.8rem;
  color: var(--muted);
}

/* AI Design is priced per request bundle, not per month of team time. */
.aiplan {
  margin-top: 18px;
  padding: 26px 30px;
  border-radius: var(--r-lg);
  background: #fff;
  border: 1px solid var(--line);
  display: grid;
  gap: 20px 34px;
  align-items: center;
  grid-template-columns: minmax(0, 1fr) auto;
}
.aiplan__tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--ink);
}
.aiplan__tag .k-icon {
  color: var(--accent);
}
.aiplan__desc {
  margin: 8px 0 0;
  font-size: 0.92rem;
  color: var(--ink-2);
  max-width: 52ch;
}
.aiplan__buy {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.aiplan__buy .plan__price {
  margin: 0;
}
.aiplan__pick select {
  appearance: none;
  font: inherit;
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--ink-2);
  padding: 9px 34px 9px 15px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid var(--line-2);
  background: var(--paper) no-repeat right 14px center;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%236b7280' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
  transition: border-color var(--t) var(--ease);
}
.aiplan__pick select:hover,
.aiplan__pick select:focus {
  outline: none;
  border-color: var(--accent);
}
.aiplan__specs {
  grid-column: 1 / -1;
  margin: 0;
  flex: none;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0 26px;
  border-top: 1px solid var(--line);
  padding-top: 4px;
}
.aiplan__specs li {
  border-top: 0;
}
.aiplan__specs li:first-child {
  padding-top: 11px;
}
.aiplan .k-btn {
  grid-column: 1 / -1;
  justify-self: start;
}

@media (max-width: 760px) {
  .aiplan {
    grid-template-columns: minmax(0, 1fr);
    padding: 24px;
  }
  .aiplan .k-btn {
    justify-self: stretch;
  }
}

@media (max-width: 700px) {
  .calc__terms {
    width: 100%;
    justify-content: center;
  }
  .calc__term {
    padding: 9px 12px;
    font-size: 0.82rem;
  }
}

/* On the narrowest phones the four terms are wider than the track they sit
   in, and the track has nowhere to put the overflow, so the page was being
   pushed sideways. Letting them wrap keeps the control whole. */
@media (max-width: 400px) {
  .calc__terms {
    flex-wrap: wrap;
    border-radius: 18px;
  }
  .calc__term {
    flex: 1 1 auto;
    justify-content: center;
    padding: 9px 10px;
  }
}

/* ==========================================================================
   404
   A dead end should still look like the rest of the site, so this borrows the
   section hero, .fgrid and .eco__item wholesale. Only the numeral, the echoed
   URL and the suggestion row are its own.
   ========================================================================== */
.e404__inner {
  padding-block: clamp(10px, 3vw, 30px);
}
/* Set in the display face at a size where the gradient has room to travel.
   Sits behind the headline as texture, not as a heading. */
.e404__code {
  display: block;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(5.5rem, 16vw, 11rem);
  line-height: 0.86;
  letter-spacing: -0.05em;
  margin-bottom: clamp(10px, 2vw, 20px);
  background: linear-gradient(
    115deg,
    var(--blue),
    var(--cyan) 42%,
    var(--yellow)
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.e404__url {
  margin-top: 16px;
  font-size: 0.9rem;
  color: var(--muted);
}
.e404__url code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 3px 9px;
  color: var(--ink-2);
  word-break: break-all;
}
/* The one guess we are confident about, given the weight of a card so it is
   not mistaken for another body line. */
.e404__guess {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 22px;
  padding: 10px 18px 10px 14px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: var(--sh-1);
}
.e404__guess-label {
  font-size: 0.84rem;
  color: var(--muted);
}
.e404__guess-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  color: var(--ink);
  transition:
    color var(--t) var(--ease),
    gap var(--t) var(--ease);
}
.e404__guess-link:hover {
  color: var(--accent);
  gap: 14px;
}
.e404__guess-link .k-icon {
  color: var(--accent);
}
.e404__guess-icon {
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 11px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
}
.e404__guess-icon--logo {
  background: #fff;
  border: 1px solid var(--line);
  padding: 4px;
}
.e404__guess-icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.e404__cta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 28px;
}
/* Six routes divide as 3 + 3. Left to auto-fill they land 4 + 2 on a wide
   screen, which leaves half the second row empty. */
@media (min-width: 1080px) {
  .e404__routes {
    grid-template-columns: repeat(3, 1fr);
  }
}
/* Two columns of the same row component the home page uses, so the full list
   of sixteen reads as a directory rather than a wall. */
.e404__apps {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
  gap: 12px;
}
@media (max-width: 560px) {
  .e404__guess {
    width: 100%;
    justify-content: flex-start;
  }
}

/* ==========================================================================
   Home hero: the six-product grid
   Replaces the single rotating screenshot. Tiles are links, so this is the
   first navigation on the page as well as the proof shot.
   ========================================================================== */
.hgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 20px);
}
.hgrid__tile {
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease),
    border-color var(--t) var(--ease);
}
.hgrid__tile:hover {
  transform: translateY(-6px);
  box-shadow: var(--sh-3);
  border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
}
/* Anchored to the top of the capture: these are 2255x1574 dashboards, and
   centring them cuts the header off, which is the part that says what the
   product is. */
.hgrid__shot {
  position: relative; /* the "and more" overlay anchors to this */
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--paper-2);
  border-bottom: 1px solid var(--line);
}
.hgrid__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  transition: transform 0.8s var(--ease);
}
.hgrid__tile:hover .hgrid__shot img {
  transform: scale(1.04);
}

.hgrid__foot {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 15px;
}
.hgrid__icon {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 9px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, #fff);
}
.hgrid__icon--logo {
  background: #fff;
  border: 1px solid var(--line);
  padding: 3px;
}
.hgrid__icon--logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.hgrid__name {
  font-weight: 650;
  font-size: 0.95rem;
  color: var(--ink);
  letter-spacing: -0.01em;
}
/* Parked off to the right, sliding in on hover: with six tiles, six arrows
   sitting there at rest turned the row into a column of chevrons. */
.hgrid__go {
  margin-left: auto;
  display: grid;
  place-items: center;
  color: var(--accent);
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.hgrid__tile:hover .hgrid__go {
  opacity: 1;
  transform: none;
}


.hgrid__foot-note {
  margin-top: 20px;
  text-align: center;
  font-size: 0.9rem;
  color: var(--muted);
}
.hgrid__foot-note a {
  color: var(--blue);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.hgrid__foot-note a:hover {
  text-decoration: underline;
}

/* Two up on a tablet, one on a phone: a third of a phone screen is too small
   for a dashboard capture to say anything. */
@media (max-width: 900px) {
  .hgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
/* Still two up on a phone. One per row turns six dashboards into a very long
   scroll before the page has said anything else; at this size the shot is
   read as "a dashboard" rather than for its content anyway, and the label
   under it carries the meaning. */
@media (max-width: 560px) {
  .hgrid {
    gap: 10px;
  }
  .hgrid__foot {
    padding: 10px 11px;
    gap: 8px;
  }
  .hgrid__icon {
    width: 26px;
    height: 26px;
    border-radius: 8px;
  }
  .hgrid__name {
    font-size: 0.82rem;
  }
  .hgrid__go {
    display: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .hgrid__tile:hover {
    transform: none;
  }
  .hgrid__tile:hover .hgrid__shot img {
    transform: none;
  }
}

/* ==========================================================================
   Inside Kore: the photo wall
   Four columns that drift against each other as the section passes, with two
   stat tiles cut into the grid so it carries a fact as well as a mood.
   ========================================================================== */
.collage-band {
  overflow: hidden; /* the columns ride past their box; keep them inside it */
}
.collage {
  --gap: clamp(12px, 1.2vw, 18px);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap);
  /* Wider than the 1220px text column above it, but still inside the viewport:
     bleeding it off the edge cut the outer tiles in half, which read as a
     mistake rather than as the wall carrying on past the page. */
  width: min(1440px, 100%);
  margin: clamp(28px, 3vw, 44px) auto 0;
  padding-inline: var(--gutter);
  align-items: start;
}
/* Each column is offset by its own amount, set from JS as --y. The odd ones
   also start lower, which is what breaks the grid into a wall. */
.collage__col {
  display: grid;
  gap: var(--gap);
  transform: translate3d(0, var(--y, 0px), 0);
  will-change: transform;
}
.collage__col:nth-child(2) {
  margin-top: calc(var(--gap) * 2.6);
}
.collage__col:nth-child(4) {
  margin-top: calc(var(--gap) * 1.4);
}

.collage__tile {
  position: relative;
  margin: 0;
  aspect-ratio: var(--ar, 1 / 1);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--paper-2);
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.collage__tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease);
}
/* The caption rides on a scrim rather than the photo, so it stays legible
   whatever is behind it. */
.collage__tile figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 26px 14px 12px;
  font-size: 0.8rem;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(180deg, transparent, rgba(9, 17, 28, 0.72));
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.collage__tile:hover {
  transform: translateY(-4px);
  box-shadow: var(--sh-3);
}
.collage__tile:hover img {
  transform: scale(1.06);
}
.collage__tile:hover figcaption {
  opacity: 1;
  transform: none;
}

/* A tile that is a number instead of a photograph. Same footprint, so it sits
   in the wall rather than interrupting it. */
.collage__stat {
  display: grid;
  align-content: center;
  gap: 4px;
  aspect-ratio: 1 / 1;
  padding: 20px;
  border-radius: var(--r-lg);
  background: linear-gradient(150deg, var(--ink), #16273d);
  color: #fff;
  text-align: center;
}
.collage__num {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.4vw, 2.8rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  background: linear-gradient(115deg, #fff, var(--cyan));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.collage__statlabel {
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.72);
}

@media (max-width: 900px) {
  /* Two columns, no drift: on a short viewport the offsets fight the scroll
     more than they flatter it, and initCollage stops setting --y. */
  .collage {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%;
  }
  .collage__col {
    transform: none;
  }
  .collage__col:nth-child(2) {
    margin-top: calc(var(--gap) * 1.6);
  }
  .collage__col:nth-child(4) {
    margin-top: 0;
  }
  .collage__tile figcaption {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .collage__col {
    transform: none;
  }
  .collage__tile:hover {
    transform: none;
  }
  .collage__tile:hover img {
    transform: none;
  }
}

/* ==========================================================================
   Video testimonials
   Poster cards that preview themselves muted on hover, and a single player
   they all open into.
   ========================================================================== */
.vstories {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.4vw, 20px);
  margin-top: clamp(26px, 3vw, 40px);
}
.vstory {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.vstory__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink);
  border: 1px solid var(--line);
  transition:
    transform var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.vstory__media img,
.vstory__media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The preview sits over the poster and fades in once it has frames to show,
   so the card never flashes black while it buffers. */
.vstory__media video {
  opacity: 0;
  transition: opacity 0.45s var(--ease);
}
.vstory__media video.is-ready {
  opacity: 1;
}
.vstory__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(9, 17, 28, 0) 42%,
    rgba(9, 17, 28, 0.68)
  );
  pointer-events: none;
}
.vstory__play {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 56px;
  height: 56px;
  margin: -28px 0 0 -28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  box-shadow: 0 8px 24px rgba(9, 17, 28, 0.3);
  transition:
    transform var(--t) var(--ease),
    background-color var(--t) var(--ease);
}
/* A ring that pulses outward, so the card reads as playable at a glance. */
.vstory__play::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.55);
  animation: vpulse 2.6s var(--ease) infinite;
}
@keyframes vpulse {
  0% {
    transform: scale(0.9);
    opacity: 0.9;
  }
  70% {
    transform: scale(1.25);
    opacity: 0;
  }
  100% {
    transform: scale(1.25);
    opacity: 0;
  }
}
.vstory__len {
  position: absolute;
  right: 10px;
  top: 10px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  color: #fff;
  background: rgba(9, 17, 28, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.vstory:hover .vstory__media,
.vstory:focus-visible .vstory__media {
  transform: translateY(-6px);
  box-shadow: var(--sh-3);
}
.vstory:hover .vstory__play {
  transform: scale(1.08);
  background: #fff;
}
.vstory:focus-visible .vstory__media {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

.vstory__body {
  display: block;
  padding: 14px 4px 0;
}
.vstory__quote {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.vstory__name {
  display: block;
  margin-top: 8px;
  font-size: 0.88rem;
  font-weight: 600;
}
.vstory__role {
  display: block;
  font-size: 0.82rem;
  color: var(--muted);
}

/* ---------------- The player ---------------- */
.vplayer {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 32px);
  pointer-events: none;
}
body.is-vplayer .vplayer {
  pointer-events: auto;
}
.vplayer__scrim {
  position: absolute;
  inset: 0;
  background: rgba(6, 12, 20, 0.82);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.32s var(--ease);
}
body.is-vplayer .vplayer__scrim {
  opacity: 1;
}
.vplayer__dialog {
  position: relative;
  width: min(980px, 100%);
  opacity: 0;
  transform: translateY(16px) scale(0.98);
  transition:
    opacity 0.32s var(--ease),
    transform 0.42s var(--ease-out-soft);
}
body.is-vplayer .vplayer__dialog {
  opacity: 1;
  transform: none;
}
.vplayer__stage {
  position: relative;
  display: grid;
  place-items: center;
}
.vplayer__stage video {
  width: 100%;
  max-height: min(74vh, 620px);
  border-radius: var(--r-lg);
  background: #000;
  display: block;
}
.vplayer__x {
  position: absolute;
  top: -46px;
  right: 0;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  transition:
    background-color var(--t) var(--ease),
    transform var(--t) var(--ease);
}
.vplayer__x:hover {
  background: rgba(255, 255, 255, 0.28);
  transform: rotate(90deg);
}
/* Outside the frame on a wide screen, so they never cover the controls. */
.vplayer__nav {
  position: absolute;
  top: 50%;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  transition: background-color var(--t) var(--ease);
}
.vplayer__nav:hover {
  background: rgba(255, 255, 255, 0.3);
}
.vplayer__nav--prev {
  left: -60px;
}
.vplayer__nav--next {
  right: -60px;
}
.vplayer__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-top: 16px;
  color: #fff;
}
.vplayer__name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
}
.vplayer__role {
  font-size: 0.86rem;
  color: rgba(255, 255, 255, 0.66);
  margin-top: 2px;
}
.vplayer__count {
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.5);
  flex: none;
}

@media (max-width: 1100px) {
  .vstories {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* No room beside the frame at this width, so they come inside it. */
  .vplayer__nav--prev {
    left: 8px;
  }
  .vplayer__nav--next {
    right: 8px;
  }
}
@media (max-width: 560px) {
  .vstories {
    grid-template-columns: 1fr;
  }
  .vplayer__x {
    top: -40px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .vstory__play::after {
    animation: none;
  }
  .vstory:hover .vstory__media {
    transform: none;
  }
}

/* ---------------- The "and more" tile ---------------- */
/* Last in the hero grid, always. The shot behind it is a blurred montage of
   real product screenshots, so it reads as more of the same platform rather
   than as a decorative panel. */
.hgrid__tile--more .hgrid__shot img {
  transform: scale(1.06); /* hides the soft edge the blur leaves */
}
.hgrid__tile--more:hover .hgrid__shot img {
  transform: scale(1.1);
}
.hgrid__morefx {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, 0.55),
    rgba(233, 240, 248, 0.72)
  );
}
/* The logos overlap into a stack, the way a pile of cards would. */
.hgrid__morelogos {
  display: flex;
}
.hgrid__morelogo {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 6px;
  border-radius: 13px;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 6px 16px rgba(11, 21, 36, 0.1);
  /* Transform and shadow only: the fan used to be a margin change, which the
     browser cannot interpolate and which reflows the row on every frame, so it
     jumped straight to the open position. */
  transition:
    transform 0.5s var(--ease-out-soft),
    box-shadow 0.5s var(--ease);
}
.hgrid__morelogo + .hgrid__morelogo {
  margin-left: -10px;
}
.hgrid__morelogo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Fan the stack open on hover: each card slides a little further than the one
   inside it and tilts with it, so it opens like a hand of cards rather than
   four tiles moving as a block. The delays cascade from the middle out. */
.hgrid__tile--more:hover .hgrid__morelogo,
.hgrid__tile--more:focus-visible .hgrid__morelogo {
  box-shadow: 0 10px 22px rgba(11, 21, 36, 0.16);
}
.hgrid__tile--more:hover .hgrid__morelogo:nth-child(1) {
  transform: translate(-11px, -3px) rotate(-5deg);
  transition-delay: 60ms;
}
.hgrid__tile--more:hover .hgrid__morelogo:nth-child(2) {
  transform: translate(-4px, -7px) rotate(-2deg);
  transition-delay: 20ms;
}
.hgrid__tile--more:hover .hgrid__morelogo:nth-child(3) {
  transform: translate(4px, -7px) rotate(2deg);
  transition-delay: 20ms;
}
.hgrid__tile--more:hover .hgrid__morelogo:nth-child(4) {
  transform: translate(11px, -3px) rotate(5deg);
  transition-delay: 60ms;
}
.hgrid__morecount {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--ink);
}
.hgrid__icon--more {
  background: var(--paper-2);
  border-color: var(--line);
  color: var(--ink-2);
}
@media (max-width: 560px) {
  .hgrid__morelogo {
    width: 38px;
    height: 38px;
    border-radius: 11px;
  }
  .hgrid__morecount {
    font-size: 1.3rem;
  }
}

/* ==========================================================================
   Legal documents (privacy, terms)
   The koreco layout: one column of prose, headings in caps, nothing else.
   Only the typeface and scale are this site's.
   ========================================================================== */
.legaldoc__title {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.4vw, 2.6rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 14px 0 6px;
}
/* A single measured column: legal prose set the full width of the container
   is unreadable, and the source page had that problem. */
.legaldoc__body {
  margin-top: 22px;
}
.legaldoc__body p {
  font-size: 0.95rem;
  line-height: 1.75;
  color: var(--ink-2);
  margin-bottom: 16px;
}
.legaldoc__body strong {
  color: var(--ink);
  font-weight: 650;
}
/* The headings arrive already in capitals from the source text. */
.legaldoc__body h3 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 34px 0 12px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
/* The source wraps each heading in its own <section>, which would otherwise
   collapse the margins above them. */
.legaldoc__body section {
  display: block;
}
.legaldoc__body section:first-child h3 {
  margin-top: 6px;
  border-top: 0;
  padding-top: 0;
}
.legaldoc__body a {
  color: var(--blue);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--blue) 34%, transparent);
  overflow-wrap: anywhere;
}
.legaldoc__body a:hover {
  text-decoration-color: var(--blue);
}
.legaldoc__body ul {
  margin: 0 0 16px 20px;
}
.legaldoc__body li {
  font-size: 0.95rem;
  line-height: 1.75;
  color: var(--ink-2);
}

@media (max-width: 700px) {
  .legaldoc__body p,
  .legaldoc__body li {
    font-size: 0.92rem;
  }
}

/* Pricing cards: two across below 992px.
   Auto-fit was squeezing three or four cards into the width instead, which is
   how a $334.00 price ends up wrapping onto two lines. The modifiers are named
   explicitly rather than relying on source order, since they set the same
   property at the same specificity. */
@media (max-width: 991px) {
  .plans,
  .plans--4,
  .plans--pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
/* Below this a half-width card is narrower than its own price line. */
@media (max-width: 620px) {
  .plans,
  .plans--4,
  .plans--pair {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The full-screen country picker is hung off <body> on phones, which makes it a
   sibling of the careers modal rather than a child, so it needs to out-rank it.
   The modal is 1400. */
.iti--container {
  z-index: 1500;
}
/* Our list cap is for the inline dropdown; full screen should use the height it
   has been given. */
.iti--fullscreen-popup .iti__country-list {
  max-height: none !important;
}

/* The YouTube frame keeps the film's own 16:9, unlike the portrait cards. */
.vplayer__frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: min(74vh, 620px);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #000;
}
.vplayer__frame iframe {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
}
/* Two films rather than four: keep them at a readable size and centred instead
   of stretching each across a quarter of the page. */
.vstories {
  max-width: 1120px;
  margin-inline: auto;
}
@media (min-width: 1101px) {
  .vstories--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 780px; }
}

/* An industry hero that leads with six tiles instead of one screenshot. Its
   own wrapper rather than .p-hero__media, because that one is deliberately
   bled to the screen edges on a phone: right for a single photograph, wrong
   for a grid of cards, which then loses the gutter every other block keeps. */
.p-hero__grid {
  position: relative;
  z-index: 2;
  max-width: 1220px;
  margin: clamp(30px, 3.4vw, 52px) auto 0;
}
/* Photographs, not dashboards: they read from the middle, so they are not
   pinned to the top the way a screenshot with a header bar has to be. */
.hgrid--photo .hgrid__shot img {
  object-position: 50% 50%;
}
/* Picture-only tiles: no foot, so nothing that implies a click. The card frame
   stays, which is what keeps them reading as one set with the home grid. */
.hgrid--photo .hgrid__tile {
  margin: 0;
}
.hgrid--photo .hgrid__shot {
  border-bottom: 0;
}
.hgrid--photo .hgrid__tile:hover {
  transform: none;
  box-shadow: var(--sh-1);
  border-color: var(--line);
}
.hgrid--photo .hgrid__tile:hover .hgrid__shot img {
  transform: none;
}

/* A photo set that does not divide by three: the tiles left over on the last
   row are centred instead of hanging against the left edge. Six columns so a
   pair can sit half a column in from each side, which three equal columns
   cannot do. Both classes come off on their own once the set is a multiple of
   three, so this reverts itself when a missing picture turns up. */
.hgrid--photo.hgrid--part {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
.hgrid--photo.hgrid--part .hgrid__tile {
  grid-column: span 2;
}
.hgrid--photo.hgrid--part2 .hgrid__tile:nth-last-child(2) {
  grid-column: 2 / span 2;
}
.hgrid--photo.hgrid--part1 .hgrid__tile:last-child {
  grid-column: 3 / span 2;
}
/* Two up, so the leftover is a single tile whichever remainder it was. Four
   columns here rather than six: a tile spanning half of a three-column grid
   cannot be centred, one spanning half of a four-column grid can. */
@media (max-width: 900px) {
  .hgrid--photo.hgrid--part {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .hgrid--photo.hgrid--part .hgrid__tile,
  .hgrid--photo.hgrid--part2 .hgrid__tile:nth-last-child(2) {
    grid-column: span 2;
  }
  .hgrid--photo.hgrid--part1 .hgrid__tile:last-child,
  .hgrid--photo.hgrid--part2 .hgrid__tile:last-child {
    grid-column: 2 / span 2;
  }
}

/* ==========================================================================
   COMPANY: the "and more" card that closes the leadership grid
   ========================================================================== */
/* Eleven portraits then a hard stop reads as "that is everyone". This card
   fills the empty cell at the end of the row: the photograph behind it is
   blurred right down, so it says "more people" without pretending to
   introduce anyone. */
.team__card--more {
  display: block;
  text-decoration: none;
  color: inherit;
}
.team__card--more .team__photo {
  position: relative;
}
.team__card--more .team__photo img {
  transform: scale(1.06);
  filter: saturate(0.85);
}
.team__card--more:hover .team__photo img {
  transform: scale(1.14);
}
/* A wash over the picture so the badge and the label hold at any brightness. */
.team__morefx {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  background: linear-gradient(
    170deg,
    rgba(9, 17, 28, 0.34),
    rgba(9, 17, 28, 0.62)
  );
}
.team__plus {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.42);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  box-shadow: 0 8px 24px rgba(4, 12, 22, 0.35);
  transition:
    transform var(--t) var(--ease),
    background-color var(--t) var(--ease);
}
.team__card--more:hover .team__plus {
  transform: scale(1.08);
  background: rgba(255, 255, 255, 0.26);
}
.team__moretag {
  font-size: 0.74rem;
  font-weight: 650;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 1px 10px rgba(4, 12, 22, 0.5);
}

/* Three stats to a card, so a column each rather than a row that lets a long
   one push the others off the end. */
.story__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
/* One line per label, always.

   The stats block is pinned to the bottom of the card, so a label that wrapped
   to two lines pushed that card's figures 28px higher than the card beside it
   and the row read as crooked. A column is 81px, which is the budget every
   label has to live inside; the few that did not have been shortened.

   nowrap is what holds the line, and the ellipsis is the backstop: if a label
   is ever written too long it gets visibly clipped, which is a prompt to
   shorten it, rather than silently knocking the row out of alignment again. */
.story__stat span {
  display: block;
  font-size: 0.72rem;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* On a phone the slider shows one card at a time, so there is no neighbouring
   card to line up with and the whole reason for the single line is gone. The
   column is down to 69px by then and holding the line would clip most of the
   labels, so they wrap instead. */
@media (max-width: 700px) {
  .story__stat span {
    white-space: normal;
    overflow: visible;
  }
}

/* A stat whose value is a word, not a figure. At the figure size "Streamlined"
   ran the width of the card and stopped reading as a statistic. */
.story__stat--word b {
  /* Sized so the longest word value clears the narrowest column: at the
     card min width a third is 81px, and "Streamlined" was 83 of them. */
  font-size: 0.92rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

/* The initial in place of a portrait. Same 44px footprint the photograph had,
   so the row it sits in does not move. */
.quote__mono {
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--mono, var(--blue));
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.06rem;
  line-height: 1;
  /* the display face sits slightly high in its box at this weight */
  padding-top: 1px;
  letter-spacing: 0;
  user-select: none;
}

/* --------------------------------------------------------------------------
   Numbered pricing groups

   For a product sold in stages rather than as one choice of tier. VoIP is the
   case: pick a seat, add AI minutes if the seat's allowance is not enough,
   or take a bundle that covers both. Three decisions, so three lists, and the
   numbers say they are read in order.
   -------------------------------------------------------------------------- */
.pgroup + .pgroup {
  margin-top: clamp(38px, 4vw, 58px);
}
.pgroup__head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  max-width: 780px;
  margin: 0 0 24px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
}
/* The step number, not decoration: it is why these lists are stacked rather
   than laid out as alternatives to each other. */
.pgroup__num {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--line));
}
.pgroup__title {
  font-family: var(--font-display);
  font-size: clamp(1.16rem, 1.5vw, 1.35rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.pgroup__lede {
  margin-top: 7px;
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--muted);
}

/* A two-card group is capped so the pair does not stretch half the page each,
   and it centres rather than sitting left: pushed to the left edge it left a
   third of the row empty and the group looked unfinished. */
.pgroup .plans--pair {
  margin-inline: auto;
}

/* Plain rows, no ticks: an allowance and a rate are the terms of the deal,
   not a list of things you are being given, and a column of ticks beside
   "Overage: $0.20 /min" reads as a promise it is not. */
.plan__lines {
  margin: 22px 0 0;
  display: grid;
  gap: 10px;
  flex: 1;
  align-content: start;
}
.plan__lines li {
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.5;
}
.plan__lines li b {
  color: var(--ink);
  font-weight: 650;
}
/* The figure the row turns on, inside a ticked feature. */
.plan__list li b {
  color: var(--ink);
  font-weight: 650;
}

@media (max-width: 700px) {
  .pgroup__head {
    gap: 11px;
    margin-bottom: 20px;
  }
  .pgroup__num {
    width: 26px;
    height: 26px;
    font-size: 0.85rem;
  }
}

/* --------------------------------------------------------------------------
   Spotlight cards

   One capability given its own section. Reuses .fgrid / .fcard for the frame;
   these two are the contents that grid did not already have.
   -------------------------------------------------------------------------- */

/* auto-fit rather than .fgrid's auto-fill: an empty track is collapsed instead
   of reserved, so three cards share the row evenly and the block sits centred
   under a centred heading. The cap keeps a card from going wider than its text
   wants on a large screen, and the group centres inside it. */
.spot__grid {
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  max-width: 1180px;
  margin-inline: auto;
}

/* The set of things a feature covers, as labels. Six leave types read faster
   as six chips than as a sentence listing them. */
.spot__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 16px;
}
.spot__chips li {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--line));
  border-radius: 999px;
  padding: 4px 11px;
}

.spot__list {
  display: grid;
  gap: 9px;
  margin-top: 16px;
}
.spot__list li {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 0.87rem;
  line-height: 1.5;
  color: var(--ink-2);
}
.spot__list .k-icon {
  color: var(--accent);
  flex: none;
  margin-top: 3px;
}

/* ==========================================================================
   Picture cards for applications

   The same card the industries use: a full-bleed photograph, a scrim that
   deepens on hover, and a list that unfolds under the blurb. Everything here
   is a difference of arrangement, not of treatment, because eleven products
   do not lay out like five sectors.
   ========================================================================== */

/* Eleven products do not divide into the industries' 2-2-then-two-wide
   pattern, so applications get an even grid and no card spans. */
/* Three across, stated rather than fitted. auto-fill put a fourth column in
   at full container width, which made every card narrow enough that the
   photograph stopped carrying anything. */
.ind-grid--even {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.ind-grid--even > .ind-card,
.ind-grid--even > :nth-child(4),
.ind-grid--even > :nth-child(5) {
  grid-column: auto;
}

.ind-card--app {
  min-height: 430px;
  /* Behind the photograph, so a card is never a white hole while its image
     loads and the accent still tints the edges of a dark shot. */
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--accent) 26%, #0b1524), #0b1524);
}
.ind-card--app.is-hidden {
  display: none;
}

/* Two on a tablet: three columns of a 430px card squeeze below this. */
@media (max-width: 1080px) {
  .ind-grid--even {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* The product mark, top left, above the shot. */
.ind-card__mark {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 1;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 4px 14px rgba(4, 12, 22, 0.28);
}
.ind-card__mark img {
  /* Overrides the card's own full-bleed img rule, which would otherwise
     absolutely position the logo across the whole card. */
  position: static;
  inset: auto;
  width: 26px;
  height: 26px;
  object-fit: contain;
  transition: none;
}
/* The card zooms its photograph on hover; the badge should hold still. */
.ind-card:hover .ind-card__mark img {
  transform: none;
}
.ind-card--app .ind-card__title {
  font-size: 1.24rem;
}
/* Three points, not the industries' five, so the list sits tighter. */
.ind-card--app .ind-card__list li {
  font-size: 0.86rem;
}

@media (max-width: 700px) {
  .ind-grid--even {
    grid-template-columns: 1fr;
  }
  .ind-card--app {
    min-height: 320px;
  }
}

/* ==========================================================================
   FEATURES, FOLDED INSIDE THE APPLICATIONS GRID

   Not a section of its own: the feature cards are the same .ind-card--app the
   products above them use, sitting in the same grid, so opening them extends
   that grid rather than starting a second one.

   Same fold as the home page's app row: folded is out of the flow entirely,
   out is in the flow but invisible (the frame the animation starts and ends
   on), and neither means shown. features-more.js drives the grid's height
   between the two.

   Written through .ind-grid so it outranks `.js .stagger.is-done > *`, which
   sets opacity on every child of a revealed grid and would otherwise pin the
   folded cards visible.
   ========================================================================== */
/* Hidden at first paint, not by script. The head sets .js on <html> before
   anything renders, so with scripting on the extra cards never flash into
   view and collapse again, and with scripting off they simply stay visible. */
.js .ind-grid .feat-card {
  display: none;
}
.js .ind-grid.is-feats-open .feat-card {
  display: flex;
}
.ind-grid .feat-card {
  transition:
    opacity 0.3s var(--ease),
    transform 0.3s var(--ease);
}
.ind-grid.stagger .feat-card.is-out {
  opacity: 0;
  transform: translateY(8px) scale(0.96);
  pointer-events: none;
}
/* Only while the height is in motion: the cards lift on hover and a permanent
   clip would cut the shadow off. */
.ind-grid.is-animating {
  overflow: hidden;
  transition: height 0.5s var(--ease-out-soft, var(--ease));
}
/* A feature card names its parent product where a product card says Explore,
   so the line is longer and wants holding back a little. */
/* Where the Features tab lands. The sticky header would otherwise sit over
   the first row. */
.feat-card { scroll-margin-top: 96px; }

.feat-card .ind-card__go {
  font-size: 0.78rem;
  letter-spacing: 0.02em;
}

.feats__more {
  display: flex;
  justify-content: center;
  margin-top: 28px;
  /* The anchor the Features tab lands on. Offset so the sticky header does not
     sit over the button when the browser jumps here. */
  scroll-margin-top: 96px;
}
/* Turns into a minus once the grid is open, so the button reads as a toggle
   rather than as a second way in. */
.feats__more svg:last-child {
  transition: transform 0.24s var(--ease);
}
.feats__more [aria-expanded="true"] svg:last-child {
  transform: rotate(45deg);
}

/* ==========================================================================
   Pricing: the Select a Term step

   Picking a plan does not buy it. It opens this, which asks which contract
   term you want that plan on, and only the Select in here leaves the site.
   Same two questions in the same order as the live Designed.co page.
   ========================================================================== */
.tstep {
  margin-top: 26px;
  animation: tstepIn 0.32s var(--ease) both;
}
@keyframes tstepIn {
  from { opacity: 0; transform: translateY(10px); }
}
.tstep__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.tstep__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 2.4vw, 2rem);
  letter-spacing: -0.02em;
}
/* Points back the way it came, and names the plan it is backing out of so it
   is obvious which one you are looking at the terms for. */
.tstep__back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px 9px 13px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition:
    border-color var(--t) var(--ease),
    color var(--t) var(--ease),
    background-color var(--t) var(--ease);
}
.tstep__back svg { transform: rotate(180deg); }
.tstep__back:hover {
  border-color: var(--accent);
  color: var(--ink);
  background: var(--paper-2);
}

.tstep__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}
.tstep__card {
  display: flex;
  flex-direction: column;
  padding: 24px 26px 26px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  transition:
    border-color var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.tstep__card:hover {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  box-shadow: var(--sh-2);
}
.tstep__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 18px;
}
.tstep__name {
  font-size: 1.05rem;
  font-weight: 600;
}
.tstep__flag {
  padding: 4px 10px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 10%, #fff);
  color: var(--accent);
  font-size: 0.72rem;
  font-weight: 700;
  white-space: nowrap;
}
.tstep__price {
  padding-bottom: 18px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--line);
}
.tstep__price b {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.4vw, 2.6rem);
  letter-spacing: -0.03em;
  line-height: 1;
}
.tstep__price span {
  display: block;
  margin-top: 6px;
  font-size: 0.82rem;
  color: var(--muted);
}
.tstep__card .k-btn { width: 100%; margin-top: auto; }

@media (max-width: 860px) {
  .tstep__grid { grid-template-columns: minmax(0, 1fr); }
  .tstep__head { margin-bottom: 16px; }
}

/* While the term step is up it is the only question on screen. The switcher
   above it asks the same thing a second way, and the AI row belongs to the
   list you have just stepped out of. */
.calc.is-picking .calc__controls,
.calc.is-picking .aiplan {
  display: none;
}
.calc.is-picking .tstep { margin-top: 0; }
