
/* ===== kinetic headline: real text, masked reveals, one cycling word =====
   The logo does not move. The message does. */
.hero-sub .hero-in, .hero-in{position:relative}
.kin h1{font-size:clamp(32px,5.2vw,66px);font-weight:800;text-transform:uppercase;
  letter-spacing:-.035em;line-height:1.02}
.kline{display:block;overflow:hidden;padding-bottom:.06em}
.kline > span{display:block;transform:translateY(110%);opacity:0;
  animation:kin-up .9s cubic-bezier(.22,.75,.2,1) forwards}
.kline:nth-of-type(2) > span{animation-delay:.13s}
@keyframes kin-up{to{transform:none;opacity:1}}

.strap{font-size:12.5px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;
  color:var(--grey);margin:0 0 22px}
.krule{display:block;height:4px;width:0;background:var(--orange);margin:22px 0 0;
  animation:kin-rule 1s .52s cubic-bezier(.22,.75,.2,1) forwards}
@keyframes kin-rule{to{width:min(400px,40%)}}

/* the cycling word: an inline grid so the box is as wide as the widest word
   and nothing reflows when it swaps */
.cyc{display:inline-grid;vertical-align:top}
.cyc > i{grid-area:1/1;font-style:normal;transform:translateY(.9em);opacity:0;
  transition:transform .52s cubic-bezier(.22,.75,.2,1),opacity .4s ease}
.cyc > i.on{transform:none;opacity:1}
.cyc > i.out{transform:translateY(-.9em);opacity:0}

.kfade{opacity:0;transform:translateY(14px);animation:kin-fade .85s cubic-bezier(.22,.75,.2,1) forwards}
.kfade-1{animation-delay:.34s}
.kfade-2{animation-delay:.46s}
.kfade-3{animation-delay:.58s}
@keyframes kin-fade{to{opacity:1;transform:none}}

@media(prefers-reduced-motion:reduce){
  .kline > span,.kfade{animation:none;opacity:1;transform:none}
  .krule{animation:none;width:min(400px,40%)}
  .cyc > i{transition:none}
}


/* ---------- reveal on scroll --------------------------------------------
   Sections lift and fade in as they come into view.

   The hidden state is gated twice: on :root.js-reveal, a class the script
   adds, and on a no-preference motion query. So the content is only ever
   hidden while the thing that un-hides it is actually running. Script
   blocked, observer missing, CSS half-applied, motion turned off: every one
   of those ends with the page fully readable rather than blank. This is the
   same rule the hero collage broke when it parked cards at opacity 0 and
   waited for an animation that never arrived.

   The two pinned stages are excluded in the script. Their children are
   already positioned by scroll, and a second transform on the same elements
   fights the pinning rather than adding to it. */
@media (prefers-reduced-motion: no-preference){
  :root.js-reveal [data-reveal]{
    opacity:0; transform:translateY(22px);
    transition:opacity .68s cubic-bezier(.22,.75,.2,1),
               transform .68s cubic-bezier(.22,.75,.2,1);
    transition-delay:calc(var(--i, 0) * 70ms);
  }
  :root.js-reveal [data-reveal].is-in{ opacity:1; transform:none }
}

/* ---------- home: From the blog ---------- */
.hblog-head{ display:flex; align-items:flex-end; justify-content:space-between; gap:24px; flex-wrap:wrap; margin-bottom:34px }
.hblog-head .label{ display:block; margin-bottom:14px }
.hblog-head .h2{ margin:0 }
.hblog-grid{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:22px }
.hblog-card{ position:relative; display:flex; flex-direction:column; background:#fff; border:1px solid #E0E0E0;
  border-top:3px solid #979797; padding:24px 24px 22px; transition:border-color .2s ease, box-shadow .2s ease, transform .2s ease }
.hblog-card:nth-child(even){ border-top-color:#D9EEFA }
.hblog-card:hover{ border-color:#C9C9C9; border-top-color:var(--orange); box-shadow:0 10px 28px rgba(0,0,0,.08); transform:translateY(-2px) }
.hblog-cat{ font-size:10.5px; font-weight:800; letter-spacing:.16em; text-transform:uppercase; color:var(--orange) }
.hblog-card h3{ margin:12px 0 0; font-size:17px; line-height:1.32; font-weight:800 }
.hblog-card h3 a{ color:var(--ink-900); text-decoration:none }
/* the headline link covers the whole box, so the card is one target */
.hblog-card h3 a::after{ content:""; position:absolute; inset:0 }
.hblog-card h3 a:focus-visible{ outline:none }
.hblog-card:focus-within{ outline:2px solid var(--orange); outline-offset:2px }
.hblog-card p{ margin:10px 0 0; font-size:13.5px; line-height:1.6; color:#555;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
.hblog-url{ display:block; margin:14px 0 16px; font-size:11.5px; color:#8A8A8A; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.hblog-foot{ margin-top:auto; padding-top:16px; display:flex; align-items:center; justify-content:space-between; gap:12px;
  border-top:1px solid #EEEEEE }
.hblog-meta{ font-size:11.5px; font-weight:700; letter-spacing:.04em; color:#8A8A8A }
.hblog-more{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:800; color:var(--orange); text-decoration:none }
.hblog-more svg{ width:12px; height:10px; transition:transform .2s ease }
.hblog-card:hover .hblog-more svg{ transform:translateX(3px) }
@media(max-width:980px){ .hblog-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
@media(max-width:640px){ .hblog-grid{ grid-template-columns:minmax(0,1fr) } }

/* ---------- home: rotating client references (#why) ---------- */
.qrot-label{ display:block; margin-bottom:18px; font-size:11px; font-weight:800; letter-spacing:.2em; text-transform:uppercase; color:var(--light-mid) }
.qrot-track{ display:grid }
.qrot-item{ margin:0 }
/* with JavaScript: stack the slides in one grid cell and fade between them */
.qrot.js .qrot-item{ grid-area:1/1; opacity:0; visibility:hidden; transform:translateY(6px);
  transition:opacity .45s ease, transform .45s ease, visibility 0s linear .45s }
.qrot.js .qrot-item.is-on{ opacity:1; visibility:visible; transform:none; transition:opacity .45s ease, transform .45s ease }
/* without JavaScript: all three listed */
.qrot:not(.js) .qrot-item + .qrot-item{ margin-top:30px }
.qrot .avatar{ font-size:13px; font-weight:800; letter-spacing:.04em; color:#fff; background:#666666 }
.qrot-item:nth-child(2) .avatar{ background:#979797 }
.qrot-item:nth-child(3) .avatar{ background:#323232 }
.qrot-ctl{ display:flex; align-items:center; gap:14px; margin-top:30px; padding-left:29px }
.qrot-ctl[hidden]{ display:none }
.qrot-btn{ width:40px; height:40px; display:inline-flex; align-items:center; justify-content:center; background:transparent;
  border:1.5px solid #C9C9C9; color:var(--ink-900); cursor:pointer; transition:background .2s, border-color .2s, color .2s }
.qrot-btn svg{ width:12px; height:10px }
.qrot-btn:hover,.qrot-btn:focus-visible{ background:var(--orange); border-color:var(--orange); color:#fff }
.qrot-dots{ display:flex; gap:8px }
.qrot-dots button{ width:26px; height:4px; padding:0; border:0; background:#C9C9C9; cursor:pointer; transition:background .2s, width .2s }
.qrot-dots button[aria-current="true"]{ width:40px; background:var(--orange) }
@media (prefers-reduced-motion:reduce){ .qrot.js .qrot-item{ transition:none } }

/* ---------- home: platform logos in the marquee ---------- */
.eco-box.has-logo{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px }
.eco-logo{ display:block; max-width:150px; max-height:56px; width:auto; height:auto; object-fit:contain;
  opacity:.85; transition:opacity .2s ease, transform .2s ease }
.eco-box.has-logo:hover .eco-logo{ opacity:1; transform:scale(1.04) }
.eco-name{ font-style:normal; font-size:11px; font-weight:800; letter-spacing:.18em; text-transform:uppercase; color:var(--fg-faint) }
.eco-box.has-logo:hover .eco-name{ color:#fff }
@media(max-width:700px){ .eco-logo{ max-width:110px; max-height:40px } .eco-box.has-logo{ gap:10px } }

/* ---------- home references: person photo and company logo ---------- */
.qref-by{ gap:16px }
.qref-photo{ width:64px; height:64px; border-radius:50%; flex:none; object-fit:cover;
  border:3px solid #fff; box-shadow:0 0 0 1px #DADADA }
.qrot .avatar.qref-photo{ font-size:15px }
.qref-who{ min-width:0 }
.qref-logo{ margin-left:auto; padding-left:22px; border-left:1px solid #D6D6D6;
  max-width:140px; max-height:44px; width:auto; height:auto; object-fit:contain }
@media(max-width:560px){ .qref-by{ flex-wrap:wrap } .qref-logo{ margin-left:0; padding-left:0; border-left:0; flex-basis:100%; max-width:120px } }

/* Platforms strip: room above and below the boxes so the hover border is not
   cut by the strip's overflow edge while the track is mid-scroll. The
   negative margin keeps the section's spacing the same as before. */
.marquee{ padding-block:6px; margin-block:-6px }
.eco-box:hover,.eco-box:focus-within{ border-color:#FFFFFF; box-shadow:inset 0 0 0 1px rgba(255,255,255,.35) }
