/* =====================================================================
   MAIN STYLESHEET
   ---------------------------------------------------------------------
   All values come from css/tokens.css. Sections in this file:

    1. Reset & base
    2. Layout helpers (container, 12-column grid, column widths)
    3. Shared components (eyebrow, section heading, dividers, tags,
       "Case Study" link, "See More" button, dots)
    4. Preloader
    5. Gradual blur + navbar + theme toggle
    6. Hero (intro, project list, auto-cycle progress, carousel, about text)
    7. Featured case studies
    8. Experience
    9. Testimonials
   10. Case studies list
   11. Tool stack
   12. Skillset
   13. More about me
   14. Footer
   15. Entrance animations
   16. Reduced motion

   Where px is used, a comment says why (only 1px hairlines and
   image size hints in the HTML).
   ===================================================================== */


/* =====================================================================
   1. RESET & BASE
   ===================================================================== */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Safety net: nothing on the page may create sideways scroll */
  overflow-x: clip;
}

body {
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-primary);
  font-family: var(--font-family);
  font-size: var(--fs-body);
  font-weight: var(--weight-regular);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
  transition: background-color var(--dur-base) ease, color var(--dur-base) ease;
}

/* While the preloader is showing, the page can't scroll */
html.is-loading body { overflow: hidden; }

img,
svg { display: block; max-width: 100%; }
img { height: auto; }

ul { list-style: none; padding: 0; }

a { color: inherit; text-decoration: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

strong { font-weight: var(--weight-bold); }

/* Keyboard focus ring (mouse clicks don't show it) */
:focus-visible {
  outline: 0.125rem solid var(--graphic-primary);
  outline-offset: 0.25rem;
  border-radius: 0.25rem;
}

/* The hidden <svg> that holds all icon symbols */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Text for screen readers only */
.visually-hidden {
  position: absolute !important;
  width: 1px;   /* px: standard technique, must not scale */
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 200;
  padding: var(--space-2) var(--space-4);
  background: var(--surface-tag);
  color: var(--text-strong);
  border-radius: var(--radius-tag);
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }


/* =====================================================================
   2. LAYOUT HELPERS
   ===================================================================== */

/* Centered content column with the breakpoint max-width (350 / 600 / 950 / 1200px) */
.container {
  width: min(100% - 2 * var(--page-pad), var(--container));
  margin-inline: auto;
  /* Lets children measure column widths with "cqw" (see .span-width) */
  container-type: inline-size;
}

/* 12-column grid. Children choose their columns with grid-column. */
.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
}

/* Width of N grid columns (set --cols on the element), for things that are
   not grid children but must line up with the grid, e.g. centered headings. */
.span-width,
.featured__head,
.skills__head {
  --cols: 12;
  width: calc(var(--cols) * (100cqw - 11 * var(--gutter)) / 12 + (var(--cols) - 1) * var(--gutter));
}

.page {
  position: relative;
  z-index: 1;
}

.section { padding-block: var(--section-pad); }
.section--alt { background: var(--surface-section); transition: background-color var(--dur-base) ease; }


/* =====================================================================
   3. SHARED COMPONENTS
   ===================================================================== */

/* ---- Section heading: eyebrow + title ---- */
.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--section-head-gap);
}
.section-head--center {
  margin-inline: auto;
  text-align: center;
}

.eyebrow {
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-label);
  color: var(--text-label);
}

.section-title {
  font-size: var(--fs-section-title);
  font-weight: var(--weight-bold);
  line-height: var(--lh-heading);
  color: var(--text-primary);
}

/* Pushes content down so its top lines up with the section TITLE (not the eyebrow).
   Used on large screens where the heading and content sit side by side. */
@media (min-width: 64rem) {
  .align-to-title {
    margin-top: calc(var(--fs-eyebrow) * var(--lh-label) + var(--space-1));
  }
}

/* ---- Horizontal divider ---- */
.divider {
  border: 0;
  border-top: 1px solid var(--graphic-secondary); /* px: hairline, rem can blur or vanish when zoomed */
}

/* ---- Tags ---- */
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.tag {
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-tag);
  background: var(--surface-tag);
  font-size: var(--fs-tag);
  line-height: var(--lh-label);
  color: var(--text-primary);
  transition: background-color var(--dur-base) ease;
}

/* ---- Hover underline (shared by "Case Study" links and "See More") ----
   A 1px line that grows from left to right under the label. */
.cta__label,
.see-more {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px; /* px: hairline */
  transition: background-size var(--dur-base) var(--ease-out), color var(--dur-fast) ease;
}

/* ---- "Case Study" link with arrow ---- */
.cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-cta);
  line-height: var(--lh-label);
  color: var(--text-primary);
}
.cta__arrow {
  width: 2.5rem;    /* 40px, as in Figma */
  height: 0.875rem;
  color: var(--graphic-primary);
  flex: none;
}

/* Arrow nudge: plays ONCE each time the link, its card image, or its list row is hovered */
@keyframes arrow-nudge {
  0%, 100% { transform: translateX(0); }
  45%      { transform: translateX(var(--space-2)); }
}
@media (hover: hover) {
  .cta:hover .cta__label,
  .cs-card:hover .cta__label,
  .project-item__link:hover .cta__label { background-size: 100% 1px; }

  .cta:hover .cta__arrow,
  .cs-card:hover .cta__arrow,
  .project-item__link:hover .cta__arrow {
    animation: arrow-nudge 0.7s var(--ease-in-out) 1;
  }
}

/* ---- "See More" / "See Less" ---- */
.see-more {
  margin-top: var(--space-6);
  font-size: var(--fs-see-more);
  font-weight: var(--weight-bold);   /* Label/Default/Bold */
  line-height: var(--lh-label);
  color: var(--text-label);
}
@media (hover: hover) {
  .see-more:hover { background-size: 100% 1px; color: var(--text-strong); }
}

/* Items marked data-extra stay hidden until their list is expanded */
.is-collapsed [data-extra] { display: none; }
/* …and fade in when it is */
.is-expanded [data-extra] { animation: fade-up var(--dur-slow) var(--ease-out) both; }

@keyframes fade-up {
  from { opacity: 0; transform: translateY(var(--space-3)); }
  to   { opacity: 1; transform: none; }
}

/* ---- Dots (testimonials) ---- */
.dots {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.dots__dot {
  width: 0.5rem;   /* 8px */
  height: 0.5rem;
  border-radius: var(--radius-pill);
  background: var(--graphic-secondary);
  transition: width var(--dur-base) var(--ease-out), height var(--dur-base) var(--ease-out), background-color var(--dur-base) ease;
}
.dots__dot.is-active {
  width: 0.875rem;  /* 14px */
  height: 0.875rem;
  background: var(--graphic-primary);
}
@media (hover: hover) {
  .dots__dot:not(.is-active):hover { background: var(--text-display); }
}


/* =====================================================================
   4. PRELOADER
   Two panels: the page-coloured front (logo + sliding bar) and a
   section-coloured back panel. Both slide out to the right, the back
   one a beat later, which gives the exit a little depth.
   ===================================================================== */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  display: none;
}
html.js .preloader { display: block; pointer-events: auto; }

.preloader__panel {
  position: absolute;
  inset: 0;
  transition: transform var(--dur-slow) var(--ease-in-out);
}
.preloader__panel--back { background: var(--surface-section); }
.preloader__panel--front {
  background: var(--surface-page);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
}

.preloader__logo {
  width: 5.5rem;
  height: auto;
  aspect-ratio: 133 / 69;
  color: var(--text-primary);   /* same as the navbar logo */
}

.preloader__bar {
  position: relative;
  width: 8rem;
  height: 0.25rem;
  border-radius: var(--radius-pill);
  background: var(--graphic-secondary);
  overflow: hidden;
}
.preloader__bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 50%;
  border-radius: inherit;
  background: var(--graphic-primary);
  animation: preloader-slide 1.5s linear infinite;
}
@keyframes preloader-slide {
  from { transform: translateX(-100%); }
  to   { transform: translateX(200%); }
}

/* Exit: added by JS once the page has loaded */
.preloader.is-done { pointer-events: none; }
.preloader.is-done .preloader__panel--front { transform: translateX(100%); }
.preloader.is-done .preloader__panel--back  { transform: translateX(100%); transition-delay: 0.12s; }
.preloader.is-gone { display: none !important; }

@media (min-width: 64rem) {
  .preloader__logo { width: 8rem; }
}


/* =====================================================================
   5. GRADUAL BLUR + NAVBAR + THEME TOGGLE
   ===================================================================== */

/* ---- Gradual blur ----
   Five stacked layers. Each blurs more than the last but covers a shorter
   band from the top, so the blur fades out smoothly downwards.
   Height follows the scroll state (JS sets data-nav on <html>):
   100% at the top, 90% while scrolling down, 120% while scrolling up. */
.top-blur {
  /* Base height = navbar + a little extra. Change the two multipliers to tune. */
  --blur-base: calc(var(--nav-height) + var(--space-5));
  --blur-height: var(--blur-base);              /* at the top of the page: 100% */
  position: fixed;
  inset: 0 0 auto;
  z-index: 20;
  height: var(--blur-height);
  pointer-events: none;
  transition: height 0.5s var(--ease-out);
}
html[data-nav="hidden"]  .top-blur { --blur-height: calc(var(--blur-base) * 0.9); }  /* scrolling down */
html[data-nav="visible"] .top-blur { --blur-height: calc(var(--blur-base) * 1.2); }  /* scrolling up */

/* Tint in the page colour (dark or light), strongest at the very top, so the
   navbar stays readable over any text scrolling underneath */
.top-blur::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
              color-mix(in srgb, var(--surface-page) 85%, transparent) 0%,
              color-mix(in srgb, var(--surface-page) 55%, transparent) 45%,
              transparent 100%);
  transition: background-color var(--dur-base) ease;
}

/* Light mode: a stronger page-colour tint, so text scrolling underneath
   doesn't compete with the navbar. Many small stops make an eased fade
   with no visible "corner" in the middle. */
:root[data-theme="light"] .top-blur::before {
  background: linear-gradient(to bottom,
              color-mix(in srgb, var(--surface-page) 97%, transparent) 0%,
              color-mix(in srgb, var(--surface-page) 94%, transparent) 15%,
              color-mix(in srgb, var(--surface-page) 88%, transparent) 30%,
              color-mix(in srgb, var(--surface-page) 78%, transparent) 45%,
              color-mix(in srgb, var(--surface-page) 62%, transparent) 60%,
              color-mix(in srgb, var(--surface-page) 45%, transparent) 72%,
              color-mix(in srgb, var(--surface-page) 24%, transparent) 84%,
              color-mix(in srgb, var(--surface-page) 9%, transparent) 93%,
              transparent 100%);
}

/* Light mode: a faint grain over the tint. Near-white fades only have a few
   grey levels to work with (#FBFBFB → #FFFFFF has 4), which show as stripes;
   the grain breaks the stripes up. It's too faint to read as texture. */
:root[data-theme="light"] .top-blur::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Inline SVG noise tile (160px is the tile's own size, not a layout value) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.035;
  mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%);
}

.top-blur__layer {
  position: absolute;
  inset: 0;
}
.top-blur__layer:nth-child(1) { backdrop-filter: blur(0.0625rem); -webkit-backdrop-filter: blur(0.0625rem); mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%); -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%); }
.top-blur__layer:nth-child(2) { backdrop-filter: blur(0.125rem);  -webkit-backdrop-filter: blur(0.125rem);  mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 80%);  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 80%); }
.top-blur__layer:nth-child(3) { backdrop-filter: blur(0.25rem);   -webkit-backdrop-filter: blur(0.25rem);   mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 60%);  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 60%); }
.top-blur__layer:nth-child(4) { backdrop-filter: blur(0.5rem);    -webkit-backdrop-filter: blur(0.5rem);    mask-image: linear-gradient(to bottom, #000 0%, #000 15%, transparent 40%);  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 15%, transparent 40%); }
.top-blur__layer:nth-child(5) { backdrop-filter: blur(1rem);      -webkit-backdrop-filter: blur(1rem);      mask-image: linear-gradient(to bottom, #000 0%, transparent 20%);            -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 20%); }

/* ---- Navbar ----
   Hides while scrolling down, comes back when scrolling up. */
.navbar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 30;
  padding-top: var(--nav-pad-top);
  padding-bottom: var(--nav-pad-bottom);
  transition: transform 0.5s var(--ease-out);
}
html[data-nav="hidden"] .navbar { transform: translateY(-100%); }

.navbar__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}
.navbar__logo {
  grid-column: 2;
  color: var(--text-primary);
}
.logo {
  height: var(--logo-height);
  width: auto;
  aspect-ratio: 133 / 69;
}

/* ---- Light / Dark toggle ---- */
.theme-toggle {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.3em;
  font-size: var(--fs-toggle);
  line-height: var(--lh-label);
  color: var(--text-display);
  /* Generous tap area on small screens (whole toggle is the button there) */
  min-height: 2.75rem;
  padding-inline: var(--space-2);
  margin-right: calc(-1 * var(--space-2));
  cursor: pointer;
}
.theme-toggle__option {
  display: inline-flex;
  flex-direction: column;
  text-align: center;
  color: var(--text-display);
  transition: color var(--dur-fast) ease;
}
/* Reserve the bold width so switching weight doesn't shift the text */
.theme-toggle__option::after {
  content: attr(data-label);
  font-weight: var(--weight-bold);
  height: 0;
  visibility: hidden;
  overflow: hidden;
}
.theme-toggle__option[aria-pressed="true"] {
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  cursor: default;
}
@media (hover: hover) {
  .theme-toggle__option[aria-pressed="false"]:hover { color: var(--text-strong); }
}
/* Small & medium: hovering anywhere on the toggle highlights the inactive word */
@media (hover: hover) and (max-width: 63.999rem) {
  .theme-toggle:hover .theme-toggle__option[aria-pressed="false"] { color: var(--text-strong); }
}
@media (min-width: 64rem) {
  .theme-toggle { cursor: auto; }
}


/* =====================================================================
   6. HERO
   ===================================================================== */
/* No bottom padding: the featured section follows closely so its heading
   shows at the bottom of taller screens (see .featured below). */
.hero {
  padding-top: calc(var(--nav-height) + var(--space-6));
  padding-bottom: 0;
}
.hero__grid { row-gap: var(--space-5); }

.hero__intro,
.hero__media { grid-column: 1 / -1; }

.hero__greeting,
.hero__title {
  font-size: var(--fs-intro);
  font-weight: var(--weight-regular);
  line-height: var(--lh-heading);
  color: var(--text-secondary);
}
.hero__title { margin-top: var(--space-1); }
.hero__title strong { color: var(--text-primary); }


/* ---- Project type list ----
   Small screens: one horizontally scrolling row that runs edge to edge.
   Large screens: a vertical list. */
.hero-list {
  display: flex;
  gap: var(--space-5);
  margin-top: var(--space-5);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  /* stays inside the content width */
  /* fade on the right edge only (hints that the row scrolls) */
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - var(--space-5)), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - var(--space-5)), transparent 100%);
}
.hero-list::-webkit-scrollbar { display: none; }
.hero-list li { flex: none; scroll-snap-align: start; }
.hero-list__line { display: none; }   /* large screens only (see below) */

.hero-list__item {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  text-align: left;
  padding-block: var(--space-1);
  font-size: var(--fs-hero-list);
  line-height: var(--lh-label);
  color: var(--text-display);
  white-space: nowrap;
  transition: color var(--dur-fast) ease, transform var(--dur-base) var(--ease-out);
}
/* Reserve the bold width so selecting an item doesn't shift its neighbours */
.hero-list__item::after {
  content: attr(data-label);
  font-weight: var(--weight-bold);
  height: 0;
  visibility: hidden;
  overflow: hidden;
}
.hero-list__item[aria-pressed="true"] {
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

/* ---- Auto-cycle progress ----
   A track at 50% opacity, filled at full opacity as the timer runs.
   Small/medium: an underline under the selected item. Large: the line beside it.
   JS adds .is-progressing to the active indicator to start the fill, and
   data-paused on the hero to freeze it. Without cycling the fill stays full. */
.hero-list__item[aria-pressed="true"]::before,
.hero-list__line {
  background-color: color-mix(in srgb, var(--text-secondary) 50%, transparent);
  background-image: linear-gradient(var(--text-secondary), var(--text-secondary));
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 100% 100%;
}
.hero-list__item[aria-pressed="true"]::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0.125rem;   /* 2px */
  border-radius: var(--radius-pill);
}
.hero-list__item.is-progressing::before,
.hero-list__line.is-progressing {
  animation: hero-progress var(--cycle-duration, 6s) linear both;
}
.hero[data-paused] .is-progressing,
.hero[data-paused] .is-progressing::before {
  animation-play-state: paused;
}
@keyframes hero-progress {
  from { background-size: 0% 100%; }
  to   { background-size: 100% 100%; }
}
@media (hover: hover) {
  .hero-list__item:hover { color: var(--text-strong); }
  /* Small nudge to the right hints that items are clickable */
  .hero-list__item:hover:not([aria-pressed="true"]) { transform: translateX(var(--space-2)); }
}

/* ---- Carousel ---- */
.hero-carousel {
  --slide-gap: var(--space-3);
  position: relative;
  aspect-ratio: 15 / 8;          /* image ratio 16:10 cropped by 15% */
  border-radius: var(--radius-image);
  overflow: hidden;
  isolation: isolate;
  touch-action: pan-y;            /* small screens: vertical swipes still scroll the page */
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
  background: var(--surface-tag);
}
.hero-carousel.is-dragging { cursor: grabbing; }

/* The strip of all slides. JS moves it with --offset (slide index) and --drag (px while dragging). */
.hero-carousel__track {
  --offset: 0;
  --drag: 0px;
  position: absolute;
  inset: 0;
  display: flex;
  gap: var(--slide-gap);
  transform: translate3d(calc(var(--offset) * -1 * (100% + var(--slide-gap)) + var(--drag)), 0, 0);
  transition: transform var(--carousel-duration, 0.9s) var(--ease-in-out);
  will-change: transform;
}
.hero-carousel.is-dragging .hero-carousel__track { transition: none; }

.hero-slide {
  position: relative;
  flex: 0 0 100%;
  overflow: hidden;
  border-radius: var(--radius-image);
}
.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focus, center);
  -webkit-user-drag: none;
  /* Slides that are not active sit slightly zoomed in and dimmed… */
  transform: scale(1.08);
  filter: brightness(0.6) saturate(0.8);
  transition: transform 1.2s var(--ease-out), filter 0.9s ease;
}
/* …and the active one settles into place */
.hero-slide.is-active img {
  transform: scale(1);
  filter: none;
}

/* Dots inside the image: along the bottom on small screens */
.hero-carousel__dots {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: var(--space-3);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0;
  padding: var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--overlay-on-image);
  backdrop-filter: blur(0.5rem);
  -webkit-backdrop-filter: blur(0.5rem);
}
.hero-dot {
  display: grid;
  place-items: center;
  width: 0.75rem;
  height: 0.75rem;
}
.hero-dot::before {
  content: "";
  width: 0.3125rem;   /* 5px */
  height: 0.3125rem;
  border-radius: var(--radius-pill);
  background: var(--dot-on-image);
  opacity: 0.45;
  transition: width var(--dur-base) var(--ease-out), height var(--dur-base) var(--ease-out), opacity var(--dur-base) ease;
}
.hero-dot.is-active { width: 1.25rem; }
.hero-dot.is-active::before { width: 1rem; opacity: 1; }
@media (hover: hover) {
  .hero-dot:hover::before { opacity: 0.8; }
}

/* ---- About text under the image ---- */
.hero__about {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin-top: var(--space-6);
  font-size: var(--fs-hero-support);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}
/* Facts box: same highlight gradient as the case studies (hero sits on Surface/Page) */
.hero__facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  border-radius: var(--radius-card);
  background: linear-gradient(to right, var(--surface-tag), var(--surface-page));
}

/* ---- Large screens: side by side, vertical carousel ---- */
@media (min-width: 64rem) {
  .hero { padding-top: calc(var(--nav-height) + var(--space-7)); }

  .hero__intro {
    grid-column: 1 / span 5;
    display: flex;
    flex-direction: column;
  }
  /* Image top lines up with the "I am Apurba…" line, not the greeting */
  .hero__media { grid-column: 7 / span 6; margin-top: calc(var(--fs-intro) * var(--lh-heading) + var(--space-1)); }


  /* Same look as the case study side menu: a line marks the selected item.
     Line: half a column (64-80rem) or one column (80rem+), then a gutter,
     then the items. */
  .hero-list {
    --col: calc((100cqw - 11 * var(--gutter)) / 12);
    --line-w: calc(var(--col) / 2);
    position: relative;
    flex-direction: column;
    gap: var(--space-1);
    margin-top: var(--space-6);
    margin-inline: 0;
    padding-inline: calc(var(--line-w) + var(--gutter)) 0;
    overflow: visible;
    mask-image: none;
    -webkit-mask-image: none;
  }
  .hero-list__item { padding-block: 0; }
  .hero-list__item[aria-pressed="true"]::before { content: none; }   /* the line takes over */

  /* The line. JS sets --line-y to the selected item's middle. */
  .hero-list__line {
    --line-y: 0px;
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: var(--line-w);
    height: 0.25rem;   /* 4px, same as the case study menu */
    border-radius: var(--radius-pill);
    transform: translateY(var(--line-y));
    transition: transform var(--dur-base) var(--ease-out);
    pointer-events: none;
  }

  .hero-carousel { touch-action: pan-x; }   /* vertical drags move the carousel */
  .hero-carousel__track {
    flex-direction: column;
    transform: translate3d(0, calc(var(--offset) * -1 * (100% + var(--slide-gap)) + var(--drag)), 0);
  }

  /* Dots along the right edge, stacked */
  .hero-carousel__dots {
    left: auto;
    right: var(--space-4);
    bottom: auto;
    top: 50%;
    transform: translateY(-50%);
    flex-direction: column;
  }
  .hero-dot.is-active { width: 0.75rem; height: 1.25rem; }
  .hero-dot.is-active::before { width: 0.3125rem; height: 1rem; }
}

/* XL: the line takes a whole column, as in the case study menu */
@media (min-width: 80rem) {
  .hero-list { --line-w: var(--col); }
}


/* =====================================================================
   7. FEATURED CASE STUDIES
   Large: label (col 1) · text (cols 2-6) · image (cols 7-12)
   Small/medium: image, label, text stacked.
   ===================================================================== */
.featured__head { --cols: 12; }
/* Gap after the hero = the gap between this section's heading and the first
   case study (smaller than other section gaps, so the next section shows
   below the hero on taller screens). */
.featured.section { padding-top: var(--section-head-gap); }

/* Whole card is clickable: the "Case Study" link stretches over the card.
   The image link sits above it so its tilt still follows the mouse.
   On hover the card gets a rounded Surface/Section background. The padding
   and the negative margin are always there, so nothing moves on hover:
   the background reaches a little past the content, the text stays on the grid. */
.featured__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}
.cs-card {
  --card-bleed: var(--space-5);
  position: relative;
  row-gap: var(--space-5);
  align-items: start;
  margin-inline: calc(-1 * var(--card-bleed));
  padding: var(--card-bleed);
  margin-block: calc(-1 * var(--card-bleed));
  border-radius: calc(var(--radius-image) + var(--space-2));
  transition: background-color var(--dur-base) ease;
}
.cs-card .cta::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.cs-card__media { position: relative; z-index: 1; }
.cs-card .cta:focus-visible { outline: none; }
.cs-card:has(.cta:focus-visible) {
  outline: 2px solid var(--text-primary); /* px: focus ring */
  outline-offset: 2px;
}
@media (hover: hover) {
  .cs-card:hover { background: var(--surface-section); }
}
.cs-card__media,
.cs-card__label,
.cs-card__body { grid-column: 1 / -1; }

.cs-card__media {
  display: block;
  border-radius: var(--radius-image);
}

/* 3D tilt on hover (case-study images + tool stack image).
   JS sets --tilt-x / --tilt-y in degrees while the mouse moves over it. */
[data-tilt] {
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  --tilt-scale: 1;
  transform: perspective(60rem) rotateX(var(--tilt-y)) rotateY(var(--tilt-x)) scale(var(--tilt-scale));
  transition: transform 0.6s var(--ease-out);
  will-change: transform;
}
[data-tilt].is-tilting { transition: transform 0.15s linear; }
.cs-card__media img {
  width: 100%;
  border-radius: var(--radius-image);
}

.cs-card__label {
  white-space: nowrap;  /* may run into the gutter at 64-80rem, never into the text */
  font-size: var(--fs-cs-label);
  line-height: var(--lh-label);
  color: var(--text-secondary);
}

.cs-card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
.cs-card__role {
  font-size: var(--fs-cs-role);
  font-style: italic;
  line-height: var(--lh-label);
  color: var(--text-primary);
}
.cs-card__title {
  font-size: var(--fs-cs-title);
  font-weight: var(--weight-bold);
  line-height: var(--lh-heading);
  color: var(--text-primary);
}
.cs-card__text {
  font-size: var(--fs-cs-text);
  line-height: var(--lh-body);
  color: var(--text-primary);
}
.cs-card__metric {
  font-size: var(--fs-cs-metric);
  font-weight: var(--weight-bold);
  line-height: var(--lh-label);
  color: var(--text-primary);
}
.cs-card .cta { margin-top: var(--space-6); }


@media (min-width: 64rem) {
  .featured__head { --cols: 6; }

  .cs-card__label { grid-column: 1;          grid-row: 1; }
  .cs-card__body  { grid-column: 2 / span 5; grid-row: 1; }
  .cs-card__media { grid-column: 7 / span 6; grid-row: 1; }

  .featured__list { gap: var(--space-9); }
  .cs-card { --card-bleed: var(--space-6); }
}


/* =====================================================================
   8. EXPERIENCE
   Small & medium: a simple list (first 4 shown until "See More").
   Large and up: table rows, date (3 cols) · company + role (6) · location (3).
   (At medium width the 3-column date/location cells are too narrow for
   "2024 - Now" or "Kathmandu, Nepal", so medium follows the list layout.)
   ===================================================================== */
.experience__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.exp-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--fs-exp-line);
  line-height: var(--lh-label);
  color: var(--text-primary);
}
.exp-row__date {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.status-dot {
  width: 0.75rem;    /* 12px (14px from 64rem) */
  height: 0.75rem;
  border-radius: 50%;
  background: var(--status-available);
  flex: none;
}
.exp-row__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.exp-row__company {
  font-size: var(--fs-exp-company);
  font-weight: var(--weight-bold);
}

.experience__divider { margin-block: var(--space-5); }

/* Medium: two columns, date (3 cols) · company, role and location stacked (9 cols) */
@media (min-width: 48rem) and (max-width: 63.999rem) {
  .exp-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gutter);
    row-gap: var(--space-1);
    align-items: start;
  }
  .exp-row__date  { grid-column: 1 / span 3; grid-row: 1 / span 2; }
  .exp-row__main,
  .exp-row__place { grid-column: 4 / span 9; }
}

/* Medium+: "See More" lines up with the company column (column 4) */
@media (min-width: 48rem) {
  .experience__toggle {
    margin-left: calc(3 * (100cqw - 11 * var(--gutter)) / 12 + 3 * var(--gutter));
  }
}

/* Large screens: table layout */
@media (min-width: 64rem) {
  .experience__group { gap: var(--space-5); }

  .exp-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gutter);
    align-items: start;
  }
  .exp-row__date  { grid-column: 1 / span 3; }
  .exp-row__main  { grid-column: 4 / span 6; }
  .exp-row__place { grid-column: 10 / span 3; text-align: right; }

  .status-dot { width: 0.875rem; height: 0.875rem; }  /* 14px, as in Figma */
  .experience__divider { margin-block: var(--space-5); }

}


/* =====================================================================
   9. TESTIMONIALS
   Large: heading (cols 1-5) · quotes (cols 7-12, top-aligned with the title)
   ===================================================================== */
.testimonials__head,
.quote-slider { grid-column: 1 / -1; }

.quote-slider { overflow-x: clip; }  /* hidden quotes wait just off to the side */
.quote-slider__track {
  display: grid;           /* all quotes share one cell, so the height never jumps */
}
.quote {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  opacity: 0;
  visibility: hidden;
  transform: translateX(var(--space-6));
  transition: opacity 0.7s ease, transform 0.9s var(--ease-out), visibility 0s linear 0.9s;
}
.quote.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.7s ease 0.15s, transform 0.9s var(--ease-out) 0.15s, visibility 0s;
}
.quote.is-leaving { transform: translateX(calc(-1 * var(--space-6))); }

.quote__text {
  font-size: var(--fs-quote);
  line-height: var(--lh-body);
  color: var(--text-primary);
}
.quote__by {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  line-height: var(--lh-label);
}
.quote__name {
  font-size: var(--fs-quote-name);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}
.quote__role {
  font-size: var(--fs-quote-role);
  color: var(--text-secondary);
}
.quote-slider__dots { margin-top: var(--space-5); }

@media (min-width: 64rem) {
  .testimonials__head { grid-column: 1 / span 5; margin-bottom: 0; }
  .quote-slider       { grid-column: 7 / span 6; }
  .quote              { gap: var(--space-7); }
}


/* =====================================================================
   10. CASE STUDIES LIST
   Large: heading (cols 1-4) · gap · list (cols 6-12)
   ===================================================================== */
.projects__head,
.projects__body { grid-column: 1 / -1; }

.projects__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.projects__list { width: 100%; }

/* No lines between items: a little space, and a rounded Surface/Page
   background on hover (the list sits on Surface/Section). The padding and
   negative margin are always there, so nothing moves on hover. */
.projects__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
/* Each item: title + tags on the left, arrow on the right, aligned with the title's first line.
   The "Case Study" word is hidden visually (still read by screen readers). */
.project-item__link {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--space-5);
  align-items: start;
  padding: var(--space-5);
  margin-inline: calc(-1 * var(--space-5));
  border-radius: var(--radius-card);
  transition: background-color var(--dur-base) ease;
}
/* First item's text stays level with the heading, as before */
.project-item:first-child .project-item__link { margin-top: calc(-1 * var(--space-5)); }

.project-item__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.project-item__title {
  font-size: var(--fs-list-title);
  font-weight: var(--weight-bold);
  line-height: var(--lh-label);
  color: var(--text-primary);
  transition: color var(--dur-fast) ease;
}
.project-item__skills {
  font-size: var(--fs-list-sub);
  line-height: var(--lh-label);
  color: var(--text-secondary);
}
/* Centre the arrow on the title's first line */
.project-item__link .cta {
  margin-top: calc((var(--fs-list-title) * var(--lh-label) - 0.875rem) / 2);
}
.project-item__link .cta__label {
  position: absolute;
  width: 1px;  /* px: screen-reader-only pattern */
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
@media (hover: hover) {
  .project-item__link:hover { background: var(--surface-page); }
  .project-item__link:hover .project-item__title { color: var(--text-strong); }
}
/* Small screens show 3 items before "See More" (larger screens show 4) */
@media (max-width: 47.999rem) {
  .is-collapsed [data-extra-small] { display: none; }
}

@media (min-width: 64rem) {
  .projects__head { grid-column: 1 / span 4; margin-bottom: 0; }
  .projects__body { grid-column: 6 / span 7; align-items: flex-end; }

}


/* =====================================================================
   11. TOOL STACK
   Large: text (cols 1-5) · gap · image (cols 7-11) · empty col 12
   Small: centered, image between title and text.
   ===================================================================== */
.toolstack__head,
.toolstack__text,
.toolstack__media { grid-column: 1 / -1; }

.toolstack__head { text-align: center; margin-bottom: var(--space-6); }
.toolstack__media { grid-row: 2; }
@media (min-width: 48rem) and (max-width: 63.999rem) {
  .toolstack__media { grid-column: 3 / span 8; }   /* tablet: 8 centered columns */
}
.toolstack__image { width: 100%; }
.toolstack__text {
  grid-row: 3;
  display: flex;
  flex-direction: column;
  gap: 1.6em;  /* one empty line between paragraphs, as in Figma */
  margin-top: var(--space-6);
  font-size: var(--fs-toolstack);
  line-height: var(--lh-body);
  text-align: center;
  color: var(--text-primary);
}

@media (min-width: 64rem) {
  .toolstack__grid { align-items: center; }
  .toolstack__head  { grid-column: 1 / span 5; grid-row: 1; text-align: left; margin-bottom: 0; align-self: end; }
  .toolstack__text  { grid-column: 1 / span 5; grid-row: 2; text-align: left; margin-top: var(--space-5); align-self: start; }
  .toolstack__media { grid-column: 7 / span 5; grid-row: 1 / span 2; }
}


/* =====================================================================
   12. SKILLSET
   Large: heading (10 cols, centered) · row of 3 cards + row of 2 centered cards
   Medium: 2 per row (last one centered). Small: one per row.
   Cards in the same row share a height.
   ===================================================================== */
.skills__head { --cols: 12; }

.skills__grid {
  row-gap: var(--space-6);    /* cards are as tall as their content; on large screens cards in a row share a height */
}

.skill-card {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-start;
  gap: var(--space-5);
  padding: var(--space-5);
  border: 1px solid var(--graphic-secondary); /* px: hairline */
  border-radius: var(--radius-card);
  color: var(--text-label);
  transition: background-color var(--dur-base) ease, border-color var(--dur-base) ease;
}
@media (hover: hover) {
  .skill-card:hover { background: var(--surface-page); }
}

/* Icon tile: page-coloured square with the icon in Graphic/Primary (decorative) */
.skill-card__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 4.6875rem;   /* 75px, as in Figma */
  height: 4.6875rem;
  border-radius: var(--radius-icon);
  border: 0.1875rem solid var(--surface-section); /* 3px. Shows once the card turns page-coloured on hover */
  background: var(--surface-page);
  color: var(--graphic-primary);
  transition: background-color var(--dur-base) ease, border-color var(--dur-base) ease;
}
.skill-card__icon svg { width: 2.5rem; height: 2.5rem; }

.skill-card__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-skill);
  line-height: var(--lh-body);
}
.skill-card__title {
  font-size: var(--fs-skill);
  font-weight: var(--weight-bold);
  line-height: var(--lh-label);
}

@media (min-width: 48rem) {
  .skill-card { grid-column: span 6; }
  .skill-card:last-child { grid-column: 4 / span 6; }
}

@media (min-width: 64rem) {
  .skills__head { --cols: 10; }
  .skill-card--row1 { grid-column: span 4; }
  .skill-card--row2:nth-child(4) { grid-column: 3 / span 4; }
  .skill-card--row2:nth-child(5) { grid-column: 7 / span 4; }
}


/* =====================================================================
   13. MORE ABOUT ME
   Large: text (cols 1-6) · gap · image (cols 8-12, top-aligned with the body text)
   Small: heading, image, text.
   The journey list follows the experience rows: date on the left from 48rem.
   ===================================================================== */
.about__head,
.about__media,
.about__text { grid-column: 1 / -1; }

.about__head  { margin-bottom: var(--space-6); text-align: left; }
.about__media { margin-bottom: var(--space-6); }
.about__img   { display: block; width: 100%; height: auto; }

.about__text {
  font-size: var(--fs-bio);
  line-height: var(--lh-body);
  color: var(--text-primary);
}

.journey {
  list-style: none;
  padding: 0;
  margin-block: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.journey__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.journey__date {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  line-height: var(--lh-label);
  color: var(--text-secondary);
}
.journey__title {
  font-weight: var(--weight-bold);
  line-height: var(--lh-label);
  margin-bottom: var(--space-1);
}
.journey__tags { margin-top: var(--space-2); color: var(--text-secondary); }

/* Medium+: date in its own column, title and text beside it */
@media (min-width: 48rem) {
  .journey__item {
    display: grid;
    grid-template-columns: 7.5rem minmax(0, 1fr);
    column-gap: var(--gutter);
    align-items: start;
  }
}

@media (min-width: 64rem) {
  .about__head  { grid-column: 1 / span 6; grid-row: 1; margin-bottom: var(--space-6); }
  .about__text  { grid-column: 1 / span 6; grid-row: 2; }
  .about__media { grid-column: 8 / span 5; grid-row: 2; margin-bottom: 0; align-self: start; }
}


/* =====================================================================
   14. FOOTER
   ===================================================================== */
.footer {
  position: relative;
  z-index: 1;
  padding-top: var(--section-pad);
  padding-bottom: var(--space-7);
}
.footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}
.footer__logo {
  width: 4.8125rem;  /* 77px, as in Figma */
  height: auto;
  aspect-ratio: 133 / 69;
  color: var(--text-label);
}
.footer__copy {
  font-size: var(--fs-body);  /* Body/Default */
  line-height: var(--lh-body);
  color: var(--text-label);   /* same as the footer logo */
}


/* =====================================================================
   15. ENTRANCE ANIMATIONS
   Elements with data-reveal fade up gently the first time they scroll
   into view. JS adds .is-revealed (and a small stagger delay).
   Without JS everything is simply visible.
   ===================================================================== */
html.js [data-reveal] {
  opacity: 0;
  transform: translateY(var(--space-5));
  transition: opacity 0.9s ease var(--reveal-delay, 0s), transform 1.1s var(--ease-out) var(--reveal-delay, 0s);
}
html.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}
/* The case-study image keeps its own tilt transform once revealed */
html.js .cs-card[data-reveal].is-revealed { transform: none; }


/* =====================================================================
   16. REDUCED MOTION
   For visitors who asked their device for less motion: no pulsing,
   no parallax, no sliding; changes become quick fades.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  html.js [data-reveal] { transform: none; transition: opacity 0.3s ease; }
  .hero-carousel__track { transition-duration: 0.01ms !important; }
  .hero-slide img { transform: none; transition: filter 0.3s ease; }
  [data-tilt] { transform: none !important; }
  .quote, .quote.is-active, .quote.is-leaving { transform: none; }
  .preloader__bar-fill { animation: none; transform: translateX(50%); }
}
