/* preloader.css — the logo wipe. Lifted unchanged from demo/index.html.
   Self-contained: it styles nothing outside #pre and sets no fonts or colours
   the rest of the page has to inherit. */

#pre{position:fixed;inset:0;z-index:100;background:#000;display:grid;place-items:center;isolation:isolate}

/* ── the real progress bar ──────────────────────────────────────────────────
   The FILL is driven only by events that actually happened (see the controller
   in index.html). The SHEEN on the track is not tied to progress at all — it
   runs on a CSS keyframe so that a genuine network stall still shows movement.
   Splitting those two is the point: the honest part measures, the alive part
   reassures, and neither has to pretend to be the other. */
#pre .pre-bar{position:absolute;left:50%;bottom:clamp(48px,9vh,96px);transform:translateX(-50%);
  width:min(240px,42vw);height:2px;border-radius:2px;overflow:hidden;
  background:rgba(255,255,255,.10)}
#pre .pre-bar::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.22),transparent);
  transform:translateX(-100%);animation:pre-sheen 1.5s linear infinite}
#pre .pre-bar > i{display:block;width:100%;height:100%;transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,#7C3AED,#3B82F6);border-radius:2px;will-change:transform}
@keyframes pre-sheen{to{transform:translateX(100%)}}

/* Once the bar is full it has said everything it has to say — fade it out a
   beat before the logo leaves, so the exit is one movement and not two. */
#pre.is-complete .pre-bar{opacity:0;transition:opacity .3s ease}

/* Escape route with no JS dependency: if the module script never arrived there
   is no GSAP exit to play, so the controller adds this class and the visitor
   gets the page without the cube rather than a black screen forever. */
#pre.is-rescued{opacity:0;transition:opacity .45s ease;pointer-events:none}
#pre .pre-logo{--reveal:0%;position:relative;width:clamp(360px,76vmin,840px);aspect-ratio:1;transform:translateZ(0)}
#pre .pre-logo img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;user-select:none;mix-blend-mode:screen}

/* The quiet version gives the ribbon a physical presence before its colour arrives. */
#pre .logo-ghost{opacity:.19;filter:saturate(.72) contrast(.8) brightness(.78);transform:scale(.985)}
#pre .logo-fill{position:absolute;inset:0;overflow:hidden;clip-path:polygon(0 0,calc(var(--reveal) + 10%) 0,var(--reveal) 100%,0 100%);will-change:clip-path}
#pre .logo-fill img{filter:drop-shadow(0 0 34px rgba(118,88,255,.28))}

/* A gleam meant to travel at the leading edge rather than read as a flat
   progress bar. It has never rendered — see the note in preloader.js. */
#pre .pre-logo::after{content:"";position:absolute;z-index:2;top:-4%;bottom:-4%;left:calc(var(--reveal) - 4%);width:9%;opacity:0;pointer-events:none;background:linear-gradient(90deg,transparent,rgba(255,255,255,.7),transparent);filter:blur(10px);mix-blend-mode:screen;transform:skewX(-11deg)}
#pre.is-loading .pre-logo::after{opacity:.76}

@media(prefers-reduced-motion:reduce){
  #pre .pre-logo::after{display:none}
  #pre .pre-bar::after{animation:none}   /* the fill still reports; the sheen stops */
}
