/* ============================================================
   ADDRESS — curated travel experiences
   Visual language merges three references:
   - gaelleperrin.com   → numbered editorial index that unfolds on scroll
   - hedwigtravel.com   → colored full-bleed spreads, numbered photo captions
   - serviceplusaquatics.com → tag-driven interactive contact form
   ============================================================ */

:root {
  --ink: #1C1B18;
  --ink-soft: rgba(28, 27, 24, 0.7);
  --paper: #F7F3EC;
  --paper-dim: #EFE9DD;
  --olive: #7C8355;
  --olive-dark: #5E6440;
  --pink: #C2486B;
  --pink-dark: #9E3A57;
  --navy: #25304A;
  --navy-dark: #1B2439;
  --accent-pink: #F7DDE2;
  --yellow: #E6E279;
  --line: rgba(28, 27, 24, 0.14);
  --line-on-dark: rgba(247, 243, 236, 0.22);
  --placeholder: #4A473F;

  /* Wremena Light carries the wordmark and every heading. It is not on
     Google Fonts, so it is self-hosted: until the file lands in
     assets/fonts/ the stack falls through to Fraunces, which is what the
     site shows today. Adding the file switches the whole site over with
     no further change. See assets/fonts/README.md. */
  --font-logo: 'Wremena', 'Fraunces', Georgia, serif;
  --font-display: 'Wremena', 'Fraunces', Georgia, serif;
  /* Work Sans carries every word that is not a heading. It has no Cyrillic,
     so Onest stands behind it and picks the Russian up: same humanist build,
     same weight on the page, and it carries a 200 for the thin form rows.
     Nothing else is loaded, the small journal tags included, so the site
     speaks in one voice. */
  --font-body: 'Work Sans', 'Onest', Arial, sans-serif;
  --font-ui: 'Work Sans', 'Onest', Arial, sans-serif;
  --font-num: 'Work Sans', 'Onest', Arial, sans-serif;
  --font-ui-thin: 'Work Sans', 'Onest', Arial, sans-serif;

  --container: 1320px;
  --content: 660px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

@font-face {
  font-family: 'Wremena';
  /* woff2 first (26KB against the 59KB original); the .otf the file came
     as is kept in the repo as the source and listed last */
  src: url('assets/fonts/Wremena-Light.woff2') format('woff2'),
       url('assets/fonts/Wremena-Light.woff') format('woff'),
       url('assets/fonts/Wremena%20Light.otf') format('opentype');
  font-weight: 300 400;
  font-style: normal;
  font-display: swap;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
html, body { height: 100%; }

body {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-family: var(--font-display); font-weight: 300; letter-spacing: 0.01em; }
button { font-family: inherit; }
::selection { background: var(--accent-pink); color: var(--navy); }

.container { max-width: var(--container); margin: 0 auto; padding: 0 32px; }

/* ---------- custom cursor (magnetic + label) ---------- */
.cursor {
  --cursor-d: 80px;
  position: fixed; top: 0; left: 0; width: 14px; height: 14px;
  border-radius: 50%; background: var(--ink); pointer-events: none;
  z-index: 9999; transform: translate(-50%, -50%);
  transition: width 0.25s var(--ease), height 0.25s var(--ease),
              background-color 0.25s var(--ease), opacity 0.25s ease;
  mix-blend-mode: difference; opacity: 0;
}
.cursor.is-active { opacity: 1; }
/* over the call to action the button carries the circle itself, so the
   cursor's own disc steps out of the way rather than blending with it */
.cursor.is-fill { opacity: 0; }
/* one diameter for every state the circle takes, so moving along the header
   from a link to the button to the language switch does not resize it */
.cursor.is-hover {
  width: var(--cursor-d); height: var(--cursor-d); background: var(--paper);
  display: flex; align-items: center; justify-content: center;
}
.cursor__label {
  font-family: var(--font-ui); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink); mix-blend-mode: normal;
  opacity: 0; transition: opacity 0.2s ease;
}
.cursor.is-hover .cursor__label { opacity: 1; }

/* the lens: the circle turns into a glass holding a magnified copy of the
   word underneath it, so the header needs no underline to answer a hover */
.cursor__lens { position: absolute; inset: 0; border-radius: 50%; overflow: hidden; opacity: 0; }
/* ink rather than the hover yellow: the word is read through the lens, and
   pale yellow on a pale header is not readable at any size */
.cursor__lens > span { position: absolute; white-space: nowrap; transform-origin: 0 0; color: var(--ink); }
.cursor.is-lens {
  width: var(--cursor-d); height: var(--cursor-d);
  background: var(--paper);
  mix-blend-mode: normal;
  border: 1px solid var(--line);
  box-shadow: 0 12px 30px rgba(28, 27, 24, 0.16);
}
.cursor.is-lens .cursor__lens { opacity: 1; }
.cursor.is-lens .cursor__label { display: none; }
@media (hover: none), (max-width: 860px) { .cursor { display: none; } }
@media (prefers-reduced-motion: reduce) { .cursor { transition: none; } }

/* ---------- header ---------- */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  padding: 16px 12px;
  background: transparent;
  /* the bar itself is the floating pill below, so the strip around it
     must not swallow clicks on the page underneath */
  pointer-events: none;
}
.site-header__inner {
  pointer-events: auto;
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 32px; max-width: 1760px; margin: 0 auto;
  /* glass: let the page read through the bar, and lean on saturation plus
     a lit top edge rather than a milky fill */
  background: rgba(247, 243, 236, 0.34);
  backdrop-filter: blur(22px) saturate(170%);
  -webkit-backdrop-filter: blur(22px) saturate(170%);
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 999px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 6px 24px rgba(28, 27, 24, 0.07);
  transition: background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.logo {
  font-family: var(--font-logo); font-weight: 300; font-size: 22px;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink);
}
.nav { display: flex; align-items: center; gap: 32px; }
.nav__list { display: flex; gap: 26px; list-style: none; }
.nav__link {
  font-family: var(--font-ui); font-weight: 500; font-size: 12px;
  letter-spacing: 0.09em; text-transform: uppercase;
  display: inline-block; padding-bottom: 3px;
  color: var(--ink);
  /* the page you are on stays at full strength, the rest step back */
  opacity: 0.55;
  transition: color 0.2s ease, opacity 0.2s ease, transform 0.28s var(--ease);
}
.nav__link--active { opacity: 1; }
/* over a dark block the links turn white; the fall for the pages you are not
   on is shorter there, or the words go out on the glass */
.site-header.is-over-dark .nav__link { color: #FFFFFF; opacity: 0.78; }
.site-header.is-over-dark .nav__link--active { opacity: 1; }
/* the word swells under the pointer, the way it would under a lens */
.nav__link:hover,
.site-header.is-over-dark .nav__link:hover { color: var(--yellow); opacity: 1; }
.mobile-nav__link:hover { color: var(--yellow); }

.lang-toggle {
  display: inline-flex; align-items: center;
  font-family: var(--font-ui); font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; background: none; border: none;
  margin-left: 18px; color: var(--ink);
  cursor: pointer;
}
.lang-toggle__inner { position: relative; display: inline-block; min-width: 24px; height: 1em; }
.lang-toggle__current, .lang-toggle__target { position: absolute; top: 0; left: 0; transition: opacity 0.15s ease; }
.lang-toggle__target { opacity: 0; }
.lang-toggle:hover .lang-toggle__current { opacity: 0; }
.lang-toggle:hover .lang-toggle__target { opacity: 1; }

/* соцсети в шапке: только иконки, цвет наследуется от шапки */
.social-links { display: inline-flex; align-items: center; gap: 14px; }
.social-link {
  display: inline-flex; color: var(--ink); opacity: 0.55;
  transition: color 0.2s ease, opacity 0.2s ease;
}
.social-link svg { display: block; width: 22px; height: 22px; }
.social-link:hover { color: var(--yellow); opacity: 1; }
.site-header.is-over-dark .social-link { color: #FFFFFF; opacity: 0.78; }
.site-header.is-over-dark .social-link:hover { color: var(--yellow); opacity: 1; }

.btn {
  display: inline-block; padding: 14px 30px; font-size: 12px;
  letter-spacing: 0.09em; text-transform: uppercase; border-radius: 999px;
  border: 1px solid transparent; cursor: pointer; font-family: var(--font-ui); font-weight: 500;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn--primary { background: var(--pink); color: var(--paper); }
.btn--primary:hover { background: var(--pink-dark); }
.site-header .btn--primary,
.mobile-nav .btn--primary { background: var(--navy); }
/* the pill itself keeps its blue under the pointer: the yellow arrives only
   inside a circle the size of the cursor, which follows it across the button */
.site-header .btn--primary:hover,
.mobile-nav .btn--primary:hover { background: var(--navy); }
.nav-cta { position: relative; overflow: hidden; }
.nav-cta::before {
  content: ""; position: absolute; inset: 0; background: var(--yellow);
  clip-path: circle(40px at var(--cta-x, 50%) var(--cta-y, 50%));
  opacity: 0; transition: opacity 0.22s ease; pointer-events: none;
}
.nav-cta:hover::before { opacity: 1; }
/* the word inverts against whatever passes beneath it, so it reads on the
   blue and on the yellow alike */
.nav-cta__label { position: relative; z-index: 1; color: #FFFFFF; mix-blend-mode: difference; }
@media (prefers-reduced-motion: reduce) { .nav-cta::before { transition: none; } }
.btn--outline { border-color: var(--ink); color: var(--ink); background: transparent; }
.btn--outline:hover { background: var(--ink); color: var(--paper); }
.btn--outline-light { border-color: var(--paper); color: var(--paper); background: transparent; }
.btn--outline-light:hover { background: var(--paper); color: var(--ink); }
/* the Telegram call to action: the header's yellow, and never quite still */
.btn--tg {
  background: var(--yellow); color: var(--ink); border-color: var(--yellow);
  animation: btn-hover 3.2s ease-in-out infinite alternate;
}
.btn--tg:hover { background: #EFEC96; border-color: #EFEC96; }
/* the shadow tightens as the button rises, which is what sells the lift */
@keyframes btn-hover {
  from { transform: translateY(-9px); box-shadow: 0 22px 30px rgba(28, 27, 24, 0.28); }
  to   { transform: translateY(9px);  box-shadow: 0 8px 14px rgba(28, 27, 24, 0.18); }
}
@media (prefers-reduced-motion: reduce) { .btn--tg { animation: none; } }

.btn--glass {
  background: rgba(247, 243, 236, 0.12);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-color: rgba(247, 243, 236, 0.55); color: var(--paper);
}
.btn--glass:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }

/* ---------- contact menu: the header button opens the two channels ---------- */
.contact-menu { position: relative; }
.contact-menu__list {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 40;
  min-width: 232px;
  display: flex; flex-direction: column;
  background: rgba(247, 243, 236, 0.92);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 6px;
  box-shadow: 0 18px 40px rgba(28, 27, 24, 0.18);
  /* opens from the button it hangs under */
  transform-origin: top right;
  animation: contact-menu-in 0.22s var(--ease);
}
@keyframes contact-menu-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
/* the class sets display, which would otherwise win over the UA rule for
   the hidden attribute and leave the menu open on load */
.contact-menu__list[hidden] { display: none; }
.contact-menu__item {
  display: flex; flex-direction: column; gap: 2px;
  padding: 11px 14px; border-radius: 10px;
  color: var(--ink);
  transition: background-color 0.2s ease;
}
.contact-menu__item:hover { background: rgba(28, 27, 24, 0.06); }
.contact-menu__channel {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500;
  letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.6;
}
.contact-menu__number { font-family: var(--font-num); font-size: 15px; letter-spacing: 0.02em; }

/* in the mobile panel there is no room for a popover, so both channels
   are simply on show */
.contact-menu--stacked { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.contact-menu--stacked .contact-menu__item {
  border: 1px solid var(--line); padding: 13px 16px;
}

/* the closing call to action carries the same two channels as the header.
   It stands in the middle of its column, so the list is centred on the
   button rather than hung off its edge, and it opens downward, into the
   room the canvas keeps below the button.
   The slide reveals its lines with a transform, which makes each of them a
   stacking context, so the menu also has to claim a layer of its own to
   open over the copy rather than under it. */
.contact-menu--cta { display: inline-block; z-index: 6; }
.contact-menu--cta .contact-menu__list {
  /* opaque: it opens over a photograph, not over the header's paper */
  background: var(--paper);
  right: 50%; margin-right: -116px;
  transform-origin: top center;
}
@media (max-width: 420px) {
  .contact-menu--cta .contact-menu__list { right: auto; left: 0; margin-right: 0; min-width: 0; width: 100%; }
}

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

.burger { display: none; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: 8px; }
.burger span { width: 24px; height: 2px; background: var(--ink); transition: transform 0.2s ease, opacity 0.2s ease; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.mobile-nav { display: none; }

@media (max-width: 860px) {
  .site-header { padding: 12px 8px; }
  .site-header__inner { padding: 12px 20px; border-radius: 32px; }
  .nav__list, .nav .lang-toggle, .nav .nav-cta, .nav .social-links { display: none; }
  .burger { display: flex; }
  .mobile-nav {
    display: none; pointer-events: auto;
    position: absolute; top: calc(100% + 8px); left: 8px; right: 8px;
    max-height: calc(100vh - 100%); background: rgba(247, 243, 236, 0.72);
    backdrop-filter: blur(28px) saturate(170%); -webkit-backdrop-filter: blur(28px) saturate(170%);
    flex-direction: column; padding: 24px; gap: 20px;
    border: 1px solid rgba(255, 255, 255, 0.34); border-radius: 24px; z-index: 99; overflow-y: auto;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 12px 32px rgba(28, 27, 24, 0.12);
  }
  .mobile-nav.is-open { display: flex; }
  .mobile-nav__utility { display: flex; justify-content: flex-end; padding-top: 16px; margin-top: 4px; border-top: 1px solid var(--line); }
  .mobile-nav__utility .lang-toggle { border-left: none; padding: 15px 0; margin-left: 0; font-size: 15px; }
  .mobile-nav__list { list-style: none; display: flex; flex-direction: column; gap: 4px; }
  .mobile-nav__link { display: block; padding: 10px 0; font-family: var(--font-ui); font-size: 18px; text-transform: uppercase; letter-spacing: 0.04em; }
}

/* ---------- labels / numbers (journal feel) ---------- */
.tag-label {
  font-family: var(--font-ui); font-size: 13px; letter-spacing: 0.08em;
  text-transform: uppercase; opacity: 0.7; margin-bottom: 14px; display: inline-block;
}

.num {
  font-family: var(--font-num); font-variant-numeric: tabular-nums;
}

/* ---------- photo placeholder ----------
   Deliberately a different tone from both --ink (dark sections) and
   --paper (light sections) so a placeholder never visually merges with
   an adjacent dark section into one undifferentiated black stretch.
   Each instance carries a data-ph number (see HTML) so it's obvious
   which numbered photo goes where once real images are dropped in. */
.photo-placeholder {
  background: var(--placeholder); color: var(--paper);
  display: flex; align-items: center; justify-content: center;
  text-transform: uppercase; letter-spacing: 0.1em; font-family: var(--font-ui);
  font-size: 13px; width: 100%; position: relative; overflow: hidden;
  border: 1px solid var(--line-on-dark);
}
.photo-placeholder::after { content: "Photo " attr(data-ph); }
.photo-placeholder__img {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* each photo carries its own white border, so the placeholder's hairline
   would read as a second frame — it stays only on the empty placeholder */
.photo-placeholder:has(.photo-placeholder__img) { border: none; }
.photo-placeholder--wide { aspect-ratio: 16 / 9; }
.photo-placeholder--tall { aspect-ratio: 3 / 4; }
.photo-placeholder--square { aspect-ratio: 1 / 1; }

/* ---------- hero ---------- */
.hero { position: relative; min-height: 100vh; display: flex; align-items: center; overflow: hidden; }
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media { background: var(--ink); }
.hero__media img, .hero__media video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* the loop cuts from the last frame back to the first, which reads as a
   flash; the film dips to the ink underneath it and comes back instead */
.hero__media video { transition: opacity 0.5s ease; }
.hero__media video.is-wrapping { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .hero__media video { transition: none; }
  .hero__media video.is-wrapping { opacity: 1; }
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(28,27,24,0.15) 0%, rgba(28,27,24,0.55) 60%, rgba(28,27,24,0.85) 100%);
}
.hero__content { position: relative; z-index: 2; padding: 80px 24px; text-align: center; width: 100%; color: var(--paper); }

/* The opening: the kicker fades up, the wordmark rises out of a mask with
   its letters drawing together, the line under it follows. Nothing here is
   hidden without the animation running, so a browser that refuses it still
   shows the text. */
.hero__title-mask { display: block; overflow: hidden; padding-bottom: 0.06em; margin-bottom: 18px; }
.hero__title-mask .hero__title { display: block; margin-bottom: 0; }

/* The resting state is written out rather than left to the animation's fill,
   because the animation is attached a beat after the first paint and the
   lines would otherwise flash in place and then drop back to start. It is
   held behind .reveal-ready, the class script.js sets, so a page with no
   JavaScript shows the text plainly instead of hiding it forever. */
.reveal-ready .hero__kicker { opacity: 0; }
.reveal-ready .hero__title { transform: translateY(105%); opacity: 0; }
.reveal-ready .hero__subtitle { opacity: 0; }

/* "both" belongs in the shorthand: written separately above it, the
   shorthand resets it, and every line would snap back to its start the
   moment the animation ended */
.hero__kicker { animation: hero-kicker 0.9s var(--ease) 0.15s both; }
.hero__title { animation: hero-word 1.25s var(--ease) 0.3s both; }
.hero__subtitle { animation: hero-rise 1s var(--ease) 0.85s both; }

/* the kicker settles at the tag opacity it shares with the rest of the site */
@keyframes hero-kicker {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 0.7; transform: none; }
}
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes hero-word {
  from { opacity: 0; transform: translateY(105%); letter-spacing: 0.22em; }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; letter-spacing: normal; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__kicker, .hero__title, .hero__subtitle { animation: none; }
  .reveal-ready .hero__kicker { opacity: 0.7; }
  .reveal-ready .hero__title { transform: none; opacity: 1; }
  .reveal-ready .hero__subtitle { opacity: 1; }
}
/* the hero ADDRESS is the wordmark, so it takes --font-logo (Wremena)
   rather than the sitewide heading font */
.hero__title { font-family: var(--font-logo); font-size: clamp(52px, 9vw, 108px); margin-bottom: 18px; line-height: 1.02; }
/* 780 rather than the 660 the rest of the body copy uses: the Russian lead
   needs 700 to hold two lines, and the margin keeps it there if a fallback
   face ever renders a little wider */
.hero__subtitle { font-family: var(--font-body); font-size: 21px; max-width: 780px; margin: 0 auto; line-height: 1.6; }
.hero__actions { margin-top: 36px; display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
.hero__scroll-cue {
  position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%); z-index: 2;
  width: 48px; height: 48px; border-radius: 50%; color: var(--paper);
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(247, 243, 236, 0.5);
  transition: border-color 0.2s ease, background-color 0.2s ease;
}
.hero__scroll-cue:hover { border-color: var(--paper); background: rgba(247, 243, 236, 0.12); }
.hero__scroll-arrow { animation: scroll-cue-bounce 1.8s ease-in-out infinite; }
@keyframes scroll-cue-bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .hero__scroll-arrow { animation: none; } }

/* ---------- marquee ---------- */
.marquee { background: var(--ink); color: var(--paper); overflow: hidden; white-space: nowrap; padding: 20px 0; }
.marquee__track { display: inline-flex; gap: 48px; animation: marquee-scroll 28s linear infinite; }
.marquee__item { font-family: var(--font-ui); font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.85; padding-right: 48px; }
@keyframes marquee-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } }

/* ---------- sections ---------- */
.section { padding: 120px 24px; }
.section--dark { background: var(--ink); color: var(--paper); }
.section--light { background: var(--paper); color: var(--ink); }
.section--olive { background: var(--olive); color: var(--paper); }
.section--dim { background: var(--paper-dim); color: var(--ink); }
.section__inner { max-width: var(--container); margin: 0 auto; }
.section__inner--narrow { max-width: var(--content); }
/* a section that runs out toward the edges of the screen instead of holding
   to the 1320px column: the opening of Contacts is laid out on this width */
.section--wide { padding-left: clamp(24px, 4.5vw, 88px); padding-right: clamp(24px, 4.5vw, 88px); }
.section__inner--wide { max-width: 1760px; }
.section__inner--center { text-align: center; }
.section__title { font-size: clamp(34px, 5vw, 58px); text-align: center; margin-bottom: 24px; }
.section__text {
  text-wrap: pretty; font-size: 20px; text-align: center; max-width: var(--content); margin: 0 auto 48px; }

/* =========================================================
   HOME — gallery of service cards, scrolled sideways
   Built on native overflow + scroll-snap, so touch swipe, trackpad
   and shift+wheel come from the browser itself; script.js only adds
   mouse drag, the arrows and the progress bar.
   ========================================================= */
.gallery {
  /* the gap the track keeps from the left edge of the page: the section's
     own gutter is cancelled below, and this is what is left in its place */
  --gallery-inset: 1cm;
  position: relative;
  /* the track runs the full width of the window: the section's own 24px
     gutter is cancelled here, so the last card is cut by the right edge
     of the page */
  margin-left: -24px; margin-right: -24px;
}
.gallery__track {
  list-style: none;
  display: flex; gap: 32px;
  /* the first card starts a centimetre in from the edge of the page, and a
     matching scroll padding keeps every snapped card on the same line */
  padding-left: var(--gallery-inset);
  scroll-padding-left: var(--gallery-inset);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  cursor: grab;
  /* the bar under the track is the visible progress, the native one would
     only double it */
  scrollbar-width: none; -ms-overflow-style: none;
}
.gallery__track::-webkit-scrollbar { display: none; }
/* snapping is switched off for the length of a mouse drag: it fights
   scrollLeft set from script, and on release the browser snaps anyway */
.gallery.is-dragging .gallery__track { scroll-snap-type: none; cursor: grabbing; }
.gallery.is-dragging .gallery__card { user-select: none; }

.gallery__card {
  flex: 0 0 clamp(280px, 33vw, 480px);
  scroll-snap-align: start;
}
/* the index photos are all 3:4, so the media box is 3:4 too and each frame
   shows in full, no crop */
.gallery__media { overflow: hidden; margin-bottom: 24px; }
.gallery__media .photo-placeholder { aspect-ratio: 3 / 4; }
/* every one of these files carries a white border printed into the image
   itself, an even 1.46% of the frame on each side. Scaling the image by
   1/(1 - 2 × 0.0146) pushes exactly that border past the edges of the box,
   so the photograph is bled rather than framed. */
.gallery__media .photo-placeholder__img {
  transform: scale(1.035);
  transition: transform 0.8s var(--ease);
}
.gallery__card:hover .photo-placeholder__img { transform: scale(1.09); }
.gallery__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(24px, 2.4vw, 34px); margin-bottom: 14px;
}
.gallery__text { font-size: 17px; opacity: 0.85; margin-bottom: 16px; }
.gallery__link { display: inline-block; }

/* ---------- a case card: several frames in one card ----------
   The review cases carry their own photographs instead of a page each, so
   the media box holds a small track of frames and the dots under it say how
   many there are. The dots sit outside the media box on purpose: the arrows
   of the gallery are placed at half the height of that box, and counting the
   dots into it would drop them below the middle of the photograph. */
.shots__track {
  display: flex;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
}
.shots__track::-webkit-scrollbar { display: none; }
.shots__item { flex: 0 0 100%; scroll-snap-align: start; }
.gallery__card--shots .gallery__media { margin-bottom: 14px; }
.shots__dots { display: flex; gap: 8px; margin-bottom: 20px; min-height: 7px; }
.shots__dot {
  width: 7px; height: 7px; padding: 0; border: none; border-radius: 50%;
  background: rgba(28, 27, 24, 0.25); cursor: pointer;
  transition: background 0.3s ease, transform 0.3s ease;
}
.shots__dot.is-active { background: var(--ink); transform: scale(1.3); }
@media (prefers-reduced-motion: reduce) { .shots__dot { transition: none; } }

.gallery__controls { margin-top: 40px; }
.gallery__progress { height: 1px; background: var(--line); position: relative; }
/* the bar is as wide a share of the line as the visible part is of the
   track, and travels the rest of it — width and transform are set in JS */
.gallery__progress-bar {
  position: absolute; left: 0; top: -1px; height: 3px; width: 25%;
  background: var(--ink); transition: transform 0.3s var(--ease);
}

/* the arrows sit on the photographs themselves, at the middle of their
   height — --gallery-arrow-y is measured in JS, because the height of a
   3:4 photo depends on the card width the clamp above settles on */
.gallery__arrows {
  position: absolute; left: 0; right: 0;
  top: var(--gallery-arrow-y, 30%); transform: translateY(-50%);
  display: flex; justify-content: space-between;
  /* the left arrow keeps its place on the photograph, so it moves in with
     the track rather than staying at the edge of the page */
  padding: 0 20px 0 calc(var(--gallery-inset) + 20px); z-index: 2;
  pointer-events: none;
}
/* glass rather than a solid disc: the arrows lie on the photographs, so they
   blur what is under them and let the picture keep reading through */
.gallery__arrow {
  pointer-events: auto;
  width: 52px; height: 52px; border-radius: 50%;
  border: 1px solid rgba(247, 243, 236, 0.45);
  background: rgba(247, 243, 236, 0.14);
  color: var(--paper);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  box-shadow: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, opacity 0.3s ease,
              border-color 0.3s ease;
}
.gallery__arrow svg { width: 20px; height: 20px; }
.gallery__arrow:hover:not(:disabled) {
  background: rgba(247, 243, 236, 0.3);
  border-color: rgba(247, 243, 236, 0.7);
  color: var(--paper);
}
/* where the blur is not supported the disc would go almost invisible over a
   light photograph, so it falls back to a denser tint */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .gallery__arrow { background: rgba(28, 27, 24, 0.35); }
  .gallery__arrow:hover:not(:disabled) { background: rgba(28, 27, 24, 0.5); }
}
.gallery__arrow:disabled { opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .gallery__media .photo-placeholder__img,
  .gallery__progress-bar,
  .gallery__arrow { transition: none; }
}
@media (max-width: 860px) {
  .gallery__track { gap: 20px; }
  .gallery__card { flex-basis: 78vw; }
  .gallery__controls { margin-top: 32px; }
  .gallery__arrows { padding: 0 12px 0 calc(var(--gallery-inset) + 12px); }
  .gallery__arrow { width: 44px; height: 44px; }
}

/* quote (hedwig-style colored spread) */
.quote { padding: 140px 24px; text-align: center; }
/* the philosophy spread sits on beige, so its type flips to ink */
.quote.section--olive { background: #D8D1BD; color: var(--ink); }
.quote__num { font-family: var(--font-ui); font-size: 13px; letter-spacing: 0.1em; opacity: 0.7; margin-bottom: 20px; display: block; }
.quote__text { font-family: var(--font-display); font-size: clamp(26px, 3.6vw, 44px); max-width: 900px; margin: 0 auto; line-height: 1.4; }

/* pillars */
.pillars { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; }
.pillar { text-align: left; border-top: 1px solid var(--line); padding-top: 20px; }
.pillar__num { font-family: var(--font-num); font-size: 12px; opacity: 0.55; display: block; margin-bottom: 14px; }
.pillar__title { font-family: var(--font-display); font-size: 21px; margin-bottom: 8px; }
.pillar__text { font-size: 16px; opacity: 0.8; }
@media (max-width: 1000px) { .pillars { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .pillars { grid-template-columns: 1fr; } }

.cta__actions { display: flex; gap: 20px; justify-content: center; margin-top: 32px; flex-wrap: wrap; }

/* =========================================================
   ABOUT — five full-screen slides, each composed on a
   1920×1080 canvas.

   --u is one design pixel. The canvas is the largest 16:9 box
   that fits the viewport, so every size below can be written in
   plain 1920×1080 units and the whole composition scales as one
   piece — the section always fills the screen, the artwork inside
   it always keeps the 16:9 proportions it was drawn at.
   ========================================================= */
.about-slide {
  --u: calc(min(100vw, 177.7778vh) / 1920);
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.about-slide--paper { background: var(--paper); color: var(--ink); }
.about-slide--dim   { background: var(--paper-dim); color: var(--ink); }
.about-slide--navy  { background: var(--navy); color: var(--paper); }
.about-slide--photo { background: var(--ink); color: var(--ink); }

/* Overhang on all four sides: top and bottom is the room the parallax
   drifts into, left and right crops away the shot's own white border,
   which would otherwise read as a frame around a full-bleed photo. */
.about-slide__bg { position: absolute; inset: -10% -5%; z-index: 0; }
.about-slide__bg img { width: 100%; height: 100%; object-fit: cover; }
[data-parallax] { will-change: transform; }

.about-slide__canvas {
  position: relative;
  z-index: 2;
  width: calc(1920 * var(--u));
  height: calc(1080 * var(--u));
  padding: calc(100 * var(--u)) calc(110 * var(--u));
  display: grid;
  align-content: center;
  gap: calc(70 * var(--u));
}

/* ---- shared type, all sized in canvas units ---- */
.about-word {
  font-family: var(--font-logo);
  font-size: calc(86 * var(--u));
  letter-spacing: 0.1em;
  line-height: 1;
  text-transform: uppercase;
  margin-bottom: calc(26 * var(--u));
}
.about-word--small { font-size: calc(58 * var(--u)); }
.about-title {
  font-family: var(--font-display);
  white-space: pre-line;
  font-size: calc(66 * var(--u));
  line-height: 1.08;
  text-transform: uppercase;
  margin-bottom: calc(26 * var(--u));
}
.about-title--wide { letter-spacing: 0.02em; }
/* Every spread is set from three sizes: the heading, one body size and one
   label size. A second paragraph steps back by tone, not by scale. */
.about-text {
  /* keeps a lone word off the last line where the browser supports it */
  text-wrap: pretty;
  font-size: calc(26 * var(--u));
  line-height: 1.5;
  max-width: calc(720 * var(--u));
}
.about-text--lead { font-size: calc(30 * var(--u)); }
.about-text--small { font-size: calc(26 * var(--u)); opacity: 0.82; }
.about-note {
  font-family: var(--font-ui);
  font-size: calc(18 * var(--u));
  letter-spacing: 0.12em;
  opacity: 0.7;
  margin-top: calc(30 * var(--u));
}

/* ---- photos: the frame is fixed, the shot fills it ---- */
.about-photo { position: relative; overflow: hidden; background: var(--placeholder); }
.about-photo img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.05); }
.about-photo--portrait { aspect-ratio: 3 / 4; }
.about-photo--tall { aspect-ratio: 4 / 5; }

/* ---- 01 — ADDRESS ---- */
.about-s1 {
  grid-template-columns: 1fr calc(615 * var(--u));
  align-items: center;
  gap: calc(110 * var(--u));
}
.about-s1 .about-photo { width: 100%; height: auto; aspect-ratio: 3 / 4; }
.about-s1 .about-word { font-size: calc(67 * var(--u)); margin-bottom: calc(34 * var(--u)); }
.about-s1 .about-text--lead {
  font-size: calc(29 * var(--u));
  line-height: 1.34;
  max-width: calc(900 * var(--u));
}
.about-s1 .about-note { margin-top: calc(40 * var(--u)); }

/* ---- 02 — hotels ---- */
.about-s2 {
  grid-template-columns: calc(720 * var(--u)) 1fr;
  grid-template-rows: auto auto;
  align-content: center;
  gap: calc(60 * var(--u)) calc(80 * var(--u));
}
.about-s2 .about-title { font-size: calc(56 * var(--u)); }
.about-s2 .about-text { max-width: calc(660 * var(--u));
}
.about-s2__head { grid-column: 1; grid-row: 1; align-self: end; }
.about-s2__foot { grid-column: 1; grid-row: 2; align-self: start; }
.about-s2__media {
  grid-column: 2; grid-row: 1 / span 2;
  display: grid; grid-template-columns: 1fr 1fr; gap: calc(30 * var(--u));
  align-items: center;
}
.about-s2__media .about-photo:first-child { margin-top: calc(75 * var(--u)); }
.about-s2__media .about-photo:last-child { margin-bottom: calc(75 * var(--u)); }
.about-s2__media .about-photo:last-child,
.guide-cover--b { transition-delay: 0.16s; }

/* ---- 03 — how we work ---- */
.about-s3 {
  grid-template-columns: 1fr calc(670 * var(--u));
  align-items: center;
  gap: calc(130 * var(--u));
}
.about-s3 .about-photo { height: calc(860 * var(--u)); width: 100%; }
/* the copy hangs from the same top line as the photo, as on the story frame */
.about-s3__text { align-self: start; padding-top: calc(30 * var(--u)); }
.about-s3__text .about-text { max-width: calc(780 * var(--u)); }
.about-s3__text .about-note { margin: 0 0 calc(34 * var(--u)); }

/* ---- 04 — ADDRESS guides ---- */
.about-s4 {
  grid-template-columns: calc(880 * var(--u)) 1fr;
  align-items: center;
  gap: calc(90 * var(--u));
}
.about-s4__covers { position: relative; height: calc(820 * var(--u)); }

.guide-cover {
  position: absolute;
  width: calc(400 * var(--u));
  background: var(--paper);
  color: var(--ink);
  padding: calc(16 * var(--u));
  box-shadow: 0 calc(24 * var(--u)) calc(60 * var(--u)) rgba(0, 0, 0, 0.28);
}
.guide-cover--a { left: 0; top: 0; }
.guide-cover--b { right: calc(30 * var(--u)); bottom: 0; }
.guide-cover__head { display: block; }
.guide-cover__kicker {
  display: block;
  font-family: var(--font-ui);
  font-size: calc(11 * var(--u));
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.75;
}
.guide-cover__row {
  display: flex; justify-content: space-between; align-items: baseline;
  margin: calc(34 * var(--u)) 0 calc(16 * var(--u));
}
.guide-cover__brand { font-family: var(--font-logo); font-size: calc(22 * var(--u)); letter-spacing: 0.1em; }
.guide-cover__place {
  font-family: var(--font-ui); font-weight: 600;
  font-size: calc(16 * var(--u)); letter-spacing: 0.12em;
}
.guide-cover__media { aspect-ratio: 4 / 5; overflow: hidden; background: var(--placeholder); }
.guide-cover__media img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.05); }


/* ---- 05 — closing ---- */
/* the scrim is what makes the copy legible without a panel behind it */
.about-slide--photo { color: var(--paper); }
.about-slide--photo::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background:
    radial-gradient(115% 85% at 50% 52%, rgba(10, 10, 12, 0.18) 0%, rgba(10, 10, 12, 0.66) 72%),
    linear-gradient(180deg, rgba(10, 10, 12, 0.5), rgba(10, 10, 12, 0.22) 42%, rgba(10, 10, 12, 0.62));
}
.about-s5 { place-content: center; justify-items: center; }
.about-s5__text {
  text-align: center;
  width: calc(1020 * var(--u));
  text-shadow: 0 calc(2 * var(--u)) calc(24 * var(--u)) rgba(10, 10, 12, 0.55);
}
.about-s5__text .about-text { margin: 0 auto; }
.about-s5__text .about-text + .about-text { margin-top: calc(18 * var(--u)); }
.about-s5__text .about-text--lead { font-size: calc(27 * var(--u)); }
/* on Service the closing is two sentences of equal weight, so the first
   does not step up over the second */
#service-closing .about-s5__text .about-text--lead { font-size: calc(27 * var(--u)); }
.about-s5__text .about-text { font-weight: 500; }
.about-s5__cta {
  margin-top: calc(46 * var(--u));
  font-size: calc(20 * var(--u));
  padding: calc(18 * var(--u)) calc(40 * var(--u));
  border-radius: 999px;
  background: rgba(247, 243, 236, 0.12);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(247, 243, 236, 0.55);
  color: var(--paper);
  text-shadow: none;
}
.about-s5__cta:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }

/* ---- narrow screens: the 16:9 canvas would shrink the type past
   readable, so the slides fall back to a stacked, self-sized flow ---- */
@media (max-width: 900px) {
  .about-slide { min-height: 0; overflow: visible; }
  .about-slide__canvas {
    width: 100%; height: auto;
    padding: 96px 22px 84px;
    grid-template-columns: 1fr;
    gap: 34px;
  }
  #about-01 .about-slide__canvas { padding-top: 128px; }

  .about-word, .about-s1 .about-word { font-size: clamp(38px, 11vw, 58px); margin-bottom: 16px; }
  .about-word--small { font-size: clamp(32px, 9vw, 46px); }
  .about-title, .about-s2 .about-title { font-size: clamp(26px, 7.4vw, 38px); margin-bottom: 16px; }
  .about-text { font-size: 16px; max-width: none; }
  .about-text--lead,
  .about-s1 .about-text--lead,
  .about-s5__text .about-text--lead { font-size: 17px; line-height: 1.5; }
  .about-s1 .about-text--lead, .about-s2 .about-text { max-width: none; }
  .about-s1 .about-note { margin-top: 20px; }
  /* on a phone the photo reads first, then the claim under it */
  .about-s1 .about-photo { order: -1; }
  .about-text--small { font-size: 16px; }
  .about-note { font-size: 12px; margin-top: 20px; }

  .about-s1 .about-photo,
  .about-s3 .about-photo { height: auto; width: 100%; }

  .about-s2__head, .about-s2__foot, .about-s2__media {
    grid-column: 1; grid-row: auto;
  }
  .about-s2__media { gap: 14px; }
  .about-s2__media .about-photo:first-child,
  .about-s2__media .about-photo:last-child { margin: 0; }

  .about-s4__covers {
    position: static; height: auto;
    display: grid; grid-template-columns: 1fr 1fr;
    align-items: start; column-gap: 16px; row-gap: 10px;
  }
  .guide-cover { position: static; width: auto; padding: 10px; box-shadow: none; }
  .guide-cover--a { grid-column: 1; grid-row: 1; }
  .guide-cover--b { grid-column: 2; grid-row: 1; }
  .guide-cover__kicker { font-size: 8px; }
  .guide-cover__row { margin: 14px 0 8px; gap: 8px; }
  .guide-cover__brand { font-size: 12px; letter-spacing: 0.06em; }
  .guide-cover__place { font-size: 8px; }
  /* the arc only reads as a pointer next to a card it can point at */

  /* the bleed layer overhangs the section, so this one still clips */
  .about-slide--photo { min-height: 74vh; overflow: hidden; }
  .about-s5__text { width: 100%; }
  .about-s5__cta { font-size: 14px; padding: 14px 26px; margin-top: 26px; }
}

/* =========================================================
   SERVICE — five spreads on the same 1920×1080 canvas as About.
   .about-slide supplies --u, the type kit and the closing scrim;
   everything here only places the service copy on that canvas.
   ========================================================= */
.about-slide--olive { background: var(--olive); color: var(--paper); }

/* the opener: claim left, photo right, same proportions as About 01 */
.svc-intro {
  grid-template-columns: 1fr calc(600 * var(--u));
  align-items: center;
  gap: calc(110 * var(--u));
}
.svc-intro .about-photo { width: 100%; aspect-ratio: 3 / 4; }
.svc-intro .about-title { font-size: calc(60 * var(--u)); }
.svc-intro .about-text--lead { font-size: calc(28 * var(--u)); max-width: calc(860 * var(--u)); }

/* a service spread: copy on one side, photography on the other.
   --mirror swaps the columns, so consecutive services alternate. */
.svc {
  grid-template-columns: 1fr calc(700 * var(--u));
  align-items: center;
  gap: calc(90 * var(--u));
}
.svc--mirror { grid-template-columns: calc(700 * var(--u)) 1fr; }

.svc__text .about-title { font-size: calc(44 * var(--u)); margin-bottom: calc(22 * var(--u)); }
.svc__text .about-text { font-size: calc(22 * var(--u)); max-width: calc(700 * var(--u)); }
/* описание под услугой набрано мельче основного абзаца */
.svc__text .svc__deliverable { font-size: calc(19 * var(--u)); margin-top: calc(16 * var(--u)); opacity: 0.82; }


.svc-list { list-style: none; margin: calc(26 * var(--u)) 0 0; display: grid; gap: calc(14 * var(--u)); }
.svc-list li {
  position: relative;
  padding-left: calc(34 * var(--u));
  font-size: calc(22 * var(--u));
  line-height: 1.4;
  max-width: calc(700 * var(--u));
}
.svc-list li::before {
  content: "•";
  position: absolute; left: 0; top: 0;
  font-family: var(--font-ui);
  opacity: 0.5;
}

.svc-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: calc(20 * var(--u)); margin-top: calc(38 * var(--u)); }
.svc-price__value {
  font-family: var(--font-num);
  font-size: calc(22 * var(--u));
  letter-spacing: 0.01em;
  padding: calc(12 * var(--u)) calc(26 * var(--u));
  border: 1px solid currentColor;
  border-radius: 999px;
  white-space: nowrap;
}
.svc-price__note { font-size: calc(16 * var(--u)); opacity: 0.7; }

/* every service photograph carries its own white border, so the frame keeps
   the shot's own proportions (3:4) and shows it whole: cropping it to a
   taller box, or letting it overhang for a drift, would eat that border */
.svc__media .about-photo,
.svc-intro .about-photo { aspect-ratio: 3 / 4; background: #FFFFFF; }
.svc__media .about-photo { width: 100%; }
/* these two spreads run the photo full height, which brings its top edge up
   under the floating header; it is dropped and trimmed so it clears the bar */
#hotels .svc__media, #concierge .svc__media { align-self: start; margin-top: calc(150 * var(--u)); }
#hotels .svc__media .about-photo,
#concierge .svc__media .about-photo { width: calc(560 * var(--u)); margin-left: auto; }
#concierge .svc__media .about-photo { margin-left: 0; margin-right: auto; }
/* the shot sits flush in its frame, with no overhang to crop the border */
.svc__media .about-photo img,
.svc-intro .about-photo img {
  position: static;
  width: 100%; height: 100%;
  object-fit: contain;
}
/* the pair stands level: both frames share one top line, with no tilt and
   no drift, so the spread reads as two photographs and not as a collage */
.svc__media--pair { display: grid; grid-template-columns: 1fr 1fr; gap: calc(38 * var(--u)); align-items: start; }

/* ---- narrow screens: the same stacked fallback as the About slides ---- */
@media (max-width: 900px) {
  .svc-intro, .svc, .svc--mirror { grid-template-columns: 1fr; gap: 28px; }
  #service-intro .about-slide__canvas { padding-top: 128px; }
  .svc-intro .about-title, .svc__text .about-title { font-size: clamp(26px, 7.4vw, 38px); margin-bottom: 14px; }
  .svc-intro .about-text--lead { font-size: 16px; max-width: none; }
  .svc-intro .about-photo { order: -1; }
  .svc__text .about-text, .svc-list li { max-width: none; }
  .svc__deliverable { margin-top: 12px; }
  .svc-list { gap: 10px; margin-top: 18px; }
  .svc-list li { font-size: 15px; padding-left: 22px; }
  .svc-price { gap: 12px; margin-top: 24px; }
  .svc-price__value { font-size: 16px; padding: 11px 20px; }
  .svc-price__note { font-size: 12px; }
  .svc__media--pair { gap: 10px; }
}

/* =========================================================
   CONTACTS — big-type hero form (Claude Design "offline" reference)
   ========================================================= */
.section--white { background: #FFFFFF; }

.interest-picker__label {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(30px, 3.6vw, 52px);
  line-height: 1.35; letter-spacing: 0.01em;
  max-width: none; margin-bottom: 32px;
}
.interest-picker__label-line { display: block; text-wrap: pretty; white-space: nowrap; }
@media (max-width: 720px) { .interest-picker__label-line { white-space: normal; } }
.interest-picker__tags {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
  max-width: 600px; margin-bottom: 36px;
}
.interest-tag {
  font-family: var(--font-ui); font-size: 10px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 14px 8px; border-radius: 999px; border: 1px solid var(--line);
  background: transparent; color: var(--ink); cursor: pointer;
  transition: background-color 0.35s ease, color 0.35s ease, border-color 0.35s ease, transform 0.35s ease;
}
.interest-tag:hover { border-color: var(--ink); }
.interest-tag.is-selected { background: var(--navy); color: var(--paper); border-color: var(--navy); transform: translateY(-2px); }
@media (max-width: 600px) { .interest-picker__tags { grid-template-columns: repeat(2, 1fr); max-width: none; } }

.contact-grid { display: flex; flex-direction: column; gap: 56px; max-width: var(--container); margin: 0 auto; }
/* on the wide opening the question, the tags and the form spread across the
   screen: the copy grows with it, the tags sit one row of five, and the form
   keeps a readable measure while its send button holds the right edge */
.section__inner--wide .interest-picker__label { font-size: clamp(30px, 3.9vw, 62px); margin-bottom: 44px; }
.section__inner--wide .interest-picker__tags {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 18px; max-width: 1080px; margin-bottom: 52px;
}
.section__inner--wide .contact-grid { max-width: none; }
.section__inner--wide .contact-form__fields,
.section__inner--wide .contact-form__foot { max-width: 1080px; }
.section__inner--wide .contact-info { justify-content: space-between; }
@media (max-width: 900px) {
  .section__inner--wide .interest-picker__tags { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: none; }
}
@media (max-width: 600px) {
  .section__inner--wide .interest-picker__tags { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.contact-form {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: clamp(32px, 5vw, 84px);
  row-gap: 20px;
}
/* the hairline that ties the question above to the form answering it */
.contact-form::before {
  content: ""; position: absolute; left: 0; bottom: 100%; margin-bottom: 8px;
  width: 1px; height: 26px; background: linear-gradient(to bottom, transparent, var(--line));
}
.contact-form__fields { grid-column: 1; max-width: 640px; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
/* the submit sits beside the rows rather than under them */
.contact-form__foot {
  grid-column: 2; grid-row: 1;
  display: flex; align-items: center; justify-content: center;
}

/* the rows carry no rule of their own: the line is drawn under the row the
   pointer is on, and the ink one below takes over while the field is in use.
   The only line that stays is the one above the contact details. */
.form-field {
  position: relative; padding: 30px 0 12px;
  border-bottom: 1px solid transparent;
  transition: border-color 0.35s ease;
}
.contact-form .form-field:hover { border-bottom-color: var(--line); }
.form-field label {
  position: absolute; left: 0; top: 30px; font-family: var(--font-ui-thin); font-weight: 200;
  font-size: clamp(24px, 2.9vw, 40px); line-height: 1.3; color: var(--placeholder);
  pointer-events: none; transform-origin: 0 0;
  transition: transform 0.4s var(--ease), font-size 0.4s var(--ease), letter-spacing 0.4s var(--ease), color 0.3s ease;
}
.form-field input, .form-field textarea {
  width: 100%; border: none; background: transparent; font-family: var(--font-ui-thin); font-weight: 200;
  font-size: clamp(24px, 2.9vw, 40px); line-height: 1.3; color: var(--ink); padding: 0; outline: none;
}
.form-field textarea { min-height: 1.3em; resize: none; display: block; }
/* the label floats up and out of the way once the field is in use */
.contact-form .form-field:focus-within label,
.contact-form .form-field input:not(:placeholder-shown) + label,
.contact-form .form-field textarea:not(:placeholder-shown) + label {
  transform: translateY(-30px);
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--placeholder);
}
.form-field::after {
  content: ""; position: absolute; left: 0; bottom: -1px; height: 1px; background: var(--ink);
  width: 0%; transition: width 0.5s var(--ease);
}
.form-field:focus-within::after { width: 100%; }

/* Кнопка отправки: в покое чёткий жёлтый круг, под курсором он расплывается.
   Заливка живёт на псевдоэлементе, поэтому её можно размыть, не тронув слово:
   размытие включается вместе с синим кругом и гаснет вместе с ним. Синий круг
   кнопка рисует внутри себя (script.js прячет курсор и ведёт --send-x /
   --send-y), а слово вычитает то, что под ним, и читается и на жёлтом,
   и на синем, как надпись на кнопке в шапке. */
.form-submit {
  position: relative; isolation: isolate; flex-shrink: 0;
  width: 176px; height: 176px; border-radius: 50%;
  background: none; border: none; color: var(--ink); cursor: pointer; will-change: transform;
  font-family: var(--font-ui); font-size: 13px; letter-spacing: 0.18em; text-transform: uppercase;
  transition: transform 0.45s var(--ease);
}
/* заливка: в покое ровный круг с чёткой границей, под курсором расплывается
   и чуть раскрывается, чтобы пятно осталось того же размера, что круг */
.form-submit::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%; z-index: 0;
  background: var(--yellow);
  filter: blur(0px); transform: scale(1);
  transition: transform 0.55s var(--ease), filter 0.45s ease;
  pointer-events: none;
}
/* синий круг: диаметр курсора и такая же мягкая граница, без ободка */
.form-submit::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; z-index: 1;
  background: radial-gradient(circle 40px at var(--send-x, 50%) var(--send-y, 50%),
                             #213E60 55%, rgba(33, 62, 96, 0) 100%);
  opacity: 0; transition: opacity 0.25s ease;
  pointer-events: none;
}
.form-submit:hover::after { opacity: 1; }
.form-submit:hover::before { transform: scale(1.12); filter: blur(22px); }
/* слово лежит поверх обоих кругов и инвертирует то, что под ним */
.form-submit__label { position: relative; z-index: 2; font-weight: 500; color: #FFFFFF; mix-blend-mode: difference; }
.form-submit:focus-visible { outline: 2px solid var(--ink); outline-offset: 6px; }
/* магнит срабатывает раньше, чем указатель доходит: пятно ведёт наведение */
.form-submit.is-magnet-near::before { transform: scale(1.14); filter: blur(24px); }
@media (prefers-reduced-motion: reduce) {
  .form-submit, .form-submit::before, .form-submit::after { transition: none; }
}

.contact-info {
  display: flex; flex-direction: row; align-items: baseline; gap: 40px; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding-top: 28px;
}
.contact-info__title { font-family: var(--font-ui); font-size: 19px; font-weight: 500; letter-spacing: 0.01em; }
.contact-info__row { display: flex; align-items: baseline; gap: 12px 32px; flex-wrap: wrap; }
.contact-info__label { font-family: var(--font-ui); font-size: 15px; font-weight: 500; }
.contact-info__value { font-family: var(--font-ui); font-size: 15px; font-weight: 300; color: var(--ink-soft); word-break: break-word; }
.contact-info__value:hover { color: var(--pink); }
/* на Service этот блок живёт без курсорного круга, и подсветка ссылки
   тоже снята: почта и телефоны читаются одним тоном */
.contact-info[data-cursor-plain] .contact-info__value:hover { color: var(--ink-soft); }
/* the numbers stack, so the label keeps sitting next to the first of them */
.contact-info__values { display: flex; flex-direction: column; gap: 6px; }

.form-message { grid-column: 1 / -1; display: none; margin-top: 16px; font-size: 17px; }
.form-message.is-visible { display: block; animation: formFade 0.5s ease both; }
.form-message--success { font-style: italic; color: var(--pink); }
.form-message--error { color: var(--pink-dark); }
@keyframes formFade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (max-width: 760px) {
  /* no room for a column beside the rows: the button drops back underneath */
  .contact-form { grid-template-columns: minmax(0, 1fr); }
  .contact-form__fields { width: 100%; max-width: none; }
  .contact-form__foot { grid-column: 1; grid-row: auto; max-width: none; justify-content: flex-start; margin-top: 20px; }
  .form-submit { width: 132px; height: 132px; font-size: 11px; }
  .form-submit::after { background: radial-gradient(circle 34px at var(--send-x, 50%) var(--send-y, 50%), #213E60 55%, rgba(33, 62, 96, 0) 100%); }
  /* the contact line stacks into label / value pairs instead of breaking raggedly */
  .contact-info { flex-direction: column; align-items: stretch; gap: 20px; }
  .contact-info__row { display: grid; grid-template-columns: auto 1fr; gap: 10px 20px; align-items: baseline; }
  .contact-info__value { justify-self: start; }
}

/* ---------- footer ---------- */

/* =========================================================
   CONTACTS — the two closing slides, drawn on the same
   1920×1080 canvas as About: .about-slide supplies --u, the
   type kit (.about-word / .about-text / .about-note) and the
   full-bleed scrim, so only the per-slide layout lives here.
   ========================================================= */

/* ---- the direct channels, over the full-bleed frame ---- */
.contacts-s3 { place-content: center; justify-items: center; }
.contacts-s3__text {
  text-align: center;
  width: calc(1440 * var(--u));
  text-shadow: 0 calc(2 * var(--u)) calc(24 * var(--u)) rgba(10, 10, 12, 0.55);
}
.contacts-s3__text .about-text { margin: 0 auto; }
.channels {
  list-style: none;
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: calc(36 * var(--u));
  margin-top: calc(50 * var(--u));
  padding-top: calc(38 * var(--u));
  border-top: 1px solid var(--line-on-dark);
}
.channel { display: flex; flex-direction: column; align-items: center; gap: calc(12 * var(--u)); }
.channel__label {
  font-family: var(--font-ui); font-size: calc(16 * var(--u));
  letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.6;
}
.channel__value {
  font-family: var(--font-display); font-size: calc(32 * var(--u)); line-height: 1.2;
  padding-bottom: calc(4 * var(--u)); word-break: break-word;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size 0.5s var(--ease);
}
.channel__value:hover { background-size: 100% 1px; }
.channel__copy {
  font-family: var(--font-ui); font-size: calc(13 * var(--u));
  letter-spacing: 0.1em; text-transform: uppercase;
  background: none; border: none; color: inherit; cursor: pointer;
  padding: calc(4 * var(--u)) 0; opacity: 0.5; transition: opacity 0.3s ease, color 0.3s ease;
}
.channel__copy:hover { opacity: 1; }
.channel__copy.is-copied { opacity: 1; color: var(--accent-pink); }

/* ---- the trip brief ---- */
.contacts-plan { align-content: center; justify-items: center; gap: calc(54 * var(--u)); }
.contacts-plan__head { text-align: center; }
.contacts-plan__title {
  font-size: calc(58 * var(--u)); letter-spacing: 0.04em;
  margin-bottom: calc(18 * var(--u));
}
.contacts-plan__sub {
  font-family: var(--font-ui); font-size: calc(17 * var(--u)); font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase; opacity: 0.7;
}
.plan-form { width: 100%; display: flex; flex-direction: column; gap: calc(38 * var(--u)); }
.plan-form__row { display: grid; gap: calc(38 * var(--u)) calc(60 * var(--u)); }
.plan-form__row--three { grid-template-columns: repeat(3, 1fr); }
.plan-form__row--two { grid-template-columns: repeat(2, 1fr); }
/* the rows arrive one after another rather than all at once */
.plan-form__row:nth-of-type(2) { transition-delay: 0.09s; }
.plan-form__row:nth-of-type(3) { transition-delay: 0.18s; }
.plan-form__row:nth-of-type(4) { transition-delay: 0.27s; }
.plan-form__foot {
  display: flex; flex-direction: column; align-items: center;
  gap: calc(10 * var(--u)); margin-top: calc(6 * var(--u));
  transition-delay: 0.36s;
}
.plan-form__submit {
  font-family: var(--font-ui); font-size: calc(17 * var(--u)); font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  padding: calc(22 * var(--u)) calc(54 * var(--u)); border-radius: calc(6 * var(--u));
  background: var(--paper); color: var(--ink); border: none; cursor: pointer;
  will-change: transform; transition: background-color 0.35s ease, color 0.35s ease;
}
.plan-form__submit:hover { background: #FFFFFF; }

/* ---- form controls inside a slide ----
   Sized in canvas units so they scale with the composition, and the label
   floats up instead of vanishing: a row of three fields is too dense to
   lose the question once it has been answered. */
.about-slide .form-field {
  padding: calc(26 * var(--u)) 0 calc(12 * var(--u));
  border-bottom: 1px solid var(--line-on-dark);
}
.about-slide .form-field label {
  top: calc(26 * var(--u)); font-size: calc(24 * var(--u)); font-weight: 300;
  color: rgba(247, 243, 236, 0.7); transform-origin: left top;
  transition: transform 0.45s var(--ease), opacity 0.3s ease;
}
.about-slide .form-field input,
.about-slide .form-field textarea {
  font-size: calc(24 * var(--u)); font-weight: 300; color: var(--paper); padding: 0;
}
.about-slide .form-field textarea {
  min-height: calc(96 * var(--u)); max-height: calc(150 * var(--u)); overflow-y: auto;
}
.about-slide .form-field::after { background: var(--paper); bottom: -1px; }
.about-slide .form-field:focus-within label,
.about-slide .form-field input:not(:placeholder-shown) + label,
.about-slide .form-field textarea:not(:placeholder-shown) + label {
  opacity: 1;
  transform: translateY(calc(-26 * var(--u))) scale(0.62);
}

/* ---- narrow screens: the canvas falls back to stacked flow ---- */
@media (max-width: 900px) {
  .contacts-s3__text { width: 100%; }
  .channels { grid-template-columns: 1fr; gap: 20px; margin-top: 26px; padding-top: 22px; }
  .channel { gap: 6px; }
  .channel__label { font-size: 11px; }
  .channel__value { font-size: 19px; }
  .channel__copy { font-size: 11px; }

  .contacts-plan { gap: 26px; justify-items: stretch; }
  .contacts-plan__title { font-size: clamp(24px, 6.6vw, 34px); margin-bottom: 12px; }
  .contacts-plan__sub { font-size: 11px; letter-spacing: 0.14em; }
  .plan-form { gap: 22px; }
  .plan-form__row { gap: 22px; }
  .plan-form__row--three, .plan-form__row--two { grid-template-columns: 1fr; }
  .plan-form__foot { gap: 12px; margin-top: 4px; }
  .plan-form__submit { font-size: 12px; padding: 16px 30px; border-radius: 4px; }

  .about-slide .form-field { padding: 20px 0 8px; }
  .about-slide .form-field label { top: 20px; font-size: 15px; }
  .about-slide .form-field input,
  .about-slide .form-field textarea { font-size: 16px; }
  .about-slide .form-field textarea { min-height: 76px; max-height: none; }
  .about-slide .form-field:focus-within label,
  .about-slide .form-field input:not(:placeholder-shown) + label,
  .about-slide .form-field textarea:not(:placeholder-shown) + label {
    transform: translateY(-19px) scale(0.78);
  }
}

/* ---------- footer ---------- */
/* a pane of glass over the dark, so the closing block reads as its own
   surface rather than running on from the section above it */
.site-footer {
  position: relative;
  padding: 64px 24px 48px; text-align: center;
  background:
    linear-gradient(180deg, rgba(247, 243, 236, 0.10), rgba(247, 243, 236, 0.045) 120px);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid rgba(247, 243, 236, 0.16);
  box-shadow: inset 0 1px 0 rgba(247, 243, 236, 0.10);
  color: var(--paper); font-size: 14px;
}
/* the dark the glass sits on: the pane itself is only a film */
.site-footer::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--ink);
}
.site-footer__tagline { font-family: var(--font-display); font-size: 21px; margin-bottom: 14px; }
.site-footer__rights { font-family: var(--font-ui); font-size: 12px; letter-spacing: 0.03em; opacity: 0.55; }

/* ---------- page transition overlay ---------- */
.page-transition {
  position: fixed; inset: 0; background: var(--ink); z-index: 10000;
  transform: translateY(100%); pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .page-transition { display: none; } }

/* ---------- reveal-on-scroll utility ---------- */
[data-reveal] { opacity: 0; transform: translateY(28px); }
.reveal-ready [data-reveal] { transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
[data-reveal].is-visible { opacity: 1; transform: translateY(0); }

/* data-reveal="blur" — photos arrive out of focus and settle into place */
[data-reveal="blur"] { opacity: 0; transform: scale(1.05); filter: blur(20px); }
.reveal-ready [data-reveal="blur"] {
  transition: opacity 1s var(--ease), transform 1.5s var(--ease), filter 1.2s var(--ease);
}
[data-reveal="blur"].is-visible { opacity: 1; transform: scale(1); filter: blur(0); }

/* data-reveal-stagger — the parts of a block arrive one after another
   rather than as one slab. script.js writes the per-child delay; the
   attribute alone is enough for the CSS below to hold. */
[data-reveal-stagger] > [data-reveal],
[data-reveal-stagger] .svc-list > [data-reveal] { will-change: opacity, transform; }

/* data-reveal-words — the line assembles itself, each word settling out of
   a blur a beat after the one before it. script.js does the splitting. */
[data-reveal-words] .word {
  display: inline-block;
  opacity: 0;
  filter: blur(12px);
  transform: translateY(8px);
}
.reveal-ready [data-reveal-words] .word {
  transition: opacity 0.8s var(--ease), filter 0.8s var(--ease), transform 0.8s var(--ease);
}
[data-reveal-words].is-visible .word { opacity: 1; filter: blur(0); transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal-words] .word { opacity: 1; filter: none; transform: none; transition: none; }
}

/* data-reveal="fade" — for a layer something else already transforms */
[data-reveal="fade"] { opacity: 0; transform: none; }
.reveal-ready [data-reveal="fade"] { transition: opacity 1.4s var(--ease); }
[data-reveal="fade"].is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal="blur"] { transform: none; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}

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