/* Dark hero: atmosphere built from gradients (no photo). Layers move a few px with the cursor via --mx/--my. */
.hdark{position:relative;isolation:isolate;overflow:hidden;min-height:100svh;padding-top:var(--header-h);background:#030a16;color:#fff;--blue-light:#3b9de8;--mx:0;--my:0}
.hdark__bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.hdark__bg>*{position:absolute;will-change:transform}
.hdark__base{inset:0;background:radial-gradient(120% 80% at 50% -10%,#0d2242 0%,#061226 45%,#030a16 100%)}
/* The light is shaped like the logo's shield: a large soft glow masked to the shield path, plus a faint edge. */
.hdark__shield{--shield:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 41.5 48.58'><path d='M20.75 0.79L40.75 7.79V23.79C40.75 35.79 32.25 44.29 20.75 47.79C9.25 44.29 0.75 35.79 0.75 23.79V7.79L20.75 0.79Z' fill='black'/></svg>");aspect-ratio:41.5/48.58}
.hdark__shield--main{right:-4vw;bottom:-26vh;width:min(64vw,62rem);-webkit-mask:var(--shield) center/contain no-repeat;mask:var(--shield) center/contain no-repeat;background:linear-gradient(205deg,rgba(10,40,100,.35) 0%,rgba(18,85,190,.55) 40%,rgba(30,130,235,.8) 72%,rgba(70,175,255,.92) 100%);filter:blur(22px);transform:rotate(-14deg) translate3d(calc(var(--mx)*30px),calc(var(--my)*20px),0)}
.hdark__shield--edge{right:-4vw;bottom:-26vh;width:min(64vw,62rem);overflow:visible;filter:blur(1.2px);opacity:.7;transform:rotate(-14deg) translate3d(calc(var(--mx)*30px),calc(var(--my)*20px),0)}
.hdark__shield--ghost{left:-30vw;top:-8vh;width:min(78vw,78rem);-webkit-mask:var(--shield) center/contain no-repeat;mask:var(--shield) center/contain no-repeat;background:linear-gradient(160deg,rgba(24,90,190,.42) 0%,rgba(12,50,120,.26) 55%,rgba(6,25,70,.08) 100%);filter:blur(36px);transform:rotate(18deg) translate3d(calc(var(--mx)*-22px),calc(var(--my)*-14px),0)}
/* one soft diagonal streak, as if light grazes the shield's edge */
.hdark__streak{left:-20%;bottom:-10%;width:110vw;height:16vh;background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(60,150,240,.10) 35%,rgba(150,210,255,.28) 52%,rgba(60,150,240,.10) 70%,rgba(0,0,0,0) 100%);filter:blur(22px);transform:rotate(-24deg) translate3d(calc(var(--mx)*-26px),calc(var(--my)*-16px),0)}
/* Uploaded background photo: covers the section, drifts slightly with the cursor; generated shields are hidden. */
.hdark__photo{inset:-3%;width:106%;height:106%;max-width:none;object-fit:cover;object-position:center;transform:translate3d(calc(var(--mx)*18px),calc(var(--my)*12px),0)}
.hdark--image .hdark__shield,.hdark--image .hdark__streak{display:none}
.hdark--image .hdark__grain{opacity:.05}
/* Dotted word: a particle field that assembles into the card's compliance name, behind the copy and the card. */
.hdark__word{inset:0;width:100%;height:100%;transform:none}
@media (max-width:64em){.hdark__word{display:none}}
/* film grain keeps the gradients from looking flat */
.hdark__grain{inset:0;opacity:.07;mix-blend-mode:overlay;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .8 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");background-size:180px 180px}

/* Everything must fit one viewport: sizes and gaps scale with height. Figma @1080: h1 48px x2 lines, intro 16px x2, button, 64px, card, logos. */
.hdark{--hd-gap:clamp(.75rem,2.4vh,1.75rem);--hd-h1:clamp(2.125rem,calc(1rem + 1.4vw + 1.6vh),3.25rem)}
/* A rounded section riding up over this hero needs room to do it, or it lands on the
   client logos. The hero grows by exactly the lift, so its own content still fits one
   viewport and the panel's top edge comes to rest on the fold. */
.hdark:has(+ .svc){padding-bottom:var(--section-lift)}

.hdark__inner{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;padding-block:clamp(1.25rem,5vh,3.75rem) clamp(2.5rem,6vh,4rem);min-height:calc(100svh - var(--header-h))}
.hdark__copy{text-align:center;max-width:46rem}
.hdark__title{margin:0 auto;max-width:13.5em;font-family:var(--font-display);font-weight:var(--w-display);font-size:var(--hd-h1);line-height:1.1;letter-spacing:var(--h1-track);color:#fff}
.hdark__title em{font-style:italic;font-weight:var(--w-display);color:var(--blue-light)}
.hdark__title strong,.hdark__title b{font-weight:var(--w-display);color:var(--blue-light)}
.hdark__sub{margin:var(--hd-gap) auto 0;max-width:30rem;font-size:1rem;line-height:1.6;letter-spacing:0;color:rgba(255,255,255,.82)}
.hdark__cta{display:flex;justify-content:center;margin-top:calc(var(--hd-gap)*1.3)}
.hdark__stage{position:relative;width:100%;margin-top:clamp(1.5rem,5.9vh,4rem)}
.epack{z-index:2}

@media (max-width:64em){
  .hdark__shield--main,.hdark__shield--edge{right:-30vw;bottom:-12vh;width:120vw}
  .hdark__shield--ghost{left:-60vw;width:140vw}
  .hdark__streak{left:-60%;width:200vw}
}
@media (prefers-reduced-motion:reduce){.hdark__bg>*{transform:none!important}}

/* Client logos under the card: a ticker. The row is a track that view.js clones until it is
   at least two containers wide, then slides by exactly one set (--set-w) so the loop is
   seamless at any logo count. Speed is a constant px/s, so the duration (--set-dur) scales
   with the set rather than racing when there are few logos. Without JS, or with reduced
   motion, it is a plain centred row. The edges fade so logos arrive and leave softly. */
.hdark__logos{position:relative;width:100%;margin-top:clamp(2.25rem,6vh,4.5rem);overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}
.hdark__logos-track{display:flex;justify-content:center;align-items:center;gap:clamp(2.5rem,4vw,4.5rem);width:max-content;min-width:100%;margin:0 auto}
.hdark__logo{height:1.1875rem;width:auto;max-width:8rem;object-fit:contain;opacity:.85;flex:none}
.js .hdark__logos{opacity:0;animation:hdark-logos-in .9s var(--ease) .9s both}
@keyframes hdark-logos-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.js .hdark__logos.is-ticking{-webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}
.js .hdark__logos.is-ticking .hdark__logos-track{justify-content:flex-start;margin:0;animation:hdark-ticker var(--set-dur,20s) linear infinite}
.js .hdark__logos.is-ticking:hover .hdark__logos-track{animation-play-state:paused}
@keyframes hdark-ticker{from{transform:translateX(0)}to{transform:translateX(calc(var(--set-w,0px) * -1))}}
@media (prefers-reduced-motion:reduce){
  .js .hdark__logos{animation:none;opacity:1}
  .js .hdark__logos.is-ticking .hdark__logos-track{animation:none;justify-content:center;margin:0 auto}
}
@media (max-width:36em){.hdark__logos{margin-top:2rem}.hdark__logos-track{gap:1.75rem}}

/* Short laptop screens: two rows visible instead of three, tighter bottom. */
@media (min-width:36.01em) and (max-height:840px){
  .epack__rowbox{height:calc(2*2.75rem + 1.25rem)}
  .hdark__inner{padding-bottom:1rem}
}

/* ---------- Split layout: copy left, evidence card right, standards in dots along the bottom ----------
   Composition only. Buttons, type scale and card are untouched; below the canvas breakpoint it falls
   back to the centred stack, since the dotted band is not drawn there anyway. */
@media (min-width:64.01em){
  .hdark--split .hdark__inner{
    display:grid;
    grid-template-columns:minmax(0,1.04fr) minmax(0,1fr);
    grid-template-rows:1fr auto;
    align-items:center;
    column-gap:clamp(2rem,5vw,5.5rem);
    padding-bottom:clamp(7.5rem,19vh,12rem);
  }
  .hdark--split .hdark__copy{grid-column:1;grid-row:1;align-self:center;justify-self:start;max-width:36rem;text-align:left}
  .hdark--split .hdark__title{margin:0;max-width:11.5em}
  .hdark--split .hdark__sub{margin-left:0;margin-right:0;max-width:32rem}
  .hdark--split .hdark__cta{justify-content:flex-start}
  .hdark--split .hdark__stage{grid-column:2;grid-row:1/3;align-self:center;margin-top:0}
  .hdark--split .epack{margin-left:auto;margin-right:0;width:min(100%,34rem)}
  .hdark--split .hdark__logos{grid-column:1;grid-row:2;justify-content:flex-start;align-self:end;margin-top:clamp(2rem,5vh,3.5rem)}
}
/* The bottom band needs its room back on a short screen, where the centred layout gives it up. */
@media (min-width:64.01em) and (max-height:840px){
  .hdark--split .hdark__inner{padding-bottom:clamp(6rem,15vh,9rem)}
}

/* Label, the muted line under the button, and the card caption. */
.hdark .hdark__eyebrow{margin:0 0 clamp(.75rem,1.8vh,1.25rem);color:rgba(255,255,255,.7)}
.hdark__note{margin:calc(var(--hd-gap)*.9) 0 0;font-size:.8125rem;line-height:1.5;color:rgba(255,255,255,.55)}
.hdark__caption{max-width:min(100%,32.75rem);margin:clamp(.75rem,1.6vh,1.25rem) auto 0;font-size:.75rem;line-height:1.5;color:rgba(255,255,255,.45);text-align:right}
@media (max-width:64em){.hdark__caption{text-align:center}}

@media (min-width:64.01em){.hdark--split .hdark__caption{max-width:min(100%,34rem);margin-right:0}}

/* ---- phones: the banner is one screen -------------------------------------
   The banner fills the window and the card is cropped by its bottom edge rather than shrunk
   to fit. The card is an illustration of evidence being written, not a list to read: showing
   its top and letting the rest run off the screen says "this continues" far better than a
   miniature of the whole thing, and it leaves the copy the room it needs. */
@media (max-width:36em){
  /* The section's own bottom padding goes with the lift it was reserved for (see services). */
  .hdark{padding-bottom:0}
  .hdark__inner{height:calc(100svh - var(--header-h));padding-block:1.75rem 0;overflow:hidden}
  .hdark__copy{flex:none}

  /* Tightened, so the copy ends high enough for the card to get a worthwhile strip. */
  .hdark .hdark__eyebrow{font-size:.75rem;margin-bottom:.625rem}
  .hdark__copy .sec-sub{margin-top:.875rem}
  .hdark__cta{margin-top:1.25rem}
  .hdark__note{margin-top:.75rem}

  /* The logos move above the card: they are a short row and they would otherwise be the thing
     cropped off the bottom, which is the one element here that has to be seen in full. */
  .hdark__logos{order:1;flex:none;margin-top:1.25rem}
  .hdark__stage{order:2;flex:1 1 auto;min-height:0;overflow:hidden;margin-top:1.25rem}

  /* Small print about a cropped illustration, itself cropped, is noise. It stays on every
     wider screen where the card is shown whole. */
  .hdark__caption{display:none}

  /* One row at a time. There is no room on a phone for a stack, and a stack means the row
     being written is the faint one at the bottom while finished rows take the space. So the
     rows share a single slot: whichever row is being written is the only one drawn, and when
     it is done it goes and the next takes its place. Fixed height, so nothing shifts. */
  .hdark .epack__rowbox{height:4.75rem;min-height:0;clip-path:inset(0 -3rem)}
  .hdark .epack__rows{gap:0}
  /* .epack .epack__row, not .epack__row: the shared stylesheet shows a waiting row at the
     same specificity, and it loads after this one. */
  .hdark .epack .epack__row{display:none}
  .hdark .epack .epack__row.is-typing,
  .hdark .epack .epack__row.is-current,
  .hdark .epack:not(.is-live) .epack__row.is-done:last-child{display:flex}
}
