/* ============================================================
   LUXOR — Design Project service page
   Desktop-first pass (per design handoff, mobile is a follow-up).
   ============================================================ */

.dp {
  overflow-x: hidden;
}

/* ---------- 0. Hero: "Дизайн-проект в сочетании с BIM-технологиями" ---------- */
.dp-hero {
  position: relative;
  height: 100vh;
  max-height: 1080px;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: #191a1f;
}

.dp-hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.dp-hero__bg-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.dp-hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5) 0%, rgba(25, 26, 31, 0) 30%);
}

.dp-hero__content {
  position: relative;
  z-index: 1;
  padding-bottom: 90px;
  padding-left: calc(var(--container-padding-base) * 2);
  color: var(--color-bg-primary);
}

.dp-hero__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;
}

.dp-hero__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.dp-hero__title {
  font-size: 36px;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 1px;
  line-height: 1.2;
  margin: 0 0 12px;
  max-width: 600px;
}

.dp-hero__title-line {
  display: inline-block;
}

.dp-hero__subtitle {
  font-size: 22px;
  font-weight: var(--font-weight-medium);
  margin: 0 0 40px;
}

.dp-hero__cta img {
  width: 22px;
  height: 22px;
}

@media (hover: hover) and (pointer: fine) {
  /* The source SVG is a flat white fill, so it can't be recolored with
     a plain CSS `color` the way text can. brightness(0) first collapses
     it to solid black, then invert(10%) lifts it to ~#191919 — the
     same dark grey .border-btn.white-btn:hover already uses for the
     button's own text (assets/css/main.css:569). */
  .dp-hero__cta:hover img {
    filter: brightness(0) invert(10%);
  }
}

.dp-hero__price {
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 14px 24px 16px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(4px);
  white-space: nowrap;
}

.dp-hero__price-from {
  font-size: var(--font-size-md);
  opacity: 0.85;
}

.dp-hero__price-num {
  font-size: 20px;
  font-weight: var(--font-weight-bold);
}

.dp-hero__price-unit {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-regular);
  opacity: 0.85;
}

.dp-hero__price-gift {
  font-size: var(--font-size-lg);
}

.dp-hero__price-accent {
  color: var(--color-accent-primary);
}

/* ---------- 1. "На стыке искусства и науки" ---------- */
.dp-intersection {
  position: relative;
  padding: 160px 0 96px;
  background: var(--color-bg-primary);
  overflow: hidden;
}

.dp-intersection__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.dp-intersection__bg-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The photo itself already fades to white on its left edge — no
     extra opacity needed, that was washing it out almost completely
     combined with the fade overlay below. */
}

.dp-intersection__bg-fade {
  position: absolute;
  top: 40px;
  right: 0;
  bottom: 0;
  left: 0;
  /* Only fade the last ~260px into the section's solid background,
     so the photo stays visible through the rest of the section. */
  background: linear-gradient(to bottom, rgba(238, 238, 238, 0) 0%, rgba(238, 238, 238, 0) calc(100% - 260px), var(--color-bg-primary) 100%);
}

.dp-intersection__content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.dp-intersection__title {
  font-size: var(--font-size-6xl);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--color-text-primary);
  max-width: 820px;
  margin: 0 0 24px;
}

.dp-intersection__subtitle {
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-regular);
  color: #232323;
  letter-spacing: 0.4px;
  max-width: 810px;
  margin: 0;
}

.dp-intersection__accent {
  color: var(--color-accent-primary);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.dp-intersection__info-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  line-height: 0;
}

.dp-intersection__info-icon {
  display: inline-block;
  vertical-align: -4px;
}

.dp-intersection__tooltip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  width: 280px;
  padding: 12px 14px;
  border-radius: 8px;
  background: rgba(46, 46, 46, 0.9);
  backdrop-filter: blur(8px);
  color: #c4c4c4;
  font-size: 14px;
  font-weight: var(--font-weight-regular);
  line-height: 1.4;
  text-transform: none;
  letter-spacing: normal;
  text-align: left;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  z-index: var(--z-tooltip);
}

.dp-intersection__info-btn:hover .dp-intersection__tooltip {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* Hidden by default: above 980px .dp-intersection__items is a static
   row (see the ≤980px carousel override below), not a scrollable
   carousel, so a step indicator wouldn't mean anything there. */
.dp-intersection .custom-pagination {
  display: none;
}

.dp-intersection__items {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 100px;
  width: 100%;
  /* The connector below renders at its natural ~84px height (872px
     wide at the source SVG's own 1067:102 ratio) plus 20px of clear
     space on each side of it — 20 + 84 + 20 = 124px total, so the gap
     itself grows to fit the line instead of squashing it. */
  margin-top: 124px;
}

/* Spans exactly between the two outer circles' centers: with 3 equal
   336px items and a 100px gap, center-to-center distance is
   2×336 + 2×100 = 872px, and since the row is centered, that span
   shares the same horizontal center as the row itself. Sits in the
   (now-enlarged) gap between the subtitle and the row rather than
   crossing the circles. No explicit height — left at its own natural
   aspect ratio (undistorted) rather than squashed to fit. */
.dp-intersection__connector {
  position: absolute;
  bottom: calc(100% + 20px);
  left: 50%;
  z-index: 5;
  width: 872px;
  transform: translateX(-50%);
  pointer-events: none;
}

.dp-intersection__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 336px;
}

.dp-intersection__item-photo {
  width: 160px;
  height: 160px;
  border-radius: 50%;
  overflow: hidden;
  margin-bottom: 26px;
  /* Figma layer effects, translated 1:1:
     drop shadow (0 / 6 / 20 / 0, #000 10%),
     inner shadow (-2 / -4 / 13 / 0, #FF6100 14%),
     inner shadow (0 / 0 / 4 / 0, #FFFFFF 70%). */
  box-shadow:
    0px 6px 20px 0px rgba(0, 0, 0, 0.1),
    inset -2px -4px 13px 0px rgba(255, 97, 0, 0.14),
    inset 0px 0px 4px 0px rgba(255, 255, 255, 0.7);
  /* Figma "Background blur" (uniform, 14) */
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.dp-intersection__item-photo img {
  width: 100%;
  height: 100%;
  padding: 14px;
  object-fit: cover;
}

.dp-intersection__item-title {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 1px;
  color: #232323;
  margin: 0 0 12px;
}

.dp-intersection__item-text {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-light);
  line-height: 22px;
  letter-spacing: 0.5px;
  color: #232323;
  margin: 0;
  padding: 0 20px;
}

/* ---------- 2. "Из чего состоит дизайн-проект?" ---------- */
.dp-video {
  position: relative;
  padding: 120px 0 60px;
  background: var(--color-bg-primary);
}

.dp-video__inner {
  position: relative;
  z-index: 1;
  margin: 0 4rem;
}

@media (min-width: 1920px) {
  .dp-video__inner {
    margin: 0 12rem;
  }
}

.dp-video__title {
  text-align: center;
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-regular);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 48px;
}

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

/* Placeholder "counter" bezel behind the (currently smaller) video
   preview — stands in for the real device frame until this becomes
   a proper video. */
.dp-video__placeholder {
  position: relative;
  border-radius: 28px;
  background: #f7f7f7;
  border: 1px solid rgba(229, 229, 229, 0.5);
  padding: 8px;
  /* Animated as one rigid panel — bezel, notch and inner frame all
     tilt together, not just the frame inside a static casing. Flat
     by default; design-project.js sets the tilted starting state via
     gsap.set() and scrubs it back to flat on scroll, so a JS load
     failure just leaves it flat instead of stuck tilted. */
  transform-origin: 50% 100%;
  will-change: transform;
}

.dp-video__camera {
  /* Nested at the .dp-video__placeholder level, not inside
     .dp-video__frame (which has overflow:hidden) — the icon's own
     "ear" shapes are meant to blend into the placeholder's #f7f7f7
     bezel above the frame, so clipping them there would cut off the
     part that's supposed to show. Sitting inside the placeholder
     (the element design-project.js applies the scroll-tilt transform
     to) still means it tilts/scales together with the rest of the
     panel — transforms apply to all descendants regardless of depth. */
  position: absolute;
  top: 8px;
  left: 50%;
  z-index: 2;
  width: 160px;
  height: auto;
  transform: translateX(-50%);
  pointer-events: none;
}

.dp-video__frame {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(135deg, #7c7c7c 0%, #3d3a38 55%, #8a7161 100%);
  aspect-ratio: 1786 / 934;
}

.dp-video__screenshot {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The source render has a plain white background, not the dark
   gradient mockup shown in the design — this darkens it to match. */
.dp-video__tint {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  pointer-events: none;
}

.dp-video__player {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none;
}

/* .has-started (set once, on the first play) swaps the static poster
   for the video for good — pausing later shouldn't bring the
   screenshot back behind it. .is-playing tracks actual play/pause
   state instead, toggling just the play button and controls, so
   pausing (click the video, or the mute/progress controls fade out
   too, matching .portfolio-gallery__controls' own opacity rule
   reused from main.css) brings the play button back. */
.dp-video__frame.has-started .dp-video__player {
  display: block;
}

.dp-video__frame.has-started .dp-video__screenshot,
.dp-video__frame.has-started .dp-video__tint {
  display: none;
}

.dp-video__frame.is-playing .dp-video__play {
  display: none;
}

.dp-video__frame.is-playing .portfolio-gallery__controls {
  opacity: 1;
  pointer-events: auto;
}

.dp-video__play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(20px);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: var(--transition-default);
}

.dp-video__play:hover {
  background: var(--color-bg-primary);
  transform: translate(-50%, -50%) scale(1.06);
}

.dp-video__play img {
  width: 20px;
  height: 20px;
  margin-left: 3px;
}

/* The source SVG is a flat white fill, so it can't be recolored with
   a plain CSS `color` the way text can. brightness(0) first collapses
   it to solid black, then invert(18%) lifts it to ~#2e2e2e. */
.dp-video__play:hover img {
  filter: brightness(0) invert(18%);
}

.dp-video__cols {
  display: flex;
  justify-content: space-between;
  gap: 48px;
  margin: 56px 0 0;
  padding: 0 120px;
}

.dp-video__col {
  flex: 1;
}

.dp-video__col h4 {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  margin: 0 0 12px;
}

.dp-video__col-icon {
  width: 18px;
  height: 18px;
}

.dp-video__col-icon--db {
  width: 23px;
  height: 23px;
}

.dp-video__col-icon--blueprint {
  width: 26px;
  height: 26px;
}

.dp-video__col p {
  font-size: var(--font-size-md);
  color: var(--color-text-secondary);
  line-height: 1.5;
  margin: 0;
  /* icon (18px) + h4 gap (10px) so text lines up with the title, not the icon */
  padding-left: 28px;
  max-width: 328px;
}

.dp-video__gradient {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  height: 520px;
  background: linear-gradient(to top, #d5c5b3 0%, var(--color-bg-primary) 100%);
  pointer-events: none;
}

/* ---------- 3. "Самовыражение и домашний уют" + gallery ---------- */
.dp-lifestyle {
  position: relative;
  /* Extra bottom padding is blank canvas for .dp-steps__ghost-word to
     bleed upward into without overlapping this section's real gallery
     content — see the note on .dp-steps. */
  padding: 0 0 60px;
}

.dp-lifestyle__bg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 640px;
  /* Keeps the box no wider (relative to its height) than the source
     image (3840x1620, 64:27) — past ~1517px viewport width, 640px
     alone would make the box wider than the image, forcing
     object-fit: cover to crop vertically and cut into the image's
     own top/bottom fades that .dp-video__gradient below is tuned to
     match. Growing height with viewport width keeps the full image
     height always in frame instead. */
  min-height: 42.1875vw;
  overflow: hidden;
  z-index: 0;
}

.dp-lifestyle__bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
}

.dp-lifestyle__content {
  position: relative;
  z-index: 1;
  padding-top: 32px;
  padding-bottom: 96px;
  padding-left: calc(var(--container-padding-base) * 2);
}

@media (min-width: 1440px) {
  .dp-lifestyle__content {
    padding-top: 104px;
  }
}

.dp-lifestyle__title {
  font-size: 40px;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  line-height: 1.15;
  margin: 0 0 20px;
  max-width: 560px;
}

.dp-lifestyle__title-line {
  display: inline-block;
}

.dp-lifestyle__title-accent {
  background: linear-gradient(90deg, #b9744a 0%, #e1a57d 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.dp-lifestyle__text {
  font-size: var(--font-size-lg);
  color: #232323;
  max-width: 420px;
  line-height: 1.5;
  margin: 0 0 40px;
}

.dp-lifestyle__cta {
  display: inline-flex;
  max-width: 290px;
  background: none;
  border-color: #d4d4d4;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.dp-lifestyle__cta img {
  width: 20px;
  height: 20px;
}

/* The source SVG is a flat #202020 fill, so it can't be recolored with
   a plain CSS `color` the way text can. brightness(0) first collapses
   it to solid black, then invert(100%) flips it to white. */
@media (hover: hover) and (pointer: fine) {
  .dp-lifestyle__cta:hover {
    border-color: transparent;
  }

  .dp-lifestyle__cta:hover img {
    filter: brightness(0) invert(100%);
  }
}

.dp-lifestyle .design__swiper {
  margin-top: 64px;
}

@media (min-width: 1920px) {
  .dp-lifestyle .design__swiper {
    margin-top: 144px;
  }
}

/* The homepage's own "Визуализации" gallery gets a responsive slide
   height via .design__slider (main.css ~3103/~3229) — this swiper is
   never wrapped in that class, so it was stuck at .design__slider-img's
   shared base height (678px, main.css:2956) at every viewport, way
   oversized relative to a narrow phone screen instead of shrinking
   like the homepage one does. Reproducing both of that rule's tiers
   scoped to .dp-lifestyle instead of adding the .design__slider class
   itself, which would also pull in that class's other unrelated
   homepage-specific rules. */
@media (max-width: 1440px) {
  .dp-lifestyle .design__swiper .swiper-slide .design__slider-img {
    height: auto;
    aspect-ratio: 16 / 9;
  }
}

@media (max-width: 670px) {
  .dp-lifestyle .design__swiper .swiper-slide .design__slider-img {
    height: 460px;
    width: auto;
    object-fit: cover;
    object-position: center;
  }
}

/* ---------- "Этапы и сроки" accordion ---------- */
.dp-steps {
  position: relative;
  padding: 250px 0 0;
  background: var(--color-bg-primary);
}

.dp-steps__ghost {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.dp-steps__ghost-word {
  position: absolute;
  font-size: 280px;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  color: #f8f8f8;
  white-space: nowrap;
  letter-spacing: 1px;
}

.dp-steps__ghost-word--1 {
  top: -80px;
  left: -80px;
}

.dp-steps__ghost-word--2 {
  top: 150px;
  right: -160px;
}

/* .dp-steps has no max-width, so these fixed left/right offsets pin
   the words to the viewport edges at any width — past 1920px that
   leaves them far from the (still max-width-capped) content column.
   Percentage offsets scale with the viewport instead, pulling both
   words back toward center on very wide screens. */
@media (min-width: 1920px) {
  .dp-steps__ghost-word--1 {
    left: 12%;
  }

  .dp-steps__ghost-word--2 {
    right: 12%;
  }
}

.dp-steps__header {
  position: relative;
  z-index: 1;
  margin-bottom: 40px;
  /* Matches the rows' own 91px left padding below, so the heading and
     every row's content (open or closed) line up on the same edge. */
  padding-left: 91px;
}

.dp-steps__title {
  font-size: 40px;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 0 0 16px;
}

.dp-steps__subtitle {
  font-size: var(--font-size-xl);
  color: var(--color-text-primary);
  max-width: 460px;
  line-height: 1.4;
  margin: 0;
}

.dp-steps__accent {
  color: var(--color-accent-primary);
  font-weight: var(--font-weight-semibold);
}

.dp-steps__panel {
  position: relative;
  z-index: 1;
  background: #f8f8f8;
  padding: 35px 0 1px;
}

/* .dp-steps__panel only has 1px of its own bottom padding, so the last
   row would otherwise sit flush against the panel's bottom edge. Comes
   before .is-open below so opening the last item still gets the
   (larger) open-state padding instead of this one. */
.dp-steps__item:last-child {
  padding-bottom: 30px;
}

.dp-steps__item.is-open {
  padding-bottom: 35px;
}

/* When an open item isn't last, the next item's own margin-top below
   (16px, same rule as this item's own is-open margin-top above) is
   now what creates the bottom gap — so this item's own 35px padding
   would otherwise stack on top of that and make the bottom gap bigger
   than the top one. Only the actual last item keeps the 35px, since
   there it's clearing the panel's edge instead, not another row. */
.dp-steps__item.is-open:not(:last-child) {
  padding-bottom: 0;
}

/* Same idea as the next-row fix below, mirrored for the row *before* an
   open item: without this, an open item's row (and its hover highlight)
   sits flush against whatever row precedes it, with no equivalent gap
   to the one below it. Skipped when the open item is first (nothing
   above it to clear). */
.dp-steps__item + .dp-steps__item.is-open {
  margin-top: 16px;
}

/* The open item's own 35px padding-bottom already clears its body-inner
   from the panel/next row, but the very next row's :hover highlight
   (its own rounded background, filling right up to the row's edge)
   still reads as touching that boundary with no breathing room. A
   little extra top margin scoped to just this adjacent row fixes that
   without adding gap between every other closed row pair. */
.dp-steps__item.is-open + .dp-steps__item .dp-steps__row {
  margin-top: 16px;
}

.dp-steps__row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 39px 44px 39px 91px;
  border: none;
  background: none;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: var(--transition-default);
}

.dp-steps__row:hover {
  background: var(--color-bg-primary);
  border-radius: 16px;
}

.dp-steps__item.is-open .dp-steps__row {
  background: var(--color-bg-primary);
  /* Square bottom corners (vs. .dp-steps__row:hover's all-round 16px)
     so the row sits flush against .dp-steps__body-inner below it
     instead of the two rounded edges visually pinching apart where
     they meet. */
  border-radius: 16px 16px 0 0;
  padding: 47px 44px 16px 91px;
}

.dp-steps__row-left,
.dp-steps__row-right {
  display: flex;
  align-items: center;
  gap: 24.5px;
}

.dp-steps__row-right {
  gap: 30px;
}

.dp-steps__num {
  position: relative;
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #2e2e2e;
  color: var(--color-bg-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-lg);
}

.dp-steps__num--active {
  background: var(--color-accent-primary);
}

/* Connector line hanging from the active step's number, down past the
   row into the description below (the row/body are siblings with
   default overflow:visible, so this isn't clipped at the row's own
   edge). scaleY(0) -> scaleY(1) with transform-origin:top grows it
   downward from the circle instead of just fading in in place; the
   eased transition reads as a quick grow to ~80% that settles the
   last stretch into place, rather than a linear reveal. */
.dp-steps__num-line {
  position: absolute;
  top: 100%;
  left: 50%;
  width: 2px;
  height: 60px;
  background: var(--color-accent-primary);
  transform: translateX(-50%) scaleY(0);
  transform-origin: top;
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}

.dp-steps__num--active .dp-steps__num-line {
  transform: translateX(-50%) scaleY(1);
}

.dp-steps__row-title {
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-regular);
  color: var(--color-text-primary);
  letter-spacing: 0.5px;
}

.dp-steps__duration {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-medium);
  color: var(--color-black);
  background: var(--color-bg-primary);
  border-radius: 19px;
  padding: 8px 17px 8px 14px;
  white-space: nowrap;
}

.dp-steps__arrow {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  transition: transform var(--duration-medium) var(--ease-out);
}

.dp-steps__arrow img {
  width: 100%;
  height: 100%;
  display: block;
}

.dp-steps__item.is-open .dp-steps__arrow {
  transform: rotate(180deg);
}

/* Height is driven by GSAP (design-project.js) tweening to/from
   "auto" for a smooth open/close instead of the old instant
   display:none/flex swap. overflow:hidden clips it while collapsed;
   the actual padding/background live on .dp-steps__body-inner so a
   height:0 body has no residual padding making it non-zero. */
.dp-steps__body {
  height: 0;
  overflow: hidden;
}

.dp-steps__item.is-open .dp-steps__body {
  height: auto;
}

.dp-steps__body-inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
  background: var(--color-bg-primary);
  border-radius: 0 0 16px 16px;
  /* 91px row padding + 38px number + 24.5px row-left gap, so the
     description/CTA line up under .dp-steps__row-title, not the number. */
  padding: 0 44px 45px 153.5px;
}

.dp-steps__desc {
  font-size: 18px;
  color: #232323;
  line-height: 1.4;
  max-width: 836px;
  margin: 0;
}

.dp-steps__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 14px;
  padding: 8px 20px;
  border-radius: 40px;
  background: var(--color-accent-primary);
  color: var(--color-bg-primary);
  font-size: var(--font-size-lg);
  text-decoration: none;
  transition: var(--transition-default);
}

.dp-steps__cta:hover {
  box-shadow: 0 2px 12px 0 rgba(255, 120, 38, 0.8);
}

/* ---------- "Чтобы вам все понравилось" perks grid ---------- */
.dp-perks {
  padding: 80px 0;
  background: var(--color-bg-primary);
}

.dp-perks__title {
  font-size: 38px;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 1px;
  text-align: center;
  margin: 0 0 80px;
}

/* Hidden by default: above 760px .dp-perks__grid is a static 4-column
   grid (see below), not a scrollable carousel, so a step indicator
   wouldn't mean anything there. */
.dp-perks .custom-pagination {
  display: none;
}

.dp-perks__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}

.dp-perks__card {
  display: flex;
  flex-direction: column;
  background: var(--color-bg-secondary);
  border-radius: 24px;
  padding: 12px;
}

.dp-perks__icon {
  width: 44px;
  height: 44px;
  margin-bottom: 16px;
}

.dp-perks__card-title {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  margin: 0 0 8px;
}

.dp-perks__card-text {
  font-size: var(--font-size-md);
  color: var(--color-text-primary);
  line-height: 1.4;
  margin: 0 0 24px;
}

.dp-perks__photo {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 16px;
  overflow: hidden;
  margin-top: auto;
}

.dp-perks__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.35s ease;
}

.dp-perks__card:hover .dp-perks__photo img {
  transform: scale(1.08);
}

/* ---------- 4. "Анатомия дизайн-проекта" ---------- */
.dp-anatomy {
  position: relative;
  padding: 0 0 100px;
  background: var(--color-bg-primary);
  text-align: center;
}

.dp-anatomy__label {
  font-size: var(--font-size-2xl);
  color: var(--color-text-tertiary);
  text-transform: uppercase;
  letter-spacing: 2px;
  margin: 0 0 8px;
}

.dp-anatomy__title {
  font-size: var(--font-size-6xl);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  margin: 0 0 28px;
}

.dp-anatomy__credit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 0 0 48px;
}

.dp-anatomy__credit img {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.dp-anatomy__credit p {
  max-width: 600px;
  font-size: var(--font-size-md);
  color: var(--color-text-secondary);
  margin: 0;
}

.dp-anatomy__credit em {
  font-style: italic;
  color: var(--color-text-primary);
}

.dp-anatomy__bg {
  position: absolute;
  top: 220px;
  left: 50%;
  z-index: 0;
  width: 1500px;
  max-width: 90%;
  transform: translateX(-50%);
  pointer-events: none;
}

@media (min-width: 1920px) {
  .dp-anatomy__bg {
    top: 140px;
  }
}

.dp-anatomy__bg img {
  display: block;
  width: 100%;
  height: auto;
  -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent 100%);
  mask-image: radial-gradient(closest-side, #000 55%, transparent 100%);
}

.dp-anatomy > .container,
.dp-anatomy__slider {
  position: relative;
  z-index: 1;
}

.dp-anatomy__slider {
  max-width: 1757px;
  margin: 0 auto;
  padding: 0 0 40px;
}

.dp-anatomy__swiper {
  /* Swiper 11's own base CSS styles the `.swiper` class, not the
     legacy `.swiper-container` name — without this, slides rendered
     in normal document flow instead of the coverflow carousel. */
  position: relative;
  overflow: hidden;
}

/* On wide viewports the outermost slides land right at this container's
   edge and get hard-clipped mid-card by overflow:hidden. A `mask-image`
   here would fade that smoothly, but it sits above .dp-anatomy__card's
   own backdrop-filter blur in the ancestor chain — masking an ancestor
   breaks descendant backdrop-filter (same family of conflict as the
   card's own ::before border-ring, which fought backdrop-filter for the
   same reason). These overlay gradients fade the edges instead, without
   ever touching an element that's an ancestor of the blurred cards. */
.dp-anatomy__swiper::before,
.dp-anatomy__swiper::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  /* The offset-±2 cards sit ~725.8px from the active card's center (see
     ANATOMY_GAP/ANATOMY_SHRINK in applyAnatomyTransforms,
     design-project.js) — below ~1452px viewport width there's no room
     left over before the fade would start eating into that card, and
     below that same width the card starts getting clipped by this
     container's own overflow:hidden regardless. Scaling the fade down
     with the leftover space keeps it from swallowing a card that's
     otherwise still visible; it only reaches its full 120px again once
     the slider hits its own 1757px max-width, as originally designed. */
  width: clamp(0px, calc((100vw - 1452px) / 2), 120px);
  z-index: 2;
  pointer-events: none;
}

.dp-anatomy__swiper::before {
  left: 0;
  background: linear-gradient(to right, var(--color-bg-primary), transparent);
}

.dp-anatomy__swiper::after {
  right: 0;
  background: linear-gradient(to left, var(--color-bg-primary), transparent);
}

.dp-anatomy__swiper .swiper-wrapper {
  align-items: center;
}

/* Every card shares the same intrinsic 440×540 box before the custom
   scale/position transform in design-project.js shrinks the side slides
   — anchoring that scale to the center keeps every card's visual center
   on the same horizontal axis as the active card, instead of pooling at
   one edge. */
.dp-anatomy__swiper .swiper-slide {
  transform-origin: center center;
}

/* Every slide keeps the same intrinsic width/height (Swiper's loop math
   for slidesPerView:'auto' pre-computes clone slides from each slide's
   real layout size at init — changing that live on whichever slide is
   active broke looping and caused a visible snap mid-transition). The
   center-is-bigger look below comes entirely from coverflowEffect.scale
   in design-project.js, which is a paint-only transform and never
   touches layout — same mechanism as .design__swiper /
   .portfolio-gallery__swiper. */
.dp-anatomy__slide {
  width: 396px;
}

.dp-anatomy__card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 486px;
  box-sizing: border-box;
  padding: 8px;
  border-radius: var(--radius-2xl);
  overflow: hidden;
  text-align: left;
  background: rgba(255, 255, 255, 0.4);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
}

/* Gradient stroke drawn as a 1px ring via mask-composite, independent
   of the card's own fill/backdrop-filter — a dual-background-clip
   gradient border here fought with backdrop-filter and rendered the
   stroke at the fill's opacity instead of solid. */
.dp-anatomy__card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(to top, #DDDDDD, #EEEEEE);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

.dp-anatomy__card-media {
  position: relative;
  flex: 0 0 65%;
  min-height: 0;
  border-radius: calc(var(--radius-2xl) - 8px);
  overflow: hidden;
}

.dp-anatomy__card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.dp-anatomy__card--tour {
  display: flex;
  align-items: flex-end;
}

.dp-anatomy__card--tour .dp-anatomy__card-img {
  flex: 1;
  height: 100%;
  min-height: 0;
  border-radius: calc(var(--radius-2xl) - 8px);
}

.dp-anatomy__tour-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 5px 10px;
  border: none;
  border-radius: 100px;
  background: rgba(20, 20, 20, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--color-bg-primary);
  font-size: var(--font-size-sm);
  text-align: left;
  line-height: 1.3;
  cursor: pointer;
}

.dp-anatomy__tour-btn img {
  width: 64px;
  height: 64px;
  flex-shrink: 0;
}

.dp-anatomy__tour-btn-text {
  display: block;
  white-space: nowrap;
  padding-right: 12px;
}

.dp-anatomy__card-info {
  padding: 0 20px;
}

.dp-anatomy__card-title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  margin: 12px 0 8px;
}

.dp-anatomy__card-text {
  font-size: var(--font-size-sm);
  color: var(--color-text-primary);
  line-height: 1.4;
  margin: 0;
}

/* Same light-dots/orange-active pagination as .dp-perks and
   .dp-intersection; mobile (≤760px) overrides the spacing below. */
.dp-anatomy .custom-pagination {
  position: static;
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 8px;
}

.dp-anatomy .custom-pagination .swiper-pagination-bullet {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #d9d9d9;
  opacity: 1;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.dp-anatomy .custom-pagination .swiper-pagination-bullet-active {
  background-color: var(--color-accent-primary);
}

.dp-anatomy__arrow {
  position: absolute;
  top: 46%;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--color-border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  background: var(--color-bg-primary);
  transition: var(--transition-default);
  z-index: 2;
}

.dp-anatomy__arrow:hover {
  background: var(--color-text-primary);
}

.dp-anatomy__arrow--prev {
  left: 40px;
}

.dp-anatomy__arrow--next {
  right: 40px;
}

/* The next/prev SVGs are the same left-pointing glyph (see the source
   assets) — mirror it here for "next" instead of shipping a second
   asset. */
.dp-anatomy__arrow--next img {
  transform: scaleX(-1);
}

.dp-anatomy__footer {
  margin-top: 8px;
  text-align: center;
}

.dp-anatomy__pdf {
  /* .border-btn's own `display:flex` is a block-level box that fills
     its container's width by default — inline-flex shrink-wraps to
     content instead, like every other pill button on this page. */
  display: inline-flex;
  height: 60px;
  padding-left: 2px;
  border-color: #E4E4E4;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: #616161;
}

@media (hover: hover) and (pointer: fine) {
  .dp-anatomy__pdf:hover {
    background-color: #fff;
    color: #191919;
  }
}

.dp-anatomy__pdf img {
  width: 50px;
  height: 50px;
}

/* ---------- Baudrillard quote ---------- */
.dp-quote {
  padding: 100px 0;
  background: var(--color-bg-primary);
}

.dp-quote__wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 80px;
}

.dp-quote__attribution {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 0 0 530px;
}

.dp-quote__avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.dp-quote__attribution-text {
  max-width: 450px;
  font-size: var(--font-size-md);
  line-height: 1.5;
  color: var(--color-text-primary);
  margin: 0;
}

.dp-quote__main {
  flex: 0 1 600px;
  margin: 0;
  font-family: Georgia, "Times New Roman", Times, serif;
  font-style: italic;
  font-size: var(--font-size-4xl);
  line-height: 1;
  color: var(--color-text-primary);
}

/* ---------- 5. "Цены" ---------- */
.dp-prices {
  padding: 100px 0 140px;
  background: var(--color-bg-primary);
}

.dp-prices__top {
  display: none;
}

.dp-prices__wrap {
  display: flex;
  align-items: flex-start;
  gap: 64px;
  /* .container already contributes one unit of left padding — adding a
     second here doubles the total without hardcoding a value that
     would only be right at one breakpoint. */
  padding-left: var(--container-padding-base);
  /* Overrides .container's shared 1750px cap: .dp-prices__cards is
     flex:1, so past 1440px it would keep stretching wider all the way
     to that cap — capping the wrap itself at 1440px keeps the cards
     (and everything else here) the same size from 1440px up. */
  max-width: 1440px;
}

.dp-prices__text {
  flex: 0 0 400px;
  /* .dp-prices__card-head has its own 32px top padding, so "Luxor"/
     "LuxorPRO" sit 32px below the card's top edge — matching that
     here lines "Цены" up on the same row as those headings. */
  margin-top: 32px;
}

.dp-prices__title {
  font-size: var(--font-size-5xl);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  margin: 0 0 20px;
}

.dp-prices__desc {
  font-size: var(--font-size-md);
  color: var(--color-text-secondary);
  line-height: 1.5;
  max-width: 300px;
  margin: 0 0 40px;
}

.dp-prices__cta {
  display: inline-flex;
}

.dp-prices__cards {
  display: flex;
  gap: 10px;
  flex: 1;
}

.dp-prices__card {
  position: relative;
  flex: 1;
  height: 634px;
  border-radius: var(--radius-2xl);
  overflow: hidden;
  display: block;
  color: var(--color-bg-primary);
  text-decoration: none;
}

.dp-prices__card-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-out);
}

.dp-prices__card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 50%);
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .dp-prices__card:hover .dp-prices__card-bg {
    transform: scale(1.05);
  }

  .dp-prices__card:hover .dp-prices__tag {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
  }
}

.dp-prices__tag {
  position: absolute;
  top: 24px;
  right: 24px;
  z-index: 2;
  padding: 6px 14px;
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  transition: var(--transition-default);
}

.dp-prices__tag--orange {
  background: var(--color-accent-primary);
}

.dp-prices__tag--red {
  background: #d13b2b;
}

.dp-prices__card-head {
  position: relative;
  z-index: 2;
  padding: 32px 0 0 32px;
}

.dp-prices__card-head::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 200px;
  background: linear-gradient(to bottom, #695f57 0%, rgba(105, 95, 87, 0) 100%);
  pointer-events: none;
  z-index: -1;
}

.dp-prices__card--luxor .dp-prices__card-head::after {
  background: linear-gradient(to bottom, #ad9582 0%, rgba(173, 149, 130, 0) 100%);
}

.dp-prices__card-head h3 {
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  margin: 0 0 6px;
}

.dp-prices__card-head p {
  font-size: var(--font-size-sm);
  opacity: 0.85;
  margin: 0;
}

.dp-prices__card-head .dp-prices__card-desc {
  font-size: var(--font-size-md);
}

.dp-prices__card--pro .dp-prices__card-desc {
  max-width: 300px;
}

.dp-prices__card-price {
  position: absolute;
  left: 32px;
  bottom: 32px;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: 4px;
}

.dp-prices__from {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  text-transform: uppercase;
}

.dp-prices__num {
  font-size: 80px;
  font-weight: var(--font-weight-light);
  line-height: 0.73;
}

.dp-prices__unit {
  font-size: var(--font-size-md);
  opacity: 0.85;
  line-height: 1;
}

/* ---------- Shared grey backdrop behind .dp-meet + .dp-faq ---------- */
.dp-meet-faq-bg {
  position: relative;
  background: #f8f8f8;
}

.dp-meet-faq-bg__fade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 160px;
  background: linear-gradient(to bottom, #fff 0%, rgba(255, 255, 255, 0) 100%);
  pointer-events: none;
}

/* ---------- "Давайте знакомиться" intro form ---------- */
.dp-meet {
  position: relative;
  padding: 100px 0 0;
}

/* Shown only ≤760px (see the media query below), in place of .dp-meet
   above — desktop keeps the current dp-meet form untouched. */
.dp-meet__mobile-form {
  display: none;
}

.dp-meet__wrapper {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 120px;
}

.dp-meet__content {
  display: flex;
  flex-direction: column;
  max-width: 560px;
  margin-top: 60px;
  /* .dp-meet__wrapper centers the content+media pair as one group, so
     content's rendered left edge floats wherever that centering leaves
     it — not aligned with .dp-prices__text's edge below. .dp-meet__media
     has a fixed width (420px) and must stay exactly where centering
     puts it, so instead of switching the wrapper off justify-content:
     center (which would also drag media into a new position), this
     shifts content sideways with a transform — that doesn't participate
     in flex sizing, so it doesn't affect the group's centering math or
     media's position at all.
     The math (both sides use --vw, the site's scrollbar-corrected
     100vw custom prop from main.js, and P = --container-padding-base):
     - .dp-meet__wrapper is a plain .container (max-width 1750px, this
       codebase's --container-width-max) centered on the viewport, with
       content further centered inside it against the 420px media at a
       120px gap (1100px total). Nested centering cancels the 1750px
       cap out entirely — algebraically it reduces to content sitting
       at (--vw / 2) - 550px from the viewport edge, full stop.
     - .dp-prices__wrap is also a .container but overrides max-width to
       1440px and re-declares padding-left: P — same property, same
       specificity as .container's own, so (main.css loading before
       design-project.css) it just replaces .container's value with an
       identical one; despite a comment there calling this a 2nd unit
       of padding, it isn't additive and .dp-prices__text really sits
       at just 1x P in from wherever the (1440px-capped) wrap's own
       left edge lands: (min(--vw, 1440px) - --vw) / -2 + P, i.e.
       P + max(0px, --vw/2 - 720px).
     Subtracting the two gives this element's shift. Assumes content
     actually renders at its 560px max-width, which holds from the
     ~761px desktop cutover up through very wide screens; only in a
     narrow band under ~1100px total wrapper width would content itself
     shrink below 560px and this drift slightly, since a static
     transform can't track that dynamic shrink. */
  transform: translateX(calc(
    var(--container-padding-base)
    + max(0px, (var(--vw, 100vw) / 2) - 720px)
    - (var(--vw, 100vw) / 2)
    + 550px
  ));
}

.dp-meet__title {
  font-size: 40px;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 1px;
  /* Was 16px margin + the parent's 40px flex gap (56px total) —
     halved to 28px. The flex gap is gone now (it applied uniformly to
     every child), so the text→form spacing it used to provide is
     restated as the text's own margin-bottom below. */
  margin: 0 0 28px;
}

.dp-meet__text {
  font-size: var(--font-size-xl);
  color: var(--color-text-primary);
  line-height: 1.4;
  margin: 0 0 40px;
}

.dp-meet__inputs {
  flex-direction: row;
  gap: 20px;
}

.dp-meet__inputs .lux-input {
  flex: 1;
}

.dp-meet__hint {
  font-style: normal;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
}

.dp-meet__media {
  flex-shrink: 0;
  width: 420px;
}

.dp-meet__media img {
  /* Pre-composed cutout (arch backdrop + portrait baked into one PNG
     with transparency) — shown at its own natural shape, not clipped
     into a rounded box like a plain rectangular photo would be. */
  width: 100%;
  height: auto;
  display: block;
}

/* ---------- "Вопросы и ответы" FAQ accordion ---------- */
.dp-faq {
  padding: 0 0 120px;
}

.dp-faq__panel {
  /* .container is already width:100%/margin:0 auto — shrinking the
     width (rather than adding literal margin to a 100%-wide box, which
     would overflow) keeps it centered at every viewport size while
     still insetting 2rem on each side. */
  width: calc(100% - 4rem);
  margin-left: auto;
  margin-right: auto;
  background: var(--color-bg-primary);
  border-radius: var(--radius-2xl);
  padding: 80px 60px;
  text-align: center;
}

.dp-faq__title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-size: var(--font-size-6xl);
  font-weight: var(--font-weight-regular);
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 0 0 24px;
}

.dp-faq__title-icon-wrap {
  position: relative;
  display: flex;
  flex: none;
}

/* 70px ellipse behind the icon; absolute so it doesn't change the
   title's layout size. */
.dp-faq__title-icon-wrap::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 70px;
  height: 70px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #E9DFDB;
}

.dp-faq__title-icon {
  position: relative;
  width: 64px;
  height: 64px;
  object-fit: contain;
}

.dp-faq__subtitle {
  max-width: 620px;
  margin: 0 auto 48px;
  font-size: var(--font-size-xl);
  color: var(--color-text-primary);
  line-height: 1.4;
}

.dp-faq__subtitle a {
  color: var(--color-accent-primary);
  text-decoration: underline;
}

.dp-faq__list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-align: left;
}

.dp-faq__row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  background: none;
  border: none;
  padding: 22px 36px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}

.dp-faq__item {
  background: #f9f9f9;
  /* Transparent by default (not just omitted) so gaining a real border
     on open doesn't change the box's size/position. */
  border: 1px solid transparent;
  border-radius: 100px;
  /* 0.6s to match design-project.js's own open/close height tween
     duration, so the corners round from pill to card (and back) in
     step with the row growing/shrinking instead of on their own timer. */
  transition: border-radius 0.6s var(--ease-out),
    background-color 0.6s var(--ease-out),
    border-color 0.6s var(--ease-out);
}

.dp-faq__item.is-open {
  background: var(--color-bg-primary);
  border-color: #e2e2e2;
  border-radius: var(--radius-2xl);
}

.dp-faq__row-left {
  display: flex;
  align-items: center;
  gap: 19px;
}

.dp-faq__num {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #2e2e2e;
  color: var(--color-bg-primary);
  font-size: var(--font-size-xl);
}

.dp-faq__item.is-open .dp-faq__num {
  background: var(--color-accent-primary);
}

.dp-faq__row-title {
  font-size: var(--font-size-xl);
  color: var(--color-text-primary);
}

.dp-faq__item.is-open .dp-faq__row-title {
  font-weight: var(--font-weight-semibold);
}

.dp-faq__arrow {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  transition: transform var(--duration-medium) var(--ease-out);
}

.dp-faq__arrow img {
  width: 100%;
  height: 100%;
  display: block;
  /* Some mobile browsers treat a direct tap on an <img> as an image
     gesture (long-press-to-save, drag) instead of passing it through
     as a click on the parent .dp-faq__row button — this forces every
     tap in the icon's box straight through to the button. */
  pointer-events: none;
}

.dp-faq__item.is-open .dp-faq__arrow {
  transform: rotate(180deg);
}

/* height:0/overflow:hidden (not display:none) so the open/close is a
   smooth GSAP height tween in design-project.js instead of an instant
   snap — the padding lives on .dp-faq__body-inner so a height:0 body
   has no residual padding forcing it non-zero (same split as
   .dp-steps__body / .dp-steps__body-inner). */
.dp-faq__body {
  height: 0;
  overflow: hidden;
}

.dp-faq__item.is-open .dp-faq__body {
  height: auto;
}

.dp-faq__body-inner {
  padding: 0 36px 36px 100px;
}

.dp-faq__desc {
  max-width: 900px;
  margin: 0 0 32px;
  font-size: var(--font-size-lg);
  color: var(--color-text-primary);
  line-height: 1.4;
}

.dp-faq__vote {
  display: inline-flex;
  align-items: center;
  gap: 24px;
  background: var(--color-bg-secondary);
  border-radius: 100px;
  padding: 14px 24px;
}

.dp-faq__vote-label {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-medium);
}

.dp-faq__vote-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--font-size-md);
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.dp-faq__vote-btn:hover {
  opacity: 0.7;
}

.dp-faq__vote-btn.is-voted {
  cursor: default;
  opacity: 0.5;
}

.dp-faq__vote-btn img {
  width: 24px;
  height: 24px;
}

/* ---------- Desktop-only for this pass ---------- */
@media (max-width: 980px) {
  .dp-video__cols,
  .dp-prices__wrap {
    flex-wrap: wrap;
  }
  /* Stacked text -> cards: half of the desktop 64px gap. */
  .dp-prices__wrap {
    row-gap: 32px;
  }
  /* Fixed-width line stretched to connect the two outer circles only
     makes sense in the single-row layout above — once items wrap it
     no longer spans anything meaningful. */
  .dp-intersection__connector {
    display: none;
  }
  /* .dp-intersection__content's align-items: center auto-centers a
     child that's wider than the column, letting it overflow evenly on
     both sides with no margin needed — the extra margin-left this had
     was double-compensating on top of that built-in centering, pushing
     it an extra --container-padding-base too far left (invisible,
     since .dp-intersection's own overflow: hidden clips it) while
     coming up exactly that much short on the right (very visible).
     Percentage width still resolves against the containing block
     regardless of align-items, so 100% + 2x the container's own
     padding reaches both true screen edges on its own. */
  .dp-intersection__items {
    justify-content: flex-start;
    flex-wrap: nowrap;
    gap: 24px;
    margin-top: 40px;
    width: calc(100% + (2 * var(--container-padding-base)));
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scroll-padding: 0;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .dp-intersection__items::-webkit-scrollbar {
    display: none;
  }
  /* scroll-snap-align: start (not center) so the last card's snap
     target is unambiguously "flush with the scrollport's left edge" —
     for a full-width card that also puts its right edge flush, without
     relying on the browser computing a centering offset that can land
     a few px short of the true max scroll position on the final item. */
  .dp-intersection__item {
    width: auto;
    flex: 0 0 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }
  .dp-intersection .custom-pagination {
    position: relative;
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 44px;
  }
  .dp-intersection .custom-pagination .swiper-pagination-bullet {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #d9d9d9;
    opacity: 1;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }
  .dp-intersection .custom-pagination .swiper-pagination-bullet-active {
    background-color: var(--color-accent-primary);
  }

  /* Native scroll-snap carousel — kept inset within .dp-prices__wrap's
     own .container padding (unlike .dp-intersection__items above),
     so each card keeps a visible side gutter instead of going flush
     to the screen edges. */
  .dp-prices__cards {
    flex: none;
    width: 100%;
    flex-wrap: nowrap;
    padding: 0;
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .dp-prices__cards::-webkit-scrollbar {
    display: none;
  }
  .dp-prices__card {
    flex: 0 0 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }
}

@media (max-width: 760px) {
  /* Desktop doubles this to visually separate it from the rest of the
     page's plain .container-aligned content (see the rule above) — on
     mobile it should just line up with everything else instead,
     matching e.g. .portfolio-mobile__header's plain .container. */
  .dp-hero__content {
    padding-left: var(--container-padding-base);
    padding-bottom: 30px;
  }

  .dp-hero__subtitle {
    font-size: 20px;
    white-space: nowrap;
  }

  .dp-hero__price {
    display: none;
  }

  /* 160px top padding (desktop's value, no mobile override existed)
     is way more breathing room than a phone screen needs above this
     section's title. */
  .dp-intersection {
    padding-top: 80px;
  }

  /* Desktop's 3 equal columns become 2-up-1-below: each col is sized
     to exactly half the row (minus half the gap) so only 2 fit per
     line, and the 3rd wraps to its own line — where the existing
     justify-content: space-between (unchanged from desktop) places a
     lone leftover item at the start of the line, i.e. left-aligned,
     with no extra rule needed for that part. */
  .dp-video__cols {
    padding: 0;
    flex-wrap: wrap;
    gap: 24px;
  }

  .dp-video__col {
    flex: 0 0 calc(50% - 12px);
  }

  .dp-hero__title {
    font-size: 32px;
  }

  /* "Дизайн-проект" and "BIM-технологиями" both have a hyphen, which
     browsers treat as a natural break point even under normal
     wrapping — without this they were splitting onto a 2nd line right
     at that hyphen. Each phrase is meant to read as one line (that's
     what the <br>s between them are already for), so force it. */
  .dp-hero__title-line {
    white-space: nowrap;
  }

  .dp-intersection__title {
    font-size: 24px;
  }

  .dp-video__title {
    font-size: 24px;
  }

  /* Same treatment as .dp-hero__content above: desktop's doubled
     padding-left is for separating this from plain .container content
     at wide viewports — on mobile it should just line up like
     everything else, with the same 30px bottom padding as the hero. */
  .dp-lifestyle__content {
    padding-left: var(--container-padding-base);
    padding-bottom: 30px;
  }

  .dp-lifestyle__title {
    font-size: 32px;
  }

  .dp-lifestyle__cta {
    display: flex;
    max-width: none;
    margin-top: 260px;
    color: #fff;
  }

  .dp-lifestyle__cta img {
    filter: brightness(0) invert(100%);
  }

  /* Manually offsetting word 2 by a top value equal to word 1's
     font-size (assuming line-height: 1 makes the line box exactly
     that tall) still left a visible gap — a font's actual glyphs sit
     inside their line box with some leading above/below even at
     line-height: 1, so that math doesn't land the two flush. Letting
     them stack in normal flow instead sidesteps guessing at the
     font's real metrics entirely: the browser lays consecutive lines
     back-to-back on its own with zero gap, no manual offset needed. */
  .dp-steps__ghost {
    display: flex;
    flex-direction: column;
    align-items: center;
    top: -30px;
  }

  .dp-steps__ghost-word {
    position: static;
    font-size: 120px;
    line-height: 1;
  }

  /* line-height: 1 makes the line BOX flush against word 1's with zero
     gap, but both words are all-caps with no descenders — the font's
     own ascent/descent metrics still reserve descender space under
     word 1 (and equivalent space above word 2) that no glyph actually
     uses, reading as a visual gap even though the boxes themselves
     touch. Pulling word 2 up compensates for that unused space.
     Approximate — nudge this if a gap (or overlap) is still visible. */
  .dp-steps__ghost-word--2 {
    margin-top: -25px;
  }

  .dp-lifestyle .design__swiper {
    margin-top: 0;
  }

  .dp-intersection__subtitle {
    font-size: 20px;
  }

  /* No hover on touch: the tooltip opens on tap (.is-open, set in
     design-project.js) and is centered on the screen instead of
     hanging off the icon. */
  .dp-intersection__tooltip {
    position: fixed;
    top: 50%;
    bottom: auto;
    left: 50%;
    width: min(280px, calc(100vw - 32px));
    transform: translate(-50%, -50%);
  }

  .dp-intersection__info-btn:hover .dp-intersection__tooltip {
    opacity: 0;
    visibility: hidden;
    transform: translate(-50%, -50%);
  }

  .dp-intersection__info-btn.is-open .dp-intersection__tooltip {
    opacity: 1;
    visibility: visible;
  }

  .dp-perks {
    padding-top: 30px;
  }

  .dp-perks__title {
    font-size: 24px;
    margin-bottom: 40px;
  }

  .dp-anatomy__title {
    font-size: 32px;
  }

  .dp-intersection__item-photo {
    width: 200px;
    height: 200px;
  }

  .dp-video__inner {
    margin: 0 16px;
  }

  /* Desktop lays attribution + quote out side by side with fixed
     530px/600px widths — on a narrow viewport those don't shrink,
     so the row overflows and the two blocks read as run-together
     text instead of separate stacked ones. */
  .dp-quote {
    padding-top: 0;
  }

  .dp-prices {
    padding-top: 0;
    padding-bottom: 70px;
  }

  .dp-prices__title {
    font-size: 32px;
  }

  /* Mobile-only decorative cap above the section: a white 70px tab
     (top stroke, 16px top corners) with an orange glow ellipse behind
     it, shifted 20px up so only its upper part peeks out. */
  .dp-prices__top {
    display: block;
    position: relative;
    height: 70px;
    margin: 0 var(--container-padding-base);
  }

  .dp-prices__top::before {
    content: "";
    position: absolute;
    top: -20px;
    left: 50%;
    width: 370px;
    height: 70px;
    transform: translateX(-50%);
    border-radius: 50%;
    background: rgba(255, 97, 0, 0.15);
    filter: blur(16px);
  }

  .dp-prices__top::after {
    content: "";
    position: absolute;
    inset: 0;
    background: #fff;
    border-top: 1px solid #e6e6e6;
    border-radius: 16px 16px 0 0;
  }

  .dp-quote__wrapper {
    flex-direction: column;
    align-items: flex-start;
    gap: 64px;
  }

  .dp-quote__attribution {
    flex: none;
    flex-direction: column;
    align-items: center;
    width: 100%;
  }

  .dp-quote__attribution-text {
    max-width: none;
    text-align: center;
    padding-left: 20px;
    padding-right: 20px;
  }

  .dp-quote__avatar {
    width: 109px;
    height: 109px;
  }

  .dp-quote__main {
    flex: none;
    width: 100%;
    text-align: center;
  }

  .dp-meet {
    display: none;
  }

  .dp-meet__mobile-form {
    display: block;
  }

  /* FAQ — mobile layout from Figma (node 2620:229): the icon stacks
     above the title instead of sitting beside it, the subtitle is
     dropped, the panel loses its wide desktop gutters, rows shrink to
     a compact pill, and the open row becomes a bordered white card
     with a boxed (not pill) vote prompt below it. */
  .dp-faq__panel {
    width: 100%;
    padding: 32px 20px;
  }

  /* Icon sits between the words in the markup (desktop); on mobile it
     moves above the text line via grid placement. */
  .dp-faq__title {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: center;
    justify-items: center;
    column-gap: 0.3em;
    row-gap: 8px;
    font-size: 24px;
    margin: 0 0 24px;
  }

  .dp-faq__title-text {
    white-space: nowrap;
  }

  .dp-faq__title-icon-wrap {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  .dp-faq__title-icon {
    width: 80px;
    height: 80px;
  }

  .dp-faq__subtitle {
    display: none;
  }

  .dp-faq__list {
    gap: 8px;
  }

  .dp-faq__row {
    padding: 12px 8px;
    gap: 12px;
  }

  .dp-faq__row-left {
    gap: 9px;
  }

  .dp-faq__num {
    width: 34px;
    height: 34px;
    font-size: 18px;
  }

  .dp-faq__row-title {
    font-size: 18px;
  }

  .dp-faq__arrow-wrap {
    padding: 8px 8px 4px;
  }

  .dp-faq__arrow {
    width: 16px;
    height: 16px;
  }

  .dp-faq__item.is-open {
    background: var(--color-bg-primary);
    border: 1px solid #e2e2e2;
    border-radius: var(--radius-2xl);
  }

  .dp-faq__body-inner {
    padding: 12px 20px 24px;
  }

  .dp-faq__desc {
    font-size: 16px;
    margin: 0 0 24px;
  }

  /* Label forced onto its own line (flex-basis:100%) so the wrapping
     row container puts the two vote buttons together underneath it,
     centered — no wrapper element needed for that middle row. */
  .dp-faq__vote {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    row-gap: 13px;
    column-gap: 40px;
    border-radius: 12px;
    padding: 14px 20px 22px;
  }

  .dp-faq__vote-label {
    flex-basis: 100%;
    text-align: center;
  }

  .dp-faq__vote-btn img {
    width: 32px;
    height: 32px;
  }

  /* Steps — mobile layout from Figma (node 2620:230): the header
     centers and drops its left-aligned offset, and the flat list of
     rows on a shared grey panel becomes individual grey pills with a
     4px gap — the open row becomes its own bordered white card
     instead of just gaining a rounded background in place.
     .dp-steps__num-line (design-project.css, near .dp-steps__num)
     carries over unchanged here — it's absolutely positioned off the
     number circle itself, not the row-left/row-right split, so it
     doesn't need a mobile override to keep working. */
  .dp-steps {
    padding-top: 60px;
  }

  .dp-steps__header {
    padding-left: 0;
    text-align: center;
    margin-bottom: 16px;
  }

  .dp-steps__title {
    font-size: 24px;
    margin: 0 0 8px;
  }

  .dp-steps__subtitle {
    font-size: 18px;
    max-width: none;
    margin: 0 auto;
  }

  .dp-steps__panel {
    background: none;
    padding: 0 0 20px;
  }

  /* .dp-steps__list is also .container, so it already carries one unit
     of side padding on its own — same convention as .dp-hero__content
     on mobile (single var(--container-padding-base), not doubled up
     with .dp-steps__panel's own side padding on top of it). */
  .dp-steps__list {
    padding-left: var(--container-padding-base);
    padding-right: var(--container-padding-base);
  }

  .dp-steps__item {
    margin-bottom: 4px;
  }

  .dp-steps__item:last-child,
  .dp-steps__item.is-open {
    padding-bottom: 0;
  }

  /* .dp-steps__duration lives inside .dp-steps__row-right alongside
     the arrow, but only the duration should drop to its own line
     below the title, left-aligned under it — the arrow stays exactly
     where it already was, on the first line. .dp-steps__row-right's
     own box only spans that narrow right-hand column, too narrow to
     give a "full row width" line to wrap onto, so display: contents
     removes that box from layout entirely, promoting duration and the
     arrow to be direct flex items of .dp-steps__row itself (still in
     the same DOM/paint order). justify-content: space-between (kept
     as-is, unchanged from desktop) is what already places the arrow
     on the right of the first line — duration's own flex-basis: 100%
     below wraps just it onto a second line, where space-between with
     a single item left-aligns it, under the title. */
  .dp-steps__row {
    flex-wrap: wrap;
    padding: 16px 9px 17px 10px;
    gap: 12px;
    border-radius: var(--radius-lg);
    background: var(--color-bg-secondary);
  }

  .dp-steps__row-right {
    display: contents;
  }

  .dp-steps__item.is-open .dp-steps__duration {
    order: 3;
    flex-basis: 100%;
    margin-top: 4px;
    /* Lines its left edge up with the title's, past the 30px number
       circle + 12px .dp-steps__row-left gap it sits behind — without
       this it's flush with the row's own edge instead, sitting under
       the number rather than the title. */
    margin-left: 42px;
  }

  .dp-steps__row:hover {
    background: var(--color-bg-secondary);
    border-radius: var(--radius-lg);
  }

  .dp-steps__item.is-open .dp-steps__row {
    padding: 16px 9px 17px 10px;
    background: var(--color-bg-primary);
    border: 1px solid #e5e5e5;
    border-bottom: none;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  /* min-width: 0 lets this shrink/let its title wrap internally under
     space pressure instead of the default flex min-width: auto (which
     floors it at the title's own min-content width) — without it,
     .dp-steps__row-left + the now-60px .dp-steps__arrow together could
     exceed the row's width for a longer title like "Встреча с
     дизайнером", pushing the arrow itself onto .dp-steps__duration's
     wrapped second line instead of it staying with the title. */
  .dp-steps__row-left {
    min-width: 0;
    gap: 12px;
  }

  .dp-steps__arrow {
    flex-shrink: 0;
  }

  .dp-steps__num {
    width: 30px;
    height: 30px;
    font-size: 18px;
  }

  .dp-steps__num-line {
    height: 30px;
  }

  /* Full width, unlike the desktop figure's 90vw cap. */
  .dp-anatomy__bg {
    width: 100%;
    max-width: none;
    top: 140px;
  }

  /* The desktop figure fades to transparent at its edges via a radial
     mask (design-project.css, .dp-anatomy__bg img) — over this white
     section background that reads as a white gradient eating into the
     photo's left/right edges. Dropping the mask on mobile keeps the
     image solid edge to edge instead. */
  .dp-anatomy__bg img {
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* Below 760px the desktop coverflow fan (design-project.js gates its
     Swiper init to min-width: 761px) is replaced entirely by a plain
     native scroll-snap carousel of full-width cards — the fan's fixed
     396px card width has nowhere to shrink to on a phone, and the
     reference design shows a single full-bleed card with dots, not
     shrunk neighbors peeking in. */
  .dp-anatomy__swiper {
    overflow: visible;
  }

  .dp-anatomy__swiper::before,
  .dp-anatomy__swiper::after {
    display: none;
  }

  .dp-anatomy__swiper .swiper-wrapper {
    align-items: stretch;
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }

  .dp-anatomy__swiper .swiper-wrapper::-webkit-scrollbar {
    display: none;
  }

  .dp-anatomy__slide {
    width: auto;
    flex: 0 0 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }

  /* The last 5 of the 10 slides in the DOM are a documented repeat
     that only exists so the desktop coverflow's loop mode has enough
     slides (see the HTML comment above the 6th slide) — only the
     first 5 are real, dotted, swipeable content on mobile. */
  .dp-anatomy__slide:nth-child(n + 6) {
    display: none;
  }

  /* .dp-anatomy__swiper's own padding wouldn't create real breathing
     room for the card — now that each slide is its own full-width
     native-scroll snap point (not JS-transformed), width: calc(100% -
     28px) + this margin insets the card symmetrically within it. */
  .dp-anatomy__card {
    width: calc(100% - 28px);
    margin-left: 14px;
    margin-right: 14px;
  }

  .dp-anatomy__arrow {
    display: none;
  }

  .dp-anatomy .custom-pagination {
    position: static;
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 44px;
  }

  .dp-anatomy .custom-pagination .swiper-pagination-bullet {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #d9d9d9;
    opacity: 1;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }

  .dp-anatomy .custom-pagination .swiper-pagination-bullet-active {
    background-color: var(--color-accent-primary);
  }

  .dp-steps__row-title {
    font-size: 20px;
  }

  /* Hidden on closed rows to match the mobile design — it only
     reappears (restyled, no pill background) on the open item. */
  .dp-steps__duration {
    display: none;
  }

  .dp-steps__item.is-open .dp-steps__duration {
    display: flex;
    background: none;
    padding: 0;
    border-radius: 0;
    font-size: 16px;
    color: #8b8b8b;
  }

  .dp-steps__arrow {
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .dp-steps__arrow img {
    width: 28px;
    height: 28px;
  }

  .dp-steps__body-inner {
    padding: 0 10px 24px 52px;
    margin-top: 0;
    border: 1px solid #e5e5e5;
    border-top: none;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--color-bg-primary);
    gap: 15px;
  }

  .dp-steps__desc {
    font-size: 16px;
    max-width: none;
  }

  .dp-steps__cta {
    padding: 10px 24px;
    font-size: 16px;
  }

  /* Perks — native scroll-snap peek-free carousel, same convention as
     .dp-intersection__items above: one full-width card per view,
     centered, with dots tracked by hand in design-project.js since
     there's no JS Swiper instance driving it. */
  .dp-perks__grid {
    display: flex;
    flex-wrap: nowrap;
    justify-content: flex-start;
    gap: 16px;
    /* .container already contributes 16px of its own padding at this
       breakpoint (--container-padding-base) — cancel that first so
       this carousel's own 20px padding is the only inset, and the
       track itself spans the full viewport width for correct snap
       math, instead of overflowing past it. */
    margin: 0 -16px;
    padding: 0 20px;
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .dp-perks__grid::-webkit-scrollbar {
    display: none;
  }
  .dp-perks__card {
    flex: 0 0 100%;
    scroll-snap-align: center;
    scroll-snap-stop: always;
  }
  /* Swiper's own base CSS (swiper-bundle.min.css) makes .swiper-
     pagination-bullets position: absolute; bottom: 8px by default —
     since .dp-perks__pagination is a plain sibling of .dp-perks__grid
     here (not nested inside a positioned swiper container the way
     Swiper normally expects), that left it floating over whatever
     ancestor actually is positioned instead of following the card grid
     in normal flow, overlapping it regardless of margin-top. Forcing
     it back to static makes it lay out after the grid like a normal
     block, so margin-top actually creates the gap it looks like it
     should. */
  .dp-perks .custom-pagination {
    position: static;
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 32px;
  }
  .dp-perks .custom-pagination .swiper-pagination-bullet {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #d9d9d9;
    opacity: 1;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }
  .dp-perks .custom-pagination .swiper-pagination-bullet-active {
    background-color: var(--color-accent-primary);
  }

  .dp-video {
    padding-top: 0;
  }

  /* 20% shorter than the desktop 634px. */
  .dp-prices__card {
    height: 507px;
  }
}

/* Mobile-only fullscreen video player, opened from .dp-video__play at
   <=760px (see design-project.js). Mirrors the homepage
   .portfolio-gallery lightbox (close, play, progress, mute) and reuses
   its .portfolio-gallery__mute/__progress styles from main.css. Hidden
   entirely on desktop, where the panel plays inline instead. */
.dp-video-modal {
  display: none;
}

@media (max-width: 760px) {
  .dp-video-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.92);
  }

  .dp-video-modal.is-open {
    display: flex;
  }

  .dp-video-modal__close {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 37px;
    height: 37px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
  }

  .dp-video-modal__media {
    position: relative;
    width: 100%;
    background: #000;
  }

  .dp-video-modal__video {
    display: block;
    width: 100%;
    max-height: 100vh;
    object-fit: contain;
  }

  .dp-video-modal__play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 64px;
    height: 64px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(20px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    cursor: pointer;
  }

  .dp-video-modal__play img {
    width: 20px;
    height: 20px;
    margin-left: 3px;
  }

  .dp-video-modal.is-playing .dp-video-modal__play {
    display: none;
  }

  .dp-video-modal__controls {
    position: absolute;
    left: 16px;
    right: 16px;
    bottom: 16px;
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .dp-video-modal .portfolio-gallery__mute {
    width: 40px;
    height: 40px;
  }

  /* 3px track is too thin to hit on touch — the pseudo-element grows
     the tappable area without changing how the bar looks. */
  .dp-video-modal .portfolio-gallery__progress {
    position: relative;
  }

  .dp-video-modal .portfolio-gallery__progress::before {
    content: "";
    position: absolute;
    inset: -14px 0;
  }
}
