/*
  shr-hero-ribbon.css — homepage-only animated gradient ribbon.

  ONE continuous ribbon runs from the top of the header, through the hero and
  across the stats band. It is drawn in three separate layers ("bands") because
  a single blend mode cannot serve both backgrounds: on navy the ribbon needs a
  LIGHTENING blend (screen) to read at all, while on the light-grey stats band
  screen paints to near-white — invisible — so that band needs a DARKENING one
  (multiply). Each band is clipped to its own section, but the artwork inside
  every band is sized to the FULL wrapper and offset, so the three line up into
  one continuous shape across the section boundaries.

  Motion is 100% `transform`. Nothing animates background-size/position — those
  repaint a large blurred image every frame, which stutters badly in Safari.
  transform is handed to the GPU compositor: rasterise once, then move it.

  --flow-h / --hero-h / --head-h are published on <html> by shr-hero-ribbon.js.
*/

/* ═══════════ Bands ═══════════ */
.s2u-band { position: absolute; left: 0; right: 0; overflow: hidden; pointer-events: none; z-index: 3; }
.s2u-flow { position: relative; isolation: isolate; }

.s2u-band--hero  { top: 0; height: var(--hero-h, 60%); }
.s2u-band--stats { top: var(--hero-h, 60%); height: calc(var(--flow-h, 100%) - var(--hero-h, 60%)); }

/* Overscanned 25% each side: the sweep + swell would otherwise drag the
   artwork's own rectangular edge into view at the extremes of the loop.
   Identical in every band, which is what keeps them in register. */
.s2u-band__art {
	position: absolute; left: -25%; width: 150%;
	height: calc(var(--flow-h, 100%) * 1.5);
	animation: s2u-ribbon-sweep 24s ease-in-out infinite alternate;
	will-change: transform;
}
.s2u-band--hero  .s2u-band__art { top: calc(var(--flow-h, 100%) * -.25); }
.s2u-band--stats .s2u-band__art { top: calc(-1 * var(--hero-h, 60%) - var(--flow-h, 100%) * .25); }

/* Two nested transforms, because one element can only animate `transform`
   once: outer sweeps, inner beats. They multiply into one compound motion and
   both stay on the compositor. The 7s delay lets the sweep lead on load. */
.s2u-band__pulse {
	position: absolute; inset: 0;
	background: url('assets/hero-ribbon.svg') center center / cover no-repeat;
	animation: s2u-ribbon-beat 11s ease-in-out 7s infinite;
	transform-origin: 60% 45%;
	will-change: transform;
}

@keyframes s2u-ribbon-sweep {
	from { transform: translate3d(-14%, 12%, 0) rotate(-2.5deg); }
	to   { transform: translate3d( 14%, -12%, 0) rotate( 2.5deg); }
}
/* lub-dub: a big swell, a smaller echo, then rest */
@keyframes s2u-ribbon-beat {
	0%   { transform: scale(1.00); }
	18%  { transform: scale(1.12); }
	32%  { transform: scale(1.05); }
	48%  { transform: scale(1.15); }
	70%  { transform: scale(1.02); }
	100% { transform: scale(1.00); }
}

/* Hero band: lighten onto navy. This blend is also what tints the headline —
   white stays white, mid-tones pick up the ribbon's colour as it passes. */
.s2u-band--hero {
	mix-blend-mode: screen; opacity: .80;
	/* Mask 1 keeps the lower-left clear for headline, lead and CTAs.
	   Mask 2 eases off at the bottom so the handover to the stats band is a
	   crossfade rather than a hard tonal step at the section edge. */
	-webkit-mask-image: linear-gradient(104deg, transparent 5%, rgba(0,0,0,.4) 26%, #000 46%),
	                    linear-gradient(180deg, #000 0 74%, rgba(0,0,0,.78) 90%, rgba(0,0,0,.45) 100%);
	        mask-image: linear-gradient(104deg, transparent 5%, rgba(0,0,0,.4) 26%, #000 46%),
	                    linear-gradient(180deg, #000 0 74%, rgba(0,0,0,.78) 90%, rgba(0,0,0,.45) 100%);
	-webkit-mask-composite: source-in;
	        mask-composite: intersect;
}

/* Stats band: multiply onto the grey. It carries noticeably more opacity than
   the hero band on purpose — a darkening blend on light grey reads far weaker
   than a lightening one on navy, and without this the ribbon looks broken at
   the boundary rather than continuous. */
.s2u-band--stats {
	mix-blend-mode: multiply; opacity: .38;
	-webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,.5) 0%, rgba(0,0,0,.9) 10%, #000 22%, rgba(0,0,0,.6) 66%, transparent 100%);
	        mask-image: linear-gradient(180deg, rgba(0,0,0,.5) 0%, rgba(0,0,0,.9) 10%, #000 22%, rgba(0,0,0,.6) 66%, transparent 100%);
}

/* ═══════════ Header band + dark header (homepage only) ═══════════
   The band sits INSIDE <header> (which has no overflow:hidden of its own, so
   the nav dropdowns still escape it) and clips itself. Its artwork is offset
   by the header height so it continues the hero's coordinate space. */
.s2u-home .s2u-header {
	background:
		repeating-linear-gradient(90deg, rgba(255,255,255,.035) 0 1px, transparent 1px 56px),
		repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 56px),
		var(--s2u-navy-grad);
	border-bottom-color: rgba(255, 255, 255, .12);
	transition: background .25s ease, border-color .25s ease;
}
.s2u-home .s2u-header__inner { position: relative; z-index: 2; }
.s2u-band--head { top: 0; bottom: 0; height: auto; z-index: 1; mix-blend-mode: screen; opacity: .8; }
.s2u-band--head .s2u-band__art { top: calc(var(--head-h, 0px) - var(--flow-h, 100%) * .25); }

/* Text that sat on the light bar has to flip for the dark one. The nav pill
   and search stay white, which is exactly why they were built as pills — the
   link contrast does not change as the gradient drifts underneath. */
.s2u-home .s2u-header .s2u-wordmark { color: #fff; }
.s2u-home .s2u-header .s2u-header__tld { color: rgba(255, 255, 255, .6); }
.s2u-home .s2u-header .s2u-header__cart { color: #fff; }
.s2u-home .s2u-header .s2u-header__cart:hover { background: rgba(255, 255, 255, .14); color: #fff; }
.s2u-home .s2u-header .s2u-burger { color: #fff; }
.s2u-home .s2u-header .s2u-burger:hover { background: rgba(255, 255, 255, .14); color: #fff; }

/* Scrolled past the hero, the sticky bar would be floating over light content
   with light text. .is-stuck restores the normal solid header. */
.s2u-home .s2u-header.is-stuck {
	background: var(--s2u-bg); border-bottom-color: var(--s2u-divider);
}
.s2u-home .s2u-header.is-stuck .s2u-wordmark { color: var(--s2u-navy); }
.s2u-home .s2u-header.is-stuck .s2u-header__tld { color: var(--s2u-neutral-600); }
.s2u-home .s2u-header.is-stuck .s2u-header__cart,
.s2u-home .s2u-header.is-stuck .s2u-burger { color: var(--s2u-navy); }
.s2u-home .s2u-header.is-stuck .s2u-band--head { opacity: 0; }
.s2u-band--head { transition: opacity .25s ease; }

/* ═══════════ Blueprint art frame sits ABOVE the ribbon ═══════════
   Without this the ribbon paints over the shredder illustration and washes it
   out — the frame is a positioned child of the hero, so it joins the same
   stacking context as the bands and just needs to outrank them (band = 3).

   The panel fill is a flat gradient, NOT backdrop-filter. A backdrop blur over
   a layer that animates every frame forces the blur to be recomputed every
   frame, which is exactly the kind of cost this whole effect was built to
   avoid. Side by side the two are indistinguishable here. */
.s2u-home .s2u-hero__art {
	z-index: 4;
	background: linear-gradient(160deg, rgba(17, 27, 39, .72) 0%, rgba(30, 46, 66, .55) 55%, rgba(45, 62, 85, .5) 100%);
	border-color: rgba(255, 255, 255, .42);
}

/* ═══════════ Guards ═══════════ */
@media (prefers-reduced-motion: reduce) {
	.s2u-band__art, .s2u-band__pulse { animation: none; }
}
@media (max-width: 680px) {
	/* Sideways travel on a narrow screen just shoves the ribbon off-canvas, so
	   phones keep the heartbeat only — pure scale on an already-composited
	   layer is the cheapest thing a phone GPU can animate. */
	.s2u-band__art { animation: none; }
	.s2u-band__pulse { animation-duration: 14s; animation-delay: 4s; transform-origin: 70% 40%; }
	.s2u-band--hero { opacity: .68; }
	.s2u-band--stats { opacity: .25; }
}
