/* ==========================================================================
   home.css — Home page only: hero, services, projects, stack, CTA.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: calc(100dvh - var(--header-h));
  display: flex;
  align-items: center;
  overflow: hidden;
}


.hero-inner {
  position: relative;
  z-index: 1;
  padding-block: var(--sp-8);
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.8fr);
  align-items: center;
  gap: clamp(var(--sp-6), 5vw, var(--sp-8));
}

.hero-content {
  max-width: 680px;
  display: grid;
  gap: var(--sp-5);
  justify-items: start;
}

/* Animated "what I build" stack — adapted from the supplied reference. */
.build-motion {
  width: min(100%, 430px);
  justify-self: end;
  padding: clamp(2rem, 4vw, 3.25rem) clamp(1.5rem, 3vw, 2.5rem);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--r-lg);
  background: #1D191B;
  box-shadow: var(--shadow-lg);
}

.build-motion-list {
  display: grid;
  gap: 10px;
  align-items: start;
}

.build-motion-row {
  display: grid;
  grid-template-columns: clamp(42px, 5vw, 58px) auto;
  width: max-content;
  max-width: 100%;
  min-height: clamp(54px, 5.4vw, 68px);
  overflow: hidden;
  font-family: var(--font-display);
  font-size: clamp(1.55rem, 2.5vw, 2.25rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.035em;
}

.build-motion-row:first-child {
  margin-left: clamp(22px, 4vw, 48px);
}

.build-motion-marker,
.build-motion-label {
  position: relative;
  display: grid;
  place-items: center;
}

.build-motion-marker {
  background: var(--tone);
  animation: build-marker-cycle 8s var(--ease-out) infinite;
  animation-delay: var(--row-delay);
}

.build-motion-marker i {
  width: clamp(14px, 1.7vw, 20px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in srgb, var(--tone) 36%, #171315);
  animation: build-dot-cycle 8s var(--ease-out) infinite;
  animation-delay: var(--row-delay);
}

.build-motion-label {
  z-index: 0;
  justify-items: start;
  padding-inline: clamp(18px, 2.4vw, 28px);
  white-space: nowrap;
  color: #1D191B;
  background: #FAF9F9;
  animation: build-text-cycle 8s var(--ease-out) infinite;
  animation-delay: var(--row-delay);
}

.build-motion-label::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--tone);
  clip-path: inset(0 100% 0 0);
  animation: build-fill-cycle 8s var(--ease-out) infinite;
  animation-delay: var(--row-delay);
}

@keyframes build-fill-cycle {
  0%    { clip-path: inset(0 100% 0 0); }
  5%,
  20%   { clip-path: inset(0 0 0 0); }
  25%,
  100%  { clip-path: inset(0 0 0 100%); }
}

@keyframes build-text-cycle {
  0%,
  2%    { color: #1D191B; }
  7%,
  22%   { color: #FFFFFF; }
  25%,
  100%  { color: #1D191B; }
}

@keyframes build-marker-cycle {
  0%,
  2%    { background: var(--tone); }
  7%,
  22%   { background: color-mix(in srgb, var(--tone) 38%, #171315); }
  25%,
  100%  { background: var(--tone); }
}

@keyframes build-dot-cycle {
  0%,
  2%    { background: color-mix(in srgb, var(--tone) 36%, #171315); }
  7%,
  22%   { background: var(--tone); }
  25%,
  100%  { background: color-mix(in srgb, var(--tone) 36%, #171315); }
}

/* Sized so the headline holds its two authored lines instead of rewrapping;
   `balance` would break line 2 early, so opt out of it here. */
.hero-title {
  font-size: clamp(2.2rem, 1.3rem + 3.4vw, 3.6rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: 0.02em;
  text-wrap: initial;
}

/* Headline highlights — one hue per emphasised word */
.hl-green  {
  color: var(--hl-green);
  -webkit-text-fill-color: var(--hl-green);
}

.hl-violet {
  color: var(--hl-violet);
  -webkit-text-fill-color: var(--hl-violet);
}

.hero-sub {
  font-size: 1.05rem;
  max-width: 46ch;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

/* Stats strip */
.hero-stats {
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: var(--sp-5) var(--sp-6);
  margin-top: var(--sp-3);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  width: 100%;
}

.hero-stats dt {
  font-size: var(--fs-xs);
  color: var(--text-3);
  order: 2;
}

.hero-stats dd {
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  order: 1;
}

.hero-stats > div {
  display: grid;
}

/* Scroll cue */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--sp-5);
  transform: translateX(-50%);
  z-index: 1;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  color: var(--text-2);
  transition: transform var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.scroll-cue:hover {
  transform: translateX(-50%) translateY(3px);
  color: var(--text);
}

.scroll-cue svg {
  width: 16px;
  height: 16px;
}

/* --------------------------------------------------------------------------
   2. SECTION HEADS
   -------------------------------------------------------------------------- */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}

.section .eyebrow {
  margin-bottom: var(--sp-3);
}

/* --------------------------------------------------------------------------
   3. OPEN SOURCE — GitHub repo cards
   The head and grid sit straight on the page — the cards' own borders are
   the only ones in the section. Each card is a stretched link: the anchor
   covers the whole card via ::after, so the tags and meta stay plain text
   but the entire card is one click target.
   -------------------------------------------------------------------------- */

.repos-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}

/* The panel's eyebrow drops the leading rule and takes the accent colour */
.eyebrow-bare {
  color: var(--accent-strong);
  margin-bottom: var(--sp-2);
}

.eyebrow-bare::before {
  content: none;
}

.repos-head h2 {
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2rem);
}

.repos-all {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
  padding-bottom: 0.25rem;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-2);
  transition: color var(--dur-fast) var(--ease-out);
}

.repos-all:hover {
  color: var(--text);
}

.gh-mark {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  transition: color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-snap);
}

/* ---- Grid ---- */
.repo-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4);
}

.repo-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  padding: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-elevated);
  transition: border-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-snap),
              background-color var(--dur-base) var(--ease-out);
}

.repo-card::before {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  pointer-events: none;
  height: 3px;
  background: linear-gradient(90deg, var(--repo-color), transparent 88%);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 520ms var(--ease-out);
}

.repo-card::after {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  top: -90px;
  right: -72px;
  width: 210px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--repo-soft) 0 32%, transparent 70%);
  opacity: 0;
  transform: translate(26px, -20px) scale(0.55);
  transition: opacity var(--dur-base) var(--ease-out),
              transform 620ms var(--ease-snap);
}

.repo-card > * {
  z-index: 1;
}

.repo-card:hover,
.repo-card:focus-within {
  border-color: color-mix(in srgb, var(--repo-color) 46%, var(--line));
  background-color: color-mix(in srgb, var(--repo-soft) 25%, var(--bg-elevated));
  box-shadow: 0 20px 42px -26px color-mix(in srgb, var(--repo-color) 65%, transparent);
  transform: translateY(-5px) rotate(var(--repo-lean));
}

.repo-card:hover::before,
.repo-card:focus-within::before {
  transform: scaleX(1);
}

.repo-card:hover::after,
.repo-card:focus-within::after {
  opacity: 1;
  transform: translate(0) scale(1);
}

/* ---- Title row ---- */
.repo-link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Stretch the anchor over the whole card. Grid items paint atomically in
   order, so the later cells sit above this overlay no matter its z-index —
   making them pointer-inert is what actually lets the click through. */
.repo-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.repo-card > :not(.repo-link) {
  pointer-events: none;
}

.repo-name {
  margin-right: auto;
  transition: color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out),
              letter-spacing var(--dur-base) var(--ease-out);
}

/* lucide swaps the <i> for an <svg> carrying the same class, so size the
   element itself here rather than a descendant. */
.repo-out {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  padding: 5px;
  box-sizing: content-box;
  border-radius: 50%;
  color: var(--text-3);
  background: transparent;
  transition: color var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-snap);
}

.repo-card:hover .repo-out,
.repo-card:focus-within .repo-out {
  color: #FFFFFF;
  background: var(--repo-color);
  transform: translate(3px, -3px) rotate(10deg);
}

.repo-card:hover .gh-mark,
.repo-card:focus-within .gh-mark {
  color: var(--repo-color);
  transform: rotate(-10deg) scale(1.14);
}

.repo-card:hover .repo-name,
.repo-card:focus-within .repo-name {
  color: var(--repo-color);
  letter-spacing: 0;
  transform: translateX(3px);
}

.repo-desc {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-2);
  max-width: none;
}

/* ---- Topic tags — one hue per card, set by the modifier below ---- */
.repo-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.repo-tag {
  padding: 0.15rem 0.6rem;
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: 500;
  background: var(--tag-bg, var(--bg-sunken));
  color: var(--tag-ink, var(--text-2));
  transition: color var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-snap);
}

.repo-card:hover .repo-tag,
.repo-card:focus-within .repo-tag {
  background: color-mix(in srgb, var(--repo-color) 17%, #FFFFFF);
  transform: translateY(-2px);
}

.repo-card:hover .repo-tag:nth-child(2),
.repo-card:focus-within .repo-tag:nth-child(2) {
  transition-delay: 45ms;
}

.repo-card:hover .repo-tag:nth-child(3),
.repo-card:focus-within .repo-tag:nth-child(3) {
  transition-delay: 90ms;
}

.repo-card--accent {
  --repo-color: var(--accent);
  --repo-soft: var(--accent-soft);
  --repo-lean: -0.3deg;
  --tag-bg: var(--accent-soft);
  --tag-ink: var(--accent-ink);
}

.repo-card--ok {
  --repo-color: var(--ok);
  --repo-soft: var(--ok-soft);
  --repo-lean: 0.3deg;
  --tag-bg: var(--ok-soft);
  --tag-ink: var(--ok-ink);
}

.repo-card--info {
  --repo-color: #4777B5;
  --repo-soft: var(--info-soft);
  --repo-lean: 0.3deg;
  --tag-bg: var(--info-soft);
  --tag-ink: var(--info-ink);
}

.repo-card--violet {
  --repo-color: #7B4C95;
  --repo-soft: var(--violet-soft);
  --repo-lean: -0.3deg;
  --tag-bg: var(--violet-soft);
  --tag-ink: var(--violet-ink);
}

/* ---- Language + stars + forks ---- */
.repo-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--text-2);
  max-width: none;
}

.repo-lang,
.repo-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/* An author `display` beats the UA sheet's [hidden] rule, so restate it —
   without this the zero-count chips repos.js leaves hidden still show. */
.repo-stat[hidden] {
  display: none;
}

.repo-lang i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--dot, var(--text-3));
}

.repo-stat svg {
  width: 13px;
  height: 13px;
  color: var(--text-3);
}

.repo-stat b {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   4. PROJECTS
   -------------------------------------------------------------------------- */
.project-feature {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--sp-4);
}

.project-feature-visual {
  background: var(--text);
  min-height: 220px;
  overflow: hidden;
}

.project-feature-visual img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.project-feature-body {
  padding: var(--sp-6);
  display: grid;
  gap: var(--sp-3);
  align-content: center;
}

.project-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
}

.project-card {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  box-shadow: var(--shadow-sm);
}

.project-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.project-meta-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

.project-link {
  margin-left: auto;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   5. TECH STACK
   -------------------------------------------------------------------------- */
.stack-title {
  max-width: 26ch;
  margin-bottom: var(--sp-6);
}

.tech-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.6rem 1.1rem;
  border-radius: var(--r-full);
  border: 1px solid var(--line);
  background: var(--bg-elevated);
  font-size: var(--fs-sm);
  font-weight: 500;
  white-space: nowrap;
}

.tech-pill img {
  width: 22px;
  height: 22px;
  object-fit: contain;
}

/* --------------------------------------------------------------------------
   6. CTA BAND
   -------------------------------------------------------------------------- */
.cta-band {
  background: var(--bg-sunken);
}

.cta-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
}

.cta-actions {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   7. RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .hero-inner {
    grid-template-columns: 1fr;
  }

  .build-motion {
    width: min(100%, 520px);
    justify-self: start;
  }

  .project-feature {
    grid-template-columns: 1fr;
  }

  .project-feature-visual {
    min-height: 150px;
  }

  .hero-stats {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-4);
  }
}

@media (max-width: 640px) {
  .hero {
    min-height: auto;
  }

  .hero-inner {
    padding-block: var(--sp-7) var(--sp-8);
  }

  .build-motion {
    padding: var(--sp-5) var(--sp-4);
  }

  .build-motion-row {
    grid-template-columns: 42px auto;
    min-height: 52px;
    font-size: clamp(1.35rem, 8vw, 1.85rem);
  }

  .build-motion-row:first-child {
    margin-left: 18px;
  }

  .project-grid,
  .repo-grid {
    grid-template-columns: 1fr;
  }

  .repos-head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
  }

  .section-head {
    flex-direction: column;
    align-items: flex-start;
  }

  .scroll-cue {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .repo-card,
  .repo-card::before,
  .repo-card::after,
  .repo-card .gh-mark,
  .repo-card .repo-name,
  .repo-card .repo-out,
  .repo-card .repo-tag {
    transition: none;
  }

  .repo-card:hover,
  .repo-card:focus-within {
    transform: none;
  }

  .build-motion-marker,
  .build-motion-marker i,
  .build-motion-label,
  .build-motion-label::before {
    animation: none;
  }

  .build-motion-row:first-child .build-motion-marker {
    background: color-mix(in srgb, var(--tone) 38%, #171315);
  }

  .build-motion-row:first-child .build-motion-marker i {
    background: var(--tone);
  }

  .build-motion-row:first-child .build-motion-label {
    color: #FFFFFF;
  }

  .build-motion-row:first-child .build-motion-label::before {
    clip-path: inset(0);
  }
}



/* --------------------------------------------------------------------------
   8. MOMENTS — photo on one side, the story on the other.
   The whole card is one click target: .moment-link stretches over it via
   ::after, so the photo is clickable while staying a plain <figure> whose
   alt text still describes the picture.
   -------------------------------------------------------------------------- */
.moments-sub {
  margin-top: var(--sp-2);
  max-width: 52ch;
}

.moments-list {
  display: grid;
  gap: var(--sp-5);
  margin-top: var(--sp-6);
}

.moment {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(var(--sp-4), 3vw, var(--sp-6));
  align-items: center;
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: calc(var(--r-lg) + 4px);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}

.moment:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
}

/* ---- Photo ----
   Hover motion, in three layers that read as one gesture:
   1. the frame tilts toward the cursor — tilt.js writes --rx/--ry on the
      card ([data-tilt]) and the custom properties inherit down to here, so
      the photo tilts while the text beside it stays put;
   2. the image itself pushes in and drifts up a touch;
   3. a soft highlight sweeps across once.
   tilt.js only runs on hover-capable fine pointers, so touch gets a plain
   card and reduced motion is handled at the bottom of this section. */
.moment-shot {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--bg-sunken);
  transform:
    perspective(900px)
    rotateX(var(--rx, 0deg))
    rotateY(var(--ry, 0deg));
  transition: transform var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
  will-change: transform;
}

/* The card carries [data-tilt] only to source the pointer values — it must
   not tilt itself, or the text would swing with the photo. */
.moment[data-tilt] {
  transform: none;
}

.moment:hover .moment-shot {
  box-shadow: var(--shadow-lg);
}

.moment-shot img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out),
              filter var(--dur-slow) var(--ease-out);
}

.moment:hover .moment-shot img {
  transform: scale(1.08) translateY(-1.5%);
  filter: saturate(1.06) contrast(1.02);
}

/* Highlight sweep — parked off the left edge, crosses once on hover */
.moment-shot::after {
  content: "";
  position: absolute;
  inset: -10% -60%;
  background: linear-gradient(
    105deg,
    transparent 40%,
    rgba(255, 255, 255, 0.34) 50%,
    transparent 60%
  );
  transform: translateX(-65%);
  opacity: 0;
  pointer-events: none;
}

.moment:hover .moment-shot::after {
  opacity: 1;
  transform: translateX(65%);
  transition: transform 900ms var(--ease-out), opacity 200ms linear;
}

/* ---- Story ---- */
.moment-body {
  display: grid;
  gap: var(--sp-3);
  align-content: center;
  padding-right: var(--sp-2);
}

.moment-meta {
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}

.moment-body h3 {
  font-size: var(--fs-h3);
}

.moment-body p {
  font-size: var(--fs-sm);
  line-height: 1.65;
  max-width: 46ch;
}

.moment-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--accent-strong);
}

.moment-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  width: fit-content;
  margin-top: var(--sp-1);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Stretch the link over the whole card. Note this link must NOT also carry
   .link-draw — that sets position:relative and owns ::after for its
   underline, which would anchor this overlay to the text instead. */
.moment-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.moment > :not(.moment-body),
.moment-body > :not(.moment-link) {
  pointer-events: none;
}

@media (max-width: 760px) {
  .moment {
    grid-template-columns: 1fr;
  }

  .moment-body {
    padding: 0 var(--sp-2) var(--sp-2);
  }
}

@media (prefers-reduced-motion: reduce) {
  .moment-shot,
  .moment:hover .moment-shot img {
    transform: none;
  }

  .moment:hover .moment-shot img {
    filter: none;
  }

  .moment-shot::after {
    display: none;
  }
}
