/* ── Scroll reveal ───────────────────────────────────────────────────── * * Elements start visible. The `is-revealable` class is added by script only * once an IntersectionObserver exists to reveal them again,so a failed * script or a blocked file can never leave content permanently hidden — * the failure mode is "no animation",never "no content". */ .js .is-revealable{opacity: 0;transform: translateY(var(--sdi-reveal-distance));transition: opacity var(--sdi-duration-reveal) var(--sdi-ease-out),transform var(--sdi-duration-reveal) var(--sdi-ease-out);will-change: opacity,transform}.js .is-revealable.is-revealed{opacity: 1;transform: none;will-change: auto}.js .is-revealable{transition-delay: calc(var(--sdi-reveal-index,0) * 70ms)}/* * Image clip reveal,for the one or two places a softer entrance suits. * * The clip goes on the slot's children, never on the slot itself, and that
 * is load-bearing rather than stylistic. Chromium subtracts an element's own * clip-path from the area IntersectionObserver measures,so an element that * starts fully clipped reports a ratio of zero,never intersects,and after * its first entry never fires again — being hidden is precisely why it is * never unhidden. A split section on the preview page was permanently blank * because of it. Clipping the children leaves the observed box unclipped and * the wipe looks identical. */ .js .is-revealable--clip{opacity: 1;transform: none}.js .is-revealable--clip > *{clip-path: inset(0 0 100% 0);transition: clip-path var(--sdi-duration-reveal) var(--sdi-ease-out)}.js .is-revealable--clip.is-revealed > *{clip-path: inset(0 0 0 0)}.js .sdi-hero__inner > *{animation: sdi-enter var(--sdi-duration-slow) var(--sdi-ease-out) backwards}.js .sdi-hero__inner > *:nth-child(1){animation-delay: 40ms}.js .sdi-hero__inner > *:nth-child(2){animation-delay: 120ms}.js .sdi-hero__inner > *:nth-child(3){animation-delay: 200ms}.js .sdi-hero__inner > *:nth-child(4){animation-delay: 280ms}@keyframes sdi-enter{from{opacity: 0;transform: translateY(12px)}to{opacity: 1;transform: none}}.js .sdi-parallax{will-change: transform}.js .sdi-parallax > img,.js .sdi-parallax > .sdi-media__placeholder{transform: translate3d(0,var(--sdi-parallax-offset,0),0) scale(1.08);transition: transform 60ms linear}.sdi-stat__value[data-countup]{font-variant-numeric: tabular-nums}@media (prefers-reduced-motion: reduce){*,*::before,*::after{animation-duration: 0.01ms !important;animation-iteration-count: 1 !important;transition-duration: 0.01ms !important;transition-delay: 0ms !important;scroll-behavior: auto !important}.js .is-revealable,.js .is-revealable--clip,.js .is-revealable--clip > *{opacity: 1 !important;transform: none !important;clip-path: none !important}.js .sdi-parallax > img,.js .sdi-parallax > .sdi-media__placeholder{transform: none !important}.sdi-card--interactive:hover,.entry--card:hover,.sdi-button:hover{transform: none !important}.sdi-card--interactive:hover .sdi-media > img,.entry--card:hover .entry__media img{transform: none !important}}@media print{.js .is-revealable,.js .is-revealable--clip,.js .is-revealable--clip > *{opacity: 1 !important;transform: none !important;clip-path: none !important}.js .sdi-hero__inner > *{animation: none !important}}