/* ==========================================================================
   Animation — reveal states, keyframes, page transition, loader
   ========================================================================== */

/* ---- Page loader ---------------------------------------------------------- */
.page-loader {
  position: fixed; inset: 0;
  z-index: 999;
  background: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity .6s var(--ease), visibility .6s var(--ease);
}
.page-loader.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }
.page-loader__mark {
  font-family: var(--font-display);
  font-size: 2rem;
  letter-spacing: 0.3em;
  color: var(--black);
  overflow: hidden;
}
.page-loader__mark span {
  display: inline-block;
  transform: translateY(110%);
  animation: loaderRise .7s var(--ease) forwards;
}
.page-loader__mark span:nth-child(1) { animation-delay: 0.05s; }
.page-loader__mark span:nth-child(2) { animation-delay: 0.10s; }
.page-loader__mark span:nth-child(3) { animation-delay: 0.15s; }
.page-loader__mark span:nth-child(4) { animation-delay: 0.20s; }
.page-loader__mark span:nth-child(5) { animation-delay: 0.25s; }
.page-loader__mark span:nth-child(6) { animation-delay: 0.30s; }
@keyframes loaderRise {
  to { transform: translateY(0); }
}

body.is-loading { overflow: hidden; }

/* ---- Hero load-in sequence (plays once, on page load — not scroll-driven) --
   Mirrors the tresmarescapital.com opening: background settles first, the
   portrait eases in with a soft scale, then the heading cascades in word by
   word, then supporting copy. Triggered by main.js adding .is-hero-loaded
   to <section class="hero"> after the page loader hides.
   ---------------------------------------------------------------------- */
.hero__bg {
  opacity: 0;
  transition: opacity 1.1s var(--ease);
}
.hero__portrait { opacity: 0; transition: opacity 1.2s var(--ease); transition-delay: 0.15s; }
.hero__portrait img {
  transform: scale(1.06) translateX(1.5rem);
  transition: transform 1.4s var(--ease-soft);
  transition-delay: 0.15s;
}
.hero.is-hero-loaded .hero__portrait img { transform: scale(1) translateX(0); }
.hero__pretitle {
  opacity: 0;
  transform: translateY(20rem);
  transition: opacity 2s var(--ease), transform 2s var(--ease);
  transition-delay: 0.3s;
}
.hero__desc {
  opacity: 0;
  transform: translateY(1.4rem);
  transition: opacity .85s var(--ease), transform .85s var(--ease);
  transition-delay: 0.95s;
}
.hero.is-hero-loaded .hero__bg { opacity: 1; }
.hero.is-hero-loaded .hero__portrait { opacity: 1; }
.hero.is-hero-loaded .hero__pretitle { opacity: 1; transform: translateY(0); }
.hero.is-hero-loaded .hero__desc { opacity: 1; transform: translateY(0); }

/* Hero title word cascade — each word rides in on its own delay (set inline
   via --d by main.js) instead of the uniform scroll-reveal timing below. */
.hero__title .split-word > span {
  transition-duration: 0.95s;
}

/* ---- Scroll fill-color text (e.g. belief statement) -----------------------
   Words start muted grey; as the paragraph travels up through the viewport
   they progressively switch to full ink color, tracking scroll position
   (not a one-shot reveal) — driven by animation.js: initScrollFillText().
   ---------------------------------------------------------------------- */
[data-fill-text] { color: transparent; } /* avoid FOUC before JS wraps words */
[data-fill-text].is-split { color: inherit; }
.fill-word {
  color: var(--grey-line);
  transition: color 0.25s linear;
}
.fill-word.is-filled { color: var(--ink); }

/* ---- Generic scroll reveal primitives ------------------------------------- */
[data-reveal] {
  opacity: 0;
  transition: opacity .9s var(--ease), transform .9s var(--ease);
  will-change: transform, opacity;
}
[data-reveal="fade-up"] { transform: translateY(4.5rem); }
[data-reveal="fade-in"] { transform: none; }
[data-reveal="fade-left"] { transform: translateX(-4rem); }
[data-reveal="fade-right"] { transform: translateX(4rem); }
[data-reveal="scale-in"] { transform: scale(0.94); }

[data-reveal].is-inview {
  opacity: 1;
  transform: none;
}

/* stagger children automatically via inline --d custom property set in JS */
[data-reveal] { transition-delay: var(--d, 0s); }

/* ---- Image reveal (mask wipe) ---------------------------------------------- */
.reveal-mask {
  position: relative;
  overflow: hidden;
}


/* ---- Split text reveal ------------------------------------------------------ */
.split-line { display: block; overflow: hidden; }
.split-line > span {
  display: inline-block;
  transform: translateY(105%);
  transition: transform .8s var(--ease); line-height: normal;
  transition-delay: var(--d, 0s);
}
.split-line.is-inview > span { transform: translateY(0); }

.split-word { display: inline-block; overflow: hidden; }
.split-word > span {
  display: inline-block;
  transform: translateY(0%);
  transition: transform .7s var(--ease);
  transition-delay: var(--d, 0s);
}
.split-word.is-inview > span { transform: translateY(0); }

/* ---- Counter animation --------------------------------------------------- */
[data-counter] { font-variant-numeric: tabular-nums; }

/* ---- Sticky section (services intro pin) ---------------------------------- */
.pillar__meta { position: sticky; top: 15rem; }



/* ---- Ping (map dots) -------------------------------------------------------- */
@keyframes ping {
  0% { transform: scale(0.6); opacity: 0.9; }
  100% { transform: scale(2.2); opacity: 0; }
}

/* ---- Custom cursor (desktop only) -----------------------------------------
   Small dot by default; grows into a ring over links/buttons; grows further
   into a filled circle with a "Scroll" label over the carousels — mirrors
   the cursor treatment on tresmarescapital.com. Disabled entirely on touch
   (see the pointer:coarse rule) and gated behind a JS-added <html> class so
   the native cursor stays put if JS fails to load.
   ---------------------------------------------------------------------- */
.cursor {
  position: fixed;
  top: 0; left: 0;
  width: 1.2rem; height: 1.2rem;
  border-radius: 50%;
  background: var(--black);
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition: width .3s var(--ease), height .3s var(--ease),
              background .3s var(--ease), border-color .3s var(--ease);
  display: none;
  align-items: center;
  justify-content: center;
}
html.has-custom-cursor .cursor { display: flex; }
html.has-custom-cursor,
html.has-custom-cursor a,
html.has-custom-cursor button,
html.has-custom-cursor .carousel__viewport,
html.has-custom-cursor .map-dot { /*cursor: none;*/ }

.cursor.is-link {
  width: 4.4rem; height: 4.4rem;
  background: transparent;
  border: 1px solid var(--black);
}
.cursor.is-link.is-on-dark { border-color: var(--white); }

.cursor.is-drag {
  width: 9rem; height: 9rem;
  background: var(--black);
}
.cursor__label {
  opacity: 0;
  font-family: var(--font-caption);
  font-size: 1.2rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--white);
  transition: opacity .2s var(--ease);
}
.cursor.is-drag .cursor__label { opacity: 1; }

@media (pointer: coarse) {
  .cursor { display: none !important; }
  html.has-custom-cursor, html.has-custom-cursor a, html.has-custom-cursor button { cursor: auto; }
}

/* ---- Button hover / magnetic ------------------------------------------------ */
.main-nav__cta,
.leadership__cta {
  transition: background .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}
.main-nav__cta:hover,
.leadership__cta:hover {
  background: var(--black);
  color: var(--white);
}

/* ---- Nav underline pre-set (defined mostly in style.css) -------------------- */

/* ---- Parallax helper --------------------------------------------------------- */
[data-parallax] { will-change: transform; }

/* ---- Statistic block subtle float on scroll --------------------------------- */
.stat-block[data-reveal-toggle] {
  opacity: 0;
  transition: opacity .6s var(--ease);
  transition-delay: calc(var(--i, 0) * 0.08s);
}
.stat-block[data-reveal-toggle] .stat-block__inner {
  transition: transform .6s var(--ease);
  transition-delay: calc(var(--i, 0) * 0.08s);
  transform: skewX(12deg) translateY(2.4rem);
}
.stat-block[data-reveal-toggle].is-inview { opacity: 1; }
.stat-block[data-reveal-toggle].is-inview .stat-block__inner { transform: skewX(12deg) translateY(0); }

/* ---- Case card entrance stagger handled via [data-reveal] + JS delay -------- */

/* ---- Cursor-follow glow for hero (mouse parallax ambient) -------------------- */
.hero__glow {
  position: absolute;
  width: 60rem; height: 60rem;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(192,0,0,0.08), transparent 70%);
  pointer-events: none;
  z-index: 1;
  will-change: transform;
}
