/* ==========================================================================
   Animations and interactions
   All motion can be switched off: the "Motion" switch in the header, or
   the visitor's system "Reduce motion" setting, adds .motion-off to <html>
   (see the kill switch at the end of this file).
   ========================================================================== */

:root {
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 0.2s;
  --dur-base: 0.45s;
  --dur-slow: 0.8s;
}

/* --------------------------------------------------------------------------
   Logo: E, T and the alien head are separate SVG paths
   -------------------------------------------------------------------------- */
.logo {
  display: block;
  overflow: visible;
}

.logo__e,
.logo__t {
  fill: var(--color-ink);
}

.logo__head {
  fill: #6e0600;
  filter: drop-shadow(0 2px 1px rgb(0 0 0 / 0.1));
}

.logo__e,
.logo__t,
.logo__head {
  transform-box: fill-box;
}

.logo__head {
  transform-origin: 50% 100%;
}

/* --------------------------------------------------------------------------
   Loading screen and page curtain (built by js/main.js).
   The boot script in each page's <head> adds .is-loading (first visit of the
   session) or .is-arriving (came from another page) before the first paint.
   -------------------------------------------------------------------------- */

/* Covers that exist before main.js runs, so nothing flashes.
   They hide themselves after a few seconds if the script ever fails. */
html.is-loading::after,
html.is-arriving::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 999;
  animation: cover-failsafe 0s 5s forwards;
}

html.is-loading::after {
  background: var(--color-bg);
}

html.is-arriving::after {
  background: var(--color-ink);
}

@keyframes cover-failsafe {
  to { visibility: hidden; }
}

/* Hero waits behind the loader / curtain and plays once it lifts */
html.is-loading .hero__text > *,
html.is-loading .hero__avatar,
html.is-arriving .hero__text > *,
html.is-arriving .hero__avatar {
  animation-play-state: paused;
}

/* ---------- Loading screen ---------- */
.loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  pointer-events: none;
}

.loader__panel {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--color-bg);
  transition: transform 0.9s var(--ease-in-out);
}

/* Second layer: ink, then a thin red edge, slide up right after the cream panel */
.loader__panel--ink {
  background: var(--color-ink);
  border-bottom: 6px solid var(--color-accent);
  transition-delay: 0.12s;
}

.loader .logo {
  width: min(260px, 60vw);
  height: auto;
}

.loader__tag {
  position: absolute;
  left: var(--gutter);
  bottom: var(--gutter);
  max-width: 60%;
  color: var(--color-ink-soft);
  font-size: var(--fs-sm);
}

.loader.is-done .loader__panel {
  transform: translateY(-100%);
}

.loader.is-done .loader__panel:not(.loader__panel--ink) > * {
  opacity: 0;
  transform: translateY(-40px);
  transition: opacity 0.4s, transform 0.6s var(--ease-in-out);
}

/* ---------- Page curtain ---------- */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: var(--color-ink);
  pointer-events: none;
  transform: translateY(100%);
  border-radius: 50% 50% 0 0 / 120px 120px 0 0;
}


.curtain.is-covering {
  transform: none;
  border-radius: 0;
  transition:
    transform 0.6s var(--ease-in-out),
    border-radius 0.6s var(--ease-in-out);
}


.curtain.is-instant {
  transition: none;
}

.curtain.is-leaving {
  transform: translateY(-100%);
  border-radius: 0 0 50% 50% / 0 0 120px 120px;
  transition:
    transform 0.8s var(--ease-in-out),
    border-radius 0.8s var(--ease-in-out);
}


/* ---------- Logo ---------- */

/* Logo intro (every page load), step 1: E and T draw their outline (trim path), then fill.
   pathLength="1" on the paths makes the dash values 0–1. */
.logo .logo__e,
.logo .logo__t {
  stroke: var(--color-ink);
  stroke-width: 0.9;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  animation:
    logo-trim 1s var(--ease-in-out) both,
    logo-fill 0.45s ease-out both;
}

.logo .logo__e {
  animation-delay: 0.1s, 0.95s;
}

.logo .logo__t {
  animation-delay: 0.3s, 1.15s;
}

/* Step 2: the alien rises out of the baseline (clipped by #logo-ground),
   stretches on the way up, squashes on landing and bounces to rest */
.logo .logo__head {
  animation:
    logo-head-rise 1.1s 1.35s both,
    logo-head-idle 7s 3.5s ease-in-out infinite;
}

@keyframes logo-trim {
  from { stroke-dashoffset: 1; }
  to { stroke-dashoffset: 0; }
}

@keyframes logo-fill {
  from { fill-opacity: 0; stroke-opacity: 1; }
  to { fill-opacity: 1; stroke-opacity: 0; }
}

@keyframes logo-head-rise {
  0% {
    transform: translateY(150%) scale(0.9, 1.1);
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1);
  }
  /* Stretch: thin and tall while moving up fast */
  35% {
    transform: translateY(-30%) scale(0.82, 1.22);
    animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1);
  }
  /* Apex: back to normal shape as it slows down */
  48% {
    transform: translateY(-38%) scale(1, 1);
    animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5);
  }
  /* Falling: stretches again */
  62% {
    transform: translateY(-4%) scale(0.9, 1.12);
    animation-timing-function: ease-out;
  }
  /* Landing: squash, wide and short */
  70% {
    transform: translateY(0) scale(1.28, 0.72);
    animation-timing-function: cubic-bezier(0.3, 0.6, 0.5, 1);
  }
  /* Small rebound */
  82% {
    transform: translateY(-12%) scale(0.94, 1.08);
    animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.6);
  }
  /* Second, softer squash */
  91% {
    transform: translateY(0) scale(1.1, 0.9);
    animation-timing-function: ease-out;
  }
  100% {
    transform: none;
  }
}

/* Hover: the alien jumps and the letters nudge.
   The intro animations stay in the list so leaving hover doesn't replay them. */
.site-header__logo:hover .logo__head {
  animation:
    logo-head-rise 1.1s 1.35s both,
    logo-head-idle 7s 3.5s ease-in-out infinite,
    logo-head-jump 0.7s var(--ease-out);
}

.site-header__logo:hover .logo__e {
  transform: translateX(-2px);
}

.site-header__logo:hover .logo__t {
  transform: translateY(-2px);
}

.logo__e,
.logo__t {
  transition: transform var(--dur-fast) var(--ease-out);
}

@keyframes logo-head-idle {
  0%, 82%, 100% { transform: rotate(0); }
  86% { transform: rotate(-14deg); }
  90% { transform: rotate(10deg); }
  94% { transform: rotate(-4deg); }
}

@keyframes logo-head-jump {
  0% { transform: none; }
  25% { transform: translateY(2px) scale(1.15, 0.85); }
  55% { transform: translateY(-9px) scale(0.92, 1.1) rotate(-8deg); }
  80% { transform: translateY(1px) scale(1.06, 0.94); }
  100% { transform: none; }
}

/* ---------- Home hero entrance ---------- */
.hero__text > *,
.hero__avatar {
  animation: rise-in var(--dur-slow) var(--ease-out) both;
}

.hero__text > :nth-child(1) { animation-delay: 0.2s; }
.hero__text > :nth-child(2) { animation-delay: 0.35s; }
.hero__text > :nth-child(3) { animation-delay: 0.5s; }
.hero__text > :nth-child(4) { animation-delay: 0.65s; }

.hero__avatar {
  animation:
    avatar-in 1s 0.3s var(--ease-out) both,
    float 6s 1.3s ease-in-out infinite;
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(24px); }
}

@keyframes avatar-in {
  from { opacity: 0; transform: translateY(30px) rotate(4deg) scale(0.95); }
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* ---------- Scroll reveal (classes added by js/main.js) ---------- */
/* Uses the translate/scale properties so hover effects that use
   transform (cards, chips) still work on revealed elements */
.js .reveal {
  opacity: 0;
  translate: 0 32px;
  transition:
    opacity var(--dur-slow) var(--ease-out),
    translate var(--dur-slow) var(--ease-out),
    scale 1.1s var(--ease-out),
    transform var(--dur-base) var(--ease-out);
  transition-delay: calc(var(--stagger, 0) * 90ms), calc(var(--stagger, 0) * 90ms), 0s, 0s;
}

.js .reveal.is-visible {
  opacity: 1;
  translate: none;
}

/* Dividers draw themselves from left to right */
.js .divider.reveal {
  opacity: 1;
  translate: none;
  scale: 0 1;
  transform-origin: left center;
}

.js .divider.reveal.is-visible {
  scale: 1 1;
}

/* ---------- Case-study reading progress bar ---------- */
@supports (animation-timeline: scroll()) {
  .case-study::before {
    content: "";
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 10;
    height: 4px;
    background: var(--color-accent);
    transform-origin: left center;
    animation: reading-progress linear both;
    animation-timeline: scroll(root);
  }

  @keyframes reading-progress {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
  }
}

/* ---------- Section Detail panels open smoothly ---------- */
@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  .disclosure::details-content {
    height: 0;
    overflow: clip;
    transition:
      height var(--dur-base) var(--ease-out),
      content-visibility var(--dur-base) allow-discrete;
  }

  .disclosure[open]::details-content {
    height: auto;
  }
}

.disclosure[open] .disclosure__panel {
  animation: rise-in var(--dur-base) var(--ease-out) both;
}

.disclosure summary::before {
  transition: transform var(--dur-base) var(--ease-bounce);
}

/* ---------- Hover and press interactions ---------- */

/* Buttons fill from left to right */
.btn {
  background: linear-gradient(var(--color-ink) 0 0) no-repeat left / 0% 100%;
  transition:
    background-size var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.btn:hover {
  background: linear-gradient(var(--color-ink) 0 0) no-repeat left / 100% 100%;
  color: var(--color-bg);
}

.btn:active,
.chip:active {
  transform: scale(0.96);
}

/* Skill chips lift and turn red */
.chip {
  transition:
    transform var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast);
}

.chip:hover {
  transform: translateY(-3px);
  background: var(--color-accent);
}

/* Social icons pop */
.social a {
  transition:
    transform var(--dur-fast) var(--ease-bounce),
    background-color var(--dur-fast);
}

.social a:hover {
  transform: translateY(-3px) rotate(-6deg) scale(1.08);
}

/* Project cards lift, the image zooms in */
.card {
  transition: transform var(--dur-base) var(--ease-out);
}

.card:hover {
  transform: translateY(-6px);
}

.card__media {
  transition: box-shadow var(--dur-base) var(--ease-out);
}

.card:hover .card__media {
  box-shadow: 0 16px 32px -16px rgb(21 21 21 / 0.35);
}

.card__media img {
  transition: transform var(--dur-slow) var(--ease-out);
}

.card:hover .card__media img {
  transform: scale(1.05);
}

.tag {
  transition: transform var(--dur-fast) var(--ease-out);
}

.card:hover .tag {
  transform: translateY(-2px);
}

.card:hover .tag:nth-child(2) { transition-delay: 40ms; }
.card:hover .tag:nth-child(3) { transition-delay: 80ms; }

/* Gallery images grow slightly on hover */
.strip img,
.motion-item img {
  transition: transform var(--dur-base) var(--ease-out);
}

.strip:not(.is-dragging) img:hover,
.motion-item:hover img {
  transform: scale(1.02);
}

/* About-page avatar photo tilts toward the cursor (js/main.js) */
.about-intro__photo {
  transition: transform var(--dur-base) var(--ease-out);
}


/* --------------------------------------------------------------------------
   Interactions that are not motion-heavy (always on)
   -------------------------------------------------------------------------- */

/* Nav: animated underline instead of a plain text-decoration */
.site-nav a {
  position: relative;
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--dur-base) var(--ease-out);
}

.site-nav a:hover {
  text-decoration: none;
}

.site-nav a:hover::after,
.site-nav a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.site-nav a[aria-current="page"]::after {
  background: var(--color-ink);
}

/* --------------------------------------------------------------------------
   Cursor: a simple dot, drawn by the operating system (no lag, no motion).
   Black by default. Over clickable things it turns red on light surfaces and
   white on dark ones (chips, social icons, filled buttons), so it always contrasts.
   Each dot has a thin outline so it stays visible over photos.
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  html,
  html * {
    cursor: url("../assets/images/cursor-ink.svg") 2 2, auto;
  }

  a,
  a *,
  button,
  summary,
  summary * {
    cursor: url("../assets/images/cursor-red.svg") 2 2, pointer;
  }

  .chip,
  .social a,
  .social a *,
  .btn:hover {
    cursor: url("../assets/images/cursor-white.svg") 2 2, pointer;
  }
}

/* Drag-to-scroll galleries */
.strip.is-dragging {
  scroll-snap-type: none;
  user-select: none;
}

.strip.is-dragging img {
  pointer-events: none;
}

/* ==========================================================================
   Kill switch: no motion at all
   .motion-off comes from the header switch or, by default, from the system
   "Reduce motion" setting (decided by the boot script in each page's <head>).
   The media query covers visitors with JavaScript disabled.
   ========================================================================== */
html.motion-off {
  scroll-behavior: auto;
}

html.motion-off *,
html.motion-off *::before,
html.motion-off *::after {
  animation: none !important;
  transition: none !important;
}

html.motion-off .reveal {
  opacity: 1 !important;
  translate: none !important;
  scale: none !important;
}

html.motion-off .logo__e,
html.motion-off .logo__t {
  stroke: none !important;
}

@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) *,
  html:not(.motion-on) *::before,
  html:not(.motion-on) *::after {
    animation: none !important;
    transition: none !important;
  }

  html:not(.motion-on) .logo__e,
  html:not(.motion-on) .logo__t {
    stroke: none !important;
  }
}

/* --------------------------------------------------------------------------
   Title glow (js/main.js): while active, the title's letters are painted by
   its background (red circles over ink), clipped to the text.
   -------------------------------------------------------------------------- */
.title-glow {
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* High-contrast / forced-colors mode removes backgrounds, so keep real text color */
@media (forced-colors: active) {
  .title-glow {
    background: none !important;
    -webkit-text-fill-color: CanvasText;
  }
}
