/* ============================================================
   ENGRAVING BY SILVA — eng-motion.css   (see eng-motion.js for the API)
   Loaded after engraving.css on the hub, product, create and order
   pages. Only transform / opacity / clip-path / filter animate;
   prefers-reduced-motion turns the whole layer off.
   ============================================================ */

/* ============ 1. AMBIENT CANVAS ============
   z-index:-1 sits above the body's concrete stage wall (which propagates
   to the root canvas) and below every box, so translucent sections still
   read as glass over concrete and the header (50) / drawer (90) /
   toast (100) / loader (200) are untouched. */
#eng-ambient{
  position:fixed; inset:0; width:100%; height:100%;
  z-index:-1; pointer-events:none;
  opacity:0; transition:opacity 1.6s ease .35s;
}
#eng-ambient.on{ opacity:1; }

/* ============ 2. SCROLL PROGRESS ============ */
.eng-progress{
  position:fixed; top:0; left:0; right:0; height:2px;
  z-index:60;                      /* above the sticky header, below overlays */
  pointer-events:none;
}
.eng-progress i{
  display:block; height:100%; transform:scaleX(0); transform-origin:0 50%;
  will-change:transform;
  background:linear-gradient(90deg, rgba(226,226,230,.18), rgba(242,242,244,.85));
  box-shadow:0 0 10px rgba(255,255,255,.3);
}
html.is-loading .eng-progress{ opacity:0; }

/* ============ 3. PARALLAX ============ */
[data-parallax]{
  transform:translate3d(0, var(--py, 0px), 0);
  transition-property:opacity, filter;      /* never transition the parallax transform */
}

/* ============ 4. TILT + GLARE ============
   JS sets position:relative only when the element is static, so a
   tilt on an already-positioned card keeps its own positioning. */
[data-tilt]{
  transform:perspective(900px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg)) translate3d(0, var(--py, 0px), 0);
  transition-property:transform, opacity, filter;
  transition-duration:.45s;
  transition-timing-function:cubic-bezier(.2,.7,.2,1);
}
[data-tilt]::after{
  content:""; position:absolute; inset:0; border-radius:inherit;
  pointer-events:none; opacity:0; transition:opacity .4s ease;
  background:radial-gradient(circle at var(--gx,50%) var(--gy,50%), rgba(255,255,255,.06), rgba(255,255,255,0) 58%);
}
[data-tilt].m-hot::after{ opacity:1; }

/* ============ 5. MAGNETIC ============ */
[data-magnetic]{
  transform:translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transition:transform .3s cubic-bezier(.2,.7,.2,1), background .2s, color .2s, border-color .2s, box-shadow .2s;
}
/* beats .btn:hover's translateY(-1px); the hover shadow still comes from .btn:hover */
.btn[data-magnetic]:hover{ transform:translate3d(var(--mx, 0px), var(--my, 0px), 0); }
/* while the cursor is inside, follow it almost immediately;
   on leave the class goes and the slower easing springs it back */
[data-magnetic].m-hot, [data-tilt].m-hot{ transition-duration:.09s; transition-delay:0s; }

/* ============ 6. BUTTON PRESS ============ */
.btn:active{ transform:scale(.98); }
.btn[data-magnetic]:active{ transform:translate3d(var(--mx,0px), var(--my,0px), 0) scale(.98); }

/* ============ 7. REVEAL — blur to sharp rise ============
   Upgrades the .reveal / .in pair that mountReveal() already drives. */
.reveal{
  opacity:0; transform:translateY(18px); filter:blur(6px);
  transition-property:opacity, transform, filter;
  transition-duration:.7s;
  transition-timing-function:cubic-bezier(.2,.7,.2,1);
  transition-delay:calc(var(--i, 0) * 80ms);
}
.reveal.in{ opacity:1; transform:none; filter:blur(0px); }
/* an element that reveals AND tilts/parallaxes keeps its composed transform:
   it fades and sharpens, but never fights over transform. */
.reveal[data-tilt], .reveal.in[data-tilt]{
  transform:perspective(900px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg)) translate3d(0, var(--py, 0px), 0);
}
.reveal[data-parallax], .reveal.in[data-parallax]{
  transform:translate3d(0, var(--py, 0px), 0);
  transition-property:opacity, filter;
}

/* ============ 8. HEADING ETCH ============
   --e0 / --e1 are the left and right edge of the last line of text,
   measured by the JS with a Range so the wipe and the laser track the
   words, not the block. Without JS they fall back to the full width. */
[data-etch]{ position:relative; }
[data-etch].etch-run{ animation:mEtchWipe .9s cubic-bezier(.25,.72,.2,1) both; }
@keyframes mEtchWipe{
  from{ clip-path:inset(-.45em calc(100% - var(--e0, 0px)) -.4em -.14em); }
  to  { clip-path:inset(-.45em calc(100% - var(--e1, 100%) - .35em) -.4em -.14em); }
}
[data-etch]::after{
  content:""; position:absolute; bottom:-.16em; height:1px;
  left:var(--e0, 0px); right:auto; width:calc(var(--e1, 100%) - var(--e0, 0px));
  pointer-events:none; opacity:0; transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg, rgba(255,255,255,.18), rgba(255,255,255,.95) 72%, #fff);
  box-shadow:0 0 8px rgba(255,255,255,.55);
}
[data-etch].etch-run::after{ animation:mEtchLine 1.35s cubic-bezier(.25,.72,.2,1) forwards; }
@keyframes mEtchLine{
  0%{ transform:scaleX(0); opacity:0; }
  7%{ opacity:1; }
  66%{ transform:scaleX(1); opacity:1; }
  100%{ transform:scaleX(1); opacity:0; }
}
[data-etch].etch-done::after{ opacity:0; }

/* ============ 9. SECTION HAIRLINE ============ */
.section{ position:relative; }
.section::after{
  content:""; position:absolute; left:0; right:0; top:0; height:1px;
  pointer-events:none; transform:scaleX(0); transform-origin:50% 50%;
  transition:transform .8s cubic-bezier(.2,.7,.2,1);
  background:linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.24) 50%, rgba(255,255,255,0));
}
.section.sec-in::after{ transform:scaleX(1); }
/* the hero seam is a deliberate dissolve — no line there */
.section.after-hero::after{ display:none; }

/* ============ 10. LASER LINK UNDERLINE ============ */
.eng-footer a, .head-nav a{ position:relative; }
.eng-footer a::after, .head-nav a::after{
  content:""; position:absolute; left:0; right:0; bottom:-3px; height:1px;
  pointer-events:none; transform:scaleX(0); transform-origin:0 50%;
  transition:transform .45s cubic-bezier(.2,.7,.2,1);
  background:linear-gradient(90deg, rgba(255,255,255,.45), #fff);
  box-shadow:0 0 6px rgba(255,255,255,.45);
}
.eng-footer a:hover::after, .eng-footer a:focus-visible::after,
.head-nav a:hover::after, .head-nav a:focus-visible::after{ transform:scaleX(1); }
/* not on the brand lockup, the legal line, or the dropdown rows */
.eng-footer .brand::after, .eng-footer .disclaimer a::after{ display:none; }
@media (max-width:820px){ .head-nav a::after{ display:none; } }

/* ============ 11. FOCUS ============ */
:focus-visible{ outline:2px solid rgba(226,226,230,.95); outline-offset:3px; }
.btn:focus-visible, .nav-arrow:focus-visible{ outline-offset:4px; }
input:focus-visible, select:focus-visible, textarea:focus-visible{ outline-offset:1px; }

/* ============ 12. COARSE POINTERS ============
   No hover here — drop the tilt/magnetic transforms so those cards
   never get a permanent composited layer on a phone. */
@media (hover:none), (pointer:coarse){
  [data-tilt]{ transform:translate3d(0, var(--py, 0px), 0); }
  [data-tilt]::after{ display:none; }
  [data-magnetic], .btn[data-magnetic]:hover{ transform:none; }
}

/* ============ 13. REDUCED MOTION ============ */
@media (prefers-reduced-motion:reduce){
  #eng-ambient{ transition:none; }
  .reveal, .reveal.in{ opacity:1; transform:none; filter:none; transition:none; }
  [data-parallax]{ transform:none; }
  [data-tilt]{ transform:none; transition:none; }
  [data-tilt]::after{ display:none; }
  [data-magnetic]{ transform:none; transition:none; }
  .btn:active, .btn[data-magnetic]:active{ transform:none; }
  [data-etch].etch-run, [data-etch].etch-run::after{ animation:none; }
  [data-etch]::after{ display:none; }
  .section::after{ transform:scaleX(1); transition:none; }
  .eng-footer a::after, .head-nav a::after{ transition:none; }
  .eng-progress i{ transition:none; }
}
