/* Gear Heads motion layer.
   Everything here is gated on html.js (set inline in <head>) so the site reads fully without JavaScript,
   and switched off entirely for visitors who ask for reduced motion. */

/* ---------- page-to-page transitions (Chrome, Edge, Safari 18+) ---------- */
@view-transition {
  navigation: auto;
}
::view-transition-old(root) {
  animation: vt-dim 0.5s cubic-bezier(0.4, 0, 0.2, 1) both;
}
::view-transition-new(root) {
  animation: vt-beam 0.65s cubic-bezier(0.65, 0, 0.35, 1) both;
  -webkit-mask-image: linear-gradient(105deg, #000 0 42%, rgba(0, 0, 0, 0.35) 50%, transparent 58% 100%);
  mask-image: linear-gradient(105deg, #000 0 42%, rgba(0, 0, 0, 0.35) 50%, transparent 58% 100%);
  -webkit-mask-size: 320% 100%;
  mask-size: 320% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
/* the old page dims like a garage going dark */
@keyframes vt-dim {
  to {
    filter: brightness(0.35);
  }
}
/* the new page is swept in by a headlight beam from the left, slightly over-bright as it lands */
@keyframes vt-beam {
  from {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
    filter: brightness(1.25);
  }
  to {
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
    filter: brightness(1);
  }
}

/* ---------- intro: logo reveal on the first page of a visit ---------- */
.intro {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  background: #0d0d0d;
  color: #fff;
  transition: clip-path 0.9s cubic-bezier(0.76, 0, 0.24, 1);
  clip-path: inset(0 0 0 0);
  cursor: pointer;
}
.intro.is-leaving {
  clip-path: inset(0 0 100% 0);
}
.intro__inner {
  position: relative;
  width: min(560px, 78vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
}
.intro__logo {
  width: 100%;
  height: auto;
  clip-path: inset(0 100% 0 0);
  animation: intro-wipe 1s cubic-bezier(0.65, 0, 0.35, 1) 0.15s forwards;
}
.intro__sheen {
  position: absolute;
  inset: 0 0 auto;
  aspect-ratio: 900 / 249;
  background: linear-gradient(
    100deg,
    transparent 30%,
    rgba(255, 255, 255, 0.9) 48%,
    transparent 66%
  );
  background-size: 250% 100%;
  background-position: 120% 0;
  -webkit-mask: url("../img/logo-full-light.webp") center / contain no-repeat;
  mask: url("../img/logo-full-light.webp") center / contain no-repeat;
  animation: intro-sheen 1.1s ease-out 0.9s forwards;
}
.intro__rev {
  width: 100%;
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
  border-radius: 2px;
}
.intro__rev i {
  display: block;
  height: 100%;
  width: 100%;
  transform-origin: left;
  transform: scaleX(0);
  background: linear-gradient(90deg, #ff9800 70%, #ff3b30);
  animation: intro-rev 1.2s cubic-bezier(0.3, 0.7, 0.2, 1) 0.1s forwards;
}
.intro__skip {
  font-family: var(--font-gauge);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}
@keyframes intro-wipe {
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes intro-sheen {
  to {
    background-position: -120% 0;
  }
}
@keyframes intro-rev {
  to {
    transform: scaleX(1);
  }
}

/* ---------- scroll progress + header behaviour ---------- */
.scroll-rev {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  z-index: 70;
  pointer-events: none;
}
.scroll-rev i {
  display: block;
  height: 100%;
  transform-origin: left;
  transform: scaleX(var(--progress, 0));
  background: linear-gradient(90deg, #ff9800 80%, #ff3b30);
}
.site-header {
  transition:
    transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1),
    border-color 0.2s;
}
.js .site-header.is-hidden {
  transform: translateY(-100%);
}

/* logo: a light sweep runs across the artwork on hover */
.logo {
  position: relative;
}
.logo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 35%,
    rgba(255, 255, 255, 0.95) 50%,
    transparent 65%
  );
  background-size: 260% 100%;
  background-position: 130% 0;
  -webkit-mask: url("../img/logo-dark.webp") left center / contain no-repeat;
  mask: url("../img/logo-dark.webp") left center / contain no-repeat;
  pointer-events: none;
}
.logo:hover::after,
.logo:focus-visible::after {
  animation: logo-sheen 0.9s ease-out;
}
@keyframes logo-sheen {
  to {
    background-position: -130% 0;
  }
}

/* ---------- reveals ---------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 0.9s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.9s cubic-bezier(0.2, 0.8, 0.2, 1);
  transition-delay: var(--reveal-delay, 0s);
}
.js [data-reveal="fade"] {
  transform: none;
}
.js [data-reveal="scale"] {
  transform: scale(0.96);
}
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* image wipe: photos open like a garage door */
.js [data-reveal="wipe"] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.2s cubic-bezier(0.76, 0, 0.24, 1);
  transition-delay: var(--reveal-delay, 0s);
}
.js [data-reveal="wipe"].is-in {
  clip-path: inset(0 0 0 0);
}

/* hero eyebrow: letters flicker like a dashboard readout, then lock in left to right */
.js .hero__intro > .eyebrow:first-child:not(.is-decoding):not(.is-decoded) {
  opacity: 0;
}
.decode-word {
  white-space: nowrap;
}
.decode-char {
  position: relative;
  display: inline-block;
}
.is-decoding .decode-char.is-waiting {
  visibility: hidden;
}
.is-decoding .decode-char:not(.is-scrambling) {
  transition: opacity 0.2s ease;
}
.is-decoding .decode-char.is-scrambling {
  -webkit-text-fill-color: transparent;
}
.is-decoding .decode-char.is-scrambling::after {
  content: attr(data-glyph);
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  text-align: center;
  -webkit-text-fill-color: currentColor;
  opacity: 0.5;
}

/* ghost buttons: the fill sweeps in from the left instead of snapping on */
.js .btn--ghost {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.js .btn--ghost::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--color-ink);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.5s cubic-bezier(0.76, 0, 0.24, 1);
}
.js .btn--ghost:is(:hover, :focus-visible)::before {
  transform: scaleX(1);
  transform-origin: left center;
}
.js .btn--ghost:is(:hover, :focus-visible) {
  background: transparent;
  color: #fff;
}
.js .section--night .btn--ghost::before {
  background: #fff;
}
.js .section--night .btn--ghost:is(:hover, :focus-visible) {
  background: transparent;
  color: var(--color-ink);
}

/* hero buttons rise in just after the headline words */
.hero__intro > div {
  --reveal-delay: 0.35s;
}

/* headline words rise out of a mask */
.word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.08em;
  margin-bottom: -0.08em;
}
.word__inner {
  display: inline-block;
}
.js .split-words .word__inner {
  transform: translateY(105%);
  transition: transform 1s cubic-bezier(0.2, 0.8, 0.2, 1);
  transition-delay: calc(var(--word-index, 0) * 55ms + var(--reveal-delay, 0s));
}
.js .split-words.is-in .word__inner {
  transform: none;
}

/* statement text lights up word by word as it scrolls past */
.statement {
  font-size: clamp(30px, 4.4vw, 64px);
  font-weight: 300;
  line-height: 1.12;
  letter-spacing: -0.025em;
  max-width: 22ch;
  text-wrap: balance;
}
.statement .lit {
  color: var(--color-ink);
  transition: color 0.25s;
}
.js .statement .lit {
  color: #8a877f;
}
.js .statement .lit.is-lit {
  color: var(--color-ink);
}
.section--night .statement .lit.is-lit {
  color: #fff;
}
.js .section--night .statement .lit {
  color: #666666;
}

/* ---------- parallax + tilt + magnetic ---------- */
[data-parallax] {
  will-change: transform;
}
[data-tilt] {
  transform-style: preserve-3d;
  transition:
    transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1),
    box-shadow 0.3s;
}
[data-tilt] .tilt-glare {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    400px circle at var(--gx, 50%) var(--gy, 50%),
    rgba(255, 255, 255, 0.35),
    transparent 45%
  );
  opacity: 0;
  transition: opacity 0.3s;
}
[data-tilt]:hover .tilt-glare {
  opacity: 1;
}
.card[data-tilt] {
  position: relative;
}
.card--dark[data-tilt] .tilt-glare {
  background: radial-gradient(
    400px circle at var(--gx, 50%) var(--gy, 50%),
    rgba(255, 152, 0, 0.22),
    transparent 45%
  );
}
.btn {
  will-change: transform;
}

/* ---------- marquee ---------- */
.marquee {
  overflow: hidden;
  -webkit-mask: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  gap: 56px;
  animation: marquee 38s linear infinite;
}
.marquee:hover .marquee__track {
  animation-play-state: paused;
}
.marquee__item {
  font-family: var(--font-gauge);
  font-size: clamp(14px, 1.4vw, 18px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 56px;
  color: var(--color-ink-soft);
}
.marquee__item::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-accent);
}
@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

/* ---------- back to top: a gear that fills as you scroll ---------- */
.to-top {
  position: fixed;
  right: max(20px, env(safe-area-inset-right, 0px));
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  z-index: 45;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 0;
  background: var(--color-ink);
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  opacity: 0;
  transform: translateY(16px);
  pointer-events: none;
  transition:
    opacity 0.3s,
    transform 0.3s;
}
/* On phones the fixed call bar owns the bottom edge, so the button sits above it */
@media (max-width: 860px) {
  .to-top {
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));
    width: 46px;
    height: 46px;
  }
}
.to-top.is-shown {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.to-top svg {
  position: absolute;
  inset: 0;
  transform: rotate(-90deg);
}
.to-top__ring {
  stroke-dasharray: 151;
  stroke-dashoffset: calc(151 - 151 * var(--progress, 0));
  transition: stroke-dashoffset 0.1s linear;
}
.to-top span {
  font-size: 18px;
  transition: transform 0.3s;
}
.to-top:hover span {
  transform: translateY(-3px);
}
@media (max-width: 860px) {
  .to-top {
    bottom: calc(92px + env(safe-area-inset-bottom, 0px));
    width: 46px;
    height: 46px;
  }
}

/* ---------- hover polish ---------- */
.photo {
  transition: transform 1.2s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.work-card {
  overflow: visible;
}
.work-card .photo-frame {
  overflow: hidden;
  border-radius: var(--radius-card);
}
.work-card:hover .photo {
  transform: scale(1.04);
}
.nav a {
  position: relative;
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 1.5px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.nav a:hover::after,
.nav a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

@media (prefers-reduced-motion: reduce) {
  .intro {
    display: none !important;
  }
  .js [data-reveal],
  .js [data-reveal="wipe"],
  .js .split-words .word__inner {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .js .statement .lit {
    color: inherit !important;
  }
  [data-parallax] {
    transform: none !important;
  }
  .marquee__track {
    animation: none;
  }
  @view-transition {
    navigation: none;
  }
}

/* keep the page still while the intro plays, so nothing scrolls past unrevealed */
html.intro-playing, html.intro-playing body { overflow: hidden; }

/* ---------- race-start header ----------
   On load the logo pulls onto the grid, the menu launches item by item, the CTA arrives,
   and a redline streak crosses the bottom edge. Only runs when motion.js adds .is-racing,
   so the header is always visible without JavaScript. */
.site-header::after {
  content: "";
  position: absolute; left: 0; bottom: -1px; height: 2px; width: 34%;
  background: linear-gradient(90deg, transparent, #ff3b30 45%, #ff9800 85%, #fff);
  transform: translateX(-110%) skewX(-30deg);
  opacity: 0; pointer-events: none;
}
.site-header.is-racing::after { animation: race-streak 1.1s cubic-bezier(.6, 0, .2, 1) .35s both; }
.site-header.is-racing .logo { animation: race-pull-in .75s cubic-bezier(.16, 1, .3, 1) both; }
.site-header.is-racing .nav a { animation: race-launch .6s cubic-bezier(.16, 1, .3, 1) both; animation-delay: calc(.18s + var(--grid-slot, 0) * 60ms); }
.site-header.is-racing .site-header__cta { animation: race-arrive .7s cubic-bezier(.16, 1, .3, 1) .55s both; }
.site-header.is-racing .site-header__cta .btn__dot { animation: race-launch-dot .5s cubic-bezier(.16, 1, .3, 1) 1.05s both; }

@keyframes race-pull-in {
  0% { opacity: 0; transform: translateX(-90px) skewX(-24deg); filter: blur(8px); }
  60% { opacity: 1; transform: translateX(6px) skewX(4deg); filter: blur(0); }
  100% { opacity: 1; transform: none; filter: none; }
}
@keyframes race-launch {
  0% { opacity: 0; transform: translateX(-28px) skewX(-18deg); filter: blur(4px); }
  100% { opacity: 1; transform: none; filter: none; }
}
@keyframes race-arrive {
  0% { opacity: 0; transform: translateX(60px) skewX(18deg); filter: blur(6px); }
  70% { opacity: 1; transform: translateX(-4px) skewX(-3deg); filter: blur(0); }
  100% { opacity: 1; transform: none; filter: none; }
}
@keyframes race-launch-dot {
  0% { transform: translateX(-10px) scale(.6); box-shadow: 0 0 0 0 rgba(255, 152, 0, .7); }
  60% { transform: translateX(3px) scale(1.08); box-shadow: 0 0 0 8px rgba(255, 152, 0, 0); }
  100% { transform: none; box-shadow: 0 0 0 0 rgba(255, 152, 0, 0); }
}
@keyframes race-streak {
  0% { opacity: 0; transform: translateX(-110%) skewX(-30deg); }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; transform: translateX(310%) skewX(-30deg); }
}

/* menu hover: the underline shoots across like a speed streak, the label leans into the corner */
.nav a { display: inline-block; transition: transform .3s cubic-bezier(.16, 1, .3, 1), color .2s; }
.nav a::after {
  height: 2px; bottom: -7px;
  background: linear-gradient(90deg, transparent, #ff3b30 40%, #ff9800);
  transform: scaleX(0) skewX(-30deg); transform-origin: left;
}
.nav a:hover { transform: skewX(-6deg); }
.nav a:hover::after { transform: scaleX(1) skewX(-30deg); transform-origin: left; }
.nav a[aria-current="page"]::after { transform: scaleX(1) skewX(-30deg); background: linear-gradient(90deg, #ff3b30, #ff9800); }

/* CTA hover: the arrow launches forward and leaves speed lines behind */
.site-header__cta .btn__dot { position: relative; overflow: visible; }
.site-header__cta .btn__dot::before {
  content: ""; position: absolute; right: 70%; top: 50%; width: 22px; height: 10px; margin-top: -5px;
  background: repeating-linear-gradient(180deg, rgba(255, 152, 0, .9) 0 2px, transparent 2px 4px);
  opacity: 0; transform: scaleX(0); transform-origin: right; transition: transform .25s, opacity .25s;
}
.site-header__cta:hover .btn__dot { transform: translateX(5px); }
.site-header__cta:hover .btn__dot::before { opacity: 1; transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .site-header.is-racing::after, .site-header.is-racing .logo, .site-header.is-racing .nav a,
  .site-header.is-racing .site-header__cta, .site-header.is-racing .site-header__cta .btn__dot { animation: none !important; }
  .nav a:hover { transform: none; }
}
@media (max-width: 860px) {
  .nav a:hover { transform: none; }
}

/* keep the race streak inside the screen while it runs; vertical overflow stays visible for the mobile menu */
.site-header { overflow-x: clip; }

/* photo strip driven by motion.js: drag to move, no CSS drift while it runs */
.marquee--photos.is-driven { cursor: grab; touch-action: pan-y; user-select: none; }
.marquee--photos.is-driven.is-dragging { cursor: grabbing; }
.marquee--photos.is-driven .marquee__track { animation: none; will-change: transform; }
.marquee--photos img { transition: transform .35s cubic-bezier(.2, .8, .2, 1), filter .35s; will-change: transform; pointer-events: none; -webkit-user-drag: none; }

/* ---------- paint glare: a studio light runs across each photo once, and again on hover ---------- */
.js .photo-frame {
  position: relative;
  isolation: isolate;
}
.js .photo-frame::after,
.js .work-card .photo-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    105deg,
    transparent 30%,
    rgba(255, 255, 255, 0.06) 40%,
    rgba(255, 255, 255, 0.3) 49%,
    rgba(255, 255, 255, 0.38) 50%,
    rgba(255, 255, 255, 0.3) 51%,
    rgba(255, 255, 255, 0.06) 60%,
    transparent 70%
  );
  mix-blend-mode: screen;
  transform: translateX(-110%);
}
.js .photo-frame.is-glared::after {
  animation: paint-glare 1.3s cubic-bezier(0.45, 0, 0.2, 1) 0.25s both;
}
.js .work-card:hover .photo-frame::before {
  animation: paint-glare 0.9s cubic-bezier(0.45, 0, 0.2, 1) both;
}
@keyframes paint-glare {
  to {
    transform: translateX(110%);
  }
}

/* ---------- shift lights: hovering a main button lights green, amber, red, then flashes the shift point ---------- */
.js .btn--dark,
.js .btn--light {
  position: relative;
}
.js .btn--dark::after,
.js .btn--light::after {
  content: "";
  position: absolute;
  left: 24px;
  right: 54px;
  bottom: 6px;
  height: 3px;
  border-radius: 2px;
  pointer-events: none;
  background: linear-gradient(90deg, #22c55e 0 34%, #f5b400 34% 67%, #ef4444 67% 100%);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 7px, transparent 7px 10px);
  mask: repeating-linear-gradient(90deg, #000 0 7px, transparent 7px 10px);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.12s;
}
.js .btn--dark:is(:hover, :focus-visible, :active)::after,
.js .btn--light:is(:hover, :focus-visible, :active)::after {
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.5s steps(8, end);
  animation: shift-flash 0.16s steps(1, end) 0.55s 3;
}
@keyframes shift-flash {
  50% {
    opacity: 0.15;
  }
}

@media (prefers-reduced-motion: reduce) {
  .photo-frame::after,
  .photo-frame::before,
  .btn--dark::after,
  .btn--light::after {
    display: none !important;
  }
}
