/*
 * er-wow.css
 *
 * Phase 2 wow-tier renderer styles. Single CSS file for the new
 * 2026-stunning element pack so we only add ONE entry to
 * CSS_ALWAYS_LOADED instead of 12.
 *
 * Naming convention: every element root is .el-<name>; nested parts use
 * BEM (.el-<name>__part). Every animation honors prefers-reduced-motion
 * via a single tail block at the bottom of the file.
 *
 * Token usage: defaults use --site-* tokens with sane fallbacks so a
 * tenant who hasn't set a token still gets a reasonable look.
 */

/* ───────────────────────── Magnetic link / button ───────────────────────── */

.el-magnetic-link {
  /* Transform written by useMagnetic via inline style; the transition
     here applies only when the element snaps back to rest (transform="" ). */
  transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ───────────────────────── Mesh gradient ───────────────────────── */

.el-mesh-gradient {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--site-bg, transparent);
}

.el-mesh-gradient__layer {
  position: absolute;
  inset: -20%;
  pointer-events: none;
  z-index: 0;
  filter: blur(80px) saturate(1.1);
  opacity: var(--mesh-intensity, 0.85);
  will-change: transform;
}

.el-mesh-gradient__layer--a {
  background: radial-gradient(circle at 30% 30%, var(--mesh-c1, transparent) 0%, transparent 55%);
  animation: el-mesh-drift-a var(--mesh-speed, 18s) ease-in-out infinite alternate;
}

.el-mesh-gradient__layer--b {
  background: radial-gradient(circle at 70% 60%, var(--mesh-c2, transparent) 0%, transparent 55%);
  animation: el-mesh-drift-b calc(var(--mesh-speed, 18s) * 1.4) ease-in-out infinite alternate;
}

.el-mesh-gradient__layer--c {
  background: radial-gradient(circle at 50% 80%, var(--mesh-c3, transparent) 0%, transparent 50%);
  animation: el-mesh-drift-c calc(var(--mesh-speed, 18s) * 0.85) ease-in-out infinite alternate;
}

.el-mesh-gradient__content {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: clamp(24px, 6vw, 80px);
}

@keyframes el-mesh-drift-a {
  from { transform: translate3d(-8%, -6%, 0) scale(1); }
  to   { transform: translate3d(12%, 8%, 0) scale(1.15); }
}

@keyframes el-mesh-drift-b {
  from { transform: translate3d(10%, 6%, 0) scale(1.1); }
  to   { transform: translate3d(-6%, -10%, 0) scale(0.95); }
}

@keyframes el-mesh-drift-c {
  from { transform: translate3d(0, 12%, 0) scale(0.9); }
  to   { transform: translate3d(8%, -6%, 0) scale(1.2); }
}

/* ───────────────────────── Infinite logo strip ───────────────────────── */

.el-logo-strip {
  position: relative;
  width: 100%;
  overflow: hidden;
  /* Edge mask so the marquee fades out gracefully at the gutters. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
}

.el-logo-strip--empty {
  padding: 24px;
  text-align: center;
  border: 1px dashed var(--site-border-muted, transparent);
  border-radius: 12px;
}

.el-logo-strip__hint {
  margin: 0;
  font-size: 13px;
  color: var(--site-text-muted, currentColor);
}

.el-logo-strip__track {
  display: flex;
  align-items: center;
  gap: var(--logo-gap, 64px);
  width: max-content;
  animation: el-logo-strip-loop var(--logo-speed, 32s) linear infinite;
  will-change: transform;
}

.el-logo-strip[data-direction="reverse"] .el-logo-strip__track {
  animation-direction: reverse;
}

.el-logo-strip--pause-on-hover:hover .el-logo-strip__track {
  animation-play-state: paused;
}

.el-logo-strip__item {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--logo-h, 40px);
  text-decoration: none;
  color: inherit;
}

.el-logo-strip__item img {
  display: block;
  height: 100%;
  width: auto;
  max-width: 200px;
  object-fit: contain;
  transition: opacity 200ms ease, filter 200ms ease;
}

.el-logo-strip--grayscale .el-logo-strip__item img {
  filter: grayscale(100%);
  opacity: 0.7;
}

.el-logo-strip--grayscale .el-logo-strip__item:hover img {
  filter: grayscale(0%);
  opacity: 1;
}

.el-logo-strip__placeholder {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--site-text-muted, currentColor);
}

@keyframes el-logo-strip-loop {
  /* Each item is duplicated; -50% lands the second copy exactly where the
     first started, so the loop is seamless. */
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* ───────────────────────── Flip card ───────────────────────── */

.el-flip-card {
  perspective: 1200px;
  width: 100%;
  height: 100%;
  cursor: default;
}

.el-flip-card--click {
  cursor: pointer;
}

.el-flip-card__inner {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: inherit;
  transition: transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transform-style: preserve-3d;
}

.el-flip-card--axis-y.el-flip-card--hover:hover .el-flip-card__inner,
.el-flip-card--axis-y.is-flipped .el-flip-card__inner {
  transform: rotateY(180deg);
}

.el-flip-card--axis-x.el-flip-card--hover:hover .el-flip-card__inner,
.el-flip-card--axis-x.is-flipped .el-flip-card__inner {
  transform: rotateX(180deg);
}

.el-flip-card__face {
  position: absolute;
  inset: 0;
  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
  display: flex;
  flex-direction: column;
  background: var(--site-card-bg, var(--site-surface, transparent));
  color: var(--site-card-text, var(--site-fg, inherit));
  border-radius: var(--site-card-radius, 12px);
  padding: 24px;
  overflow: hidden;
  box-shadow: var(--site-shadow-md, 0 6px 24px rgba(0, 0, 0, 0.08));
}

.el-flip-card--axis-y .el-flip-card__face--back {
  transform: rotateY(180deg);
}

.el-flip-card--axis-x .el-flip-card__face--back {
  transform: rotateX(180deg);
}

.el-flip-card:focus-visible {
  outline: 2px solid var(--site-accent, transparent);
  outline-offset: 4px;
  border-radius: var(--site-card-radius, 12px);
}

/* ───────────────────────── Bento grid ───────────────────────── */

.el-bento-grid {
  display: grid;
  gap: var(--bento-gap, 16px);
  width: 100%;
}

.el-bento-grid--feature-3x3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: minmax(var(--bento-min-h, 180px), 1fr);
}

/* First child in feature-3x3 spans 2 columns (the hero cell). */
.el-bento-grid--feature-3x3 > .el-bento-grid__cell:first-child,
.el-bento-grid--feature-3x3 > .el-bento-grid__cell--a {
  grid-column: span 2;
  grid-row: span 2;
}

.el-bento-grid--mixed-2x4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(var(--bento-min-h, 180px), 1fr);
}

.el-bento-grid--mixed-2x4 > .el-bento-grid__cell:nth-child(4n+1) {
  grid-column: span 2;
}

.el-bento-grid--showcase-4 {
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  grid-template-rows: repeat(3, minmax(var(--bento-min-h, 180px), 1fr));
}

.el-bento-grid--showcase-4 > .el-bento-grid__cell:first-child {
  grid-row: span 3;
}

.el-bento-grid__cell {
  position: relative;
  overflow: hidden;
  border-radius: var(--bento-radius, 16px);
  background: var(--site-card-bg, var(--site-surface, transparent));
  box-shadow: var(--site-shadow-sm, 0 2px 8px rgba(0, 0, 0, 0.06));
  transition:
    transform 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow 360ms ease,
    border-color 360ms ease;
  border: 1px solid var(--site-border-muted, transparent);
  /* Stagger fade-in on first paint; cells animate in over 540ms with a
     per-index delay computed from --bento-stagger * --bento-i. */
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  animation: el-bento-cell-in 540ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
  animation-delay: calc(var(--bento-stagger, 60ms) * var(--bento-i, 0));
}

.el-bento-grid__cell:hover {
  transform: translate3d(0, -2px, 0) scale(var(--bento-zoom, 1.04));
  box-shadow: var(--site-shadow-lg, 0 12px 40px rgba(0, 0, 0, 0.18));
  border-color: var(--site-accent, transparent);
  z-index: 2;
}

.el-bento-grid__cell-inner {
  width: 100%;
  height: 100%;
  display: flex;
}

@keyframes el-bento-cell-in {
  to { opacity: 1; transform: translate3d(0, 0, 0); }
}

@container site style(--site-bp: mobile) {
  .el-bento-grid--feature-3x3,
  .el-bento-grid--mixed-2x4,
  .el-bento-grid--showcase-4 {
    grid-template-columns: 1fr;
    grid-auto-rows: minmax(var(--bento-min-h, 180px), auto);
  }
  .el-bento-grid--feature-3x3 > .el-bento-grid__cell:first-child,
  .el-bento-grid--feature-3x3 > .el-bento-grid__cell--a,
  .el-bento-grid--showcase-4 > .el-bento-grid__cell:first-child,
  .el-bento-grid--mixed-2x4 > .el-bento-grid__cell:nth-child(4n+1) {
    grid-column: 1 / -1;
    grid-row: auto;
  }
}
@media (max-width: 768px) {
  .el-bento-grid--feature-3x3,
  .el-bento-grid--mixed-2x4,
  .el-bento-grid--showcase-4 {
    grid-template-columns: 1fr;
    grid-auto-rows: minmax(var(--bento-min-h, 180px), auto);
  }
  .el-bento-grid--feature-3x3 > .el-bento-grid__cell:first-child,
  .el-bento-grid--feature-3x3 > .el-bento-grid__cell--a,
  .el-bento-grid--showcase-4 > .el-bento-grid__cell:first-child,
  .el-bento-grid--mixed-2x4 > .el-bento-grid__cell:nth-child(4n+1) {
    grid-column: 1 / -1;
    grid-row: auto;
  }
}

/* ───────────────────────── Horizontal scroll section ───────────────────────── */

.el-hscroll {
  position: relative;
  width: 100%;
}

.el-hscroll__track {
  display: flex;
  gap: var(--hscroll-gap, 20px);
  padding: 0 var(--hscroll-pad, 24px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scroll-behavior: smooth;
}

.el-hscroll__track > * {
  flex: 0 0 auto;
  width: var(--hscroll-item-w, 320px);
  max-width: 90vw;
  scroll-snap-align: start;
}

.el-hscroll--wheel-pan .el-hscroll__track {
  /* Wheel-pan gets a slightly faster snap settle; the JS handler does the
     vertical→horizontal translation inside the renderer. */
  scroll-snap-type: x proximity;
}

/* Custom scrollbar for the horizontal track — small, branded, unobtrusive. */
.el-hscroll__track::-webkit-scrollbar {
  height: 6px;
}
.el-hscroll__track::-webkit-scrollbar-track {
  background: transparent;
}
.el-hscroll__track::-webkit-scrollbar-thumb {
  background: var(--site-border-muted, transparent);
  border-radius: 999px;
}
.el-hscroll__track::-webkit-scrollbar-thumb:hover {
  background: var(--site-accent, transparent);
}

/* ───────────────────────── Kinetic heading ───────────────────────── */

.el-kinetic-heading {
  display: inline-block;
  perspective: 800px;
}

.el-kinetic-heading__inner {
  display: inline-block;
  /* CSS var driven by KineticHeadingRenderer's rAF scroll tick */
  --kinetic-skew: 0deg;
}

.el-kinetic-heading__char,
.el-kinetic-heading__space {
  display: inline-block;
  white-space: pre;
  transform-origin: 50% 50%;
  transition: transform 90ms linear;
}

.el-kinetic-heading--active .el-kinetic-heading__char {
  transform: skewY(var(--kinetic-skew, 0deg));
}

/* ───────────────────────── Sticky scroll storytelling ───────────────────────── */

.el-sticky-scroll {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: start;
  --el-padding-default: clamp(40px, 6vw, 80px) clamp(20px, 4vw, 60px);
}

.el-sticky-scroll__media-col {
  position: relative;
  min-height: calc(100vh - var(--sticky-top, 96px) - 80px);
}

.el-sticky-scroll__media {
  position: sticky;
  top: var(--sticky-top, 96px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.el-sticky-scroll__media-img {
  width: 100%;
  height: auto;
  max-height: calc(100vh - var(--sticky-top, 96px) - 120px);
  object-fit: contain;
  border-radius: var(--site-radius, 12px);
  box-shadow: var(--site-shadow-lg, 0 12px 40px rgba(0, 0, 0, 0.18));
  transition: opacity 320ms ease;
}

.el-sticky-scroll__media-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px dashed var(--site-border-muted, transparent);
  border-radius: var(--site-radius, 12px);
  color: var(--site-text-muted, currentColor);
  font-size: 13px;
}

.el-sticky-scroll__progress {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

.el-sticky-scroll__progress-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--site-border-muted, transparent);
  transition: background 240ms ease, transform 240ms ease;
}

.el-sticky-scroll__progress-dot.is-active {
  background: var(--site-accent, transparent);
  transform: scale(1.4);
}

.el-sticky-scroll__content-col {
  display: flex;
  flex-direction: column;
  gap: 12vh;
  padding: 20vh 0;
}

.el-sticky-scroll__panel {
  opacity: 0.5;
  transition: opacity 360ms ease, transform 360ms ease;
}

.el-sticky-scroll__panel.is-active {
  opacity: 1;
  transform: translateX(0);
}

@container site style(--site-bp: mobile) {
  .el-sticky-scroll {
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .el-sticky-scroll__media-col {
    min-height: 0;
  }
  .el-sticky-scroll__media {
    position: relative;
    top: 0;
  }
  .el-sticky-scroll__content-col {
    padding: 24px 0;
    gap: 32px;
  }
}
@media (max-width: 768px) {
  .el-sticky-scroll {
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .el-sticky-scroll__media-col {
    min-height: 0;
  }
  .el-sticky-scroll__media {
    position: relative;
    top: 0;
  }
  .el-sticky-scroll__content-col {
    padding: 24px 0;
    gap: 32px;
  }
}

/* ───────────────────────── Scroll sequence ───────────────────────── */

.el-scroll-sequence {
  position: relative;
  width: 100%;
  height: var(--ss-height, 300vh);
}

.el-scroll-sequence--empty {
  height: auto;
  padding: 24px;
  text-align: center;
  border: 1px dashed var(--site-border-muted, transparent);
  color: var(--site-text-muted, currentColor);
  border-radius: 12px;
  font-size: 13px;
}

.el-scroll-sequence__sticky {
  position: sticky;
  top: var(--ss-sticky-top, 0);
  width: 100%;
  height: calc(100vh - var(--ss-sticky-top, 0px));
  overflow: hidden;
  background: var(--site-bg, transparent);
}

.el-scroll-sequence__frame {
  width: 100%;
  height: 100%;
  display: block;
}

.el-scroll-sequence__frame--cover {
  object-fit: cover;
}

.el-scroll-sequence__frame--contain {
  object-fit: contain;
}

/* ───────────────────────── Path morph ───────────────────────── */

.el-path-morph {
  width: 100%;
  display: block;
}

.el-path-morph__svg {
  width: 100%;
  height: 100%;
  display: block;
  /* The `d:` property is animatable in modern browsers — use a soft
     transition for a subtle morph between the two states. Older browsers
     just snap, which is acceptable. */
  transition: d 1200ms cubic-bezier(0.65, 0, 0.35, 1);
}

.el-path-morph__svg path {
  transition: d 1200ms cubic-bezier(0.65, 0, 0.35, 1);
}

/* ───────────────────────── Image trail (cursor canvas) ───────────────────────── */

.el-image-trail {
  position: relative;
  width: 100%;
  isolation: isolate;
}

.el-image-trail__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  mix-blend-mode: screen;
}

.el-image-trail__content {
  position: relative;
  z-index: 1;
}

/* ───────────────────────── Spotlight (Item 5) ───────────────────────── */

.el-spotlight {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--site-bg, transparent);
  /* Default x/y center the spotlight before pointer enters. */
  --spot-x: 50%;
  --spot-y: 50%;
}

.el-spotlight::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    var(--spot-radius, 320px) circle at var(--spot-x, 50%) var(--spot-y, 50%),
    var(--spot-color, transparent) 0%,
    transparent 70%
  );
  opacity: var(--spot-intensity, 0.7);
  transition: background-position 60ms linear;
  z-index: 0;
}

.el-spotlight__content {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  padding: clamp(24px, 6vw, 80px);
}

@media (prefers-reduced-motion: reduce) {
  .el-spotlight::before {
    background-position: center !important;
  }
}

/* ───────────────────────── Number ticker (Item 6) ───────────────────────── */

.el-number-ticker {
  display: inline-flex;
  align-items: baseline;
  gap: 0.1em;
  font-variant-numeric: tabular-nums;
}

.el-number-ticker__value {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* ───────────────────────── Glitch text (Item 7) ───────────────────────── */

.el-glitch-text {
  position: relative;
  display: inline-block;
  color: inherit;
}

.el-glitch-text__visible {
  position: relative;
  z-index: 1;
}

.el-glitch-text__layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  mix-blend-mode: screen;
}

.el-glitch-text__layer--r {
  color: var(--glitch-r, currentColor);
  animation: evara-glitch-r var(--glitch-speed, 2400ms) infinite linear alternate;
}

.el-glitch-text__layer--b {
  color: var(--glitch-b, currentColor);
  animation: evara-glitch-b var(--glitch-speed, 2400ms) infinite linear alternate;
}

@keyframes evara-glitch-r {
  0%, 100% {
    transform: translate3d(0, 0, 0);
    clip-path: inset(0 0 0 0);
  }
  20% {
    transform: translate3d(calc(-2px * var(--glitch-intensity, 0.6)), calc(-1px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(15% 0 60% 0);
  }
  40% {
    transform: translate3d(calc(2px * var(--glitch-intensity, 0.6)), calc(1px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(45% 0 25% 0);
  }
  60% {
    transform: translate3d(calc(-1px * var(--glitch-intensity, 0.6)), calc(2px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(70% 0 5% 0);
  }
}

@keyframes evara-glitch-b {
  0%, 100% {
    transform: translate3d(0, 0, 0);
    clip-path: inset(0 0 0 0);
  }
  20% {
    transform: translate3d(calc(2px * var(--glitch-intensity, 0.6)), calc(1px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(60% 0 15% 0);
  }
  40% {
    transform: translate3d(calc(-2px * var(--glitch-intensity, 0.6)), calc(-1px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(30% 0 50% 0);
  }
  60% {
    transform: translate3d(calc(1px * var(--glitch-intensity, 0.6)), calc(-2px * var(--glitch-intensity, 0.6)), 0);
    clip-path: inset(5% 0 75% 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .el-glitch-text__layer { display: none; }
}

/* ───────────────────────── Content marquee (Item 8) ───────────────────────── */

.el-content-marquee {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.el-content-marquee--edge-fade {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
}

.el-content-marquee--empty {
  padding: 24px;
  text-align: center;
  border: 1px dashed var(--site-border-muted, transparent);
  border-radius: 12px;
}

.el-content-marquee__hint {
  margin: 0;
  font-size: 13px;
  color: var(--site-text-muted, currentColor);
}

.el-content-marquee__track {
  display: flex;
  width: max-content;
  animation: evara-content-marquee var(--cmarquee-speed, 40s) linear infinite;
  will-change: transform;
}

.el-content-marquee[data-direction='reverse'] .el-content-marquee__track {
  animation-direction: reverse;
}

.el-content-marquee--pause-on-hover:hover .el-content-marquee__track {
  animation-play-state: paused;
}

.el-content-marquee__copy {
  display: flex;
  align-items: stretch;
  gap: var(--cmarquee-gap, 48px);
  padding-right: var(--cmarquee-gap, 48px);
  flex: 0 0 auto;
}

.el-content-marquee--fixed-w .el-content-marquee__copy > * {
  width: var(--cmarquee-item-w, 320px);
  flex: 0 0 var(--cmarquee-item-w, 320px);
}

@keyframes evara-content-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .el-content-marquee__track {
    animation: none !important;
  }
}

/* ───────────────────────── Reveal curtain (Item 9) ───────────────────────── */

.el-reveal-curtain {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.el-reveal-curtain__panel {
  position: absolute;
  top: 0;
  height: 100%;
  background: var(--curtain-color, transparent);
  z-index: 2;
  transition: transform var(--curtain-duration, 1200ms) cubic-bezier(0.65, 0, 0.35, 1);
}

.el-reveal-curtain__content {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
}

/* Split — two panels meet at the center; on open they slide apart. */
.el-reveal-curtain--split-center .el-reveal-curtain__panel--a {
  left: 0;
  width: 50%;
  transform: translateX(0);
}
.el-reveal-curtain--split-center .el-reveal-curtain__panel--b {
  right: 0;
  width: 50%;
  transform: translateX(0);
}
.el-reveal-curtain--split-center.is-open .el-reveal-curtain__panel--a {
  transform: translateX(-100%);
}
.el-reveal-curtain--split-center.is-open .el-reveal-curtain__panel--b {
  transform: translateX(100%);
}

/* Wipe left — single panel covers the whole section, slides off to left. */
.el-reveal-curtain--wipe-left .el-reveal-curtain__panel--a {
  left: 0;
  width: 100%;
  transform: translateX(0);
}
.el-reveal-curtain--wipe-left .el-reveal-curtain__panel--b { display: none; }
.el-reveal-curtain--wipe-left.is-open .el-reveal-curtain__panel--a {
  transform: translateX(-100%);
}

.el-reveal-curtain--wipe-right .el-reveal-curtain__panel--a {
  left: 0;
  width: 100%;
  transform: translateX(0);
}
.el-reveal-curtain--wipe-right .el-reveal-curtain__panel--b { display: none; }
.el-reveal-curtain--wipe-right.is-open .el-reveal-curtain__panel--a {
  transform: translateX(100%);
}

@media (prefers-reduced-motion: reduce) {
  .el-reveal-curtain__panel {
    display: none;
  }
}

/* ───────────────────────── Page exit animations (Item 2) ───────────────────────── */

/*
 * View Transitions API automatically pairs entry + exit pseudo-elements
 * (::view-transition-old / ::view-transition-new) when a navigation
 * happens. ViewTransitionsNav writes data-page-transition on <body>
 * keyed off SiteSettings.pageTransition.type — these rules consume it
 * to define what the OUTGOING page does, not just the incoming one.
 *
 * Browser support: Chromium has full support; Safari + Firefox skip
 * the transition entirely (we already gracefully fall back via the
 * has-startViewTransition feature detect). The duration is read from
 * --evara-page-transition-duration set by ViewTransitionsNav.
 */

/* Shared base — every transition pairs old/new. The `::view-transition-*`
   pseudos are auto-created by the browser on a successful nav. */

@supports (view-transition-name: none) {
  /* fadeThrough: old fades out fully, new fades in. */
  body[data-page-transition='fadeThrough']::view-transition-old(root) {
    animation: evara-page-fade-out var(--evara-page-transition-duration, 280ms) ease-in forwards;
  }
  body[data-page-transition='fadeThrough']::view-transition-new(root) {
    animation: evara-page-fade-in var(--evara-page-transition-duration, 280ms) ease-out forwards;
  }

  /* slideLeft: old slides left out, new slides in from right. */
  body[data-page-transition='slideLeft']::view-transition-old(root) {
    animation: evara-page-slide-out-left var(--evara-page-transition-duration, 280ms) ease-in forwards;
  }
  body[data-page-transition='slideLeft']::view-transition-new(root) {
    animation: evara-page-slide-in-right var(--evara-page-transition-duration, 280ms) ease-out forwards;
  }

  /* slideRight: mirror of slideLeft. */
  body[data-page-transition='slideRight']::view-transition-old(root) {
    animation: evara-page-slide-out-right var(--evara-page-transition-duration, 280ms) ease-in forwards;
  }
  body[data-page-transition='slideRight']::view-transition-new(root) {
    animation: evara-page-slide-in-left var(--evara-page-transition-duration, 280ms) ease-out forwards;
  }

  /* crossfade: both sides fade simultaneously (the default-ish cinematic). */
  body[data-page-transition='crossfade']::view-transition-old(root),
  body[data-page-transition='crossfade']::view-transition-new(root) {
    animation-duration: var(--evara-page-transition-duration, 280ms);
    animation-timing-function: ease-in-out;
  }
  body[data-page-transition='crossfade']::view-transition-old(root) {
    animation-name: evara-page-fade-out;
  }
  body[data-page-transition='crossfade']::view-transition-new(root) {
    animation-name: evara-page-fade-in;
  }

  /* morphHero: relies on shared element transitions — author tags
     elements with viewTransitionName (Phase 1 wiring) and the browser
     auto-pairs them. Unmatched roots fade to keep the chrome smooth. */
  body[data-page-transition='morphHero']::view-transition-old(root),
  body[data-page-transition='morphHero']::view-transition-new(root) {
    animation: evara-page-fade-quick calc(var(--evara-page-transition-duration, 280ms) * 0.7) ease-out forwards;
  }
}

@keyframes evara-page-fade-out {
  to { opacity: 0; }
}
@keyframes evara-page-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes evara-page-fade-quick {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes evara-page-slide-out-left {
  to { transform: translate3d(-8%, 0, 0); opacity: 0; }
}
@keyframes evara-page-slide-out-right {
  to { transform: translate3d(8%, 0, 0); opacity: 0; }
}
@keyframes evara-page-slide-in-left {
  from { transform: translate3d(-8%, 0, 0); opacity: 0; }
  to   { transform: translate3d(0, 0, 0); opacity: 1; }
}
@keyframes evara-page-slide-in-right {
  from { transform: translate3d(8%, 0, 0); opacity: 0; }
  to   { transform: translate3d(0, 0, 0); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body[data-page-transition]::view-transition-old(root),
  body[data-page-transition]::view-transition-new(root) {
    animation: none !important;
  }
}

/* ───────────────────────── Scroll-timeline reveal (Item 1) ───────────────────────── */

/*
 * Drop-in CSS animations driven by the View Timeline API. Consumers add
 * .scroll-tl-* classes to an element AND give it a view-timeline-name
 * (handled by useScrollTimeline). Browsers without the API gracefully
 * fall back to normal time-based playback — the animation still plays,
 * just not bound to scroll.
 *
 * Why this matters: native scroll-driven animations replace the
 * IntersectionObserver-driven reveal pattern with browser-orchestrated
 * progress, which composites on the GPU thread and never jitters
 * during scroll. This is the engine layer that makes "scroll = the
 * animation" feel premium without JS rAF.
 */

@keyframes evara-tl-fade-up {
  from { opacity: 0; transform: translate3d(0, 32px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes evara-tl-zoom-in {
  from { opacity: 0; transform: scale(0.92); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes evara-tl-slide-left {
  from { opacity: 0; transform: translate3d(-48px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes evara-tl-slide-right {
  from { opacity: 0; transform: translate3d(48px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

.scroll-tl-fade-up,
.scroll-tl-zoom-in,
.scroll-tl-slide-left,
.scroll-tl-slide-right {
  animation-fill-mode: both;
  animation-duration: 1s;
  animation-timing-function: linear;
}

.scroll-tl-fade-up    { animation-name: evara-tl-fade-up; }
.scroll-tl-zoom-in    { animation-name: evara-tl-zoom-in; }
.scroll-tl-slide-left { animation-name: evara-tl-slide-left; }
.scroll-tl-slide-right{ animation-name: evara-tl-slide-right; }

@media (prefers-reduced-motion: reduce) {
  .scroll-tl-fade-up,
  .scroll-tl-zoom-in,
  .scroll-tl-slide-left,
  .scroll-tl-slide-right {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ───────────────────────── ScrollReveal default (Phase 4) ───────────────────────── */

/*
 * Wraps section bodies with a scroll-triggered reveal. SSR ships the
 * hidden state; the client adds .is-revealed when the section enters the
 * viewport (see src/components/public/ScrollReveal.tsx).
 *
 * Above-fold sections never get this wrapper (they'd FOUC the hero).
 * The whole thing is a no-op when SiteSettings.motion.enableScrollReveal
 * is false (the wrapper renders children naked).
 */

.scroll-reveal {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity 720ms cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 720ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--scroll-reveal-delay, 0ms);
  will-change: opacity, transform;
}

.scroll-reveal.is-revealed {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/*
 * Native scroll-timeline path — when the wrapper detects CSS
 * animation-timeline support, it drops .scroll-reveal--timeline on the
 * element + sets view-timeline-name. We swap from the class-flipped
 * transition to a keyframe animation bound to the view timeline. Browser
 * composites this on the GPU thread, no main-thread work per scroll
 * frame.
 */
@supports (animation-timeline: view()) {
  .scroll-reveal--timeline {
    animation-name: evara-scroll-reveal;
    animation-timeline: --evara-reveal-tl;
    animation-fill-mode: both;
    animation-range: cover 0% cover 30%;
    /* When the timeline path is active, the legacy class-flip transition
       is unused; reset it so it can't double-animate on browsers that
       support both. */
    transition: none;
  }
}

@keyframes evara-scroll-reveal {
  from { opacity: 0; transform: translate3d(0, 24px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-reveal,
  .scroll-reveal--timeline {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
}

/* ───────────────────────── Image renderer Phase 2 motion props ───────────────────────── */

/* hover-zoom: figure clips, image scales on hover. */
.el-image--hover-zoom {
  overflow: hidden;
  border-radius: var(--el-image-radius, var(--site-radius, 12px));
}

.el-image--hover-zoom .el-image__img {
  transition: transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}

.el-image--hover-zoom:hover .el-image__img {
  transform: scale(var(--el-image-hover-zoom, 1.06));
}

/* ken-burns: continuous slow zoom + drift loop. */
.el-image--ken-burns {
  overflow: hidden;
  border-radius: var(--el-image-radius, var(--site-radius, 12px));
}

.el-image--ken-burns .el-image__img {
  animation: el-image-ken-burns 24s ease-in-out infinite alternate;
  transform-origin: center center;
  will-change: transform;
}

@keyframes el-image-ken-burns {
  from { transform: scale(1) translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(2%, -2%, 0); }
}

/* parallax: figure has .evara-parallax (existing engine class); the
   engine in src/lib/animations/engine.ts reads --evara-parallax-y and
   sets transform: translate3d(0, var(--evara-parallax-y), 0). The
   `data-parallax-speed` attribute scales the offset. */

/* ───────────────────────── Reduced motion (kill switch) ───────────────────────── */
/* Single tail block — every animated rule above honors the user preference. */

@media (prefers-reduced-motion: reduce) {
  .el-magnetic-link {
    transform: none !important;
    transition: none !important;
  }

  .el-mesh-gradient__layer {
    animation: none !important;
  }

  .el-logo-strip__track {
    animation: none !important;
  }

  .el-flip-card__inner {
    transition: none !important;
  }

  .el-bento-grid__cell {
    /* Skip the entrance animation; show the cell at rest. */
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }

  .el-bento-grid__cell:hover {
    transform: none !important;
  }

  .el-kinetic-heading__char,
  .el-kinetic-heading__space {
    transform: none !important;
    transition: none !important;
  }

  .el-sticky-scroll__panel {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  .el-sticky-scroll__media-img {
    transition: none !important;
  }

  .el-path-morph__svg path {
    transition: none !important;
  }

  .el-image--hover-zoom .el-image__img,
  .el-image--ken-burns .el-image__img {
    transition: none !important;
    animation: none !important;
    transform: none !important;
  }

  .sticky-progress__fill {
    /* Reduced-motion: instant snap, no eased fill. */
    transition: none !important;
  }
}

/* ───────────────────────── Sticky stacked cards (Item 4) ───────────────────────── */

/*
 * Stripe / Linear-style stacking deck. Each card is sticky-positioned with
 * a top value that grows by --ssc-offset for every card index, so cards pile
 * up like a deck instead of overlapping at the same line. Cards beneath the
 * active one progressively scale down + fade via the --card-i index variable
 * (set inline by the renderer per child).
 */
.el-sticky-stacked-cards {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--ssc-gap, 80px);
  width: 100%;
}

.el-sticky-stacked-cards__card {
  position: sticky;
  /* Each card sticks at a slightly lower top than the one above it so the
     deck reveals card headers as the visitor scrolls down. */
  top: calc(var(--ssc-top, 80px) + var(--ssc-offset, 24px) * var(--card-i, 0));
  transform-origin: top center;
  /* Cards beneath the active one scale down + fade. The active card resets
     these via the .is-active selector below. */
  transform: scale(calc(1 - (1 - var(--ssc-scale, 0.96)) * var(--depth-from-active, 0)));
  opacity: calc(1 - (1 - var(--ssc-opacity, 0.7)) * var(--depth-from-active, 0));
  transition:
    transform 360ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 360ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, opacity;
}

/*
 * Approximate "depth-from-active": before any JS runs (or when no card has
 * yet been marked active), every card reads as fully active. Once the
 * renderer toggles is-active on the top card, sibling cards (which always
 * sit ABOVE the active card in DOM order, since the active one is the
 * top of the deck) animate to their tucked state.
 *
 * Because we don't know depth in pure CSS, we lean on the renderer to flip
 * is-active and give NEAR cards (any non-active) the tucked look. This is
 * a single-step "active vs not" — simple and matches the Linear-style feel.
 */
.el-sticky-stacked-cards__card {
  --depth-from-active: 0;
}

.el-sticky-stacked-cards__card:not(.is-active) {
  --depth-from-active: 1;
}

.el-sticky-stacked-cards__inner {
  width: 100%;
  height: 100%;
}

/* Downgraded mode (reduced-motion / save-data) — render a normal stack
   with the configured gap; no sticky, no scale, no fade. */
.el-sticky-stacked-cards.is-downgraded .el-sticky-stacked-cards__card {
  position: relative;
  top: auto;
  transform: none;
  opacity: 1;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .el-sticky-stacked-cards__card {
    position: relative !important;
    top: auto !important;
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
}
