/* ============================================================
   effects.css — motion, cursor, marquee, admin chrome
   Hidden/pre-animation states ONLY under html.motion-ok so
   no-JS and reduced-motion users always see everything.
   ============================================================ */

/* ---- scroll progress bar ---- */
.progress{
  position:fixed; top:0; left:0; right:0; height:3px; z-index:95;
  background:linear-gradient(90deg, var(--sapphire), var(--canary));
  transform:scaleX(0); transform-origin:left;
  box-shadow:0 0 12px rgba(var(--sapphire-rgb),.6);
}

/* ---- reveals ---- */
html.motion-ok [data-reveal]{
  opacity:0; transform:translateY(26px);
  transition:opacity .7s var(--ease), transform .7s var(--ease);
}
html.motion-ok [data-reveal].in{ opacity:1; transform:none; }
html.motion-ok [data-reveal][data-reveal-delay="1"]{ transition-delay:.12s; }
html.motion-ok [data-reveal][data-reveal-delay="2"]{ transition-delay:.24s; }
html.motion-ok [data-reveal][data-reveal-delay="3"]{ transition-delay:.36s; }

/* ---- kinetic split text ---- */
html.motion-ok [data-split] .ch{
  display:inline-block;
  opacity:0; transform:translateY(.55em) rotate(3deg);
  transition:opacity .55s var(--ease), transform .55s var(--ease);
  transition-delay:calc(var(--i) * 30ms);
}
html.motion-ok [data-split].in .ch{ opacity:1; transform:none; }
[data-split] .ch{ white-space:pre; }
[data-split] .word{ display:inline-block; white-space:nowrap; }

/* hero accent swap */
.swipe-word.swap{ opacity:0; transform:translateY(.4em); }
html.motion-ok .swipe-word{ transition:opacity .3s var(--ease), transform .3s var(--ease); }

/* ---- orb drift ---- */
html.motion-ok .orb{ animation:orbDrift 14s ease-in-out infinite alternate; }
html.motion-ok .orb-d{ animation-duration:18s; animation-delay:-6s; }
/* interactive orbs: no drift — its scale(1.08) would skew the pocket's client→mask mapping */
html.motion-ok .orb-b, html.motion-ok .orb-b2, html.motion-ok .orb-c{ animation:none; }
@keyframes orbDrift{
  from{ transform:translate3d(0,0,0) scale(1); }
  to{ transform:translate3d(4%, 6%, 0) scale(1.08); }
}
/* parallax overrides drift transform via translate on a wrapper var */
html.motion-ok [data-parallax]{ will-change:transform; }

/* ---- marquee ---- */
html.motion-ok .mq-track{ animation:mq 28s linear infinite; }
html.motion-ok .mq-band:hover .mq-track,
html.motion-ok .mq-track.paused{ animation-play-state:paused; }
@keyframes mq{ to{ transform:translateX(-50%); } }

/* ---- custom cursor ---- */
.cursor-dot, .cursor-ring{ display:none; }
html.cur-on .cursor-dot{
  display:block; position:fixed; z-index:130; pointer-events:none;
  width:7px; height:7px; border-radius:50%;
  background:var(--canary); box-shadow:0 0 10px rgba(var(--canary-rgb),.8);
  transform:translate(-50%,-50%);
  left:0; top:0;
}
html.cur-on .cursor-ring{
  display:flex; align-items:center; justify-content:center;
  position:fixed; z-index:129; pointer-events:none;
  width:38px; height:38px; border-radius:50%;
  border:1.5px solid rgba(var(--sapphire-rgb),.75);
  box-shadow:0 0 18px rgba(var(--sapphire-rgb),.35);
  transform:translate(-50%,-50%);
  left:0; top:0;
  transition:width .25s var(--ease), height .25s var(--ease), border-color .25s var(--ease), opacity .25s var(--ease);
}
html.cur-on .cursor-ring.big{ width:64px; height:64px; border-color:var(--canary); box-shadow:0 0 22px rgba(var(--canary-rgb),.4); }
html.cur-on .cursor-ring.hidden, html.cur-on .cursor-dot.hidden{ opacity:0; }
html.cur-on body{ cursor:none; }
html.cur-on a, html.cur-on button{ cursor:none; }
/* native cursor restored where it matters */
html.cur-on input, html.cur-on textarea, html.cur-on [contenteditable="true"]{ cursor:text; }
html.cur-on body.admin, html.cur-on body.admin *{ cursor:auto; }
html.cur-on .ba-grip{ cursor:ew-resize; }

/* ---- before/after discovery halo: pulses until first touch ---- */
@keyframes baPulse{
  from{ box-shadow:0 0 26px rgba(var(--sapphire-rgb),.8), 0 0 0 0 rgba(var(--sapphire-rgb),.45); }
  to{   box-shadow:0 0 26px rgba(var(--sapphire-rgb),.8), 0 0 0 18px rgba(var(--sapphire-rgb),0); }
}
html.motion-ok .ba-compare[data-untouched] .ba-grip::after{ animation:baPulse 2.2s ease-out infinite; }

/* ---- magnetic + tilt (transforms set from JS) ---- */
[data-magnetic]{ will-change:transform; }
[data-tilt]{ will-change:transform; }

/* ---- reduced motion: kill everything, show everything ---- */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
}
html.reduced-motion [data-reveal], html.reduced-motion [data-split] .ch{ opacity:1 !important; transform:none !important; }
html.reduced-motion .mq-track{ animation:none; }
html.reduced-motion .orb{ animation:none; }

/* ============================================================
   ADMIN CHROME
   ============================================================ */
.admin-bar{
  position:fixed; bottom:18px; left:50%; transform:translateX(-50%);
  z-index:110; display:flex; gap:8px; align-items:center; flex-wrap:wrap; justify-content:center;
  background:rgba(var(--veil-rgb),.92); backdrop-filter:blur(14px);
  border:1px solid rgba(var(--sapphire-rgb),.4); border-radius:16px;
  padding:10px 14px; max-width:94vw;
  box-shadow:0 16px 50px rgba(0,0,0,.55), 0 0 30px rgba(var(--sapphire-rgb),.15);
}
.admin-bar[hidden]{ display:none; }
.admin-badge{
  font-size:12px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--canary); padding-right:10px; border-right:1px solid var(--line);
  white-space:nowrap;
}
.admin-bar button{
  font-size:13px; font-weight:600; padding:8px 14px; border-radius:10px;
  border:1px solid var(--line); color:var(--ink); white-space:nowrap;
  transition:border-color var(--t), background var(--t);
}
.admin-bar button:hover{ border-color:var(--sapphire); background:rgba(var(--sapphire-rgb),.12); }
.admin-bar button.primary{ border-color:var(--sapphire); background:rgba(var(--sapphire-rgb),.18); }
.admin-bar button.danger{ border-color:rgba(255,93,93,.5); color:var(--danger); }

body.admin [data-editable]{
  outline:1.5px dashed rgba(var(--canary-rgb),.5); outline-offset:4px; border-radius:4px;
  min-height:1em;
}
body.admin [data-editable]:hover, body.admin [data-editable]:focus{
  outline-color:var(--canary); outline-style:solid;
}
.edit-mini:hover{ background:rgba(var(--sapphire-rgb),.15); }

/* ---- entry-tease invitation: theme pill pulses once after the intro wipe lands ---- */
@keyframes teaseNudge{
  0%,100%{ transform:none; box-shadow:0 0 0 0 rgba(var(--sapphire-rgb),0); }
  20%{ transform:scale(1.14) rotate(-6deg); }
  40%{ transform:scale(1.08) rotate(5deg); box-shadow:0 0 18px 2px rgba(var(--sapphire-rgb),.55); }
  60%{ transform:scale(1.1) rotate(-3deg); }
  80%{ transform:scale(1.04); }
}
html.motion-ok .theme-pill.tease-nudge{ animation:teaseNudge .9s var(--ease) 1; }

/* ===== theme wipe — circular reveal from the nav toggle (View Transitions API).
   JS only starts a transition under motion-ok, so reduced-motion keeps the instant swap. */
::view-transition-old(root), ::view-transition-new(root){ animation:none; mix-blend-mode:normal; }
::view-transition-new(root){ animation:vtWipe .55s ease; }
@keyframes vtWipe{
  from{ clip-path:circle(0 at var(--vt-x, 50%) var(--vt-y, 50%)); }
  to{ clip-path:circle(var(--vt-r, 150vmax) at var(--vt-x, 50%) var(--vt-y, 50%)); }
}
