/* ==========================================================================
   site.css — custom layer on top of the Webflow export
   --------------------------------------------------------------------------
   Loaded AFTER normalize.css, webflow.css and the generated
   shyams-portfolio CSS on every page. All hand-written customisations
   live here (previously duplicated as inline <style>/<script> blocks
   on each page).

   Contents
   1. Theme transition        — smooth dark/light cross-fade
   2. Tools marquee           — continuous logo strip, pause on hover
   3. Project-card carousel   — seamless infinite image drift, pause on hover
   4. Accessibility           — reduced-motion guard
   ========================================================================== */


/* 1. Theme transition ---------------------------------------------------- */
/* Cross-fades colours when .light-theme is toggled on <body>. */

body,
body * {
  transition:
    background-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    border-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    fill 500ms cubic-bezier(0.65, 0, 0.35, 1),
    stroke 500ms cubic-bezier(0.65, 0, 0.35, 1);
}

/* Glass / bordered elements: their own `transition` in the Webflow CSS
   (border-only, 200ms) overrides the global rule above, which made the
   glass background snap instantly on theme change. Restore the 500ms
   theme fade while keeping the 200ms border hover. */
.glass-effect,
.border-effect {
  transition:
    background-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    fill 500ms cubic-bezier(0.65, 0, 0.35, 1),
    stroke 500ms cubic-bezier(0.65, 0, 0.35, 1),
    border-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1),
    border 200ms cubic-bezier(0.645, 0.045, 0.355, 1);
}

/* Theme toggle: the Webflow rule .links-switch-wrapper.glass-effect.border-effect
   (higher specificity) redefines `transition` without background-color,
   which made its glass background snap on theme change. Same fix, matched
   specificity: 500ms theme fade + the original 200ms transform/border. */
.links-switch-wrapper.glass-effect.border-effect {
  transition:
    background-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    fill 500ms cubic-bezier(0.65, 0, 0.35, 1),
    stroke 500ms cubic-bezier(0.65, 0, 0.35, 1),
    transform 200ms cubic-bezier(0.645, 0.045, 0.355, 1),
    border-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1),
    border 200ms cubic-bezier(0.645, 0.045, 0.355, 1);
}

/* Card hover accents: keep colour changes in sync with the 200ms border
   hover (arrows, link text, resume vertical lines). */
.card-button-static-link-text,
.card-button-static-link-arrow,
.card-button-rotate-arrow,
.vertical-line {
  transition:
    color 200ms cubic-bezier(0.645, 0.045, 0.355, 1),
    background-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1);
}

/* Theme-aware logos (inlined SVGs on Backroom): black in light mode,
   white in dark mode, via currentColor. */
.card-project-logo-01,
.card-project-logo-04 {
  color: var(--_theme---text--normal);
}

/* Keep those logos in sync with the rest of the theme fade. Their shapes
   paint with `currentColor`, so they already follow the 500ms `color`
   transition on the <svg> root. The global `body *` rule, though, also gives
   every inner <rect>/<path> its OWN 500ms fill/stroke transition — a second
   ease chasing the already-easing currentColor — which makes the mark land a
   beat after the background and text. Switching the inner shapes' transition
   off lets them track `color` directly, so the logo changes with the theme,
   not after it. */
.card-project-logo-01 *,
.card-project-logo-04 * {
  transition: none;
}


/* 2. Tools marquee ("My Tools" section) ---------------------------------- */

.marquee-wrapper {
  overflow: hidden;
}

.marquee-container {
  animation: marquee-scroll 24s linear infinite;
}

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

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}


/* 3. Project-card image carousel ----------------------------------------- */
/* Replaces the old Webflow w-slider inside .card-project.
   Markup:
     <div class="card-project-slider" style="--carousel-duration: 32s">
       <div class="card-carousel-track">
         <img class="card-project-image" …>  (one full set)
         <img class="card-project-image" …>  (identical duplicate set,
                                              aria-hidden="true")
       </div>
     </div>
   The track holds exactly two identical sets of images, each image
   carrying the same right-hand margin, so translateX(-50%) lands
   precisely on the start of the duplicate set → a seamless loop with
   no blank space. Speed stays constant across cards because
   --carousel-duration is set per card at 11s per unique image. */

.card-project-slider {
  height: 300px;                 /* same height the w-slider used */
  overflow: hidden;
  position: relative;
  background-color: transparent;
}

.card-carousel-track {
  display: flex;
  width: max-content;
  height: 100%;
  animation: card-carousel-scroll var(--carousel-duration, 44s) linear infinite;
  will-change: transform;
}

.card-carousel-track .card-project-image {
  height: 100%;
  width: auto;
  flex: none;
  margin-right: var(--_responsive---general-spacing--margin-x);
  object-fit: cover;
}

.card-project-slider:hover .card-carousel-track {
  animation-play-state: paused;
}

@keyframes card-carousel-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}


/* 4. Motion-design gallery (Backroom) ------------------------------------- */
/* Video cards are no longer cropped to the fixed 500px w-background-video
   height at any breakpoint: each card keeps its width behaviour but takes
   its height from the video's real aspect ratio, set per card via
   --video-ar inline (1280/720, 720/404, 520/292). All six videos are
   within 0.3% of 16:9, so the desktop 2-column grid rows stay aligned;
   the sub-pixel difference is absorbed by object-fit: cover. */

.card-project-motion-video {
  height: auto;
  aspect-ratio: var(--video-ar, 16 / 9);
}


/* 5. Page crossfade ------------------------------------------------------- */
/* Site-wide fade between pages, using the theme background colour as the
   fade target. Enter: <html> starts with `.is-loading` (set pre-paint in
   each page's <head>), removed on load to fade the body up from the
   background. Leave: site.js adds `.is-leaving` on internal navigation to
   fade the body down before the browser follows the link.

   The rule below re-declares body's transition so the opacity fade sits
   ALONGSIDE the existing 500ms theme colour fade (a bare `transition:
   opacity` rule would clobber it). Only `body` fades — never `body *` —
   so the Webflow IX2 opacity animations on the hero/cards are untouched. */
html body {
  transition:
    background-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    border-color 500ms cubic-bezier(0.65, 0, 0.35, 1),
    fill 500ms cubic-bezier(0.65, 0, 0.35, 1),
    stroke 500ms cubic-bezier(0.65, 0, 0.35, 1),
    opacity 350ms ease;
}

html.is-loading body,
html.is-leaving body {
  opacity: 0;
}

/* No fade at all when the visitor prefers reduced motion. */
@media (prefers-reduced-motion: reduce) {
  html.is-loading body,
  html.is-leaving body {
    opacity: 1;
  }
}


/* 5b. Directional page slide (Home <-> Backroom) -------------------------- */
/* Codrops-style "move to left / from right". The whole page (<body>) slides:
   going Home -> Backroom the old page exits to the LEFT and the new one
   enters FROM THE RIGHT; Backroom -> Home is the mirror image. site.js adds
   the leaving class before navigating and stashes the entry direction; the
   destination's pre-paint <head> snippet adds the matching entering class.
   Only Home <-> Backroom use this; every other link keeps the crossfade. */
html.pt-leaving-left,
html.pt-leaving-right,
html.pt-from-right,
html.pt-from-left {
  overflow-x: hidden; /* hide the off-screen half mid-slide (no scrollbar) */
}

/* The slide is applied to the body's content children, NOT to <body> itself,
   and the header + floating theme-switch wrapper are excluded — so those two
   stay pinned to the viewport while the rest of the page slides underneath. */
@media (prefers-reduced-motion: no-preference) {
  html.pt-leaving-left body > :not(.header):not(#theme-toggle) {
    animation: pt-to-left 600ms cubic-bezier(0.77, 0, 0.175, 1) both;
  }
  html.pt-leaving-right body > :not(.header):not(#theme-toggle) {
    animation: pt-to-right 600ms cubic-bezier(0.77, 0, 0.175, 1) both;
  }
  html.pt-from-right body > :not(.header):not(#theme-toggle) {
    animation: pt-from-right 600ms cubic-bezier(0.77, 0, 0.175, 1) both;
  }
  html.pt-from-left body > :not(.header):not(#theme-toggle) {
    animation: pt-from-left 600ms cubic-bezier(0.77, 0, 0.175, 1) both;
  }
}

@keyframes pt-to-left {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}
@keyframes pt-to-right {
  from { transform: translateX(0); }
  to   { transform: translateX(100%); }
}
@keyframes pt-from-right {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
@keyframes pt-from-left {
  from { transform: translateX(-100%); }
  to   { transform: translateX(0); }
}

/* Header stays put — like the theme-switch wrapper. Webflow's page-load
   interaction (IX2) slides the header down from translateY(-150%) on every
   load, so it re-drops after each page transition. Forcing the transform off
   with !important overrides the inline transform IX2 writes each frame, and
   also keeps the header visible despite its exported off-screen start state.
   The header is already excluded from the page slide, so this makes it truly
   static throughout. */
.header {
  transform: none !important;
}

/* Hero intro: each block slides in from OUTSIDE its own wrapper and is clipped
   by it (both .hero-text and .hero-image-wrapper already have overflow:hidden)
   — the text slides in from the left (left-to-right), the image from the right
   (right-to-left). No opacity change on the slide. The Webflow fly-ins are
   neutralised in the interaction data, and these start once the page slide has
   finished (600ms). */
@media (prefers-reduced-motion: no-preference) {
  .hero-text > * {
    animation: hero-text-in 700ms cubic-bezier(0.65, 0, 0.35, 1) 600ms both;
  }
  .hero-image {
    animation: hero-image-in 700ms cubic-bezier(0.65, 0, 0.35, 1) 600ms both;
  }
}

@keyframes hero-text-in {
  from { opacity: 0; transform: translateX(-100%); }
  to   { opacity: 1; transform: translateX(0); }
}

@keyframes hero-image-in {
  from { opacity: 0; transform: translateX(100%); }
  to   { opacity: 1; transform: translateX(0); }
}


/* 6. Utility pages (404 / 401) -------------------------------------------- */
/* Brand-matched layout: fixed header (as on the main pages), centred
   message, footer pinned to the bottom. The generated `.utility-page-wrap`
   rule hard-codes height:100vh; here it becomes the flexible middle row so
   the footer sits at the foot of the viewport rather than below the fold. */
body.utility-page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

body.utility-page .utility-page-wrap {
  flex: 1 0 auto;
  height: auto;
  min-height: 0;
  padding: var(--_responsive---page-spacing--page-gutter);
}

body.utility-page .utility-page-content {
  width: min(440px, 86vw);
  text-align: center;
  grid-row-gap: var(--_responsive---general-spacing--margin-x-5);
}

/* Big status code — centred, in the heading typeface and highlight colour. */
.utility-code {
  margin: 0 0 var(--_responsive---general-spacing--margin-x-25);
  font-family: var(--font-family--heading);
  color: var(--_theme---text--highlight);
  font-size: var(--_responsive---font-size--4x);
  line-height: 1;
  text-align: center;
}

/* Headings and body copy on these pages use the normal text colour. */
body.utility-page .utility-page-content h2 {
  color: var(--_theme---text--normal);
}

.utility-message {
  margin-top: var(--_responsive---general-spacing--margin-x-25);
  color: var(--_theme---text--normal);
  text-align: center;
}

/* "Back to home" link. Borders come from the `.border-effect` class (dashed
   → solid highlight on hover); here we only add the pill shape, spacing and
   text colour. */
.utility-home-button {
  align-self: center;
  margin-top: var(--_responsive---general-spacing--margin-x);
  padding: var(--_responsive---general-spacing--margin-x-5)
           var(--_responsive---general-spacing--margin-2x);
  border-radius: var(--_responsive---border-styles--radius-round);
  font-family: var(--font-family--paragraph);
  color: var(--_theme---text--normal);
  text-decoration: none;
  transition: color 200ms cubic-bezier(0.645, 0.045, 0.355, 1);
}

.utility-home-button:hover {
  color: var(--_theme---text--highlight);
}

/* 401 password form, matched to the theme. */
body.utility-page .utility-page-form label {
  margin-top: var(--_responsive---general-spacing--margin-x-5);
  color: var(--_theme---text--normal);
  font-family: var(--font-family--paragraph);
  text-align: left;
}

/* Field border comes from the `.border-effect` class; keep it transparent,
   rounded and themed, and warm the border to highlight on focus. */
body.utility-page .utility-page-form .w-input {
  margin-bottom: var(--_responsive---general-spacing--margin-x-5);
  background-color: #0000;
  border-radius: var(--_responsive---border-styles--radius-round);
  color: var(--_theme---text--normal);
  font-family: var(--font-family--paragraph);
}

body.utility-page .utility-page-form .w-input::placeholder {
  color: var(--_theme---text--mono-04);
}

body.utility-page .utility-page-form .w-input:focus {
  border-style: solid;
  border-color: var(--_theme---text--highlight);
  outline: none;
}

/* Submit button. Borders come from `.border-effect`; pill shape + text
   colour only. */
body.utility-page .utility-page-form .w-button {
  align-self: center;
  margin-top: var(--_responsive---general-spacing--margin-x-5);
  padding: var(--_responsive---general-spacing--margin-x-5)
           var(--_responsive---general-spacing--margin-2x);
  background-color: #0000;
  border-radius: var(--_responsive---border-styles--radius-round);
  font-family: var(--font-family--paragraph);
  color: var(--_theme---text--normal);
  transition: color 200ms cubic-bezier(0.645, 0.045, 0.355, 1);
}

body.utility-page .utility-page-form .w-button:hover {
  color: var(--_theme---text--highlight);
}

body.utility-page .utility-page-form .w-form-fail {
  margin-top: var(--_responsive---general-spacing--margin-x-5);
  color: var(--_theme---text--highlight);
}


/* 7. Accessibility -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .marquee-container,
  .card-carousel-track {
    animation-play-state: paused;
  }
}
