/* =========================================================
   life.css: living details for the v6 invitation (life coder).
   Only lf-* classes and pseudo-elements. Nothing here changes the box of an input, label or
   button: the magnetic pull uses the translate property, the press uses scale on :active,
   and the injected spans are absolutely placed. Motion sits behind html:not(.still); html.still
   shows the end state. The JS side is life.js. Plain text only in comments.
   ========================================================= */

/* 1. Buttons ------------------------------------------------
   Every .btn. Sheen: ::before swept across on hover (700 ms). Magnetic pull: life.js sets
   --lf-mx and --lf-my (max 6px, fine pointers only), applied through the translate property so
   it composes with the hover lift. Press: scale .97 and an ink ripple (life.js). */

.btn {
  overflow: hidden;
  translate: var(--lf-mx, 0px) var(--lf-my, 0px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  translate: none;
}

.btn::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; inset: 0;
  pointer-events: none;
  opacity: 0;
  transform: translateX(-120%);
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .6) 50%, transparent 60%);
}

@keyframes lf-sheen {
  from { transform: translateX(-120%); opacity: 1; }
  to   { transform: translateX(120%); opacity: 1; }
}

@media (hover: hover) {
  html:not(.still) .btn:not(:disabled):not([aria-disabled="true"]):hover::before {
    animation: lf-sheen 700ms var(--ease-out) both;
  }
}

html:not(.still) .btn:not(:disabled):not([aria-disabled="true"]):active {
  scale: .97;
}

.lf-ripple {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(28,10,13, .3), rgba(28,10,13, .12) 55%, rgba(28,10,13, 0));
}

.btn--seal .lf-ripple {
  background: radial-gradient(closest-side, rgba(255, 255, 255, .45), rgba(217, 191, 138, .14) 55%, rgba(217, 191, 138, 0));
}

/* 2. Form ---------------------------------------------------
   a. Text fields and the textarea: a gold rule draws outward from the centre on focus.
      life.js adds an absolutely placed span under each field (aria-hidden).
   b. Radios and checkboxes: a gold disc flashes over the box once on change (life.js adds
      an absolutely placed .lf-fill inside the label). It fades out, so nothing stays on top
      of the input's own look. */

.lf-field {
  position: relative;
}

.lf-under {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, #b8955a, #d9bf8a 50%, #b8955a);
  transform: scaleX(0);
  pointer-events: none;
}

@keyframes lf-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

html:not(.still) .lf-under.is-on {
  animation: lf-draw 520ms var(--ease-out) both;
}

html.still .lf-under.is-on { transform: scaleX(1); }

.lf-check {
  position: relative;
}

.lf-fill {
  position: absolute;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(184, 149, 90, .9), rgba(184, 149, 90, .4) 60%, rgba(184, 149, 90, 0));
}

html.still .lf-fill { display: none; }

/* 4. Candle -------------------------------------------------
   A warm 420 px glow that follows the pointer on desktop (life.js). It sits above the stage
   and the atmosphere canvas (z 5) and below the content (z 10). Hidden until the first
   pointermove, and in still mode. */

.lf-candle {
  position: fixed;
  left: 0;
  top: 0;
  width: 420px;
  height: 420px;
  z-index: 6;
  border-radius: 50%;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;
  background: radial-gradient(closest-side,
    rgba(243, 230, 196, 1) 0%,
    rgba(217, 191, 138, .55) 35%,
    rgba(184, 149, 90, .18) 68%,
    rgba(184, 149, 90, 0) 100%);
  transition: opacity .6s ease;
}

.lf-candle.is-on {
  opacity: .3;
}

html.still .lf-candle { display: none; }

