/* ==========================================================================
   Elucidate — hero background, "the silk"
   The dark-navy hero backdrop shared by index.html and eli.html. Link it after
   css/elucidate-tokens.css, and load js/elucidate-silk.js at the end of <body>
   (it draws the ribbon). Don't copy either into a page: recolour the ribbon
   with a modifier instead (below).

   Markup — the hero that holds it must be position: relative and should be
   isolation: isolate + overflow: hidden, with its content at z-index 1. The
   script listens for the pointer on that hero (the background ignores it).

     <div class="elu-hero-bg" aria-hidden="true">
       <div class="elu-hero-glow">
         <div class="elu-hero-wash is-ember"></div>
         <div class="elu-hero-wash is-blue"></div>
         <div class="elu-hero-wash is-cyan"></div>
         <div class="elu-hero-shape is-ember"></div>
         <div class="elu-hero-shape is-blue"></div>
         <div class="elu-hero-shape is-cyan"></div>
       </div>
       <div class="elu-hero-silk"><canvas></canvas></div>
       <div class="elu-hero-noise"></div>
     </div>

   Layers:
     1. floating colour — on a navy base, three soft washes of ember / blue /
        cyan light and three blurred shapes, each drifting slowly on its own
        loop (the shapes fade in first);
     2. the silk — a twisting ribbon of 64 fine lines along the bottom and up
        the right-hand side, drawn on the canvas by js/elucidate-silk.js. The
        pointer brushes it: nearby lines part, are carried along, then settle;
     3. a touch of grain.
   The ribbon is designed on a 1280 × 720 box and stretched to the hero; its
   fade masks are px for that box.

   Ribbon colour: the lines blend from --elu-silk-from to --elu-silk-to across
   the ribbon (sky blue → lavender by default). Recolour it with a modifier on
   .elu-hero-silk — .is-ember (Eli) — rather than setting the two properties
   on a page; add a new modifier here if a page needs another colourway.
   ========================================================================== */

.elu-hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  background: linear-gradient(165deg, var(--eh-navy-deep) 0%, var(--eh-navy) 45%, var(--eh-navy-mid) 100%);
}
.elu-hero-bg > * { position: absolute; inset: 0; pointer-events: none; }

/* 1a · floating colour, base — three soft washes, each boxed to the visible
   extent of its glow so it fades out exactly at the box edge and can drift
   without a seam. At rest they equal these full-hero gradients:
     ember  ellipse  55% 35% at 78% 18%, clear by 55%   (halved 2026-10-27)
     blue   ellipse  90% 80% at 12% 90%, clear by 60%
     cyan   ellipse  70% 50% at 50% 50%, clear by 55%
   Slower and wider loops than the shapes above them. */
.elu-hero-wash {
  position: absolute;
  animation: eluHeroWashA 34s ease-in-out infinite;
  will-change: transform;
}
.elu-hero-wash.is-ember {
  width: 60.5%; height: 38.5%;
  top: -1.3%; left: 47.8%;
  background: radial-gradient(closest-side, rgba(234,88,12,0.22), transparent);
}
.elu-hero-wash.is-blue {
  width: 108%; height: 96%;
  top: 42%; left: -42%;
  background: radial-gradient(closest-side, rgba(45,90,255,0.28), transparent);
  animation: eluHeroWashB 41s ease-in-out infinite;
}
.elu-hero-wash.is-cyan {
  width: 77%; height: 55%;
  top: 22.5%; left: 11.5%;
  background: radial-gradient(closest-side, rgba(0,212,255,0.08), transparent);
  animation: eluHeroWashC 29s ease-in-out infinite;
}

/* 1b · floating colour, shapes — each fades in, then drifts on its own slow,
   asymmetric loop so the light never lines up. The ember one is a halo
   behind the top of the hero's right-hand card, centred 270px in from the
   right edge and 190px down (was 900px wide; halved 2026-10-27). */
.elu-hero-shape {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0;
  animation: eluHeroShapeIn 2s ease-out forwards;
  will-change: transform;
}
.elu-hero-shape.is-ember {
  width: 420px; height: 420px;
  top: -20px; right: 60px;
  background: radial-gradient(circle, rgba(251,146,60,0.28) 0%, transparent 70%);
  animation: eluHeroShapeIn 2s ease-out 0.3s forwards, eluHeroDriftA 22s ease-in-out 2.5s infinite;
}
.elu-hero-shape.is-blue {
  width: 720px; height: 720px;
  bottom: -200px; left: -160px;
  background: radial-gradient(circle, rgba(45,90,255,0.32) 0%, transparent 70%);
  animation: eluHeroShapeIn 2s ease-out 0.6s forwards, eluHeroDriftB 28s ease-in-out 2.8s infinite;
}
.elu-hero-shape.is-cyan {
  width: 460px; height: 460px;
  top: 40%; left: 45%;
  background: radial-gradient(circle, rgba(0,212,255,0.18) 0%, transparent 70%);
  animation: eluHeroShapeIn 2s ease-out 0.9s forwards, eluHeroDriftC 18s ease-in-out 3.1s infinite;
}

/* 2 · the silk — masked so it fades out towards the top-left, where the
   headline sits. Hidden until the script marks the hero visible, then fades
   in (again each time the hero scrolls back on screen). */
.elu-hero-silk {
  --elu-silk-from: #7dafff;   /* sky blue  */
  --elu-silk-to:   #beaaff;   /* lavender  */
  opacity: 0;
  -webkit-mask-image:
    linear-gradient(to top, black 0, rgba(0,0,0,.8) 200px, transparent 360px),
    linear-gradient(to left, black 0, rgba(0,0,0,.75) 220px, transparent 520px);
  mask-image:
    linear-gradient(to top, black 0, rgba(0,0,0,.8) 200px, transparent 360px),
    linear-gradient(to left, black 0, rgba(0,0,0,.75) 220px, transparent 520px);
}
/* Eli: ember → soft peach, a warm ribbon against the homepage's cool one. */
.elu-hero-silk.is-ember {
  --elu-silk-from: var(--eh-ember-bright);
  --elu-silk-to:   var(--eh-ember-soft);
}
.elu-hero-silk canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.elu-hero-bg.is-visible .elu-hero-silk { animation: eluHeroSilkIn 1.6s var(--eh-ease) both; }

/* 3 · grain */
.elu-hero-noise {
  opacity: .06;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
}

@keyframes eluHeroShapeIn {
  from { opacity: 0; transform: scale(0.85); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes eluHeroDriftA {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(-40px, 30px) scale(1.04); }
  66%      { transform: translate(20px, -30px) scale(0.98); }
}
@keyframes eluHeroDriftB {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(60px, -40px) scale(1.06); }
}
@keyframes eluHeroDriftC {
  0%, 100% { transform: translate(0, 0) scale(1); opacity: 0.85; }
  50%      { transform: translate(-30px, 25px) scale(1.10); opacity: 1; }
}
/* Washes: translate is % of each wash's own box. */
@keyframes eluHeroWashA {
  0%, 100% { transform: translate(0, 0) scale(1); }
  40%      { transform: translate(-7%, 9%) scale(1.06); }
  70%      { transform: translate(-2%, -4%) scale(1.02); }
}
@keyframes eluHeroWashB {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(8%, -6%) scale(1.05); }
}
@keyframes eluHeroWashC {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(9%, -8%) scale(1.08); }
  66%      { transform: translate(-8%, 6%) scale(0.96); }
}
@keyframes eluHeroSilkIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Reduced motion: the colour holds still at full strength; the script draws
   the ribbon as one still frame. */
@media (prefers-reduced-motion: reduce) {
  .elu-hero-wash, .elu-hero-shape, .elu-hero-silk {
    animation: none !important;
    opacity: 1 !important;
  }
}
@media print {
  .elu-hero-silk { animation: none !important; opacity: 1; }
}
