/* Shared "light & speed" effects for marketing pages (landing hero, signup).
   Pointer-driven vars (--mx/--my/--px/--py) come from spotlight_controller.js. */

.fx-blob { position: absolute; width: 60%; height: 80%; border-radius: 50%; filter: blur(80px); opacity: .22; animation: fx-drift 14s ease-in-out infinite alternate; }
.fx-blob-green { background: #22c55e; left: -10%; top: -20%; }
.fx-blob-purple { background: #a855f7; right: -10%; bottom: -30%; animation-delay: -7s; }
.fx-grain {
  opacity: .45;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .12 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.fx-fade {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
  mask-composite: intersect;
}
.fx-spot { background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 40%), rgb(0 0 0 / .05), transparent 70%); }
.fx-rise { animation: fx-rise .7s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d, 0ms); }
.fx-streak { animation: fx-streak var(--t, 2.6s) cubic-bezier(.7, 0, .3, 1) infinite; animation-delay: var(--d, 0ms); }
.fx-shine {
  background: linear-gradient(100deg, #000 40%, #9ca3af 50%, #000 60%) 0 0 / 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: fx-shine 4s ease-in-out 1s infinite;
}
.fx-float {
  transform: translate(calc(var(--px, 0) * var(--k)), calc(var(--py, 0) * var(--k)));
  transition: transform .4s cubic-bezier(.2, .8, .2, 1);
}

@keyframes fx-drift { to { transform: translate(18%, 12%) scale(1.15); } }
@keyframes fx-rise { from { opacity: 0; transform: translateY(14px); filter: blur(6px); } }
@keyframes fx-streak { from { transform: translateX(-100%); } to { transform: translateX(400%); } }
@keyframes fx-shine { 0%, 60% { background-position: 100% 0; } 100% { background-position: -50% 0; } }

/* Signup: the form reacts as it fills in. Step 1 ("create account") lights up
   once every field is valid, and the submit button wakes up. */
.signup .fx-step-1 { transition: background-color .2s, color .2s, box-shadow .2s; }
.signup:has(.signup-form:valid) .fx-step-1 { background: #000; color: #fff; box-shadow: 0 0 0 4px rgb(34 197 94 / .25); }
.signup-form [type=submit] { transition: transform .15s, box-shadow .2s, background-color .15s; }
.signup-form:valid [type=submit] { box-shadow: 0 12px 28px -10px rgb(0 0 0 / .6); }
.signup-form:valid [type=submit]:hover { transform: translateY(-2px); }
.signup-form [type=submit]:active { transform: translateY(0); }
.signup input { transition: box-shadow .2s, border-color .15s; }

/* Connection code box lights up once a valid code is pasted (connection_code_controller
   un-hides the "valid" hint). Slack codes go green, Teams codes (nat1.) purple. */
[data-controller~="connection-code"]:has([data-connection-code-target="valid"]:not(.hidden)) [data-connection-code-target="input"] {
  border-color: #22c55e; box-shadow: 0 0 0 4px rgb(34 197 94 / .15);
}
[data-connection-code-prefix-value="nat1."]:has([data-connection-code-target="valid"]:not(.hidden)) [data-connection-code-target="input"] {
  border-color: #a855f7; box-shadow: 0 0 0 4px rgb(168 85 247 / .15);
}
[data-connection-code-target="input"] { transition: border-color .2s, box-shadow .2s; }

/* Post-checkout celebration (billing/_success): check draws, confetti bursts,
   then the setup steps tick off one by one. */
.celebrate[hidden] { display: none; }
.celebrate { animation: celebrate-fade .3s ease-out both; }
.celebrate-check circle { stroke-dasharray: 151; stroke-dashoffset: 151; animation: celebrate-draw .5s ease-out .1s forwards; }
.celebrate-check path { stroke-dasharray: 36; stroke-dashoffset: 36; animation: celebrate-draw .3s ease-out .5s forwards; }
.celebrate-burst span {
  position: absolute; left: 50%; top: 50%; width: 8px; height: 8px; margin: -4px; border-radius: 50%; opacity: 0;
  animation: celebrate-burst .9s cubic-bezier(.1, .8, .3, 1) .55s both;
}
.celebrate-rise { animation: fx-rise .6s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d); }
.celebrate-step { animation: fx-rise .5s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d); }
.celebrate-step span { animation: celebrate-tick .3s ease-out forwards; animation-delay: calc(var(--d) + .45s); }
@keyframes celebrate-fade { from { opacity: 0; } }
@keyframes celebrate-draw { to { stroke-dashoffset: 0; } }
@keyframes celebrate-burst {
  0% { opacity: 1; transform: rotate(var(--a)) translateY(0) scale(1); }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(var(--r) * -1)) scale(.4); }
}
@keyframes celebrate-tick { 50% { transform: scale(1.3); } to { background: #22c55e; border-color: #22c55e; } }

@media (prefers-reduced-motion: reduce) {
  .fx-rise, .fx-shine, .fx-blob, .celebrate-rise, .celebrate-step { animation: none; }
  .celebrate-check circle, .celebrate-check path { animation: none; stroke-dashoffset: 0; }
  .celebrate-step span { animation: none; background: #22c55e; border-color: #22c55e; }
  .fx-streak, .celebrate-burst { display: none; }
  .fx-float { transition: none; }
}
