/* ═══════════════════════════════════════════════════════════════════
   CABANA · THE LOOM
   ───────────────────────────────────────────────────────────────────
   The arrival animation for /shopping.

   A cloth weaves itself. Warp threads drop, weft shoots across, over
   and under, and a pattern appears. Then it dissolves into the page.

   Six decisions worth stating.

   · This one is light. Every other arrival on this platform is dark
     because every other page is; shopping.html is built on #FCFCFD
     and a dark gate opening onto it would flash white at the handover
     and read as a different product. The set is consistent in pace
     and structure, not in brightness.

   · A loom, because the page says sellers and makers. Weaving is the
     most direct possible picture of something being made, it belongs
     to the continent the page is about, and no shopping site on earth
     uses it — they all use a skeleton grid of grey rectangles, which
     is a picture of a database.

   · The interlace is real, not implied. Warp threads run continuous
     top to bottom. Weft threads are dashed so their gaps fall exactly
     on the cells where they pass under, and the phase flips every
     row. That is the definition of a plain weave, and it costs one
     dash pattern rather than a cell-by-cell render.

   · Threads are straight lines, which is what SVG is for. The tours
     canopy spent six attempts learning that organic shapes fight
     vectors; this subject does not.

   · The draw-on is a transform, never stroke-dashoffset. dasharray is
     already carrying the weave, so animating its offset would slide
     the pattern sideways rather than draw the thread. Each row scales
     from its own edge instead, which is also the cheaper of the two.

   · Green is the commission mark and appears nowhere else, exactly as
     it does on the page above.

   Scoped under .wv- so it cannot touch the page it opens onto.
   ═══════════════════════════════════════════════════════════════════ */

#shop-gate{
  /* ── shopping.html's own tokens ── */
  --wv-glass:#FCFCFD;
  --wv-glass-2:#F4F5FB;
  --wv-ink:#0A0A14;
  --wv-ink-soft:#4A4C66;
  --wv-ink-faint:#8E90AD;

  /* ── the palette the cloth is woven in ── */
  --wv-violet:#6D28FF;
  --wv-lilac:#B8A4F4;
  --wv-blue:#4361FF;
  --wv-green:#00A082;     /* the commission mark, and nothing else */

  --wv-ease:cubic-bezier(.7,0,.2,1);
  --wv-soft:cubic-bezier(.22,1,.36,1);
  --wv-snap:cubic-bezier(.2,1.25,.3,1);

  position:fixed;
  inset:0;
  z-index:2147483000;
  overflow:hidden;
  background:var(--wv-glass);
  contain:strict;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}

html.wv-lock,
html.wv-lock body{ overflow:hidden !important; }

.wv-stage{ position:absolute; inset:0; overflow:hidden; }

/* The page's own aurora, faintly, so the gate and the page underneath
   are lit the same way. */
.wv-air{
  position:absolute; inset:-10%;
  background:
    radial-gradient(46% 34% at 12% 8%,  rgba(109,40,255,.11), transparent 70%),
    radial-gradient(40% 30% at 88% 92%, rgba(184,164,244,.13), transparent 72%),
    linear-gradient(180deg, #FCFCFD 0%, #F7F7FB 60%, #F2F2F8 100%);
}

/* ═══ 1 · THE CLOTH ═════════════════════════════════════════════════
   A square larger than the frame, tilted a little, so the weave runs
   off every edge and does not read as a swatch sitting on a page.  */

.wv-cloth{
  position:absolute;
  left:50%; top:50%;
  width:var(--cloth,1200px);
  height:var(--cloth,1200px);
  margin-left:calc(var(--cloth,1200px) / -2);
  margin-top:calc(var(--cloth,1200px) / -2);
  transform:rotate(-8deg);
  will-change:transform;
}
.wv-loom{
  position:absolute; inset:0;
  width:100%; height:100%;
  display:block;
  overflow:visible;
}

/* ── warp · the threads held on the frame ────────────────────────
   Continuous, top to bottom. They are what the weft passes over and
   under, so they are never dashed. */
.wv-warp{
  stroke:var(--c,#B8A4F4);
  stroke-width:var(--w,7);
  stroke-linecap:butt;
  transform-origin:50% 0;
  transform:scaleY(0);
}

/* ── weft · the thread that travels ──────────────────────────────
   Dashed so the gaps land exactly where it passes under a warp, with
   the phase flipped every row. Two numbers, and the cloth interlaces. */
.wv-weft{
  /* The thread lying on top catches slightly more light than the one
     underneath. Without this the interlace reads as a chessboard
     rather than as one thread crossing another. */
  filter:brightness(1.06);
  stroke:var(--c,#6D28FF);
  stroke-width:var(--w,7);
  stroke-linecap:butt;
  stroke-dasharray:var(--dash,14 14);
  stroke-dashoffset:var(--phase,0);
  transform-origin:var(--from,0%) 50%;
  transform:scaleX(0);
}

/* ═══ 2 · THE WORD ══════════════════════════════════════════════════ */

.wv-word{
  position:absolute;
  left:0; right:0; top:50%;
  transform:translateY(-50%);
  text-align:center;
  padding:0 30px;
  z-index:6;
  pointer-events:none;
}
/* On a light ground the type needs a plate, not a shadow: the cloth
   behind it is fully saturated by the time the word lands. */
.wv-plate{
  position:absolute;
  left:50%; top:50%;
  width:min(94vw,720px); height:min(52vh,420px);
  transform:translate(-50%,-50%);
  background:radial-gradient(60% 52% at 50% 50%,
    rgba(252,252,253,.97) 0%, rgba(252,252,253,.9) 42%, rgba(252,252,253,0) 78%);
  opacity:0;
  z-index:5;
  pointer-events:none;
}
.wv-line{
  position:relative;
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-weight:600;
  font-size:clamp(36px,10.5vw,68px);
  line-height:1.03;
  letter-spacing:-.035em;
  color:var(--wv-ink);
  opacity:0;
  transform:translateY(14px);
}
.wv-line em{
  display:block;
  font-style:normal;
  background:linear-gradient(112deg,var(--wv-violet),var(--wv-blue),var(--wv-lilac));
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
}
.wv-sub{
  position:relative;
  margin-top:16px;
  display:inline-flex; align-items:center; gap:8px;
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-size:10.5px; font-weight:600;
  letter-spacing:.2em; text-transform:uppercase;
  color:var(--wv-green);
  opacity:0;
  transform:translateY(9px);
}
/* The mark that means the price is the seller's own. */
.wv-sub i{
  width:5px; height:5px; border-radius:50%;
  background:var(--wv-green);
  display:inline-block;
}

/* ═══ 3 · SKIP ══════════════════════════════════════════════════════ */

.wv-skip{
  position:absolute;
  top:max(18px,env(safe-area-inset-top,0px));
  right:16px;
  z-index:9;
  display:inline-flex; align-items:center; gap:7px;
  padding:9px 15px;
  border-radius:100px;
  border:1px solid rgba(10,10,20,.14);
  background:rgba(252,252,253,.82);
  color:var(--wv-ink-soft);
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-size:12.5px; font-weight:500;
  cursor:pointer;
  opacity:0;
  transition:opacity .4s ease, border-color .2s ease, color .2s ease;
}
.wv-skip:hover,
.wv-skip:focus-visible{ border-color:var(--wv-violet); color:var(--wv-violet); }
.wv-skip:focus-visible{ outline:2px solid var(--wv-violet); outline-offset:3px; }
.wv-skip svg{ width:12px; height:12px; }

/* ═══ 4 · THE FINISH ════════════════════════════════════════════════
   Light rather than dark: this gate opens onto a white page, so it
   leaves by becoming one.                                          */

.wv-flood{
  position:absolute; inset:0; z-index:7;
  background:radial-gradient(76% 58% at 50% 50%,
    rgba(252,252,253,1) 0%,
    rgba(252,252,253,.92) 34%,
    rgba(244,245,251,.5) 62%,
    rgba(244,245,251,0) 80%);
  opacity:0;
  transform:scale(.3);
  pointer-events:none;
  will-change:transform,opacity;
}

/* ═══════════════════════════════════════════════════════════════════
   THE SEQUENCE
   warp → weft → the pattern holds → the word → the cloth goes to light
   ═══════════════════════════════════════════════════════════════════ */

/* ── the frame is dressed ── */
#shop-gate.wv-warping .wv-warp{
  animation:wv-drop .62s var(--wv-soft) var(--d,0ms) forwards;
}
@keyframes wv-drop{ to{ transform:scaleY(1); } }

#shop-gate.wv-warping .wv-skip{ opacity:1; }

/* ── the shuttle crosses ───────────────────────────────────────────
   Alternate rows start from opposite edges, because that is what a
   shuttle does: it goes across, and then it comes back. */
#shop-gate.wv-weaving .wv-weft{
  animation:wv-throw .5s var(--wv-ease) var(--d,0ms) forwards;
}
@keyframes wv-throw{ to{ transform:scaleX(1); } }

/* ── the cloth holds ───────────────────────────────────────────────
   A finished weave is not still. This is one slow breath across the
   whole cloth, far below any rate that could read as a flicker. */
#shop-gate.wv-held .wv-cloth{
  animation:wv-breathe 6s ease-in-out infinite alternate;
}
@keyframes wv-breathe{
  from{ transform:rotate(-8deg) scale(1); }
  to  { transform:rotate(-7.2deg) scale(1.02); }
}

/* ── the word ── */
#shop-gate.wv-say .wv-plate{ animation:wv-fade .7s var(--wv-soft) forwards; }
@keyframes wv-fade{ to{ opacity:1; } }
#shop-gate.wv-say .wv-line{ animation:wv-up .9s .12s var(--wv-soft) forwards; }
#shop-gate.wv-say .wv-sub { animation:wv-up .8s .34s var(--wv-soft) forwards; }
@keyframes wv-up{ to{ opacity:1; transform:translateY(0); } }

/* ── it goes to light ── */
#shop-gate.wv-go .wv-cloth{
  animation:wv-open 1.5s var(--wv-ease) forwards;
}
@keyframes wv-open{
  0%  { transform:rotate(-8deg) scale(1); opacity:1; }
  100%{ transform:rotate(-5deg) scale(1.5); opacity:0; }
}
#shop-gate.wv-go .wv-word{
  animation:wv-word-out .55s var(--wv-soft) forwards;
}
@keyframes wv-word-out{
  0%  { opacity:1; transform:translateY(-50%) scale(1); }
  100%{ opacity:0; transform:translateY(-50%) scale(1.05); }
}
#shop-gate.wv-go .wv-plate{ animation:wv-plate-out .5s var(--wv-soft) forwards; }
@keyframes wv-plate-out{ to{ opacity:0; } }
#shop-gate.wv-go .wv-flood{
  animation:wv-flood 1.25s .2s cubic-bezier(.38,.02,.4,1) forwards;
}
@keyframes wv-flood{
  0%  { opacity:0; transform:scale(.3); }
  40% { opacity:.6; }
  100%{ opacity:1; transform:scale(2.4); }
}
#shop-gate.wv-go .wv-skip{ opacity:0; }

#shop-gate.wv-gone{ animation:wv-out .5s ease forwards; pointer-events:none; }
@keyframes wv-out{ to{ opacity:0; } }

/* ═══════════════════════════════════════════════════════════════════
   ABBREVIATED · after the first arrival in a session
   ═══════════════════════════════════════════════════════════════════ */
#shop-gate.wv-brief .wv-word,
#shop-gate.wv-brief .wv-plate,
#shop-gate.wv-brief .wv-skip{ display:none; }
#shop-gate.wv-brief .wv-warp{ animation-duration:.3s; animation-delay:0ms; }
#shop-gate.wv-brief .wv-weft{ animation-duration:.3s; }
#shop-gate.wv-brief.wv-go .wv-cloth{ animation-duration:.75s; }
#shop-gate.wv-brief.wv-go .wv-flood{ animation-duration:.65s; animation-delay:.1s; }

/* ═══════════════════════════════════════════════════════════════════
   REDUCED MOTION
   The finished cloth, held. Nothing drops, throws, breathes or opens.
   ═══════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  #shop-gate .wv-warp { transform:scaleY(1); animation:none !important; }
  #shop-gate .wv-weft { transform:scaleX(1); animation:none !important; }
  #shop-gate .wv-cloth{ animation:none !important; transform:rotate(-8deg); }
  #shop-gate .wv-plate,
  #shop-gate .wv-line,
  #shop-gate .wv-sub  { opacity:1; transform:none; animation:none !important; }
  #shop-gate .wv-line { transform:none; }
  #shop-gate .wv-word { transform:translateY(-50%); }
  #shop-gate.wv-go .wv-cloth,
  #shop-gate.wv-go .wv-word,
  #shop-gate.wv-go .wv-flood{ animation:none !important; }
  #shop-gate.wv-go{ animation:wv-out .45s ease forwards; }
}

/* ═══════════════════════════════════════════════════════════════════
   VIEWPORT
   ═══════════════════════════════════════════════════════════════════ */
@media (min-width:820px){
  .wv-line{ font-size:clamp(48px,5vw,76px); }
}
