/* Precision 3D — lightweight animations (no libraries).
   1) page loader + busy spool  2) hero "print" title  3) card hover tilt  4) filament strand canvas
   Everything degrades to a static, fully usable page without JS and honours prefers-reduced-motion. */

/* ---------- 4) background filament strands (canvas injected by animations.js) ---------- */
.pf-strands{position:fixed;inset:0;width:100%;height:100%;z-index:-1;pointer-events:none;opacity:0;transition:opacity 1.2s ease}
.pf-strands.on{opacity:1}

/* ---------- 1) page loader (markup right after <body>) ---------- */
.pf-loader{position:fixed;inset:0;z-index:100;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  background:var(--bg,#f6f8fb);pointer-events:none;transition:opacity .35s ease,visibility .35s;
  /* safety net: hide even if JS never runs */
  animation:pf-loader-out .4s ease 3s forwards}
.pf-loader .pf-loader-txt{font-size:13px;font-weight:600;color:var(--muted,#6b7280);letter-spacing:.04em}
html.pf-ready .pf-loader{opacity:0;visibility:hidden}
@keyframes pf-loader-out{to{opacity:0;visibility:hidden}}
.pf-spool{display:inline-block;width:48px;height:48px;background:url(/img/spool.svg) center/contain no-repeat;animation:pf-spin 1.1s linear infinite}
@keyframes pf-spin{to{transform:rotate(360deg)}}

/* busy indicator while an API request is in flight (toggled by the fetch wrapper) */
.pf-busy-spool{position:fixed;left:16px;bottom:16px;z-index:70;width:34px;height:34px;padding:5px;border-radius:50%;background:#fff;
  box-shadow:0 4px 14px rgba(15,23,42,.15);pointer-events:none;opacity:0;transform:scale(.6);transition:opacity .2s,transform .2s}
.pf-busy-spool .pf-spool{width:24px;height:24px}
html.pf-busy .pf-busy-spool{opacity:1;transform:none}
.btn.pf-btn-busy::before{content:"";width:15px;height:15px;flex:none;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;animation:pf-spin .8s linear infinite}

/* ---------- 2) hero: nozzle prints the title layer by layer ---------- */
.pf-hero{position:relative;margin:4px 0 22px;padding:14px 12px 4px;border:1px solid var(--line,#e5e7eb);border-radius:16px;overflow:hidden;
  background:radial-gradient(120% 90% at 50% 0%,#ffffff 0%,#eef4ff 60%,#e3ecff 100%)}
.pf-hero svg{display:block;width:100%;max-width:820px;height:auto;margin:0 auto}
.pf-hero .pf-tagline{text-align:center;margin:0 0 12px;color:var(--muted,#6b7280);font-weight:600;letter-spacing:.02em;transition:opacity .6s ease .1s,transform .6s ease .1s}
.pf-title{font-family:system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;font-weight:800;font-size:92px}
.pf-title-ghost{fill:none;stroke:#93c5fd;stroke-width:1.2;stroke-dasharray:5 5;opacity:0;transition:opacity .5s}
.pf-title-print{fill:url(#pfFilament);stroke:#1d4ed8;stroke-width:1.5;stroke-linejoin:round}
.pf-title-lines{fill:url(#pfLayers);opacity:0;transition:opacity .9s ease}
.pf-nozzle-wrap{opacity:0;transition:opacity .45s ease,transform .7s cubic-bezier(.3,.6,.2,1)}
.pf-gantry{opacity:0;transition:opacity .45s ease}
.pf-tip{animation:pf-glow .5s ease-in-out infinite alternate}
@keyframes pf-glow{from{opacity:.65}to{opacity:1}}
/* states set by JS: pf-printing -> pf-finished. Default (no JS) = finished, filled title. */
.pf-hero.pf-printing .pf-title-ghost{opacity:.9;animation:pf-march .8s linear infinite}
.pf-hero.pf-printing .pf-title-lines{opacity:.55}
.pf-hero.pf-printing .pf-nozzle-wrap,.pf-hero.pf-printing .pf-gantry{opacity:1}
.pf-hero.pf-printing .pf-tagline{opacity:0;transform:translateY(6px)}
.pf-hero.pf-finished .pf-nozzle-wrap{opacity:0;transform:translate(40px,-60px)}
@keyframes pf-march{to{stroke-dashoffset:-20}}

/* ---------- 3) product cards float above the build plate ---------- */
.card.product{transform:perspective(900px) translateY(0) rotateX(0) rotateY(0);
  transition:transform .35s cubic-bezier(.2,.7,.2,1),box-shadow .35s ease,border-color .35s ease;
  animation:pf-rise .55s cubic-bezier(.2,.7,.2,1) backwards}
.card.product:nth-child(2){animation-delay:.06s}.card.product:nth-child(3){animation-delay:.12s}
.card.product:nth-child(4){animation-delay:.18s}.card.product:nth-child(5){animation-delay:.24s}.card.product:nth-child(n+6){animation-delay:.3s}
@keyframes pf-rise{from{opacity:0;transform:perspective(900px) translateY(14px)}}
@media (hover:hover){
  .card.product:hover{transform:perspective(900px) translateY(-6px) rotateX(var(--pf-rx,0deg)) rotateY(var(--pf-ry,0deg));
    border-color:#c7d7fe;
    /* soft shadow cast down onto the "build plate" + a faint contact shadow */
    box-shadow:0 26px 30px -20px rgba(29,78,216,.42),0 10px 16px -12px rgba(15,23,42,.18)}
  .card.product:hover img{filter:saturate(1.08)}
}
.card.product img{transition:filter .35s ease}

/* ---------- reduced motion: no movement, instant states ---------- */
@media (prefers-reduced-motion:reduce){
  .pf-strands{display:none}
  .pf-loader{transition:none;animation-duration:.01s;animation-delay:.5s}
  .pf-spool,.btn.pf-btn-busy::before{animation-duration:3s}
  .card.product,.card.product:hover{animation:none;transform:none;transition:box-shadow .2s,border-color .2s}
  .pf-hero *{animation:none!important;transition:none!important}
}

/* =====================================================================
   5) tracking timeline: filament extrudes from step to step (enhanced by JS: .pf-tl)
   ===================================================================== */
.timeline.pf-tl{margin-top:40px}
.timeline.pf-tl::before{height:6px;top:14px;border-radius:3px}
.timeline.pf-tl .bar{height:6px;top:14px;border-radius:3px;
  background:linear-gradient(90deg,#15803d,#22c55e);
  background-image:repeating-linear-gradient(90deg,rgba(255,255,255,.28) 0 2px,transparent 2px 7px),linear-gradient(90deg,#15803d,#22c55e);
  transition:width var(--pf-tl-dur,1s) cubic-bezier(.45,.05,.35,1)}
/* mini nozzle riding on the leading edge of the filament */
.timeline.pf-tl .bar::after{content:"";position:absolute;right:-9px;top:-27px;width:18px;height:24px;
  background:url(/img/nozzle.svg) center/contain no-repeat;transition:transform .5s ease,opacity .5s ease;
  filter:drop-shadow(0 2px 2px rgba(15,23,42,.18))}
.timeline.pf-tl.pf-tl-running .bar::after{animation:pf-jiggle .18s linear infinite alternate}
.timeline.pf-tl.pf-tl-done .bar::after{transform:translateY(-14px)}
.timeline.pf-tl.pf-tl-final .bar::after{transform:translateY(-22px);opacity:0}
@keyframes pf-jiggle{to{transform:translateY(-1px)}}
/* completed steps pop in as the filament reaches them (delay set per step via --pf-d) */
.timeline.pf-tl .step.done .dot{animation:pf-step-pop .5s cubic-bezier(.3,1.6,.5,1) var(--pf-d,0s) backwards}
@keyframes pf-step-pop{
  0%{background:#fff;border-color:var(--line,#e5e7eb);color:var(--muted,#6b7280);transform:scale(1)}
  55%{transform:scale(1.22)}100%{transform:scale(1)}}
.timeline.pf-tl .step.done .lbl{animation:pf-fade-in .4s ease var(--pf-d,0s) backwards}
@keyframes pf-fade-in{from{opacity:.45}}
/* current step breathes gently (not on the final "Delivered" step) */
.timeline.pf-tl .step.current:not(:last-child) .dot{animation:pf-step-pop .5s cubic-bezier(.3,1.6,.5,1) var(--pf-d,0s) backwards,pf-breathe 2.2s ease-in-out calc(var(--pf-d,0s) + .5s) infinite}
@keyframes pf-breathe{0%,100%{box-shadow:0 0 0 5px #bbf7d0}50%{box-shadow:0 0 0 9px rgba(187,247,208,.35)}}
/* unknown / non-standard status: neutral dashed line, no nozzle */
.timeline.pf-tl.pf-tl-other::before{background:repeating-linear-gradient(90deg,#d1d5db 0 8px,transparent 8px 14px)}
.timeline.pf-tl.pf-tl-other .bar{display:none}
.pf-history{list-style:none;margin:6px 0 0;padding:0 0 0 14px;border-left:2px solid var(--line,#e5e7eb);font-size:14px}
.pf-history li{position:relative;padding:4px 0 8px 10px}
.pf-history li::before{content:"";position:absolute;left:-21px;top:9px;width:10px;height:10px;border-radius:50%;background:var(--ok,#16a34a);box-shadow:0 0 0 3px #fff}
.pf-history .when{color:var(--muted,#6b7280);font-size:12px}
.pf-history li{animation:pf-slide-in .4s ease backwards}
.pf-history li:nth-child(2){animation-delay:.08s}.pf-history li:nth-child(3){animation-delay:.16s}.pf-history li:nth-child(n+4){animation-delay:.24s}

/* =====================================================================
   6) item selection + cart feedback (classes toggled by JS)
   ===================================================================== */
.card.product{position:relative}
.card.product::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;box-shadow:inset 0 0 0 2px transparent}
.card.product.pf-flash::after{animation:pf-ring .7s ease}
@keyframes pf-ring{30%{box-shadow:inset 0 0 0 2px rgba(37,99,235,.55)}}
.pf-pop{animation:pf-pop .42s cubic-bezier(.3,1.5,.5,1)}
@keyframes pf-pop{0%{transform:scale(1)}40%{transform:scale(1.045);box-shadow:0 0 0 4px rgba(37,99,235,.2)}100%{transform:scale(1)}}
.price.pf-pop,.qty span.pf-pop{display:inline-block;animation:pf-pop-num .42s cubic-bezier(.3,1.5,.5,1)}
@keyframes pf-pop-num{40%{transform:scale(1.18);color:var(--brand,#2563eb)}}
.btn.pf-added{animation:pf-added .6s ease}
@keyframes pf-added{30%{background:#16a34a;transform:scale(.97)}}
.badge.pf-bump{animation:pf-bump .5s cubic-bezier(.3,1.7,.5,1)}
@keyframes pf-bump{0%{transform:scale(1)}35%{transform:scale(1.45)}70%{transform:scale(.92)}100%{transform:scale(1)}}
/* filament blob flying from the card to the cart (outer = x, inner = y for an arc) */
.pf-fly{position:fixed;left:0;top:0;z-index:80;pointer-events:none}
.pf-fly i{display:block;width:16px;height:16px;margin:-8px 0 0 -8px;border-radius:50%;background:var(--brand,#2563eb);
  border:2px solid #fff;box-shadow:0 3px 8px rgba(15,23,42,.3)}
/* cart drawer + checkout summary line items */
.drawer.pf-opening{animation:pf-drawer-in .32s cubic-bezier(.2,.8,.2,1)}
@keyframes pf-drawer-in{from{transform:translateX(40px);opacity:.4}}
.drawer.pf-opening .cart-item,.cart-item.pf-new{animation:pf-slide-in .4s cubic-bezier(.2,.8,.2,1) backwards}
.drawer.pf-opening .cart-item:nth-child(2){animation-delay:.05s}.drawer.pf-opening .cart-item:nth-child(3){animation-delay:.1s}
.drawer.pf-opening .cart-item:nth-child(n+4){animation-delay:.15s}
#summaryLines>.line{animation:pf-slide-in .4s cubic-bezier(.2,.8,.2,1) backwards}
#summaryLines>.line:nth-child(2){animation-delay:.05s}#summaryLines>.line:nth-child(3){animation-delay:.1s}
#summaryLines>.line:nth-child(4){animation-delay:.15s}#summaryLines>.line:nth-child(n+5){animation-delay:.2s}
@keyframes pf-slide-in{from{opacity:0;transform:translateY(8px)}}

@media (prefers-reduced-motion:reduce){
  .timeline.pf-tl .bar{transition:none}
  .timeline.pf-tl .bar::after{display:none}
  .timeline.pf-tl .step .dot,.timeline.pf-tl .step .lbl,.pf-history li,.pf-pop,.price.pf-pop,.qty span.pf-pop,.btn.pf-added,.badge.pf-bump,
  .drawer.pf-opening,.drawer.pf-opening .cart-item,.cart-item.pf-new,#summaryLines>.line{animation:none!important}
  .pf-fly{display:none}
}

/* =====================================================================
   7) reveal-on-scroll (JS adds html.pf-reveal-on; without JS everything is visible)
   ===================================================================== */
html.pf-reveal-on [data-reveal]:not(.pf-in){opacity:0;transform:translateY(16px)}
html.pf-reveal-on [data-reveal]{transition:opacity .6s ease,transform .6s cubic-bezier(.2,.7,.2,1)}

/* 8) home "How it works": filament extrudes across the four steps when scrolled into view */
.pf-hiw{margin:36px 0 8px;padding:22px 18px 16px;border:1px solid var(--line,#e5e7eb);border-radius:16px;
  background:linear-gradient(180deg,#ffffff,#f3f7ff)}
.pf-hiw h2{font-size:24px;margin:0 0 2px;text-align:center}.pf-hiw>.sub{text-align:center;margin-bottom:8px}
.pf-hiw-track{position:relative;height:30px;margin:0 12.5%}
.pf-hiw-track::before,.pf-hiw-fil{content:"";position:absolute;left:0;right:0;top:20px;height:6px;border-radius:3px}
.pf-hiw-track::before{background:var(--line,#e5e7eb)}
.pf-hiw-fil{background:repeating-linear-gradient(90deg,rgba(255,255,255,.3) 0 2px,transparent 2px 7px),linear-gradient(90deg,#1d4ed8,#60a5fa);
  transform-origin:left center;transform:scaleX(1)}
.pf-hiw-noz{position:absolute;top:-4px;left:100%;width:18px;height:24px;margin-left:-9px;background:url(/img/nozzle.svg) center/contain no-repeat}
.pf-hiw-steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:14px;text-align:center}
.pf-hiw-step h3{font-size:16px;margin:6px 0 4px}.pf-hiw-step p{font-size:14px;color:var(--muted,#6b7280);margin:0}
.pf-hiw-ico{display:inline-flex;width:56px;height:56px;border-radius:50%;background:#fff;border:2px solid #c7d7fe;align-items:center;justify-content:center;box-shadow:0 6px 14px -8px rgba(29,78,216,.45)}
.pf-hiw-ico svg{width:34px;height:34px}
.pf-hiw>.small{margin:14px 0 0}
/* animated state (only when JS enabled reveal) */
html.pf-reveal-on .pf-hiw .pf-hiw-fil{transform:scaleX(0);transition:transform 2.4s cubic-bezier(.45,.05,.35,1) .2s}
html.pf-reveal-on .pf-hiw .pf-hiw-noz{left:0;opacity:1;transition:left 2.4s cubic-bezier(.45,.05,.35,1) .2s,opacity .5s ease 2.7s}
html.pf-reveal-on .pf-hiw .pf-hiw-step{opacity:0;transform:translateY(10px) scale(.96);transition:opacity .45s ease,transform .45s cubic-bezier(.3,1.5,.5,1)}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-fil{transform:scaleX(1)}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-noz{left:100%;opacity:0}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-step{opacity:1;transform:none}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-step:nth-child(1){transition-delay:.2s}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-step:nth-child(2){transition-delay:.95s}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-step:nth-child(3){transition-delay:1.7s}
html.pf-reveal-on .pf-hiw.pf-in .pf-hiw-step:nth-child(4){transition-delay:2.45s}
@media (max-width:640px){.pf-hiw-track{display:none}.pf-hiw-steps{grid-template-columns:1fr 1fr}}
@media (max-width:400px){.pf-hiw-steps{grid-template-columns:1fr}}
@media (prefers-reduced-motion:reduce){.pf-hiw-noz{display:none}}
