<section class="wrapper">
  <div class="bg"></div>

  <div class="edit">
    <div class="factor">
      <span>Slow mo</span>
      <button type="button" data-factor="dec">-</button>
      <span data-factor-value></span>
      <button type="button" data-factor="inc">+</button>
    </div>
  </div>

  <h1 class="name-wrapper" data-username>
  </h1>

  <form class="form" data-form>
    <div class="collapsable collapsable--label" data-collapsable>
      <label class="label" for="name">
        Enter a name to get started
      </label>
    </div>
    <input type="text" name="username" id="name" class="input collapsable collapsable--input" placeholder="Name" spellcheck="false" autocomplete="off" required data-collapsable>

    <div class="collapsable collapsable--btn" data-collapsable>
      <button type="submit" class="btn">
        Save
        <span>&#10095;</span>
      </button>
    </div>
  </form>

  <section class="circle" data-circle>
    <div>
      <svg class="circ-rotate" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
        <circle stroke="white" fill="none" cx="50" cy="50" r="49" vectorEffect="non-scaling-stroke" stroke="1" data-circ-svg />
      </svg>
      <p>Welcome aboard</p>
      <button class="btn" data-reset>Reset
        <span>&#10095;</span>
      </button>
    </div>
  </section>

  <p class="info">Change the slow mo value to control all the animation and transition speeds</p>

</section>
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap");

html,
body {
  height: 100%;
  margin: 0;
  line-height: 1.4;
}

button {
  cursor: pointer;
  border: 0;
  background: none;
  font-family: Inter, sans-serif;
}

h1,
p {
  margin-bottom: 0;
}

input {
  max-width: 100%;
  font-family: Inter, sans-serif;
}

label {
  font-family: Inter, sans-serif;
}

* {
  box-sizing: border-box;
}

body {
  background: rgb(10, 10, 10);
  font-family: Inter, sans-serif;

  --primary: #2a1cf7;
  --factor: 1;
}

.wrapper {
  position: relative;
  height: 100%;
  display: flex;
  padding: 1rem;
}

.btn {
  position: relative;
  font-size: 0.85rem;
  font-weight: 500;
  background: var(--primary);
  padding: 0.75rem 1.5rem;
  border-radius: 5rem;
  color: white;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
  letter-spacing: 0.02rem;
  transition: padding calc(0.07s * var(--factor)) ease;

  & span {
    font-size: 0.65rem;
    color: #eee;
    position: absolute;
    top: 36%;
    right: 1.5rem;
    height: fit-content;
    opacity: 0;
    transition: opacity calc(0.1s * var(--factor)) ease,
      translate calc(0.1s * var(--factor)) ease;
  }

  &:focus-visible {
    outline: none;
    padding-right: 2.25rem;

    & span {
      opacity: 1;
      translate: 4px 0;
    }
  }
}

.bg {
  position: absolute;
  width: 100%;
  height: 100%;
  inset: 0;
  background: linear-gradient(-45deg, #020024, #090979, #4b3090);
  background-size: 400% 400%;
  animation: gradientShift 15s ease infinite;
  height: 100vh;
}

@keyframes gradientShift {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

.form {
  overflow: hidden;
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  width: 500px;
  top: 60%;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  background: #fff;
  padding: 1.5rem 2rem;
  border-radius: 0.5rem;

  & .collapsable {
    transition: all calc(0.3s * var(--factor)) cubic-bezier(0.25, 1, 0.5, 1);
    overflow: hidden;
    opacity: 1;

    &.closed {
      height: 0;
      opacity: 0;
    }
  }

  & .collapsable--label {
    height: 24px;
  }

  & .collapsable--input {
    height: 37px;
  }

  & .label {
    color: #333;
    font-weight: 700;
  }

  & .input {
    max-width: 100%;
    font-size: 1rem;
    padding: 0.5rem 0.1rem;
    border: 0;
    border-bottom: 1.5px solid #777;
    background: none;

    &::placeholder {
      color: #777;
    }

    &:focus {
      outline: 0;
      border-color: var(--primary);
    }
  }

  & .collapsable--btn {
    height: 40px;
    margin: auto;
  }
}

@keyframes formMoveUp {
  0% {
    transform: scaleY(1);
    translate: 0 0;
    background: #ffffff;
  }
  100% {
    transform: scaleY(0.3);
    translate: 0 -30vh;
    background: #ffffff00;
  }
}
.form-move-up {
  animation: formMoveUp calc(0.7s * var(--factor)) calc(0.1s * var(--factor))
    cubic-bezier(0.85, 0, 0.15, 1) forwards;
}

.name-wrapper {
  position: absolute;
  top: 25%;
  left: 0;
  right: 0;
  color: #fff;
  margin: auto;
  width: fit-content;
  opacity: 0;
  translate: 0 0;
  font-size: 1.75rem;
  font-weight: 700;
  transition: all calc(var(--factor) * 0.2s) calc(var(--factor) * 0.6s) ease;

  &.visible {
    opacity: 1;
    translate: 0 -26px;
  }
}

.circle {
  overflow: hidden;
  position: absolute;
  padding: 2px;
  left: 0;
  right: 0;
  margin: auto;
  top: 45%;
  width: 280px;
  aspect-ratio: 1;
  border-radius: 50%;
  opacity: 0;
  visibility: hidden;
  transition: opacity calc(0.7s * var(--factor)) ease calc(0.6s * var(--factor));

  & div {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.85rem;
    width: 100%;
    height: 100%;
  }

  & p {
    margin-top: 1rem;
    color: #fff;
  }

  &.visible {
    visibility: visible;
    opacity: 1;
  }

  svg {
    position: absolute;
    inset: 0;
    margin: auto;
    max-width: 100%;

    circle {
      stroke-dasharray: 0 70;
    }
  }
}

@keyframes strokeReveal {
  from {
    opacity: 0;
    stroke-dasharray: 0 70;
  }
  to {
    opacity: 1;
    stroke-dasharray: 1 10;
  }
}
.stroke-reveal {
  animation: strokeReveal calc(2s * var(--factor))
    cubic-bezier(0.33, 1, 0.68, 1) calc(0.1s * var(--factor)) forwards;
}

@keyframes circRotate {
  from {
    rotate: 0deg;
  }
  to {
    rotate: -360deg;
  }
}

.circ-rotate {
  animation: circRotate calc(10s * var(--factor)) linear infinite forwards;
}

.edit {
  position: absolute;
  top: 1rem;
  left: 1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;

  & button {
    color: #fff;
    width: fit-content;
    font-size: 0.85rem;
    border-radius: 4px;
    padding: 0;
    line-height: 1.4;
  }

  .factor {
    display: flex;
    align-items: center;
    gap: 8px;

    span {
      color: #fff;
      font-size: 0.85rem;
    }

    button {
      padding: 4px 12px;
      background: #ffffff44;

      &:first-of-type {
        border-radius: 4px 0 0 4px;
      }
      &:last-of-type {
        border-radius: 0 4px 4px 0;
      }
    }
  }
}

.info {
  position: relative;
  color: #fff;
  margin-top: auto;
  text-align: center;
  width: 100%;
  font-size: 0.85rem;
}
const userName = (() => {
  let name = document.querySelector("[data-username]");

  return {
    setName: (val) => (name.innerText = `Hello ${val}`),
    toggle: () => name.classList.toggle("visible")
  };
})();

const circle = (() => {
  let el = document.querySelector("[data-circle]");
  let circSvg = document.querySelector("[data-circ-svg]");

  return {
    toggle: () => {
      el.classList.toggle("visible");
      circSvg.classList.toggle("stroke-reveal");
    }
  };
})();

const form = (() => {
  let formEl = document.querySelector("[data-form]");
  let formCollapsables = document.querySelectorAll("[data-collapsable]");

  formEl.addEventListener("submit", (event) => {
    event.preventDefault();
    let val = new FormData(event.target).get("username");

    userName.setName(val);
    toggle();
    userName.toggle();
    circle.toggle();
  });

  function toggle() {
    formEl.classList.toggle("form-move-up");
    formCollapsables.forEach((item) => {
      item.classList.toggle("closed");
    });
  }

  return {
    toggle
  };
})();

const editor = (() => {
  let factor = 1;

  let resetBtn = document.querySelectorAll("[data-reset]");
  let factorBtn = document.querySelectorAll("[data-factor]");
  let factorDisplay = document.querySelector("[data-factor-value]");

  resetBtn.forEach((btn) =>
    btn.addEventListener("click", () => {
      document.body.style.setProperty("--factor", 0);
      userName.toggle();
      form.toggle();
      circle.toggle();
      setTimeout(() => document.body.style.setProperty("--factor", factor), 10);
    })
  );

  factorBtn.forEach((btn) =>
    btn.addEventListener("click", (event) => {
      let action = event.target.getAttribute("data-factor");

      factor = Math.max(0, action === "inc" ? factor + 1 : factor - 1);

      document.body.style.setProperty("--factor", factor);
      updateDisplay();
    })
  );

  function updateDisplay() {
    factorDisplay.innerText = getComputedStyle(document.body).getPropertyValue(
      "--factor"
    );
  }

  function setFactor(val) {
    factor = val;
  }

  updateDisplay();

  return {
    setFactor
  };
})();
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.