/* ==========================================================================
   Visual effects: loader, page-transition curtain, custom cursor, scroll
   reveals, split text, tilt, floating buttons. Every effect is progressive:
   it only activates under html.js and is switched off by html.no-fx (JS
   failed) and by prefers-reduced-motion.
   ========================================================================== */

/* -------------------------------------------------------------- 11. Loader */
.loader {
  display: none;
}

.js .loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  background: var(--color-primary);
  color: var(--color-text-light);
  transition: opacity 600ms ease, visibility 0s 600ms;
}

.loader__name {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.loader__line {
  width: 160px;
  height: 1px;
  background: rgba(200, 169, 110, 0.25);
  overflow: hidden;
}

.loader__line i {
  display: block;
  height: 100%;
  background: var(--color-secondary);
  transform: scaleX(0);
  transform-origin: left;
  animation: loader-line 1.5s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

@keyframes loader-line {
  to {
    transform: scaleX(1);
  }
}

.js .loader.is-done,
.no-fx .loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.no-loader .loader {
  display: none;
}

/* ------------------------------------------------- 2. Page transition fade */
.curtain {
  display: none;
}

.js .curtain {
  position: fixed;
  inset: 0;
  z-index: 950;
  display: block;
  background: var(--color-primary);
  opacity: 1;
  pointer-events: none;
  transition: opacity 450ms ease;
}

.is-ready .curtain,
.no-fx .curtain {
  opacity: 0;
}

.is-leaving .curtain {
  opacity: 1;
  transition-duration: 300ms;
}

/* -------------------------------------------------------- 5. Custom cursor */
.cursor {
  display: none;
}

.has-cursor .cursor {
  display: block;
}

.has-cursor,
.has-cursor a,
.has-cursor button,
.has-cursor label,
.has-cursor [role='option'],
.has-cursor .hscroll {
  cursor: none;
}

.has-cursor input:not([type='checkbox']):not([type='range']):not([type='file']),
.has-cursor textarea {
  cursor: text;
}

.cursor__dot,
.cursor__ring {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1100;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--transition-base);
}

.cursor.is-active .cursor__dot,
.cursor.is-active .cursor__ring {
  opacity: 1;
}

.cursor__dot {
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--color-secondary);
}

.cursor__ring {
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  border: 1px solid var(--color-secondary);
}

.cursor__ring::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  background: rgba(200, 169, 110, 0.14);
  transform: scale(0);
  transition: transform var(--transition-base);
}

.cursor.is-hover .cursor__ring::after {
  transform: scale(1);
}

.cursor.is-text .cursor__dot,
.cursor.is-text .cursor__ring {
  opacity: 0;
}

/* ---------------------------------------------------- 3. Scroll animations */
.js .reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}

.js .reveal.is-in {
  opacity: 1;
  transform: none;
}

.js .reveal-scale {
  transform: scale(0.97);
  transition: transform 1200ms var(--ease-out);
}

.js .reveal-scale.is-in {
  transform: none;
}

/* Split text: words slide up from behind a mask with a staggered delay. */
[data-split] .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

[data-split] .w__i {
  display: inline-block;
  transform: translateY(115%);
  transition: transform 1000ms var(--ease-out);
  transition-delay: calc(var(--i) * 45ms + var(--d, 0ms));
}

[data-split].is-in .w__i {
  transform: none;
}

.no-fx .reveal,
.no-fx .reveal-scale,
.no-fx [data-split] .w__i {
  opacity: 1;
  transform: none;
}

/* ------------------------------------------------ 1. Parallax / 4. Magnetic */
[data-parallax] {
  will-change: transform;
}

[data-magnetic] {
  transition: background-color var(--transition-base), border-color var(--transition-base), color var(--transition-base), box-shadow var(--transition-base),
    transform 500ms var(--ease-out);
}

[data-magnetic].is-pulled {
  transition-duration: 300ms, 300ms, 300ms, 300ms, 120ms;
  will-change: transform;
}

/* Floating glass CTAs in the hero. */
.btn--float {
  animation: float 5s ease-in-out infinite;
}

.btn--float-b {
  animation-delay: -2.5s;
}

.btn--float:hover,
.btn--float.is-pulled {
  animation-play-state: paused;
}

@keyframes float {
  0%, 100% {
    translate: 0 0;
  }
  50% {
    translate: 0 -6px;
  }
}

/* ---------------------------------------------------------- Service card tilt */
/* The card follows the cursor on the `rotate` property (axis-angle set by effects.js),
   which leaves `transform` free for the scroll reveal. Perspective lives on .card-grid. */
[data-tilt],
.js .reveal[data-tilt] {
  rotate: var(--tilt, 0 0 1 0deg);
  transition: rotate 500ms var(--ease-out), box-shadow 300ms ease, border-color 300ms ease, opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
  transition-delay: 0s, 0s, 0s, var(--d, 0ms), var(--d, 0ms);
}

[data-tilt].is-tilting,
.js .reveal[data-tilt].is-tilting {
  transition-duration: 80ms, 300ms, 300ms, 900ms, 900ms;
  will-change: rotate;
}

/* ------------------------------------------------------------ Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  .js .reveal,
  .js .reveal-scale,
  [data-split] .w__i {
    opacity: 1;
    transform: none;
    transition: none;
  }

  [data-tilt] {
    rotate: none !important;
  }

  [data-magnetic] {
    transform: none !important;
  }

  .js .curtain {
    transition-duration: 1ms;
  }
}

/* ---------------------------------------------------- Hero entrance (home)
   The photo opens from a framed window to full bleed while it settles from a
   slow zoom, the gold frame draws itself, then the copy rises. */
.js .hero__media {
  clip-path: inset(22% 26% 22% 26%);
  transition: clip-path 1800ms cubic-bezier(0.76, 0, 0.24, 1);
}

.js.is-ready .hero__media,
.no-fx .hero__media {
  clip-path: inset(0);
}

.js .hero__media .media__img {
  scale: 1.28;
  transition: scale 3200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.js.is-ready .hero__media .media__img,
.no-fx .hero__media .media__img {
  scale: 1;
}

.hero::after {
  content: '';
  position: absolute;
  inset: 22% 26%;
  border: 1px solid var(--color-secondary);
  pointer-events: none;
  opacity: 0;
}

.js.is-ready .hero::after {
  animation: hero-frame 1800ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}

@keyframes hero-frame {
  0% { inset: 22% 26%; opacity: 1; }
  70% { opacity: 1; }
  100% { inset: 24px; opacity: 0.35; }
}

.js .hero__shade,
.js .hero__eyebrow,
.js .hero__sub,
.js .hero__ctas,
.js .hero__scroll {
  opacity: 0;
  transition: opacity 1200ms ease 1100ms, translate 1200ms var(--ease-out) 1100ms;
}

.js .hero__eyebrow,
.js .hero__sub,
.js .hero__ctas {
  translate: 0 24px;
}

.js.is-ready .hero__shade,
.js.is-ready .hero__eyebrow,
.js.is-ready .hero__sub,
.js.is-ready .hero__ctas,
.js.is-ready .hero__scroll,
.no-fx .hero__shade,
.no-fx .hero__eyebrow,
.no-fx .hero__sub,
.no-fx .hero__ctas,
.no-fx .hero__scroll {
  opacity: 1;
  translate: 0 0;
}

.js .hero__sub { transition-delay: 1500ms; }
.js .hero__ctas { transition-delay: 1700ms; }
.js .hero [data-split] .w__i { --d: 1000ms; }

@media (prefers-reduced-motion: reduce) {
  .js .hero__media,
  .js .hero__media .media__img,
  .js .hero__shade,
  .js .hero__eyebrow,
  .js .hero__sub,
  .js .hero__ctas,
  .js .hero__scroll {
    clip-path: none;
    scale: 1;
    opacity: 1;
    translate: 0 0;
    transition: none;
  }

  .hero::after {
    display: none;
  }
}
