/* Home page: hero, selected work and contact.
   Sections are stacked with position:sticky so each one pins while the next
   scrolls over it; the work layer is pulled up by -100vh to sit above the
   contact panel until it has scrolled past. */

/* "only light" is the strongest opt-out from a browser substituting its own
   scheme. Plain "light" was not enough to stop Chrome on Android recolouring
   the light hero and contact panels; the "only" keyword tells the browser the
   page does not support any other scheme, so forced-dark is skipped. */
:root {
  color-scheme: only light;
  /* Phones rubber-band when scrolled past either end and spring back, which
     reads as the page shifting on its own. This pins the scroll at its
     bounds. Also stops pull-to-refresh on Android. */
  overscroll-behavior-y: none;
}

body {
  background: #E3E3E3;
}

/* ------------------------------------------------------------ keyframes -- */

/* Per-letter reveal for the hero name.
   Each letter starts almost invisible against the light ground, darkens
   past the settled ink, then eases back to it. The letterpress shadows are
   the dark-ground original inverted: highlight below, shade above. */
@keyframes colorIn {
  0% {
    color: #C9C9C9;
    text-shadow:
      0 1px 2px rgba(255, 255, 255, .9),
      0 -1px 1px rgba(0, 0, 0, .10),
      0 6px 18px rgba(0, 0, 0, .10),
      0 0 34px rgba(0, 0, 0, 0),
      0 0 90px rgba(0, 0, 0, 0);
  }
  55% {
    color: #000;
  }
  100% {
    color: #1F1F1F;
    text-shadow:
      0 1px 2px rgba(255, 255, 255, .9),
      0 -1px 1px rgba(0, 0, 0, .10),
      0 6px 18px rgba(0, 0, 0, .16),
      0 0 34px rgba(0, 0, 0, .10),
      0 0 90px rgba(0, 0, 0, .05);
  }
}

/* Overshoot settle applied to the whole hero title once the letters land. */
@keyframes scaleUp {
  0% { transform: scale(.72); }
  62% { transform: scale(1.05); }
  100% { transform: scale(1); }
}

@keyframes fadeUp {
  from { transform: translateY(14px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: .001s !important;
    animation-delay: 0s !important;
    transition-duration: .001s !important;
  }
}

/* ----------------------------------------------------------------- page -- */

.page {
  position: relative;
  background: #E3E3E3;
}

/* Everything below the hero, layered above it. */
.page__stack {
  position: relative;
  z-index: 2;
}

/* Trailing spacer that lets the contact panel finish unpinning. */
.scroll-spacer {
  height: 100vh;
  pointer-events: none;
}

/* ------------------------------------------------------------------ nav -- */

.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 90;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: clamp(20px, 3vw, 36px) clamp(20px, 4vw, 48px);
  color: #1F1F1F;
  transition: color .5s ease;
  pointer-events: none;
}

.site-nav__home {
  pointer-events: auto;
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* Clips the rolling stack to a single 16px line. */
.site-nav__mask {
  display: block;
  height: 16px;
  overflow: hidden;
}

.site-nav__stack {
  display: block;
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
}

.site-nav__stack-item {
  display: block;
  height: 16px;
  line-height: 16px;
}

.site-nav__links {
  pointer-events: auto;
  display: flex;
  gap: clamp(18px, 3vw, 40px);
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.site-nav__link {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Active-section indicator; opacity and colour are toggled from JS. */
.site-nav__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #1F1F1F;
  opacity: 0;
  transition: opacity .35s;
}

/* ----------------------------------------------------------------- hero -- */

.hero {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: #E3E3E3;
  scroll-snap-align: start;
}

.hero__title {
  position: relative;
  z-index: 1;
  margin: 0;
  white-space: nowrap;
  text-align: center;
  font-weight: 600;
  font-size: clamp(28px, 7.6vw, 150px);
  line-height: 1;
  letter-spacing: -.035em;
  text-shadow:
    0 1px 2px rgba(255, 255, 255, .9),
    0 -1px 1px rgba(0, 0, 0, .10),
    0 6px 18px rgba(0, 0, 0, .16);
  transform-origin: center;
  animation: scaleUp 1.15s cubic-bezier(.34, 1.4, .4, 1) 1.3s both;
}

/* animation-delay is set per letter from JS. */
.hero__letter {
  display: inline-block;
  color: #C9C9C9;
  animation: colorIn .42s ease both;
}

.hero__letter--space {
  width: .32em;
}

/* ----------------------------------------------------------------- work -- */

.work-layer {
  position: relative;
  z-index: 2;
  background: #0F0D18;
  /* Must stay equal to the contact panel's height for the overlay to line up. */
  margin-top: -100vh;
}

.work {
  position: relative;
  z-index: 2;
  background: #0F0D18;
  border-radius: clamp(20px, 3vw, 44px) clamp(20px, 3vw, 44px) 0 0;
  box-shadow: 0 -14px 36px rgba(0, 0, 0, .28);
  border-top: 1px solid #262238;
  padding: clamp(56px, 9vh, 120px) 20% clamp(40px, 8vh, 110px);
}

.work__header {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  flex-wrap: wrap;
  padding-bottom: clamp(28px, 5vh, 60px);
}

.work__heading {
  margin: 0;
  font-weight: 600;
  font-size: clamp(28px, 4.6vw, 64px);
  letter-spacing: -.03em;
}

.work__count {
  margin: 0;
  font-size: 12px;
  letter-spacing: .16em;
  color: #7A7A7A;
}

.work-card {
  /* Fixed so all four cards match and the row never grows with the window.
     The copy in js/content/site.js is trimmed to fit this height; the mobile
     rule below sets its own. */
  height: 380px;
  display: flex;
  /* With a fixed height the two halves must stay side by side: allowed to
     wrap they stack and overflow the card. Released in the mobile rule. */
  flex-wrap: nowrap;
  gap: 0;
  align-items: stretch;
  border: 1px solid #262238;
  border-radius: 8px;
  overflow: hidden;
  background: #17141F;
  margin-bottom: clamp(44px, 7vh, 84px);
}

/* Every second card puts its image on the right. */
.work-card--reverse {
  flex-direction: row-reverse;
}

.work-card__media {
  flex: 1.5 1 460px;
  min-width: 0;
  display: block;
  overflow: hidden;
  background: #1C1926;
}

.work-card__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--img-filter);
  transition: filter .6s ease;
}

.work-card__body {
  flex: 1 1 300px;
  min-width: 0;
  /* Tightened along with the title below so the copy clears 420px. */
  padding: clamp(28px, 2.8vw, 44px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  /* Tightened with the card height so the longest card keeps clear headroom. */
  gap: 14px;
}

.work-card__title {
  margin: 0;
  font-weight: 600;
  font-size: clamp(22px, 2.2vw, 32px);
  line-height: 1.12;
  letter-spacing: -.02em;
  text-wrap: pretty;
}

.work-card__blurb {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.6;
  color: #A5A5A5;
  text-wrap: pretty;
}

/* The magnetic-fill script adds a sliding accent panel behind this and
   overrides colour and transform inline while hovered. */
.work-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 14px 22px;
  border: 1px solid #332E45;
  border-radius: 999px;
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: border-color .4s, color .4s;
}

.work-card__cta:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* The arrow is not in the Inter subset, so it renders from a fallback font
   that comes out lighter than the 600 label beside it. font-weight does not
   help — the fallback has no heavier face and the browser will not synthesise
   one for this glyph — so the outline is stroked instead. currentColor keeps
   it in step when the hover fill switches the label to white. */
.work-card__arrow {
  -webkit-text-stroke: 0.04em currentColor;
}

/* -------------------------------------------------------------- contact -- */

.contact {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 100vh;
  background: #E3E3E3;
  color: #1F1F1F;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: clamp(36px, 6vh, 64px);
  padding: clamp(80px, 12vh, 140px) 20%;
  scroll-snap-align: start;
}

/* Generated noise texture; the image itself is painted from a canvas in JS. */
.contact__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: .45;
}

.contact__heading {
  position: relative;
  z-index: 1;
  margin: 0;
  max-width: 17ch;
  text-align: center;
  font-weight: 600;
  font-size: clamp(28px, 4.2vw, 68px);
  line-height: 1.06;
  letter-spacing: -.03em;
  text-wrap: pretty;
}

.contact__accent {
  color: var(--accent);
}

.contact__links {
  position: relative;
  z-index: 5;
  pointer-events: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
}

/* The magnetic-fill script adds a sliding accent panel behind this and
   overrides colour and transform inline while hovered, the same as the work
   card buttons. */
.contact__link {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 18px 30px;
  border: 1px solid #1F1F1F;
  border-radius: 999px;
  font-size: 14px;
  letter-spacing: .06em;
  transition: color .4s, border-color .4s;
}

.contact__link:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* --------------------------------------------------------- responsive -- */

/* The 20% side padding that frames the work and contact sections on a wide
   screen leaves too little room for content once the viewport narrows. */
@media (max-width: 900px) {
  .work {
    padding: clamp(48px, 8vh, 96px) 7% clamp(36px, 6vh, 80px);
  }

  .contact {
    padding: clamp(64px, 10vh, 120px) 7%;
  }
}

@media (max-width: 620px) {
  /* The padding moves from the bar onto the links themselves, so the labels
     stay where they were while each becomes a ~44px tap target. */
  .site-nav {
    padding: 2px 20px;
  }

  .site-nav__home,
  .site-nav__link {
    padding: 14px 0;
  }

  .work {
    padding: 44px 20px 32px;
    border-radius: 20px 20px 0 0;
  }

  .work__header {
    padding-bottom: 24px;
  }

  /* Stacked as a column so the image band and the text each get a fixed
     share of the card, keeping all four the same height here too. */
  .work-card {
    height: 460px;
    flex-direction: column;
    flex-wrap: nowrap;
    margin-bottom: 32px;
  }

  .work-card__media {
    flex: 0 0 220px;
    min-width: 0;
  }

  .work-card__img {
    min-height: 0;
  }

  .work-card__body {
    flex: 1 1 auto;
    min-width: 0;
    padding: 24px 20px 28px;
    gap: 14px;
  }

  .contact {
    padding: 56px 20px;
    gap: 28px;
  }

  .contact__links {
    gap: 12px;
  }

  .contact__link {
    padding: 15px 22px;
  }

  .work-card__cta {
    padding: 15px 22px;
  }
}
