/* ESP v3 effects layer: scroll progress, back-to-top ring, pointer spotlight, label decode,
   magnetic buttons and hero parallax. Everything here is optional polish on top of style.css:
   delete this file and js/fx.js and the site works as before. */

/* ---------- Scroll progress: a thin bar in the eight system colours ---------- */
.fx-progress {
  position: fixed; inset: 0 0 auto 0; z-index: calc(var(--z-header) + 1); height: 2px; pointer-events: none;
  background: linear-gradient(90deg,
    var(--sys-power), var(--sys-busway), var(--sys-ups), var(--sys-genset),
    var(--sys-dcim), var(--sys-water), var(--sys-cooling), var(--sys-fire));
  transform: scaleX(var(--fx-scroll, 0)); transform-origin: 0 50%;
  box-shadow: 0 0 12px color-mix(in oklab, var(--sys-cooling) 50%, transparent);
}

/* ---------- Back to top, with the scroll position drawn as a ring ---------- */
.fx-top {
  position: fixed; right: 20px; bottom: 20px; z-index: var(--z-header);
  display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 50%;
  background: color-mix(in oklab, var(--bg-0) 82%, transparent); color: var(--tx-1); cursor: pointer;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px var(--rule);
  opacity: 0; visibility: hidden; transform: translateY(12px);
  transition: opacity var(--dur-panel) var(--ease-ui), transform var(--dur-panel) var(--ease-ui), visibility 0s linear var(--dur-panel);
}
.fx-top.is-on { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.fx-top:hover { background: var(--bg-3); }
.fx-top:focus-visible { outline: 2px solid var(--brand-light); outline-offset: 3px; }
.fx-top svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.fx-top circle { fill: none; stroke-width: 2; }
.fx-top .fx-top__track { stroke: var(--bg-4); }
.fx-top .fx-top__ring {
  stroke: var(--fx-accent, var(--brand-light)); stroke-linecap: round;
  stroke-dasharray: 138.23; stroke-dashoffset: calc(138.23 * (1 - var(--fx-scroll, 0)));
  transition: stroke var(--dur-big) var(--ease-ui);
}
.fx-top .ico { position: relative; width: 16px; height: 16px; transform: rotate(180deg); }

/* ---------- Pointer spotlight on cards, drawings and panels ---------- */
@media (hover: hover) and (pointer: fine) {
  .fx-spot { position: relative; isolation: isolate; }
  .fx-spot::after {
    content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; border-radius: inherit;
    background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%),
      color-mix(in oklab, var(--sys, var(--brand-light)) 16%, transparent), transparent 60%);
    opacity: 0; transition: opacity var(--dur-big) var(--ease-ui);
  }
  .fx-spot:hover::after { opacity: 1; }
  /* a hairline border that lights up under the pointer */
  .fx-spot::before {
    content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; border-radius: inherit; padding: 1px;
    background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%),
      color-mix(in oklab, var(--sys, var(--brand-light)) 85%, transparent), transparent 70%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude;
    opacity: 0; transition: opacity var(--dur-big) var(--ease-ui);
  }
  .fx-spot:hover::before { opacity: 1; }
}

/* ---------- Label decode: a cursor while the text resolves ---------- */
.fx-decoding::after {
  content: "_"; margin-left: 2px; color: var(--brand-light);
  animation: fx-blink 480ms steps(1) infinite;
}
@keyframes fx-blink { 50% { opacity: 0; } }

/* ---------- Magnetic buttons and hero parallax use the independent translate property,
   so they combine with the transforms style.css already sets. ---------- */
.fx-magnet { transition: translate 400ms cubic-bezier(.16, 1, .3, 1), filter var(--dur-ui) var(--ease-ui), background-color var(--dur-ui) var(--ease-ui), box-shadow var(--dur-ui) var(--ease-ui); }
/* the scene overhangs the hero by a few pixels so the parallax never shows an edge (.hero clips it) */
.hero__media { inset: -12px; transition: translate 900ms cubic-bezier(.16, 1, .3, 1); }

/* ---------- Hero title: a light sweep across the words after they rise ---------- */
@media (prefers-reduced-motion: no-preference) {
  .js .hero__title .line > span {
    /* 300% wide: positions 100% and 0% both show a solid end, so the text is never left uncovered */
    background: linear-gradient(100deg, var(--tx-1) 44%, #fff 50%, var(--tx-1) 56%) 100% 0 / 300% 100% no-repeat;
    -webkit-background-clip: text; background-clip: text;
    /* the background only paints inside the box: extend it under the descenders (g, y) */
    padding-bottom: .2em; margin-bottom: -.2em;
  }
  .js .hero__title.fx-shine .line > span { -webkit-text-fill-color: transparent; animation: rise 900ms cubic-bezier(.16, 1, .3, 1) both, fx-shine 2200ms 900ms cubic-bezier(.4, 0, .2, 1) both; }
  .js .hero__title.fx-shine .line:nth-child(2) > span { animation-delay: 90ms, 1050ms; }
  .js .hero__title.fx-shine .line:nth-child(3) > span { animation-delay: 180ms, 1200ms; }
}
@keyframes fx-shine { from { background-position: 100% 0; } to { background-position: 0% 0; } }

/* ---------- Reduced motion or paused motion: keep the useful parts, drop the movement ---------- */
@media (prefers-reduced-motion: reduce) {
  .fx-top, .fx-top .fx-top__ring { transition: none; }
}
html[data-motion="paused"] .hero__media,
html[data-motion="paused"] .fx-magnet { translate: none !important; }

@media print {
  .fx-progress, .fx-top { display: none; }
}
