/* =====================================================================
   emapixel — design tokens & base styles
   Palette:  ink #0B0B0F · paper #F6F4EE · volt #D6FF3F · signal #FF3D7F
   Type:     Display/Headlines — "Space Grotesk"
             Body               — "Inter"
             Labels/Stats/Mono  — "JetBrains Mono"
   ===================================================================== */

:root {
  --ink: #0b0b0f;
  --ink-soft: #16161d;
  --paper: #f6f4ee;
  --paper-dim: #ece9df;
  --volt: #d6ff3f;
  --volt-dim: #aecf2c;
  --signal: #ff3d7f;
  --grey: #8a8a8f;
  --grey-line: rgba(246, 244, 238, 0.14);
  --ink-line: rgba(11, 11, 15, 0.1);

  --font-display: "Space Grotesk", "Inter", sans-serif;
  --font-body: "Inter", -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

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

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.font-display {
  font-family: var(--font-display);
}
.font-mono {
  font-family: var(--font-mono);
}

/* Focus visibility kept intentional, not suppressed */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--volt);
  outline-offset: 3px;
}

/* --------------------------------------------------------------- */
/* Eyebrow / index labels — used because services & process really */
/* are enumerated sequences, not decoration.                       */
/* --------------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--volt-dim);
}

.eyebrow-dark {
  color: var(--signal);
}

/* --------------------------------------------------------------- */
/* Parallax layer scaffolding                                       */
/* --------------------------------------------------------------- */
.parallax-scene {
  position: relative;
  overflow: hidden;
}

.parallax-layer {
  will-change: transform;
}

/* --------------------------------------------------------------- */
/* Page-wise scroll parallax                                        */
/*                                                                   */
/* .pinned-hero gets pinned in place (via GSAP ScrollTrigger) while  */
/* .cover-page — the marquee + "why it matters" section right after  */
/* it — scrolls up and covers it, so the hero recedes like the       */
/* bottom card in a stack. Every later .page-section then arrives    */
/* with its own soft scale/radius "card" entrance as it scrolls into */
/* view. Desktop-only (see parallax.js enableParallax gate) — pinning*/
/* and per-section transforms are skipped on touch/small screens and */
/* prefers-reduced-motion to protect frame rate and avoid viewport-  */
/* resize jank from mobile browser chrome.                           */
/* --------------------------------------------------------------- */
.pinned-hero {
  z-index: 1;
  will-change: transform, opacity, filter;
}

.cover-page {
  position: relative;
  z-index: 2;
}

.page-section {
  will-change: transform, opacity;
  transform-origin: center top;
  transform-style: preserve-3d;
}

/* Fixed top progress bar — the one always-visible, unambiguous signal
   that the page is scroll-reactive. JS drives scaleX 0 -> 1 in
   parallax.js; origin-left is set via Tailwind on the element. */
#scroll-progress {
  transform: scaleX(0);
  will-change: transform;
}

/* Cursor-tilt cards — pricing plans and "why us" points get a subtle
   3D rotation toward the cursor on hover, driven by JS. Perspective
   lives on the tilt element itself so the rotation reads as depth
   instead of a flat skew. */
.tilt-card {
  transform-style: preserve-3d;
  will-change: transform;
}

/* Reveal-on-scroll base state; GSAP flips these via .is-visible */
.reveal {
  opacity: 0;
  transform: translateY(46px);
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 1s cubic-bezier(0.16, 1, 0.3, 1), transform 1s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
  }
}

/* Portfolio card entrance — scale + clip-path wipe, richer than a
   plain fade since these sit in the densest visual section. */
.reveal-card {
  opacity: 0;
  transform: scale(0.92);
  clip-path: inset(6% 6% 6% 6% round 24px);
}
.reveal-card.is-visible {
  opacity: 1;
  transform: scale(1);
  clip-path: inset(0% 0% 0% 0% round 16px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .reveal-card {
    opacity: 1;
    transform: none;
    clip-path: none;
  }
}

/* Magnetic buttons — JS drives x/y via GSAP on mousemove/mouseleave;
   this just declares the property so the first tween isn't jumpy. */
.magnetic {
  display: inline-flex;
  will-change: transform;
}

/* --------------------------------------------------------------- */
/* Marquee ticker under the hero                                    */
/* --------------------------------------------------------------- */
.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 28s linear infinite;
}
@keyframes marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

/* --------------------------------------------------------------- */
/* Grain texture overlay on dark sections — subtle, not decorative  */
/* excess. Pure CSS, no image request.                              */
/* --------------------------------------------------------------- */
.grain::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%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");
}

/* --------------------------------------------------------------- */
/* Project card hover-reveal metric (signature interaction)         */
/* --------------------------------------------------------------- */
.project-card .metric-strip {
  transform: translateY(100%);
  transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}
.project-card:hover .metric-strip,
.project-card:focus-within .metric-strip {
  transform: translateY(0);
}
.project-card img {
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.project-card:hover img {
  transform: scale(1.06);
}

/* --------------------------------------------------------------- */
/* Custom scrollbar (webkit) to match brand, kept unobtrusive       */
/* --------------------------------------------------------------- */
::-webkit-scrollbar {
  width: 10px;
}
::-webkit-scrollbar-track {
  background: var(--paper);
}
::-webkit-scrollbar-thumb {
  background: var(--ink);
  border-radius: 6px;
}

/* Sticky nav state changes handled via Alpine, transition here */
#site-nav {
  transition: background-color 0.4s ease, padding 0.4s ease, box-shadow 0.4s ease;
}

/* PDF / video viewer frame on share page */
.viewer-frame {
  aspect-ratio: 16 / 9;
  background: var(--ink);
}

/* --------------------------------------------------------------- */
/* Brand logo lockup — dot-less wordmark PNG + animated brand dot   */
/* (the red dot is a CSS element so it can ping; the "e" knockout   */
/*  shows whatever is behind, so it works on any dark surface)      */
/* --------------------------------------------------------------- */
.logo {
  position: relative;
  display: inline-block;
  line-height: 0;
}
.logo img {
  display: block;
  height: var(--logo-h, 34px);
  width: auto;
}
.logo .logo-dot {
  position: absolute;
  left: 36.8%;
  top: 14.3%;
  width: 5.8%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: #ff3131;
  transform: translate(-50%, -50%);
}
.logo .logo-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #ff3131;
  animation: logo-ping 3s ease-out infinite;
}
@keyframes logo-ping {
  0% {
    transform: scale(1);
    opacity: 0.65;
  }
  70%,
  100% {
    transform: scale(2.6);
    opacity: 0;
  }
}

/* one-time "draw-on" entrance for the header lockup */
.logo--intro img {
  animation: logo-wipe 0.85s cubic-bezier(0.16, 1, 0.3, 1) 0.15s both;
}
.logo--intro .logo-dot {
  animation: logo-dot-in 0.4s ease 0.9s both;
}
@keyframes logo-wipe {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes logo-dot-in {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .logo .logo-dot::after,
  .logo--intro img,
  .logo--intro .logo-dot {
    animation: none;
  }
}
