/* =============================================================
 * tc-animations.css
 *  Pure animation layer extracted from the index-v2 refinement.
 *  Drop-in: load AFTER your existing stylesheets.
 *  No tokens required — uses local easing/duration variables.
 *  No external dependencies.
 *
 *  Hooks (add to markup):
 *    [data-tcv2-words]         → word-by-word reveal on enter
 *    .tcv2-fade  .is-d1..is-d4 → fade-up + delay slot
 *    .tcv2-rule                → 1px rule that draws across on enter
 *    .tcv2-stat [data-pct]     → animated ring + count-up + bar
 *    .tcv2-hero / .tc-hero-media → subtle scroll parallax on video
 *    header.tc-nav             → adds .tcv2-scrolled past 32px scroll
 *    .tcv2-process / .tcv2-pstep / .tcv2-process-visual img[data-step]
 *                              → sticky-scroll step tracker
 * ============================================================= */

:root {
  --tcv2-ease:      cubic-bezier(0.2, 0.8, 0.2, 1);
  --tcv2-ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ============ WORD-BY-WORD REVEAL ============ */
.tcv2-words .tcv2-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
}
.tcv2-words .tcv2-word > span {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
  transition: transform 900ms var(--tcv2-ease), opacity 700ms var(--tcv2-ease);
  will-change: transform, opacity;
}
.tcv2-words.is-in .tcv2-word > span {
  transform: translateY(0);
  opacity: 1;
}
.tcv2-words.is-in .tcv2-word:nth-child(2)  > span { transition-delay:  60ms; }
.tcv2-words.is-in .tcv2-word:nth-child(3)  > span { transition-delay: 120ms; }
.tcv2-words.is-in .tcv2-word:nth-child(4)  > span { transition-delay: 180ms; }
.tcv2-words.is-in .tcv2-word:nth-child(5)  > span { transition-delay: 240ms; }
.tcv2-words.is-in .tcv2-word:nth-child(6)  > span { transition-delay: 300ms; }
.tcv2-words.is-in .tcv2-word:nth-child(7)  > span { transition-delay: 360ms; }
.tcv2-words.is-in .tcv2-word:nth-child(8)  > span { transition-delay: 420ms; }
.tcv2-words.is-in .tcv2-word:nth-child(9)  > span { transition-delay: 480ms; }
.tcv2-words.is-in .tcv2-word:nth-child(n+10) > span { transition-delay: 540ms; }

/* ============ FADE-UP (paragraphs, ctas, supporting blocks) ============ */
.tcv2-fade {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity   800ms var(--tcv2-ease) 200ms,
    transform 800ms var(--tcv2-ease) 200ms;
}
.tcv2-fade.is-in { opacity: 1; transform: none; }
.tcv2-fade.is-d0 { transition-delay:   0ms; }
.tcv2-fade.is-d1 { transition-delay: 120ms; }
.tcv2-fade.is-d2 { transition-delay: 240ms; }
.tcv2-fade.is-d3 { transition-delay: 360ms; }
.tcv2-fade.is-d4 { transition-delay: 480ms; }

/* ============ RULE: 1px line that draws on enter ============ */
.tcv2-rule {
  height: 1px;
  background: currentColor;
  opacity: 0.18;
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 1200ms var(--tcv2-ease);
}
.tcv2-rule.is-in { transform: scaleX(1); }

/* ============ NAV SCROLLED STATE ============ */
header.tc-nav {
  transition:
    background   320ms var(--tcv2-ease),
    border-color 320ms var(--tcv2-ease);
}
/* Project-specific colors live in your nav stylesheet; this just toggles
   a class — style .tcv2-scrolled however you prefer. Example: */
header.tc-nav.tcv2-scrolled {
  /* e.g. solid background + subtle border on scroll */
}

/* ============ HERO VIDEO / IMAGE PARALLAX ============ */
.tcv2-hero .tc-hero-media video,
.tcv2-hero .tc-hero-media img {
  will-change: transform;
}

/* ============ PULSING LOCATION DOT (optional decorative) ============ */
@keyframes tcv2-pulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(106, 111, 76, 0.28); }
  50%      { box-shadow: 0 0 0 7px rgba(106, 111, 76, 0.08); }
}
.tcv2-hero-marker-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #6A6F4C;
  animation: tcv2-pulse 2.4s ease-in-out infinite;
}

/* ============ SCROLL CUE (drop animation) ============ */
@keyframes tcv2-cue-drop {
  0%   { transform: translateY(0);   opacity: 0;   }
  50%  {                              opacity: 1;  }
  100% { transform: translateY(32px); opacity: 0;  }
}
.tcv2-hero-cue-line {
  display: inline-block;
  width: 1px;
  height: 28px;
  background: linear-gradient(180deg, transparent, currentColor);
  position: relative;
  overflow: hidden;
}
.tcv2-hero-cue-line::after {
  content: '';
  position: absolute;
  top: -10px;
  left: 0;
  width: 100%;
  height: 16px;
  background: linear-gradient(180deg, transparent, currentColor);
  animation: tcv2-cue-drop 2.2s ease-in-out infinite;
}

/* ============ STATS — RING + BAR + COUNT-UP ============ */
.tcv2-stat-ring svg {
  width: 100%; height: 100%;
  transform: rotate(-90deg);
}
.tcv2-stat-ring .tcv2-ring-bg {
  fill: none;
  stroke: rgba(0, 0, 0, 0.12);   /* override per theme */
  stroke-width: 4;
}
.tcv2-stat-ring .tcv2-ring-fg {
  fill: none;
  stroke: currentColor;          /* set color on the parent */
  stroke-width: 4;
  stroke-linecap: round;
  /* JS sets stroke-dasharray + initial stroke-dashoffset, then transitions */
}

.tcv2-stat-bar {
  position: relative;
  height: 2px;
  background: rgba(0, 0, 0, 0.08);
  border-radius: 999px;
  overflow: hidden;
}
.tcv2-stat-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: currentColor;
  border-radius: 999px;
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 1800ms var(--tcv2-ease) 200ms;
}
.tcv2-stat.is-in .tcv2-stat-bar-fill {
  transform: scaleX(var(--fill-pct, 0.6));
}

/* ============ STICKY PROCESS — visual transitions ============ */
.tcv2-process-visual img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.04);
  transition:
    opacity   900ms var(--tcv2-ease),
    transform 1600ms var(--tcv2-ease);
}
.tcv2-process-visual img.is-active {
  opacity: 1;
  transform: scale(1);
}
.tcv2-pstep {
  transition: opacity 700ms var(--tcv2-ease);
  opacity: 0.42;
}
.tcv2-pstep.is-active { opacity: 1; }

.tcv2-pstep-num::before {
  /* small marker dot — see Process step markup */
  transition:
    opacity   480ms var(--tcv2-ease),
    transform 480ms var(--tcv2-ease);
}
.tcv2-pstep.is-active .tcv2-pstep-num::before {
  opacity: 1;
  transform: scale(1.3);
}

.tcv2-process-bar-fill {
  transition: width 700ms var(--tcv2-ease);
}

/* ============ QUICK IMAGE FADE-IN (safety net) ============ */
/* Short, subtle fade — invisible on cached images, smooth on cold ones. */
img.tcv2-img-pending {
  opacity: 0;
}
img.tcv2-img-ready {
  opacity: 1;
  transition: opacity 500ms var(--tcv2-ease);
}

/* ============ REDUCED MOTION RESPECT ============ */
@media (prefers-reduced-motion: reduce) {
  .tcv2-words .tcv2-word > span,
  .tcv2-fade,
  .tcv2-rule,
  .tcv2-stat-bar-fill,
  .tcv2-process-visual img,
  .tcv2-pstep {
    transition: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
  img.tcv2-img-pending { opacity: 1 !important; }
  .tcv2-hero-marker-dot,
  .tcv2-hero-cue-line::after {
    animation: none !important;
  }
}

/* ============ PAGE TRANSITION — branded loading curtain ============ */
/* Injected + toggled by tc-animations.js. Echoes the first-visit intro splash:
   dark radial field, big logo with a warm gold bloom, gently breathing. */

/* ---- Cross-document View Transitions (progressive enhancement) ---- */
/* Chrome-based browsers only today. The `@view-transition` at-rule is an unknown
   at-rule elsewhere (Safari/Firefox) and is silently dropped, so those browsers
   simply keep the JS curtain + pre-cover path below — nothing to detect, no JS.
   Where supported, the browser holds the old page's pixels and cross-fades to the
   new page. Because BOTH pages carry the same opaque branded curtain at swap time
   (outgoing curtain ↔ incoming pre-cover/curtain), this cross-fade blends two
   near-identical curtains: the mark appears to sit perfectly still across the
   document swap — no blink, and it smooths any breathing-phase difference too. */
@view-transition {
  navigation: auto;
}
/* Retime the default root cross-fade: short enough to feel instant, long enough
   to dissolve any sub-pixel difference between the outgoing and incoming curtain. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 320ms;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;   /* instant cut — matches the JS reduced-motion path */
  }
}

/* Pre-cover: set synchronously by an inline <head> script BEFORE first paint
   when we arrive via a transition, so the incoming page never flashes its own
   content before the JS curtain (with logo) takes over on top. Carries the SAME
   field AND the SAME centered logo as the JS curtain, so the mark is on-screen
   from the very first painted frame — no blink between documents. The logo is
   nudged ~22px above center to line up with where the curtain (logo + wordmark
   stack) places it. Removed by the JS once the real curtain is mounted. */
html.tc-arriving { background: #1E211E; }
html.tc-arriving::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 2147483646;
  pointer-events: none;
  background:
    url("../images/TrueCellLogoJune-light.svg") center calc(50% - 22px) / 160px 160px no-repeat,
    radial-gradient(120% 120% at 50% 38%, #2A2F2A 0%, #1E211E 58%, #141613 100%);
}

.tc-pagefade {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(120% 120% at 50% 38%, #2A2F2A 0%, #1E211E 58%, #141613 100%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.66s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.66s;
}
.tc-pagefade.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.58s cubic-bezier(0.33, 0, 0.2, 1), visibility 0s;
}
.tc-pagefade-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6rem;
}
.tc-pagefade-logo-wrap {
  position: relative;
  display: grid;
  place-items: center;
}
.tc-pagefade-glow {
  position: absolute;
  width: 380px;
  height: 380px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(224, 164, 55, 0.18) 0%, rgba(224, 164, 55, 0) 66%);
  filter: blur(8px);
  animation: tcPageGlow 3.4s ease-in-out infinite;
  will-change: opacity, transform;
}
.tc-pagefade-logo {
  position: relative;
  width: 160px;
  height: 160px;
  animation: tcPageLogo 3.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  will-change: opacity, transform;
  backface-visibility: hidden;      /* promote to its own layer → no sub-pixel jitter */
  transform: translateZ(0);
}
.tc-pagefade-word {
  font-family: var(--sans, 'Poppins', system-ui, sans-serif);
  font-size: 1.2rem;
  font-weight: 300;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--bone-50, #EDE1D2);
  line-height: 1;
  opacity: 0.9;
}
/* Breath is centred on the RESTING state (full opacity, full scale) so it lines
   up with the static pre-cover logo — the live curtain mounts with no pop, then
   drifts gently. Small amplitude + slow, symmetric easing keeps it calm. */
@keyframes tcPageLogo {
  0%, 100% { opacity: 1;    transform: scale(1); }
  50%      { opacity: 0.9;  transform: scale(0.985); }
}
@keyframes tcPageGlow {
  0%, 100% { opacity: 0.62; transform: scale(0.96); }
  50%      { opacity: 1;    transform: scale(1.04); }
}

/* ---- Higher-fidelity splash: depth, grain, organic bloom ---- */
/* A larger, softer ambient bloom sitting behind the mark for depth.
   Slower and out of phase with the inner glow so the light feels alive. */
.tc-pagefade-logo-wrap::before {
  content: "";
  position: absolute;
  width: 620px;
  height: 620px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(224, 164, 55, 0.10) 0%, rgba(224, 164, 55, 0) 70%);
  filter: blur(26px);
  pointer-events: none;
  animation: tcPageAmbient 5.2s ease-in-out infinite;
  will-change: opacity, transform;
}
/* A warm light-sweep that travels across the mark itself — masked to the exact
   logo silhouette so it reads as light catching the object, not a ring orbiting
   it. Sits on top of the mark via screen blend. */
.tc-pagefade-logo-wrap::after {
  content: "";
  position: absolute;
  width: 160px;
  height: 160px;
  -webkit-mask: url("../images/TrueCellLogoJune-light.svg") center / contain no-repeat;
          mask: url("../images/TrueCellLogoJune-light.svg") center / contain no-repeat;
  background: linear-gradient(115deg,
    rgba(255, 241, 210, 0) 40%,
    rgba(255, 241, 210, 0.9) 50%,
    rgba(255, 241, 210, 0) 60%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  mix-blend-mode: screen;
  pointer-events: none;
  opacity: 0;
  animation: tcPageSheen 3s ease-in-out infinite;
  will-change: background-position, opacity;
}
/* Fine film grain over the whole field — reads as texture, not noise. */
.tc-pagefade::before {
  content: "";
  position: absolute;
  inset: -20%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  opacity: 0.05;
  mix-blend-mode: soft-light;
  pointer-events: none;
  animation: tcGrain 3.2s steps(4) infinite;
}
/* Soft vignette to seat the mark and deepen the field. */
.tc-pagefade::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 120% at 50% 42%, rgba(0, 0, 0, 0) 52%, rgba(0, 0, 0, 0.28) 100%);
  pointer-events: none;
}
/* Wordmark tracks in once as the curtain settles. */
.tc-pagefade-word {
  animation: tcWordIn 1.15s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes tcPageAmbient {
  0%, 100% { opacity: 0.4; transform: scale(0.94); }
  50%      { opacity: 0.9; transform: scale(1.06); }
}
@keyframes tcGrain {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-4%, 2%); }
  50%  { transform: translate(3%, -3%); }
  75%  { transform: translate(-2%, 4%); }
  100% { transform: translate(0, 0); }
}
@keyframes tcWordIn {
  from { opacity: 0; letter-spacing: 0.12em; transform: translateY(4px); }
  to   { opacity: 0.9; letter-spacing: 0.24em; transform: none; }
}
@keyframes tcPageSheen {
  0%   { background-position: 150% 0; opacity: 0; }
  30%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { background-position: -50% 0; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tc-pagefade,
  .tc-pagefade.is-active { transition: opacity 0.01s linear !important; }
  .tc-pagefade-logo,
  .tc-pagefade-glow,
  .tc-pagefade-logo-wrap::before,
  .tc-pagefade-logo-wrap::after,
  .tc-pagefade::before,
  .tc-pagefade-word { animation: none !important; }
}

/* ============ SCROLL PROGRESS — gold line under the sticky header ============ */
/* Injected into .tc-nav by tc-animations.js; width tracks scroll progress. */
.tc-scrollbar {
  position: absolute;
  left: 0;
  bottom: -1px;              /* sit over the header's 1px bottom border */
  width: 100%;
  height: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--gold, #d9a441), var(--gold-strong, #c8912f));
  box-shadow: 0 0 10px rgba(217, 164, 65, 0.45);
  z-index: 3;
  pointer-events: none;
  will-change: transform;
}
