:root {
  --cream: #FFF3EC;
  --orange: #FF5C00;
  --black: #111111;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  background: var(--cream);
  color: var(--black);
  font-family: 'Inter', sans-serif;
}

/* Hero: a tall scroll track. Its height controls how much scrolling
   it takes to play through the full clip — more height = slower scrub. */
.hero {
  position: relative;
  height: 400vh;
}

.hero__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
  background: var(--black);
}

.hero__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Navbar: fixed over the hero, transparent, white text on the dark video. */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 28px 40px;
}

.navbar__logo {
  display: flex;
  align-items: center;
  text-decoration: none;
  transition: transform 180ms ease;
}

.navbar__logo:hover {
  transform: scale(1.28);
}

.navbar__logo-mark {
  display: block;
  height: 40px;
  width: auto;
}

.navbar__links {
  display: flex;
  align-items: center;
  gap: 40px;
}

.navbar__links a {
  display: inline-block;
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #FFFFFF;
  text-decoration: none;
  transition: transform 180ms ease;
}

.navbar__links a:hover {
  transform: scale(1.28);
}

.navbar__links a.navbar__link--accent {
  color: #FF5C00;
}

/* Hero title: pinned to the bottom of the hero, sized in JS to
   always span the full hero width regardless of viewport size. The
   translateY nudges the whole title+subtitle group (both live in this one
   wrapper) up a little to make room for the CTA below — title and subtitle
   move together, at their existing scale/overlap/alignment, unaffected. */
.hero__title-wrap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  padding: 0 40px;
  z-index: 10;
  pointer-events: none;
  display: grid;
  transform: translateY(clamp(-60px, -5vh, -40px));
  /* Without this, the implicit auto column sizes itself to the tagline's
     unwrapped text width (a classic CSS Grid blowout) instead of the
     wrap's own available width, pushing the tagline off-screen at narrow
     viewports. minmax(0, 1fr) pins the column to the container. */
  grid-template-columns: minmax(0, 1fr);
}

.hero__title-canvas {
  grid-area: 1 / 1;
  display: block;
  width: 100%;
  align-self: end;
}

/* Fill layer: gradient letterforms + smoke particles, difference-blended
   against the video for automatic contrast (same reasoning as before). */
.hero__title-fill-canvas {
  mix-blend-mode: difference;
}

/* Stroke layer: crisp hairline outline on the still-solid part of each
   letter. Deliberately NOT difference-blended — a "black" source pixel
   under mix-blend-mode: difference just reveals the backdrop unchanged,
   so the stroke would be invisible if it lived on the blended layer. */
.hero__title-outline-canvas {
  mix-blend-mode: normal;
}

/* Tagline: sits in the same stacked grid cell as the title canvases, bottom
   -aligned like them, then pulled up using the title's own font size (set
   as a CSS variable by hero-title-dissolve.js) so its top edge tucks just
   under the letters' baseline — a layered editorial accent that stays
   correctly positioned at any viewport size. Centered automatically since
   it shares the title's full-width box. */
.hero__tagline {
  grid-area: 1 / 1;
  align-self: end;
  justify-self: stretch;
  position: relative;
  z-index: 1;
  transform: translateY(calc(-0.15 * var(--title-font-size, 160px)))
    scale(var(--tagline-scale, 1));
  margin: 0;
  width: 100%;
  min-width: 0;
  text-align: center;
  font-family: 'Playfair Display', serif;
  font-weight: 700;
  font-style: italic;
  font-size: clamp(3.78rem, 7.56vw, 6.615rem);
  color: #FF5C00;
}

/* Smoke overlay for the tagline's own dissolve stage — sized and positioned
   in JS to match the rendered tagline exactly, sharing its grid cell and
   the same bottom-anchored transform so the wisps originate right where
   the text sits. */
.hero__tagline-canvas {
  grid-area: 1 / 1;
  display: block;
  justify-self: center;
  align-self: end;
  transform: translateY(calc(-0.15 * var(--title-font-size, 160px)));
  z-index: 2;
}

/* CTA positioner: an independent overlay, anchored directly to the hero's
   own bottom edge (.hero__sticky is its containing block) rather than to
   the title/tagline — it never reads their position and can never push or
   resize them. Guarantees the button always has clear breathing room above
   the viewport edge, regardless of how large the title/tagline render. */
.hero__cta-positioner {
  position: absolute;
  left: 50%;
  bottom: clamp(36px, 5vh, 48px);
  transform: translateX(-50%);
  z-index: 15;
}

@media (max-width: 768px) {
  /* Nudge the whole title+subtitle group up to free extra breathing room
     above the CTA — same technique as desktop, just a bigger lift. Tighten
     the side padding too so VELVEIRO (sized in JS to fill this box's own
     width) spans almost edge-to-edge instead of desktop's wide 40px gutter. */
  .hero__title-wrap {
    padding: 0 14px;
    /* vw-based (not vh) so the lift stays consistent on short/squat phone
       viewports too — the space this needs to free up scales with the
       title's own font size, which is fit to width, not height. */
    transform: translateY(clamp(-118px, -30vw, -84px));
  }

  /* Same tuck-under-the-baseline overlap as desktop, just shrunk to one
     line (so it stays legible and doesn't wrap at phone widths) and pulled
     up less than desktop's -0.15 so the overlap with VELVEIRO stays subtle
     instead of cutting across most of the subtitle's own height. */
  .hero__tagline {
    font-size: clamp(1.7rem, 8vw, 2.5rem);
    white-space: nowrap;
    transform: translateY(calc(-0.06 * var(--title-font-size, 160px)))
      scale(var(--tagline-scale, 1));
  }

  /* Smoke overlay must track the tagline's own position exactly (see the
     comment on .hero__tagline-canvas above) — mirror its transform here. */
  .hero__tagline-canvas {
    transform: translateY(calc(-0.06 * var(--title-font-size, 160px)));
  }

  .hero__cta-positioner {
    bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  }

  /* Declutter the mobile header: keep the mark and the primary CTA,
     drop the secondary nav links so the bar doesn't feel crowded. */
  .navbar__links a:not(.navbar__link--accent) {
    display: none;
  }
}

/* CTA: "Liquid Glass" capsule button. --cta-drift/--cta-blur/--cta-opacity
   are driven by hero-tagline-dissolve.js, reusing the exact same scroll
   progress that animates the tagline — the button fades as part of that
   same second-stage sequence rather than running its own timeline.
   --cta-magnet-x/--cta-magnet-y are driven by hero-cta-magnetic.js (cursor-
   proximity "magnetic pull"); every transform below composes drift + magnet
   + its own hover/active offset rather than replacing one with another. */
.hero__cta {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 58px;
  padding: 0 36px;
  border-radius: 999px;
  overflow: hidden;
  isolation: isolate;
  pointer-events: auto;
  text-decoration: none;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: 16.5px;
  color: #FFF3EC;
  background: linear-gradient(180deg, #ff7024 0%, #ff5c00 48%, #f05200 100%);
  border: 1px solid rgba(255, 243, 236, 0.48);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 -1px 0 rgba(130, 40, 0, 0.16), 0 10px 28px rgba(17, 17, 17, 0.24);
  opacity: var(--cta-opacity, 1);
  filter: blur(var(--cta-blur, 0px));
  transform: translate(var(--cta-magnet-x, 0px), var(--cta-drift, 0px))
    translateY(var(--cta-magnet-y, 0px));
  transition: background 190ms ease, box-shadow 190ms ease,
    transform 190ms ease;
}

/* Glass reflection: a soft top highlight, layered via ::before rather than
   an extra element. Clipped to the capsule by the parent's overflow. */
.hero__cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.08) 38%,
    rgba(255, 255, 255, 0) 60%
  );
  transition: transform 190ms ease, opacity 190ms ease;
  pointer-events: none;
}

/* Cursor-tracking spotlight (see hero-cta-magnetic.js). A fixed-size
   highlight moved purely via background-position — the only way to get a
   radial-gradient "hotspot" to glide smoothly instead of snapping, since
   browsers can't tween the position baked into a gradient function itself.
   isolation: isolate on .hero__cta keeps this blend contained to the
   button's own layers rather than bleeding into the hero video behind it. */
.hero__cta::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    140px circle at center,
    rgba(255, 243, 236, 0.75),
    rgba(255, 243, 236, 0) 70%
  );
  background-repeat: no-repeat;
  background-position: var(--cta-spot-x, 50%) var(--cta-spot-y, 35%);
  opacity: var(--cta-spot-opacity, 0);
  mix-blend-mode: soft-light;
  transition: opacity 220ms ease, background-position 140ms ease-out;
  pointer-events: none;
}

.hero__cta:hover {
  background: linear-gradient(180deg, #ff8038 0%, #ff6600 48%, #f75a00 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.46),
    inset 0 -1px 0 rgba(130, 40, 0, 0.2), 0 14px 32px rgba(17, 17, 17, 0.28);
  transform: translate(var(--cta-magnet-x, 0px), var(--cta-drift, 0px))
    translateY(calc(var(--cta-magnet-y, 0px) - 6px)) scale(1.045);
}

.hero__cta:hover::before {
  transform: translateY(-2px);
  opacity: 1;
}

.hero__cta:active {
  transform: translate(var(--cta-magnet-x, 0px), var(--cta-drift, 0px))
    translateY(var(--cta-magnet-y, 0px)) scale(0.98);
}

.hero__cta:focus-visible {
  outline: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 -1px 0 rgba(130, 40, 0, 0.16), 0 0 0 2px #FFF3EC,
    0 0 0 4.5px #FF5C00, 0 10px 28px rgba(17, 17, 17, 0.24);
}

.hero__cta-arrow {
  flex-shrink: 0;
  color: #FFF3EC;
}

@media (max-width: 640px) {
  .hero__cta {
    height: 54px;
    padding: 0 26px;
    gap: 8px;
    font-size: 15.5px;
    /* .hero__cta-positioner centers via left:50% + translateX(-50%); the
       translate is a post-layout visual offset the browser can't factor
       into an auto-width box's shrink-to-fit calculation, so without this
       the button's available width is computed as if it truly started at
       the 50% mark instead of being recentered — plenty of room on
       desktop, but on narrow phones that's less than the label's natural
       width, forcing "Get a free sample" to wrap. Sizing to the content's
       own width sidesteps that calculation and keeps it on one line. */
    width: max-content;
    white-space: nowrap;
  }

  .navbar__logo-mark {
    height: 32px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__cta {
    transition: opacity 190ms ease;
    transform: none !important;
  }

  .hero__cta::before {
    transition: none;
  }

  .hero__cta:hover::before {
    transform: none;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* Portfolio track: wraps the sticky portfolio sheet. Height is auto so the
   section occupies its natural 100vh and scroll continues normally past it.
   Horizontal navigation is handled by the arrow buttons in
   portfolio-scrub.js — scroll is not consumed here. */
.portfolio-track {
  position: relative;
  height: auto;
  margin-top: 0;
}

/* Portfolio: a full-screen black "sheet" that rises from the bottom of the
   viewport as the user scrolls, driven entirely by position: sticky (no
   JS, no lag). Pure black (not var(--black), which is a softer near-black
   used elsewhere) — a deliberate hard cut from the hero/cream tones. */
.portfolio {
  position: relative;
  height: 100vh;
  z-index: 5;
  background: #000000;
  border-radius: 32px 32px 0 0;
  box-shadow: 0 -24px 60px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Drag-handle bar, like a native bottom sheet — purely decorative, signals
   "this panel slides." */
.portfolio__handle {
  flex: none;
  width: 48px;
  height: 5px;
  margin: 18px auto 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.35);
}

.portfolio__heading {
  flex: none;
  font-family: 'Playfair Display', serif;
  font-weight: 700;
  font-style: italic;
  font-size: clamp(2.5rem, 5vw, 4rem);
  color: #FFFFFF;
  margin: 60px 0 0;
  padding: 0 40px;
}

/* Filmstrip stage: clips the wider strip to the sheet's width. The strip
   is panned horizontally (translateX) by portfolio-scrub.js via the arrow
   buttons — scroll is not involved. */
.portfolio__stage {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  margin-top: 48px;
}

.portfolio__strip {
  display: flex;
  align-items: stretch;
  height: 100%;
  gap: 10px;
  padding: 0 40px;
  will-change: transform;
  transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Placeholder items — grey for now, will become the real portfolio
   images/videos. The outer .portfolio__item is the ONLY thing :hover
   drives: it zooms in, and every OTHER item in the strip shrinks and
   fades back, via the :has() rule below, so only the hovered piece ever
   reads as the focus. That's the only trigger for a size change — scroll
   never zooms anything, only pans the strip.
   The inner .portfolio__item-inner is a separate element carrying its own
   always-on "floating" idle animation (transform: translateY), so the
   hover scale (on the outer element) and the idle float (on the inner
   element) live on different transforms and never fight each other. */
.portfolio__item {
  flex: 0 0 clamp(180px, 22vw, 320px);
  height: 100%;
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1),
    opacity 320ms ease;
}

.portfolio__item:hover {
  transform: scale(1.42);
  z-index: 2;
}

.portfolio__strip:has(.portfolio__item:hover) .portfolio__item:not(:hover) {
  transform: scale(0.68);
  opacity: 0.4;
}

.portfolio__item-inner {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: #333333;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
  animation: portfolio-float 4.2s ease-in-out infinite;
}

/* Real portfolio media (video/image) fills the card, cropped to fit —
   videos are muted/looped and only play once scrolled into view (see
   portfolio-media-play.js), independent of the card's own hover/float
   transforms above. */
.portfolio__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Staggered delay/duration per item so the row floats organically rather
   than bobbing in unison. */
.portfolio__item:nth-child(1) .portfolio__item-inner { animation-duration: 3.8s; animation-delay: -0.4s; }
.portfolio__item:nth-child(2) .portfolio__item-inner { animation-duration: 4.6s; animation-delay: -1.8s; }
.portfolio__item:nth-child(3) .portfolio__item-inner { animation-duration: 4.1s; animation-delay: -0.9s; }
.portfolio__item:nth-child(4) .portfolio__item-inner { animation-duration: 5s; animation-delay: -2.6s; }
.portfolio__item:nth-child(5) .portfolio__item-inner { animation-duration: 3.6s; animation-delay: -1.3s; }
.portfolio__item:nth-child(6) .portfolio__item-inner { animation-duration: 4.8s; animation-delay: -3.1s; }
.portfolio__item:nth-child(7) .portfolio__item-inner { animation-duration: 4.3s; animation-delay: -0.2s; }
.portfolio__item:nth-child(8) .portfolio__item-inner { animation-duration: 3.9s; animation-delay: -2.2s; }

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

@media (prefers-reduced-motion: reduce) {
  .portfolio__item-inner {
    animation: none;
  }
}

/* Footer: breathing room under the filmstrip, then a secondary (outline,
   not solid-orange like the hero CTA) pill linking to the full portfolio.
   flex: none alongside .portfolio__stage's flex: 1 means adding this
   automatically shrinks the stage to make room — no hardcoded heights. */
.portfolio__footer {
  flex: none;
  display: flex;
  justify-content: center;
  margin-top: 56px;
  padding-bottom: 56px;
}

.portfolio__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 54px;
  padding: 0 34px;
  border-radius: 999px;
  border: 1.5px solid rgba(255, 243, 236, 0.45);
  background: none;
  cursor: pointer;
  color: #FFF3EC;
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.01em;
  text-decoration: none;
  transition: transform 200ms ease, background 200ms ease,
    border-color 200ms ease;
}

.portfolio__cta:hover {
  background: rgba(255, 243, 236, 0.1);
  border-color: rgba(255, 243, 236, 0.85);
  transform: scale(1.06);
}

/* Navigation arrows — absolutely positioned within .portfolio (position:
   relative), centered vertically over the stage area. Siblings of
   .portfolio__stage so they are not clipped by its overflow: hidden. */
.portfolio__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
  width: 44px;
  min-width: 44px;
  max-width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  margin: 0;
  flex: none;
  align-self: center;
  appearance: none;
  -webkit-appearance: none;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 243, 236, 0.45);
  background: rgba(0, 0, 0, 0.55);
  color: #FFF3EC;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 200ms ease, border-color 200ms ease;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.portfolio__arrow--left  { left: 12px; }
.portfolio__arrow--right { right: 12px; }

/* [hidden] is overridden by display: flex above in the same cascade;
   this rule restores the hide behaviour explicitly. */
.portfolio__arrow[hidden] { display: none !important; }

.portfolio__arrow:hover {
  background: rgba(255, 243, 236, 0.15);
  border-color: rgba(255, 243, 236, 0.85);
}

.portfolio__arrow:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #000000, 0 0 0 4.5px var(--orange);
}

@media (max-width: 640px) {
  .portfolio {
    border-radius: 24px 24px 0 0;
  }

  .portfolio__heading {
    margin-top: 40px;
    padding: 0 24px;
  }

  .portfolio__strip {
    padding: 0 24px;
    gap: 8px;
  }

  .portfolio__item {
    flex-basis: 62vw;
  }

  .portfolio__footer {
    margin-top: 36px;
    padding-bottom: 40px;
  }

  .portfolio__cta {
    height: 50px;
    padding: 0 26px;
    font-size: 14px;
  }
}

/* Left-side statement, pinned inside the hero over the video — appears
   partway through the scrub (driven by hero-copy-reveal.js off the same
   scroll progress as the title/tagline/CTA, not a one-time trigger), so it
   scrubs in and back out exactly like everything else in the hero. Each
   line's opacity/blur/scale is set directly per frame; no CSS transition
   is needed since the JS updates continuously while scrolling. */
.reveal-copy {
  position: absolute;
  left: 40px;
  top: 50%;
  transform: translateY(-50%);
  max-width: 460px;
  z-index: 10;
  pointer-events: none;
}

.reveal-line {
  margin: 0 0 18px;
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: clamp(2.07rem, 3.78vw, 2.88rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: #FFF3EC;
  text-align: left;
  text-shadow: 0 2px 16px rgba(17, 17, 17, 0.45);
}

.reveal-line:last-child {
  margin-bottom: 0;
}

.reveal-accent {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 700;
  color: #FF5C00;
}

@media (max-width: 640px) {
  .reveal-copy {
    left: 24px;
    right: 24px;
    max-width: none;
  }
}

/* FAQ: cream section with a centered intro (badge + heading) and an
   accordion list. Each answer expands via a 0fr/1fr grid-template-rows
   transition (js/faq-accordion.js just toggles .is-open) — no JS height
   measuring needed, and it collapses to auto content height cleanly. */
.faq {
  background: var(--cream);
  padding: 140px 24px;
}

.faq__intro {
  text-align: center;
  margin-bottom: 64px;
}

.faq__badge {
  display: inline-block;
  background: var(--orange);
  color: #FFFFFF;
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 18px;
  border-radius: 999px;
  margin-bottom: 24px;
}

.faq__heading {
  font-family: 'Inter', sans-serif;
  font-weight: 900;
  letter-spacing: -0.025em;
  font-size: clamp(2.75rem, 5.5vw, 4.5rem);
  line-height: 1.1;
  color: var(--black);
  margin: 0;
}

.faq__accent {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 700;
  color: var(--orange);
}

.faq__list {
  max-width: 1040px;
  margin: 0 auto;
}

.faq__item {
  border-bottom: 1px solid #F0D9CD;
}

.faq__question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 32px 0;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: clamp(1.1rem, 2vw, 1.35rem);
  color: var(--black);
}

.faq__icon {
  position: relative;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
}

.faq__icon::before,
.faq__icon::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--orange);
  transform: translate(-50%, -50%);
  transition: transform 220ms ease;
}

.faq__icon::before {
  width: 100%;
  height: 2.5px;
}

.faq__icon::after {
  width: 2.5px;
  height: 100%;
}

.faq__item.is-open .faq__icon::after {
  transform: translate(-50%, -50%) rotate(90deg) scale(0);
}

.faq__answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 280ms ease;
}

.faq__answer-inner {
  overflow: hidden;
}

.faq__answer p {
  margin: 0 0 32px;
  max-width: 780px;
  font-family: 'Inter', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: var(--brown-700, rgba(17, 17, 17, 0.65));
}

.faq__item.is-open .faq__answer {
  grid-template-rows: 1fr;
}

@media (max-width: 640px) {
  .faq {
    padding: 96px 20px;
  }

  .faq__intro {
    margin-bottom: 48px;
  }

  .faq__question {
    padding: 24px 0;
    gap: 16px;
  }
}

/* Services: cream section, left-aligned intro + a numbered list. Reveal is
   a one-shot scroll-triggered fade-up (js/services-reveal.js toggles
   .is-visible per target via IntersectionObserver, then unobserves) —
   unlike the hero/portfolio's continuous scroll-scrub, this is a plain
   in-flow section so a standard "animate in once, stay visible" reveal is
   the right fit; it doesn't reverse if you scroll back up. */
.services {
  background: var(--cream);
  color: var(--black);
  padding: 140px 24px;
}

.services__intro {
  max-width: 720px;
  margin: 0 auto;
}

.services__title {
  font-family: 'Inter', sans-serif;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  font-size: clamp(1.75rem, 6vw, 4.85rem);
  line-height: 1.05;
  color: var(--black);
  margin: 0 0 20px;
  white-space: nowrap;
}

.services__intro-text {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: 16px;
  line-height: 1.6;
  color: rgba(17, 17, 17, 0.6);
  max-width: 560px;
  margin: 0;
}

.services__list {
  max-width: 1040px;
  margin: 64px auto 0;
}

.services__row {
  display: flex;
  align-items: baseline;
  gap: 32px;
  padding: 40px 0;
  border-bottom: 1px solid #F0D9CD;
  transition: transform 280ms ease;
}

.services__row:hover {
  transform: translateX(16px);
}

.services__row:last-child {
  border-bottom: none;
}

.services__number {
  flex: none;
  width: 100px;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 700;
  font-size: clamp(2.5rem, 4vw, 3.25rem);
  line-height: 1;
  color: var(--orange);
}

.services__row-text {
  flex: 1;
  min-width: 0;
}

.services__row-title {
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  color: var(--black);
  margin: 0 0 8px;
}

.services__row-desc {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: 15px;
  line-height: 1.5;
  color: rgba(17, 17, 17, 0.55);
  max-width: 520px;
  margin: 0;
}

/* Reveal states: title/intro fade together (no stagger between them);
   each row's number and text block share the row's own stagger delay,
   with the text following the number by a beat, per spec ("the number
   appearing a moment before its text"). */
.services__title,
.services__intro-text,
.services__row .services__number,
.services__row .services__row-text {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 550ms ease-out, transform 550ms ease-out;
}

.services__intro.is-visible .services__title,
.services__intro.is-visible .services__intro-text {
  opacity: 1;
  transform: translateY(0);
}

.services__row.is-visible .services__number,
.services__row.is-visible .services__row-text {
  opacity: 1;
  transform: translateY(0);
}

.services__row:nth-child(1) { --row-delay: 0ms; }
.services__row:nth-child(2) { --row-delay: 120ms; }
.services__row:nth-child(3) { --row-delay: 240ms; }
.services__row:nth-child(4) { --row-delay: 360ms; }
.services__row:nth-child(5) { --row-delay: 480ms; }

.services__row .services__number {
  transition-delay: var(--row-delay, 0ms);
}

.services__row .services__row-text {
  transition-delay: calc(var(--row-delay, 0ms) + 90ms);
}

@media (prefers-reduced-motion: reduce) {
  .services__title,
  .services__intro-text,
  .services__row .services__number,
  .services__row .services__row-text {
    transition: none;
  }
}

@media (max-width: 640px) {
  .services {
    padding: 96px 20px;
  }

  .services__list {
    margin-top: 40px;
  }

  .services__row {
    gap: 16px;
    padding: 28px 0;
  }

  .services__number {
    width: 56px;
    font-size: clamp(1.75rem, 8vw, 2.25rem);
  }
}

/* How it works: cream section. Title sits in normal flow; the three
   steps are a scroll-scrubbed card stack (see .how-it-works__track below)
   pinned inside its own tall track — same deterministic, fully-reversible
   scroll-progress pattern as the hero/portfolio (js/how-it-works-scrub.js
   sets each card's transform/opacity directly from scroll position, no
   CSS transitions, so scrolling back up rewinds it exactly). Then a
   centered closing statement + primary CTA in normal flow after the
   track. Numbers reuse the same italic Playfair treatment introduced for
   Services' numbers, for a consistent thread between the two
   numbered-content sections. */
.how-it-works {
  background: var(--cream);
  color: var(--black);
  padding: 72px 0 140px;
}

.how-it-works__title {
  font-family: 'Inter', sans-serif;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  font-size: clamp(2.75rem, 6vw, 5rem);
  line-height: 1.05;
  color: var(--black);
  max-width: 1040px;
  margin: 0 auto 8px;
  padding: 0 24px;
}

/* Track: gives the pinned stage a defined scroll distance. 100vh for the
   sticky stage itself + 200vh of scrub room (100vh per card-to-card
   transition, 2 transitions for 3 cards). */
.how-it-works__track {
  position: relative;
  height: 300vh;
}

.how-it-works__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.how-it-works__deck {
  position: relative;
  width: min(90vw, 480px);
  height: min(60vh, 460px);
}

/* Cards are absolutely stacked in the same box; JS drives each one's own
   transform (translateY/scale/rotate) + opacity per scroll frame. Static
   z-index (card 1 highest) so the exiting card always falls away over
   the revealed stack beneath it, matching the reference animation. */
.how-it-works__card {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-radius: 28px;
  background: #FFFFFF;
  box-shadow: 0 20px 60px rgba(17, 17, 17, 0.14);
  padding: 48px 44px;
  will-change: transform, opacity;
}

.how-it-works__card:nth-child(1) { z-index: 3; }
.how-it-works__card:nth-child(2) { z-index: 2; }
.how-it-works__card:nth-child(3) { z-index: 1; }

.how-it-works__step-number {
  display: block;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 700;
  font-size: clamp(2.5rem, 4vw, 3.25rem);
  line-height: 1;
  color: var(--orange);
  margin-bottom: 20px;
}

.how-it-works__step-title {
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: clamp(1.25rem, 2.2vw, 1.5rem);
  color: var(--black);
  margin: 0 0 10px;
}

.how-it-works__step-desc {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: 15px;
  line-height: 1.6;
  color: rgba(17, 17, 17, 0.55);
  margin: 0;
}

.how-it-works__closing {
  max-width: 640px;
  margin: 48px auto 0;
  padding: 0 24px;
  text-align: center;
}

.how-it-works__closing-line {
  font-family: 'Inter', sans-serif;
  font-weight: 500;
  font-size: clamp(1.15rem, 2.2vw, 1.4rem);
  line-height: 1.5;
  color: var(--black);
  margin: 0 0 32px;
  /* Blur-to-focus reveal — same technique as the hero's reveal-copy
     lines, driven here by js/how-it-works-closing-reveal.js (a one-shot-
     per-direction IntersectionObserver toggling .is-visible, reversible
     like the rest of the site's scroll reveals, since this line sits in
     normal flow after the pinned card-stack track rather than inside a
     continuous scrub). */
  opacity: 0;
  filter: blur(14px);
  transform: scale(0.92);
  transition: opacity 600ms ease-out, filter 600ms ease-out,
    transform 600ms ease-out;
}

.how-it-works__closing-line.is-visible {
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .how-it-works__closing-line {
    transition: opacity 190ms ease;
    filter: none;
    transform: none;
  }
}

/* Same magnetic-pull + cursor-tracking-spotlight treatment as .hero__cta
   (js/hero-cta-magnetic.js drives both via --cta-magnet-x/y and
   --cta-spot-x/y/opacity) — just without the scroll-dissolve variables
   (--cta-opacity/--cta-blur/--cta-drift), which are specific to the
   hero's own reveal stage. */
.how-it-works__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  isolation: isolate;
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: 16px;
  color: #FFF3EC;
  background: linear-gradient(180deg, #ff7024 0%, #ff5c00 48%, #f05200 100%);
  border: 1px solid rgba(255, 243, 236, 0.48);
  border-radius: 999px;
  padding: 18px 34px;
  text-decoration: none;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 -1px 0 rgba(130, 40, 0, 0.16), 0 10px 28px rgba(17, 17, 17, 0.16);
  transform: translate(var(--cta-magnet-x, 0px), var(--cta-magnet-y, 0px));
  transition: background 190ms ease, box-shadow 190ms ease,
    transform 190ms ease;
}

.how-it-works__cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.08) 38%,
    rgba(255, 255, 255, 0) 60%
  );
  transition: transform 190ms ease, opacity 190ms ease;
  pointer-events: none;
}

.how-it-works__cta::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    140px circle at center,
    rgba(255, 243, 236, 0.75),
    rgba(255, 243, 236, 0) 70%
  );
  background-repeat: no-repeat;
  background-position: var(--cta-spot-x, 50%) var(--cta-spot-y, 35%);
  opacity: var(--cta-spot-opacity, 0);
  mix-blend-mode: soft-light;
  transition: opacity 220ms ease, background-position 140ms ease-out;
  pointer-events: none;
}

.how-it-works__cta:hover {
  background: linear-gradient(180deg, #ff8038 0%, #ff6600 48%, #f75a00 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.46),
    inset 0 -1px 0 rgba(130, 40, 0, 0.2), 0 14px 32px rgba(17, 17, 17, 0.2);
  transform: translate(var(--cta-magnet-x, 0px), calc(var(--cta-magnet-y, 0px) - 6px))
    scale(1.045);
}

.how-it-works__cta:hover::before {
  transform: translateY(-2px);
  opacity: 1;
}

.how-it-works__cta:active {
  transform: translate(var(--cta-magnet-x, 0px), var(--cta-magnet-y, 0px)) scale(0.98);
}

.how-it-works__cta:focus-visible {
  outline: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 -1px 0 rgba(130, 40, 0, 0.16), 0 0 0 2px #FFF3EC,
    0 0 0 4.5px #FF5C00, 0 10px 28px rgba(17, 17, 17, 0.16);
}

@media (prefers-reduced-motion: reduce) {
  .how-it-works__cta {
    transition: opacity 190ms ease;
    transform: none !important;
  }

  .how-it-works__cta::before {
    transition: none;
  }

  .how-it-works__cta:hover::before {
    transform: none;
  }
}

@media (max-width: 640px) {
  .how-it-works {
    padding: 48px 0 96px;
  }

  .how-it-works__title {
    margin-bottom: 8px;
    padding: 0 20px;
  }

  .how-it-works__deck {
    width: min(88vw, 400px);
    height: min(56vh, 420px);
  }

  .how-it-works__card {
    padding: 36px 28px;
  }

  .how-it-works__closing {
    margin-top: 32px;
    padding: 0 20px;
  }
}

/* Closing: the site's last word — dark, editorial, mirrors the portfolio
   sheet's pure black rather than var(--black). Two columns (copy+contact,
   then a single big CTA) collapsing to one on mobile, plus a thin footer
   bar with the mark and a copyright line. */
.closing {
  background: #000000;
  color: #FFFFFF;
  padding: 140px 40px 0;
}

.closing__inner {
  max-width: 1200px;
  margin: 0 auto;
  padding-bottom: 120px;
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 80px;
  align-items: center;
}

.closing__tag {
  display: inline-block;
  background: var(--orange);
  color: #FFFFFF;
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 8px 18px;
  border-radius: 999px;
  margin: 0 0 28px;
}

.closing__headline {
  font-family: 'Inter', sans-serif;
  font-weight: 900;
  letter-spacing: -0.025em;
  font-size: clamp(2.75rem, 5.2vw, 4.5rem);
  line-height: 1.05;
  color: #FFFFFF;
  margin: 0 0 28px;
}

.closing__accent {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 700;
  color: var(--orange);
}

.closing__body {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.6);
  max-width: 460px;
  margin: 0 0 48px;
}

.closing__contact {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.closing__contact-label {
  font-family: 'Inter', sans-serif;
  font-weight: 500;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.45);
  margin-bottom: 2px;
}

.closing__contact-link {
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: 15px;
  color: #FFFFFF;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 180ms ease;
}

.closing__contact-link:hover {
  color: var(--orange);
}

/* Just a flex-centering wrapper — .hero__cta supplies the button's
   actual gradient/shadow/arrow look, and reusing that class verbatim
   (rather than a lookalike) is also what puts it in
   hero-cta-magnetic.js's target list, so it gets the same magnetic
   pointer-follow "moving button" behavior as the real hero CTA. */
.closing__cta-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
}

.closing__footer {
  max-width: 1200px;
  margin: 0 auto;
  padding: 32px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.closing__footer-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.7);
}

.closing__footer-mark {
  height: 18px;
  width: auto;
  opacity: 0.85;
}

.closing__footer-copy {
  font-family: 'Inter', sans-serif;
  font-weight: 500;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.4);
}

@media (max-width: 900px) {
  .closing__inner {
    grid-template-columns: 1fr;
    gap: 56px;
  }

  .closing__cta-wrap {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  .closing {
    padding: 96px 24px 0;
  }

  .closing__inner {
    padding-bottom: 72px;
    gap: 48px;
  }

  .closing__body {
    max-width: none;
  }

  .closing__cta-wrap {
    justify-content: center;
  }

  .closing__cta {
    width: 100%;
  }

  .closing__footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 24px 0 40px;
  }
}
