Curbside Dark Logo

Curbside

Curbside Dark Logo

Curbside

/* ========== PAGE TRANSITION ========== */
.w-page-transition {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: -9999;
}

/* --- Dark layer --- */
.w-page-transition-dark {
  position: absolute;
  height: 100vh;
  inset: 0;
  background: var(--bg-dark, #000);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  opacity: 0;
  transition: opacity 0.8s cubic-bezier(0.77, 0, 0.175, 1);
   z-index: 1;
}

.w-page-transition-dark.active {
  opacity: 1;
}

/* --- Dark - Logo wrapper --- */
.w-page-transition-dark__logo-wrapper {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) translateY(50%);
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 20px;
  opacity: 0;
  transition: transform 0.8s ease, opacity 0.8s ease;
  z-index: 2;
}

.w-page-transition-dark__logo-wrapper.active {
  transform: translate(-50%, -50%) translateY(0);
  opacity: 1;
}

.w-page-transition-dark__text {
  color: var(--text-title-contrast, #fff);
  font-size: clamp(32px, 4vw, 100px);
}

.w-page-transition-dark__favicon {
  opacity: 0;
  width: 80px;
  height: 80px;
}

/* --- Light layer --- */
.w-page-transition-light {
  position: absolute;
  height: 100vh;
  inset: 0;
  background: var(--bg-body, #fff);
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(100%);
  transition: transform 1s cubic-bezier(0.77, 0, 0.175, 1);
  z-index: 3;
}

.w-page-transition-light.active {
  transform: translateY(0);
}

/* --- Light - Logo wrapper --- */
.w-page-transition-light__logo-wrapper {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) translateY(0);
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 20px;
  opacity: 0;
  transition: opacity 0.6s ease 0.3s, transform 0.6s ease 0.3s;
  z-index: 4;
}

.w-page-transition-light__logo-wrapper.active {
  opacity: 1;
  transform: translate(-50%, -50%) translateY(0);
}

.w-page-transition-light__text {
  color: var(--text-title, #000);
  font-size: clamp(32px, 4vw, 100px);
}

.w-page-transition-light__favicon {
  width: 80px;
  height: 80px;
  opacity: 0;
  transform: scale(0) rotate(-90deg);
  transition: all 0.6s ease 0.3s;
}

.w-page-transition-light__favicon.appear {
  opacity: 1;
  transform: scale(1) rotate(0);
}


document.addEventListener("DOMContentLoaded", () => {
  const dark = document.querySelector(".w-page-transition-dark");
  const darkWrapper = document.querySelector(".w-page-transition-dark__logo-wrapper");
  const light = document.querySelector(".w-page-transition-light");
  const lightWrapper = document.querySelector(".w-page-transition-light__logo-wrapper");
  const favicon = document.querySelector(".w-page-transition-light__favicon");
  const pageTransition = document.querySelector(".w-page-transition");

  if (!dark || !light || !pageTransition) return;

  /** Helper delay */
  function wait(ms) {
    return new Promise((res) => setTimeout(res, ms));
  }

  /** PAGE LEAVE (trước khi chuyển trang) **/
  function startLeave() {
    pageTransition.style.zIndex = "9999";
    dark.classList.add("active");
  }

  /** PAGE ENTER (hiệu ứng khi vào trang) **/
  async function startEnter() {
    // Luôn đảm bảo z-index cao khi bắt đầu
    pageTransition.style.zIndex = "9999";

    // Step 1: Dark layer fade in
    dark.classList.add("active");
    await wait(600);

    // Step 2: Logo/text dark xuất hiện
    darkWrapper.classList.add("active");
    await wait(800);

    // Step 3: Light layer trượt lên
    light.classList.add("active");
    lightWrapper.classList.add("active");
    await wait(1000);

    // Step 4: Logo favicon hiện ra
    favicon.classList.add("appear");
    await wait(1200);

    // Step 5: Toàn bộ transition fade out nhanh
    pageTransition.style.transition = "opacity 0.6s ease";
    pageTransition.style.opacity = "0";
    await wait(1200);

    // Step 6: Reset trạng thái cho lần sau
    dark.classList.remove("active");
    darkWrapper.classList.remove("active");
    light.classList.remove("active");
    lightWrapper.classList.remove("active");
    favicon.classList.remove("appear");

    // Reset style sau khi đã ẩn hẳn
    pageTransition.style.opacity = "";
    pageTransition.style.transition = "";

    // Đưa z-index xuống thấp để không che nội dung
    pageTransition.style.zIndex = "-9999";
  }

  /** Run on initial load **/
  startEnter();

  /** Trigger transition khi click link **/
  document.querySelectorAll("a[href]").forEach((link) => {
    link.addEventListener("click", (e) => {
      const url = link.href;
      if (
        url.includes("#") ||
        url.startsWith("mailto:") ||
        url.startsWith("tel:") ||
        link.target === "_blank"
      )
        return;

      e.preventDefault();
      startLeave();
      setTimeout(() => {
        window.location.href = url;
      }, 600);
    });
  });
});

Norikase

Category: Bar, Restaurant

An intimate omakase and bar experience where culinary mastery meets Japanese elegance and modern luxury.

Whispers of Japan
Precision in Every Frame

Brief.

A visual exploration of refined craftsmanship, celebrating the artistry of omakase dining and the serene sophistication of Japanese mixology.

Challenge.

Translating the quiet intensity of the chef’s craft and the intimacy of the space into imagery that feels both exclusive and emotionally immersive.

Stillness, Light & Craft

Through cinematic lighting, close-up textures, and atmospheric social storytelling, the project captures the essence of precision, luxury, and the meditative rhythm of fine Japanese dining.

Watch the film.