/*
 * Custom cursor. Paired with assets/js/figma-cursor.js, which only runs on fine
 * pointers, so the hidden native cursor below is gated the same way.
 *
 * Two states. Over the closing CTA the pointer becomes the green bubble of the
 * floating "Get in touch" button, cycling phone / mail / chat. Over the hero
 * card strip the same bubble, smaller, reads "Drag". Everywhere else it is the
 * system pointer: the 8px dot that used to follow it went at the client's
 * request, and with it the "none" state over the team stack, which only
 * existed to hide the dot.
 *
 * Two elements, on purpose. The outer one is nothing but a position: JS writes
 * a translate to it every frame and no transition may touch it. The inner one
 * owns every pixel you can see and every transition. Merged, a scale in the
 * same transform chain would multiply the translation and the bubble would
 * drift toward the top-left corner as it grew.
 *
 * .fh-cursor is display:contents so it creates no box. Anything fixed,
 * transformed or z-indexed between the page and these nodes would trap them in
 * its own stacking context.
 */

.fh-cursor { display: contents; }

.fh-cursor__pos {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  pointer-events: none;
  /* No transition, ever. The position is stepped frame by frame while the
     cursor follows the pointer, and must freeze dead the moment it is
     released so the fade-out happens exactly where the pointer left it. */
  transform: translate3d(-200px, -200px, 0);
  will-change: transform;
}

/* The bubble — the corner button's size, colour and shape (figma-footer.css,
   .sticky-g), so the two read as the same thing. The class name is older. */
.fh-cursor__ring {
  box-sizing: border-box;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: #bffe00;
  color: #000;
  position: relative;
  opacity: 0;
  /* The -50% centring rides along with the scale, so it grows and shrinks
     around the pointer instead of away from it. */
  transform: translate(-50%, -50%) scale(0.4);
  transition: opacity 0.18s ease-out,
              transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: opacity, transform;
}

/* pointer left the window */
.fh-cursor.is-out .fh-cursor__ring { opacity: 0; }

/* The closing section is an invitation, so the cursor carries the ways to take
   it up and cycles between them. */
.fh-cursor[data-cursor-state="contact"] .fh-cursor__ring {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Over the hero strip the bubble says the strip can be slid sideways. The
   contact bubble's size, and the corner button's: every green circle on the
   site is one 120px circle. A press squeezes it. */
.fh-cursor[data-cursor-state="drag"] .fh-cursor__ring {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
.fh-cursor[data-cursor-state="drag"].is-pressed .fh-cursor__ring {
  transform: translate(-50%, -50%) scale(0.88);
}

/* 15px, the secondary-label size, at the bubble's full scale. Keyed on
   data-cursor-kind, which outlives the state, so the label fades out with the
   bubble. */
.fh-cursor__drag {
  position: absolute;
  top: 50%;
  left: 50%;
  display: none;
  align-items: center;
  gap: 6px;
  transform: translate(-50%, -50%);
  font: 400 15px/1 Arial, Helvetica, sans-serif;
  letter-spacing: -0.3px;
  white-space: nowrap;
}
.fh-cursor__drag svg { width: 10px; height: 10px; flex: none; }
.fh-cursor__drag svg * { vector-effect: non-scaling-stroke; }
.fh-cursor[data-cursor-kind="drag"] .fh-cursor__drag { display: flex; }

/* display, not opacity: the icons cut from one to the next with no crossfade,
   which is the point — a fade at this rate reads as a blur, a cut reads as
   three ways of getting in touch. Absolutely placed so nothing reflows. */
.fh-cursor__icon {
  position: absolute;
  top: 50%;
  left: 50%;
  display: none;
  /* Drawn on a 20-unit grid, shown at 32: the size lives here so there is one
     number to change, and non-scaling-stroke below keeps the line where the
     icons were designed rather than letting the box fatten it to 2.24px. */
  width: 32px;
  height: 32px;
  transform: translate(-50%, -50%);
}
/* Not an inherited property, so it has to be set on the shapes themselves. */
.fh-cursor__icon * { vector-effect: non-scaling-stroke; }
.fh-cursor[data-cursor-state="contact"][data-cursor-icon="0"] .fh-cursor__icon--phone,
.fh-cursor[data-cursor-state="contact"][data-cursor-icon="1"] .fh-cursor__icon--mail,
.fh-cursor[data-cursor-state="contact"][data-cursor-icon="2"] .fh-cursor__icon--chat {
  display: block;
}

/* Only while the bubble is showing, and only once the script has made one: if
   it never runs — reduced motion, a coarse pointer, a JS error — the native
   cursor stays everywhere. */
@media (hover: hover) and (pointer: fine) {
  .fh-cursor-ready.fh-cursor-contact .fh-cta,
  .fh-cursor-ready.fh-cursor-contact .fh-cta *,
  .fh-cursor-ready.fh-cursor-drag .fh-marquee--cards,
  .fh-cursor-ready.fh-cursor-drag .fh-marquee--cards * { cursor: none; }
}

@media (prefers-reduced-motion: reduce) { .fh-cursor { display: none; } }
@media (hover: none), (pointer: coarse) { .fh-cursor { display: none; } }
