/* ==========================================================================
   Motion layer
   Every animation here runs on the compositor: transform and opacity only.
   Total weight: ~2.4 KB minified. No external dependencies.
   ========================================================================== */

:root {
  --ease-out-soft: cubic-bezier(.16, 1, .3, 1);
  --motion-fast: .25s;
  --motion-base: .4s;
  --motion-slow: .55s;
}

/* --------------------------------------------------------------------------
   Scroll reveal - pairs with src/scripts/reveal.ts
   The element keeps its place in the layout from the first frame (CLS = 0).
   Movement only, no fade: text and buttons keep full contrast at every moment,
   so an accessibility check never catches them half transparent.
   -------------------------------------------------------------------------- */

[data-reveal] {
  transform: translateY(18px);
  transition: transform var(--motion-slow) var(--ease-out-soft);
  will-change: transform;
}

[data-reveal].is-in {
  transform: none;
  will-change: auto;
}

/* --------------------------------------------------------------------------
   Heading gradient sweep
   background-position is the single allowed paint-stage animation.
   Use on one element per page, never more.
   -------------------------------------------------------------------------- */

.shine {
  background: linear-gradient(
    100deg,
    var(--ink) 0%,
    var(--ink) 38%,
    var(--accent) 50%,
    var(--ink) 62%,
    var(--ink) 100%
  );
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: shine 6.5s linear infinite;
}

@keyframes shine {
  from { background-position: 160% 0; }
  to   { background-position: -60% 0; }
}

/* --------------------------------------------------------------------------
   Glowing divider
   -------------------------------------------------------------------------- */

.glow-rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: .35;
  animation: glow 4s ease-in-out infinite;
}

@keyframes glow {
  0%, 100% { opacity: .25; }
  50%      { opacity: .85; }
}

/* --------------------------------------------------------------------------
   Breathing primary button - one per page
   -------------------------------------------------------------------------- */

.btn-breathe {
  animation: breathe 3.2s ease-in-out infinite;
}

.btn-breathe:hover,
.btn-breathe:focus-visible {
  animation-play-state: paused;
}

@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgb(var(--accent-rgb, 184 115 11) / .35); }
  50%      { box-shadow: 0 0 22px 2px rgb(var(--accent-rgb, 184 115 11) / .55); }
}

/* --------------------------------------------------------------------------
   Floating decorative shapes
   Negative delays keep the three variants out of sync.
   -------------------------------------------------------------------------- */

.float {
  animation: float 9s ease-in-out infinite;
}

.float--slow   { animation-duration: 13s; animation-delay: -3s; }
.float--slower { animation-duration: 17s; animation-delay: -7s; }

@keyframes float {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  33%      { transform: translate3d(0, -14px, 0) rotate(1.5deg); }
  66%      { transform: translate3d(0, 8px, 0) rotate(-1deg); }
}

/* --------------------------------------------------------------------------
   Arrow nudge on links
   -------------------------------------------------------------------------- */

.link-arrow svg,
.link-arrow .arrow {
  transition: transform var(--motion-fast) var(--ease-out-soft);
}

.link-arrow:hover svg,
.link-arrow:focus-visible svg,
.link-arrow:hover .arrow,
.link-arrow:focus-visible .arrow {
  transform: translateX(4px);
}

/* --------------------------------------------------------------------------
   Sticky header - pairs with src/scripts/header-stuck.ts
   -------------------------------------------------------------------------- */

/* Sentinel used by header-stuck.ts to detect the stuck state.
   Kept in CSS so no inline style is ever written from JS. */
.motion-sentinel { position: absolute; top: 0; height: 1px; width: 1px; }

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  padding: 18px 0;
  background: transparent;
  transition:
    background-color var(--motion-base),
    box-shadow var(--motion-base),
    padding var(--motion-base);
}

.site-header.is-stuck {
  padding: 10px 0;
  background: rgb(var(--header-bg-rgb, 12 14 18) / .82);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .06);
}

/* --------------------------------------------------------------------------
   Reading progress bar - CSS scroll-driven, no JS at all.
   Hidden where the browser does not support it; nothing else changes.
   -------------------------------------------------------------------------- */

.read-bar {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: 100;
  animation: read linear;
  animation-timeline: scroll(root block);
}

@keyframes read {
  to { transform: scaleX(1); }
}

@supports not (animation-timeline: scroll(root block)) {
  .read-bar { display: none; }
}

/* --------------------------------------------------------------------------
   Logo marquee - duplicate the track contents exactly twice in the HTML
   -------------------------------------------------------------------------- */

.marquee {
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee__track {
  display: flex;
  gap: 48px;
  width: max-content;
  animation: marquee 28s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

@keyframes marquee {
  to { transform: translateX(-50%); }
}

/* --------------------------------------------------------------------------
   Cursor spotlight - pairs with demo.js. Desktop only.
   -------------------------------------------------------------------------- */

.spot {
  position: relative;
  isolation: isolate;
}

.spot::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(
    420px circle at var(--mx, 50%) var(--my, 50%),
    rgb(var(--accent-rgb, 184 115 11) / .13),
    transparent 60%
  );
  opacity: 0;
  transition: opacity var(--motion-base);
}

.spot:hover::before { opacity: 1; }

/* --------------------------------------------------------------------------
   Live demo rows - pairs with demo.js
   -------------------------------------------------------------------------- */

[data-demo-row] {
  opacity: .45;
  transition:
    opacity var(--motion-base) var(--ease-out-soft),
    transform var(--motion-base) var(--ease-out-soft);
}

[data-demo-row].is-active {
  opacity: 1;
  transform: translateX(4px);
}

/* --------------------------------------------------------------------------
   Accordion open/close without animating height
   -------------------------------------------------------------------------- */

.acc__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--motion-base) var(--ease-out-soft);
}

.acc__body > * { overflow: hidden; }

.acc[open] .acc__body,
.acc.is-open .acc__body {
  grid-template-rows: 1fr;
}

/* ==========================================================================
   REQUIRED. Never ship a page without this block.
   ========================================================================== */

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

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

  [data-demo-row] {
    opacity: 1 !important;
    transform: none !important;
  }

  .read-bar { display: none !important; }
}
