/* BitVibe Labs — shared 3D interactive wordmark (drop-in).
   Per-letter parallax depth + pointer/touch/gyro tilt + a one-time "lit" intro
   fade. Extracted + generalized from bitvibelabs.com (site/assets/{app.js,
   styles.css}); the scroll-zoom-fade is intentionally dropped (that is
   full-hero-page specific). Pairs with wordmark-3d.js. Link AFTER the product's
   own CSS. Vendored into each product's public/brand-kit/ via sync-brand-kit.sh.

   Anti-strobe rules baked in (do NOT undo):
   • NO css transition on .bvl-wm-scene transform — the rAF loop eases it.
     A transition fights per-frame writes and strobes on fast pointer moves.
     (~/.claude/rules/no-css-transition-on-per-frame-js-property)
   • The chIn intro is gated behind the PERMANENT .lit class, never a toggled
     state class — keying it on .engaged re-fires the intro on mouse-leave.
     (~/.claude/rules/dont-retrigger-keyframe-from-toggled-class)
   • --xd (extrude depth) is quantized in JS (>0.02 step) to throttle the
     multi-layer text-shadow repaint storm.
     (~/.claude/rules/quantize-expensive-per-frame-style-writes)

   Per product: set the accent word's face colour + a darker --ext (extrusion
   side) colour, e.g.  .brand-wm .wm-accent { color: var(--primary); --ext: #0c4a36; }
*/

.bvl-wm-3d {
  font-family: var(--font-wordmark, 'Fraunces', Georgia, serif);
  font-weight: 700;
  font-variation-settings: 'SOFT' 50, 'WONK' 0;
  letter-spacing: -0.04em;
  line-height: 0.95;
  margin: 0;
  position: relative;
  display: inline-block;
  transform-style: preserve-3d;
  touch-action: none;          /* claim touch so tilt works on mobile */
  --ext: #2b2b2b;              /* default extrude-side colour (dark neutral) */
  --xd: 0;                     /* tilt magnitude 0..1 (written by rAF) */
  --depth-scale: 0;            /* eased lift 0..1 (written by rAF) */
  will-change: transform;
}

/* the rotated 3D scene — the element the rAF loop tilts (perspective is applied
   inside its transform in JS so the vanishing point is the wordmark's centre). */
.bvl-wm-3d .bvl-wm-scene {
  display: inline-block;
  transform-style: preserve-3d;
  transform: rotateX(0deg) rotateY(0deg);
  will-change: transform;
}

.bvl-wm-3d .word { display: inline-block; transform-style: preserve-3d; }

/* per-letter spans are created by wordmark-3d.js from each .word's text */
.bvl-wm-3d .ch {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 0.4em, 0);
  animation: bvlChIn 700ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) forwards;
  transform-style: preserve-3d;
  --depth: 0;
  will-change: transform;
}

/* stacked text-shadow extrude — 9 side layers + 1 ambient, all scaled by --xd
   so the wordmark is FLAT at rest and gains real thickness only as it tilts. */
.bvl-wm-3d .word,
.bvl-wm-3d .ch {
  text-shadow:
    0 calc(0.04em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.08em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.12em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.16em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.20em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.24em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.28em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.32em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.38em * var(--xd, 0)) 0 var(--ext),
    0 calc(0.46em * var(--xd, 0)) calc(0.5em * var(--xd, 0)) rgba(0, 0, 0, 0.6);
}

@keyframes bvlChIn { to { opacity: 1; transform: translate3d(0, 0, 0); } }

/* after the intro, JS adds .lit PERMANENTLY → letters rest in their JS-eased
   depth. Keyed on .lit (not a toggled state) so the intro never re-fires. */
.bvl-wm-3d.lit .ch {
  animation: none;
  opacity: 1;
  transform: translate3d(0, 0, calc(var(--depth) * 1px * var(--depth-scale, 1)));
}

@media (prefers-reduced-motion: reduce) {
  .bvl-wm-3d .ch { animation: none; opacity: 1; transform: none; }
}
