/* ==========================================================================
   Aerivo — one page, one stylesheet.

   Contents
     1.  Tokens
     2.  Reset and base
     3.  Typography
     4.  Buttons, chips, links
     5.  Navigation
     6.  Hero and clouds
     7.  Introduction
     8.  Your flight, step by step
     9.  Rails (services, fleet)
     10. The window
     11. Destinations and globe
     12. Since 1986
     13. Insights and Instagram
     14. Quote
     15. Footer
     16. Scroll reveals
     17. Opening curtain
     18. Reduced motion

   Two rules worth knowing before you change anything:

   — every size lives in part 1 and is redeclared at each breakpoint. No
     heading carries its own media query: changing `--fs-h2` is enough;
   — `--p` is a number between 0 and 1 written by main.js on every element
     carrying `data-track`. It is the scroll progress of that block, and it
     is what drives all the parallax below. No JavaScript, no `--p`, no
     movement — and nothing hidden.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Colours. The night blue carries the text, the cloud white the pages.
     The bright blue is the only accent; it needs three shades because it
     has to hold contrast on white *and* on a photograph — see the README. */
  --navy: #05275b;
  --navy-dark: #071831;
  --navy-soft: #0b2348;
  --cloud: #fcfdfe;
  --white: #ffffff;
  --accent: #0069c8; /* 5.7:1 on --cloud */
  --accent-strong: #004e96; /* hover */
  --accent-light: #5eb2ff; /* on a photograph */
  --line: rgb(5 39 91 / 0.12);
  --line-light: rgb(252 253 254 / 0.24);

  /* The sky. Four stops, straight from the original. */
  --sky: linear-gradient(#214c6f -10%, #7495b5 33.18%, #b4cadd 70.2%, #e5eaf0 100%);
  --sky-tilted: linear-gradient(-172deg, #214c6f 5%, #7495b5 25%, #b4cadd 50%, #e3ebf1 60%, #7495b5 100%);
  --sky-to-cloud: linear-gradient(to top, var(--cloud) 0%, transparent 100%);

  /* Type scale — desktop. Redeclared four times at the end of this part. */
  --fs-display: 88px;
  --fs-display-2: 72px;
  --fs-h2: 56px;
  --fs-h3: 48px;
  --fs-h4: 40px;
  --fs-lead: 20px;
  --fs-body: 16px;
  --fs-small: 14px;

  --lh-display: 1;
  --lh-title: 1.2;
  --lh-body: 1.6;
  --tracking-title: -0.02em;
  --tracking-body: -0.01em;

  /* Rhythm */
  --gutter: 56px;
  --nav-height: 100px;
  --block: 140px;
  --radius: 12px;
  --radius-sm: 8px;

  /* Motion. One duration and one curve for the interface, one longer pair
     for the reveals. Part 18 sets every duration below to 1ms. */
  --ease: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --t-ui: 300ms;
  --t-reveal: 800ms;
}

@media (max-width: 1199px) {
  :root {
    --fs-display: 82px;
    --fs-display-2: 69px;
    --fs-h2: 49px;
    --fs-h3: 43px;
    --fs-h4: 35px;
    --gutter: 40px;
    --block: 120px;
  }
}

@media (max-width: 991px) {
  :root {
    --fs-display: 77px;
    --fs-display-2: 66px;
    --fs-h2: 43px;
    --fs-h3: 38px;
    --fs-h4: 31px;
    --gutter: 30px;
    --nav-height: 88px;
    --block: 100px;
  }
}

@media (max-width: 767px) {
  :root {
    --fs-display: 62px;
    --fs-display-2: 54px;
    --fs-h2: 35px;
    --fs-h3: 31px;
    --fs-h4: 25px;
    --fs-lead: 18px;
    --block: 80px;
  }
}

@media (max-width: 479px) {
  :root {
    --fs-display: 45px;
    --fs-display-2: 40px;
    --fs-h2: 29px;
    --fs-h3: 26px;
    --fs-h4: 24px;
    --gutter: 16px;
    --nav-height: 76px;
    --block: 64px;
  }
}

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* `clip`, never `hidden`: `hidden` would turn the root into a scroll
   container and break every `position: sticky` further down the page. */
html {
  overflow-x: clip;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--cloud);
  color: var(--navy);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img,
svg {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

p,
figure,
address {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}

button {
  border: 0;
  background: none;
  cursor: pointer;
}

/* One focus ring for the whole page. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.shell {
  width: 100%;
  padding-inline: var(--gutter);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 200;
  padding: 10px 18px;
  border-radius: 999px;
  background: var(--navy);
  color: var(--cloud);
  font-size: var(--fs-small);
  transform: translateY(-200%);
  transition: transform var(--t-ui) var(--ease);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* The film grain the original lays over every sky. One 120px tile,
   repeated, at 4% — enough to kill the banding of a wide gradient. */
.hero__grain,
.globe-section__grain,
.quote__grain,
.curtain__grain {
  position: absolute;
  inset: 0;
  background-image: url('../img/noise.png');
  background-size: 120px 120px;
  opacity: 0.04;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3 {
  margin: 0;
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  line-height: var(--lh-title);
  letter-spacing: var(--tracking-title);
}

em {
  font-style: italic;
}

.eyebrow {
  color: var(--accent);
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: var(--tracking-body);
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   4. Buttons, chips, links
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 44px;
  padding-inline: 22px;
  border-radius: 999px;
  font-size: var(--fs-small);
  font-weight: 500;
  white-space: nowrap;
  transition:
    background-color var(--t-ui) var(--ease),
    color var(--t-ui) var(--ease),
    box-shadow var(--t-ui) var(--ease);
}

.btn--solid {
  background: var(--navy);
  color: var(--cloud);
}

.btn--solid:hover {
  background: var(--accent-strong);
}

.btn--outline {
  box-shadow: inset 0 0 0 1px var(--line);
}

.btn--outline:hover {
  background: var(--navy);
  color: var(--cloud);
  box-shadow: inset 0 0 0 1px transparent;
}

/* The dotted button: a filled disc with an arrow, then the label. */
.btn--dot,
.btn--pill {
  height: 48px;
  padding-inline: 4px 24px;
  gap: 16px;
}

.btn--pill {
  background: var(--white);
  color: var(--navy);
}

.btn__dot {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--navy);
  color: var(--cloud);
  flex: none;
  transition: transform var(--t-ui) var(--ease);
}

.btn__dot svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.btn--dot:hover .btn__dot,
.btn--pill:hover .btn__dot {
  transform: translateX(3px);
}

.chip {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding-inline: 10px;
  border-radius: var(--radius-sm);
  background: rgb(252 253 254 / 0.16);
  color: var(--cloud);
  font-size: 13px;
  backdrop-filter: blur(6px);
}

/* --------------------------------------------------------------------------
   5. Navigation
   -------------------------------------------------------------------------- */

.site-nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 90;
  height: var(--nav-height);
  display: flex;
  align-items: center;
  color: var(--cloud);
  transition:
    transform 400ms var(--ease),
    color var(--t-ui) var(--ease);
}

/* Out of the way while you read down the page, back as soon as you come
   up — the whole point of the full-screen photographs below. */
.site-nav.is-hidden {
  transform: translateY(-120%);
}

.site-nav__inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

/* The white pill that slides in once the hero is behind you. It sits
   behind the bar, not around it, so the layout never moves. */
.site-nav::before {
  content: '';
  position: absolute;
  inset: 16px var(--gutter);
  border-radius: 999px;
  background: var(--white);
  opacity: 0;
  transform: scaleY(0.6);
  transform-origin: top;
  transition:
    opacity var(--t-ui) var(--ease),
    transform var(--t-ui) var(--ease);
}

.site-nav.is-scrolled::before {
  opacity: 1;
  transform: scaleY(1);
}

.site-nav.is-scrolled {
  color: var(--navy);
}

.site-nav.is-scrolled .btn--solid {
  background: var(--navy);
  color: var(--cloud);
}

.site-nav__links {
  display: flex;
  align-items: center;
  gap: 32px;
  flex: 1;
  min-width: 0;
}

.site-nav__brand {
  position: absolute;
  left: 50%;
  translate: -50% 0;
}

.mark {
  width: 43px;
  height: 33px;
  fill: currentColor;
}

.site-nav__right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.lang {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  color: inherit;
  transition: background-color var(--t-ui) var(--ease);
}

.lang svg {
  width: 20px;
  height: 20px;
}

.lang:hover {
  background: rgb(5 39 91 / 0.08);
}

/* Nav link hover: the word slides up and its copy takes its place.
   `data-hover` on the span carries the copy — one element, no duplicate
   markup for a screen reader to read twice. */
.nav-link {
  font-size: var(--fs-small);
}

.nav-link span {
  position: relative;
  display: block;
  overflow: hidden;
}

.nav-link span::after {
  content: attr(data-hover);
  position: absolute;
  inset: 0;
  transform: translateY(100%);
  transition: transform var(--t-ui) var(--ease);
}

.nav-link:hover span::after {
  transform: translateY(0);
}

.nav-link span {
  transition: color var(--t-ui) var(--ease);
}

.nav-link:hover span {
  color: transparent;
}

.nav-link:hover span::after {
  color: var(--accent);
}

.burger,
.site-nav__cta-mobile {
  display: none;
}

@media (max-width: 1023px) {
  /* The links leave the bar and become a full-screen panel. It is a plain
     block in the flow when JavaScript is missing, so the menu still works. */
  .js .site-nav__links {
    position: fixed;
    inset: 0;
    z-index: -1;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 8px;
    padding: var(--nav-height) var(--gutter) var(--gutter);
    background: var(--cloud);
    color: var(--navy);
    clip-path: inset(0 0 100% 0);
    transition: clip-path 500ms var(--ease);
  }

  .js .site-nav.is-open .site-nav__links {
    clip-path: inset(0 0 0 0);
  }

  .js .site-nav__links .nav-link {
    font-family: 'Instrument Serif', Georgia, serif;
    font-size: var(--fs-h4);
    letter-spacing: var(--tracking-title);
  }

  .site-nav__cta {
    display: none;
  }

  .js .site-nav__cta-mobile {
    display: inline-flex;
    margin-top: 24px;
  }

  .burger {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    border-radius: 999px;
    background: rgb(252 253 254 / 0.16);
    backdrop-filter: blur(6px);
  }

  .site-nav.is-scrolled .burger,
  .site-nav.is-open .burger {
    background: rgb(5 39 91 / 0.08);
  }

  .burger__bar {
    display: block;
    width: 18px;
    height: 1.5px;
    background: currentColor;
    transition: transform var(--t-ui) var(--ease);
  }

  .site-nav.is-open {
    color: var(--navy);
  }

  .site-nav.is-open .burger__bar:first-child {
    transform: translateY(3.25px) rotate(45deg);
  }

  .site-nav.is-open .burger__bar:last-child {
    transform: translateY(-3.25px) rotate(-45deg);
  }
}

/* --------------------------------------------------------------------------
   6. Hero and clouds

   The block is 170vh tall on desktop. The first screen holds the title and
   the search bar; the extra 70vh is the distance the clouds need to drift.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
}

@media (min-width: 1024px) {
  .hero {
    min-height: 170vh;
  }
}

.hero__sky {
  position: absolute;
  inset: 0;
  overflow: clip;
  background: var(--sky-tilted);
}

/* The sky gradient ends on #7495b5 — a mid blue — while the section below it
   is white. The white veil (.hero__fade) was meant to hide that seam, but it
   travels upward with the scroll, so it uncovers the very edge it was there
   to cover: a bare blue band appears between the clouds and the next section.
   Fading the sky itself to white solves it wherever the veil happens to be.
   Desktop only: on a 100svh hero, 62% would wash out the search bar. */
@media (min-width: 1024px) {
  .hero__sky {
    background:
      linear-gradient(to bottom, transparent 62%, var(--cloud) 97%),
      var(--sky-tilted);
  }
}

.hero__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
}

.hero__content {
  display: flex;
  flex-direction: column;
  gap: 40px;
  height: 100%;
  /* The title sits a little under the bar, the search bar is pushed to the
     bottom by its own `margin-top: auto`. */
  padding-block: calc(var(--nav-height) + 115px) 44px;
}

.hero__title {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  text-align: center;
  color: var(--cloud);
}

.hero__title em {
  color: var(--navy);
}

/* The white haze at the bottom of the sky, which hands over to the next
   section. It rises with the scroll so the seam is never visible. */
.hero__fade {
  position: absolute;
  inset: auto 0 0;
  height: 45vh;
  background: var(--sky-to-cloud);
  transform: translate3d(0, calc(var(--p, 0) * -40vh), 0);
}

/* Cloud layers ---------------------------------------------------------- */

.clouds {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* `--drift` is a number the browser can interpolate, which is what the
   `@property` declaration buys: without a declared syntax a custom
   property jumps from 0 to 1 instead of sliding. It carries the endless
   sideways drift; `--p` carries the scroll. Two movements, one transform. */
@property --drift {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}

.clouds__layer {
  position: absolute;
  left: 0;
  width: 175%;
  max-width: none;
  will-change: transform;
  animation: cloud-drift var(--period, 240s) linear infinite;
  /* The photograph has a straight edge on both sides. Left as is, that edge
     crosses the screen as a vertical seam every time a layer half-leaves.
     Six percent of fade on each side is enough to make it disappear. */
  mask-image: linear-gradient(to right, transparent 0%, #000 6%, #000 94%, transparent 100%);
}

/* A layer starts one screen to the right and leaves by its own width on
   the left. The `--twin` copy runs the same path half a period behind, so
   there is always one of them on screen. */
@keyframes cloud-drift {
  from {
    --drift: 0;
  }
  to {
    --drift: 1;
  }
}

/* Each layer gets its own vertical speed — the original: −90%, −80%, −60% —
   its own scale, and its own period. */
.clouds__layer--back {
  --period: 360s;
  top: 10%;
  scale: 1;
  transform: translate3d(calc(100vw - var(--drift) * (100vw + 100%)), calc(var(--p, 0) * -90%), 0);
}

.clouds__layer--mid {
  --period: 240s;
  top: 60%;
  scale: 1.06;
  transform: translate3d(calc(100vw - var(--drift) * (100vw + 100%)), calc(var(--p, 0) * -80%), 0);
}

.clouds__layer--front {
  --period: 160s;
  top: 40%;
  scale: 1.12;
  transform: translate3d(calc(100vw - var(--drift) * (100vw + 100%)), calc(var(--p, 0) * -60%), 0);
}

.clouds__layer--twin {
  animation-delay: calc(var(--period) / -2);
}

/* Search bar ------------------------------------------------------------- */

.search {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  /* Ten columns out of twelve, like the original grid. */
  width: 83.334%;
  margin: auto auto 0;
  transform: translate3d(0, calc(var(--p, 0) * 70vh), 0);
}

.search__switch {
  position: relative;
  display: inline-flex;
  padding: 4px;
  border-radius: 999px;
  background: var(--white);
}

.search__radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.search__tab {
  position: relative;
  z-index: 1;
  padding: 8px 28px;
  border-radius: 999px;
  font-size: var(--fs-small);
  font-weight: 500;
  cursor: pointer;
  transition: color var(--t-ui) var(--ease);
}

.search__thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc(50% - 4px);
  border-radius: 999px;
  background: var(--navy);
  transition: transform 400ms var(--ease);
}

/* One radio, one position: `:has()` moves the thumb, no script involved. */
.search__switch:has(#soort-enkel:checked) .search__thumb {
  transform: translateX(100%);
}

#soort-retour:checked ~ .search__tab[for='soort-retour'],
#soort-enkel:checked ~ .search__tab[for='soort-enkel'] {
  color: var(--cloud);
}

.search__bar {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr)) auto;
  width: 100%;
  border-radius: var(--radius-sm);
  background: var(--white);
  overflow: clip;
}

.search__field {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  min-width: 0;
  padding: 18px 52px 18px 22px;
}

.search__field + .search__field {
  box-shadow: inset 1px 0 0 var(--line);
}

.search__label {
  color: rgb(5 39 91 / 0.65);
  font-size: 13px;
  line-height: 1.3;
}

.search__input {
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  font-size: var(--fs-small);
  font-weight: 500;
  text-overflow: ellipsis;
}

.search__input::placeholder {
  color: rgb(5 39 91 / 0.65);
  font-weight: 400;
}

.search__input:focus-visible {
  outline-offset: 2px;
}

.search__icon {
  position: absolute;
  right: 22px;
  top: 50%;
  translate: 0 -50%;
  width: 22px;
  height: 16px;
  fill: var(--navy);
  opacity: 0.25;
}

.search__submit {
  display: grid;
  place-items: center;
  width: 80px;
  background: var(--navy);
  color: var(--cloud);
  transition: background-color var(--t-ui) var(--ease);
}

.search__submit:hover {
  background: var(--accent-strong);
}

.search__submit svg {
  width: 18px;
  height: 18px;
  fill: currentColor;
}

.search__mobile {
  display: none;
}

@media (max-width: 1023px) {
  /* On a phone the four fields would be unreadable: the bar gives way to
     a single button pointing at the quote block. */
  .search__switch,
  .search__bar {
    display: none;
  }

  .search__mobile {
    display: inline-flex;
  }

  .search {
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   7. Introduction
   -------------------------------------------------------------------------- */

.intro {
  position: relative;
  z-index: 1;
  background: var(--cloud);
  padding-block: var(--block);
}

@media (min-width: 1024px) {
  .intro {
    min-height: 100vh;
  }
}

.intro__inner {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 32px;
}

.intro .eyebrow {
  grid-column: 2 / span 10;
}

.intro__title {
  grid-column: 2 / span 7;
  margin-top: 16px;
  font-size: var(--fs-h2);
}

.intro__side {
  grid-column: 7 / span 5;
  display: flex;
  flex-direction: column;
  gap: 32px;
  align-items: flex-start;
  margin-top: 60px;
}

@media (max-width: 991px) {
  .intro__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .intro .eyebrow,
  .intro__title,
  .intro__side {
    grid-column: auto;
    margin-top: 0;
  }
}

/* --------------------------------------------------------------------------
   8. Your flight, step by step

   Three photographs stacked with `position: sticky`. The frame around them
   widens to the whole viewport and drops its radius as it arrives — that is
   the `--p` of the frame, written by main.js.
   -------------------------------------------------------------------------- */

.steps {
  position: relative;
  z-index: 1;
  background: var(--cloud);
}

.steps__shell {
  padding-inline: var(--gutter);
}

.steps__frame {
  position: relative;
  border-radius: calc(var(--radius) * (1 - var(--p, 0)));
  overflow: clip;
  /* From the shell width to the full viewport, driven by scroll. */
  width: calc(100% + (100vw - 100%) * var(--p, 0));
  margin-left: calc((100% - (100% + (100vw - 100%) * var(--p, 0))) / 2);
}

/* Each step sticks to the top while the next one slides over it: three
   photographs, one screen, no script. */
.step {
  position: sticky;
  top: 0;
  height: 133svh;
  overflow: clip;
}

.step__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 220px taller than the frame, so it can drift without showing an edge. */
  scale: 1.1;
  transform: translate3d(0, calc(var(--p, 0) * -6%), 0);
}

.step__text {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 640px;
  padding-block: 56px;
  color: var(--cloud);
  text-shadow: 0 1px 24px rgb(7 24 49 / 0.45);
}

.step__title {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: var(--tracking-body);
  line-height: var(--lh-body);
}

/* Progress dots: 1px wide at rest, a 40px bar while their step is on
   screen, filling from the top as you scroll through it. */
.steps__dots {
  position: absolute;
  top: 50%;
  left: 24px;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 2;
}

.steps__dot {
  width: 2px;
  height: 4px;
  border-radius: 999px;
  background: var(--line-light);
  overflow: clip;
  transition: height 600ms var(--ease);
}

.steps__dot.is-active {
  height: 40px;
}

.steps__fill {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--cloud);
  transform-origin: top;
  transform: scaleY(var(--fill, 0));
}

@media (max-width: 767px) {
  .steps__dots {
    left: 12px;
  }

  .step__text {
    padding-block: 40px;
  }
}

/* --------------------------------------------------------------------------
   9. Rails (services, fleet)

   A native scroll-snap track: it drags with a finger, scrolls with a
   trackpad, and every card is reachable with the keyboard. The gauge below
   mirrors the scroll position — that is the only line of script involved.
   -------------------------------------------------------------------------- */

.rail-section {
  position: relative;
  z-index: 1;
  background: var(--cloud);
  padding-block: var(--block);
}

.rail-section--fleet {
  padding-top: 0;
}

@media (min-width: 1024px) {
  .rail-section {
    padding-bottom: calc(var(--block) + 80px);
  }
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 60px;
}

.section-head__title {
  font-size: var(--fs-h3);
}

.rail__track {
  display: flex;
  gap: 24px;
  padding-inline: var(--gutter);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  scroll-padding-inline: var(--gutter);
}

.rail__track::-webkit-scrollbar {
  display: none;
}

.rail__item {
  flex: 0 0 auto;
  width: min(90vw, 528px);
  scroll-snap-align: start;
}

.rail__item--jet {
  width: min(90vw, 432px);
}

.rail__gauge {
  position: relative;
  container-type: inline-size;
  height: 1px;
  margin-top: 40px;
  background: var(--line);
}

/* `100cqw` is the width of the gauge, `100%` the width of the thumb: the
   thumb travels exactly the room it has, whatever the screen. */
.rail__thumb {
  position: absolute;
  inset: 0 auto 0 0;
  width: 33%;
  background: var(--navy);
  transform: translateX(calc(var(--rail, 0) * (100cqw - 100%)));
  transition: transform 120ms linear;
}

/* Service card ----------------------------------------------------------- */

.card-service,
.card-jet {
  position: relative;
  display: block;
  border-radius: var(--radius);
  overflow: clip;
  isolation: isolate;
}

.card-service {
  aspect-ratio: 528 / 580;
}

.card-service img,
.card-jet img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale 600ms var(--ease-out);
}

.card-service:hover img,
.card-jet:hover img {
  scale: 1.05;
}

/* The photographs are bright at the bottom: without this veil the white
   labels sit at 1.5:1. It runs the full width, not just behind the text,
   so the gradient never shows a hard edge. */
.card-service::after,
.card-jet::after {
  content: '';
  position: absolute;
  inset: 40% 0 0;
  background: linear-gradient(to top, rgb(7 24 49 / 0.72), transparent);
  pointer-events: none;
}

.card-service__body,
.card-jet__body {
  position: absolute;
  inset: auto 0 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 28px;
  color: var(--cloud);
}

.card-service__name {
  font-size: var(--fs-small);
  font-weight: 500;
}

.card-service__desc {
  font-size: var(--fs-small);
  line-height: 1.4;
  color: rgb(252 253 254 / 0.92);
}

.card-service__go {
  position: absolute;
  right: 28px;
  bottom: 28px;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--white);
  color: var(--navy);
  transition: transform var(--t-ui) var(--ease);
}

.card-service__go svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.card-service:hover .card-service__go {
  transform: translateX(4px);
}

/* Jet card --------------------------------------------------------------- */

.card-jet {
  aspect-ratio: 432 / 476;
}

.card-jet__name {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--fs-h4);
  line-height: var(--lh-title);
  letter-spacing: var(--tracking-title);
}

.card-jet__specs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* --------------------------------------------------------------------------
   10. The window

   A navy veil covers the screen. Its mask is a full white rectangle *minus*
   the window silhouette, so the silhouette is punched out and you look
   through it. Both the hole and the frame grow from 320px to 152vmax.
   -------------------------------------------------------------------------- */

.window {
  position: relative;
  z-index: 2;
  height: 300svh;
  background: var(--white);
  overflow-x: clip;
}

.window__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
}

.window__view {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.clouds--window {
  transform: scale(1.4);
  transform-origin: bottom;
}

.clouds--window .clouds__layer--back {
  transform: translate3d(calc(var(--drift, 0) * -100%), calc(var(--p, 0) * -30%), 0);
}

.clouds--window .clouds__layer--mid {
  transform: translate3d(calc(var(--drift, 0) * -100%), calc(var(--p, 0) * -50%), 0);
}

.clouds--window .clouds__layer--front {
  transform: translate3d(calc(var(--drift, 0) * -100%), calc(var(--p, 0) * -40%), 0);
}

/* The headline crosses the screen diagonally while you scroll. */
.window__title {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--fs-display-2);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-title);
  color: var(--navy);
  white-space: nowrap;
  transform: translate3d(calc(100% - var(--p, 0) * 200%), calc(30vw - var(--p, 0) * 60vw), 0);
}

.window__veil {
  position: absolute;
  inset: 0;
  z-index: 3;
  background: var(--navy-dark);
  pointer-events: none;
  /* `subtract` removes the silhouette from the full rectangle: what the
     silhouette covers becomes the hole. `xor` is the WebKit spelling. */
  mask-image: linear-gradient(#000, #000), url('../img/window-hole.svg');
  mask-repeat: no-repeat;
  mask-position: center, center;
  mask-composite: subtract;
  -webkit-mask-image: linear-gradient(#000, #000), url('../img/window-hole.svg');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center, center;
  -webkit-mask-composite: xor;
  mask-size:
    100% 100%,
    calc(320px + var(--p, 0) * (152vmax - 320px)) calc(320px + var(--p, 0) * (152vmax - 320px));
  -webkit-mask-size:
    100% 100%,
    calc(320px + var(--p, 0) * (152vmax - 320px)) calc(320px + var(--p, 0) * (152vmax - 320px));
}

.window__frame {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 4;
  translate: -50% -50%;
  width: calc(320px + var(--p, 0) * (152vmax - 320px));
  max-width: none;
  pointer-events: none;
}

@media (min-width: 640px) {
  .window__veil {
    mask-size:
      100% 100%,
      calc(480px + var(--p, 0) * (152vmax - 480px)) calc(480px + var(--p, 0) * (152vmax - 480px));
    -webkit-mask-size:
      100% 100%,
      calc(480px + var(--p, 0) * (152vmax - 480px)) calc(480px + var(--p, 0) * (152vmax - 480px));
  }

  .window__frame {
    width: calc(420px + var(--p, 0) * (152vmax - 420px));
  }
}

.window__fade {
  position: absolute;
  inset: auto 0 0;
  z-index: 5;
  height: 40vh;
  background: var(--sky-to-cloud);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   11. Destinations and globe

   The original renders a WebGL sphere. Here the same equirectangular
   texture is wrapped on a disc: the background slides sideways forever,
   two gradients give it the shading of a lit sphere, and a halo stands in
   for the atmosphere. See the README for what that costs in fidelity.
   -------------------------------------------------------------------------- */

.globe-section {
  position: relative;
  min-height: 150vh;
  padding-block: calc(var(--block) + 60px) var(--block);
  overflow: clip;
  color: var(--cloud);
}

.globe-section__sky {
  position: absolute;
  inset: 0;
  background: var(--sky);
}

.band {
  position: absolute;
  width: 100%;
  max-width: none;
}

/* The white veil that ties a sky block to the white section above it. It
   pulls back as the block arrives, so the seam is only ever visible for the
   first fifth of the scroll — the original does exactly this. */
.globe-section__sky::before,
.quote__sky::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 34%;
  background: linear-gradient(to bottom, var(--cloud) 0%, transparent 100%);
  transform-origin: top;
  transform: scaleY(clamp(0, calc(1 - var(--p, 0) * 3), 1));
  z-index: 1;
}

/* The top band is the same strip of cloud, turned over: it closes the sky
   against the white section above, and drifts up as the block scrolls.

   The rotation belongs inside `transform`, after the translation. Written as
   the standalone `rotate` property it would apply *first*, and every later
   translation would run in a space turned upside down — the band would go
   down when asked to go up. */
.band--top {
  top: 0;
  transform: translate3d(0, calc(-24% - var(--p, 0) * 30%), 0) rotate(180deg);
}

.band--bottom {
  bottom: -2px;
  z-index: 2;
}

.globe-section__head {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  text-align: center;
  transform: translate3d(0, calc(30% - var(--p, 0) * 60%), 0);
}

.globe-section__badge {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line-light);
}

.globe-section__badge svg {
  width: 26px;
  height: 19px;
  fill: currentColor;
}

.globe-section__title {
  font-size: var(--fs-display-2);
  line-height: var(--lh-display);
}

.globe-section__lead {
  max-width: 46ch;
}

.globe {
  position: relative;
  z-index: 1;
  width: min(1100px, 150vw);
  aspect-ratio: 1;
  margin: 80px auto -30%;
}

.globe__halo {
  position: absolute;
  inset: -3%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgb(255 255 255 / 0.22) 64%, rgb(255 255 255 / 0.08) 71%, transparent 73%);
}

/* The texture is equirectangular: 360 degrees across an image twice as wide
   as the globe. `61%` frames Europe and Africa, which is what the original
   shows. Scrolling turns the globe by a fraction of a turn — and the pins
   move by exactly the same fraction, so they stay on their countries. */
.globe__ball {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-image: url('../img/earth.webp');
  background-size: 200% 100%;
  background-repeat: repeat-x;
  background-position-x: calc(61% + var(--p, 0) * 30%);
}

/* Shading, over the texture: a terminator on the left, a highlight top
   right, and a rim of light on the edge. Three gradients, one element. */
.globe__shade {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgb(255 255 255 / 0.35), transparent 46%),
    radial-gradient(circle at 68% 74%, rgb(3 16 38 / 0.55), transparent 62%),
    radial-gradient(circle at 50% 50%, transparent 78%, rgb(255 255 255 / 0.5) 96%);
  box-shadow: inset 0 0 60px rgb(3 16 38 / 0.35);
}

.globe__pins {
  position: absolute;
  inset: 0;
  transform: translateX(calc(var(--p, 0) * -30%));
}

.globe__pin {
  position: absolute;
  width: 26px;
  height: 34px;
  translate: -50% -100%;
  background: var(--navy);
  /* A drop with a round head: a circle merged with a point. */
  clip-path: path('M13 34C13 34 26 20.5 26 13A13 13 0 1 0 0 13c0 7.5 13 21 13 21Z');
}

.globe__pin::after {
  content: '';
  position: absolute;
  top: 8px;
  left: 50%;
  translate: -50% 0;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: var(--cloud);
  opacity: 0.9;
}

/* Twelve bases, placed by rank because a strict CSP forbids `style`. */
.globe__pin:nth-child(1) { left: 46%; top: 30%; }
.globe__pin:nth-child(2) { left: 52%; top: 26%; }
.globe__pin:nth-child(3) { left: 57%; top: 31%; }
.globe__pin:nth-child(4) { left: 50%; top: 34%; }
.globe__pin:nth-child(5) { left: 44%; top: 38%; }
.globe__pin:nth-child(6) { left: 47%; top: 36%; }
.globe__pin:nth-child(7) { left: 41%; top: 41%; }
.globe__pin:nth-child(8) { left: 45%; top: 43%; }
.globe__pin:nth-child(9) { left: 50%; top: 40%; }
.globe__pin:nth-child(10) { left: 63%; top: 39%; }
.globe__pin:nth-child(11) { left: 55%; top: 45%; }
.globe__pin:nth-child(12) { left: 49%; top: 47%; }

@media (max-width: 1023px) {
  .globe-section {
    min-height: 0;
  }

  .globe {
    width: min(420px, 92vw);
    margin: 40px auto -28%;
  }

  .globe__pin {
    width: 18px;
    height: 24px;
    clip-path: path('M9 24C9 24 18 14.5 18 9A9 9 0 1 0 0 9c0 5.5 9 15 9 15Z');
  }

  .globe__pin::after {
    top: 5px;
    width: 7px;
    height: 7px;
  }
}

/* --------------------------------------------------------------------------
   12. Since 1986
   -------------------------------------------------------------------------- */

.story {
  position: relative;
  z-index: 1;
  background: var(--cloud);
  padding-block: var(--block);
}

.story__inner {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 32px;
  align-items: center;
}

.story__figure {
  grid-column: 2 / span 5;
  aspect-ratio: 591 / 806;
  border-radius: var(--radius);
  overflow: clip;
}

.story__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Oversized so the drift never reveals an edge. */
  scale: 1.1;
  transform: translate3d(0, calc(15% - var(--p, 0) * 15%), 0);
}

.story__text {
  grid-column: 8 / span 4;
  display: flex;
  flex-direction: column;
  gap: 24px;
  align-items: flex-start;
}

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

@media (max-width: 991px) {
  .story__inner {
    grid-template-columns: minmax(0, 1fr);
  }

  .story__figure,
  .story__text {
    grid-column: auto;
  }
}

/* --------------------------------------------------------------------------
   13. Insights and Instagram
   -------------------------------------------------------------------------- */

.insights {
  position: relative;
  z-index: 1;
  background: var(--cloud);
  padding-block: var(--block);
}

.insights__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}

.card-insight {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.card-insight img {
  width: 100%;
  aspect-ratio: 475 / 347;
  object-fit: cover;
  border-radius: var(--radius-sm);
  transition: scale 600ms var(--ease-out);
}

.card-insight:hover img {
  scale: 1.02;
}

.card-insight__title {
  font-size: var(--fs-lead);
  line-height: 1.4;
}

.card-insight__tag {
  color: rgb(5 39 91 / 0.65);
  font-size: var(--fs-small);
}

.social {
  position: relative;
  z-index: 1;
  background: var(--cloud);
  padding-bottom: var(--block);
  text-align: center;
}

.social__title {
  font-size: var(--fs-h4);
  margin-bottom: 48px;
}

.social__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.card-social {
  position: relative;
  display: block;
  border-radius: var(--radius-sm);
  overflow: clip;
}

.card-social img {
  width: 100%;
  aspect-ratio: 291 / 358;
  object-fit: cover;
  transition: scale 600ms var(--ease-out);
}

.card-social:hover img {
  scale: 1.05;
}

.card-social__mark {
  position: absolute;
  left: 12px;
  bottom: 12px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgb(7 24 49 / 0.45);
  color: var(--cloud);
  backdrop-filter: blur(4px);
}

.card-social__mark svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.social__handle {
  margin-top: 32px;
  font-size: var(--fs-small);
}

.social__handle a {
  text-decoration: underline;
  text-underline-offset: 4px;
}

@media (max-width: 991px) {
  .insights__grid,
  .social__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 767px) {
  .insights__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   14. Quote
   -------------------------------------------------------------------------- */

.quote {
  position: relative;
  min-height: 150vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: clip;
  color: var(--cloud);
}

.quote__sky {
  position: absolute;
  inset: 0;
  background: var(--sky);
}

.quote__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  text-align: center;
  transform: translate3d(0, calc(60% - var(--p, 0) * 120%), 0);
}

.quote__title {
  max-width: 20ch;
  font-size: var(--fs-h4);
}

@media (max-width: 767px) {
  .quote {
    min-height: 100vh;
  }
}

/* --------------------------------------------------------------------------
   15. Footer
   -------------------------------------------------------------------------- */

.site-foot {
  position: relative;
  background: var(--cloud);
  padding-top: 56px;
}

.site-foot__inner {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 32px;
}

.site-foot__brand {
  grid-column: span 6;
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding-bottom: 56px;
}

.site-foot__logo {
  display: flex;
  align-items: center;
  gap: 14px;
}

.site-foot__logo .mark {
  width: 40px;
  height: 32px;
  fill: var(--navy);
}

.site-foot__wordmark {
  font-size: 26px;
  letter-spacing: -0.02em;
}

.site-foot__pitch {
  max-width: 28ch;
  font-size: var(--fs-small);
  color: rgb(5 39 91 / 0.65);
}

.site-foot__col {
  grid-column: span 2;
  padding-bottom: 56px;
}

.site-foot__col--contact {
  font-size: var(--fs-small);
}

.site-foot__heading {
  margin-bottom: 16px;
  color: rgb(5 39 91 / 0.65);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: var(--tracking-body);
  line-height: var(--lh-body);
}

.site-foot__col li + li,
.site-foot__col p {
  margin-top: 12px;
}

.site-foot__col a {
  transition: color var(--t-ui) var(--ease);
}

.site-foot__col a:hover {
  color: var(--accent);
}

.site-foot__col--contact a {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.site-foot__social {
  display: flex;
  gap: 8px;
  margin-top: 24px;
}

.site-foot__social a {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: var(--navy);
  color: var(--cloud);
  text-decoration: none;
}

.site-foot__social svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.site-foot__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 36px;
  padding-top: 32px;
  padding-bottom: 32px;
  font-size: var(--fs-small);
  color: rgb(5 39 91 / 0.65);
}

.site-foot__legal a {
  text-decoration: underline;
  text-underline-offset: 4px;
}

@media (max-width: 991px) {
  .site-foot__brand {
    grid-column: span 12;
    padding-bottom: 24px;
  }

  .site-foot__col {
    grid-column: span 4;
  }
}

@media (max-width: 767px) {
  .site-foot__col {
    grid-column: span 6;
    padding-bottom: 24px;
  }
}

/* --------------------------------------------------------------------------
   16. Scroll reveals

   The hidden state is written `.js [data-reveal]`. `js` is set by
   enhance.js before the first paint, so a page without JavaScript never
   hides a single line — remove the <script> tags and check.

   The observer in main.js triggers at 15% from the *bottom of the screen*,
   not at a percentage of the element: a block taller than the viewport
   would never reach its own threshold.
   -------------------------------------------------------------------------- */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  filter: blur(10px);
  transition:
    opacity var(--t-reveal) var(--ease-out),
    transform var(--t-reveal) var(--ease-out),
    filter var(--t-reveal) var(--ease-out);
}

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Word by word: main.js wraps every word in a span and numbers it. The
   50ms stagger of the original, expressed as a delay per word. */
.js [data-reveal='words'] {
  opacity: 1;
  transform: none;
  filter: none;
}

.js [data-reveal='words'] .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(20px);
  filter: blur(20px);
  transition:
    opacity var(--t-reveal) var(--ease-out),
    transform var(--t-reveal) var(--ease-out),
    filter var(--t-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 50ms);
}

.js [data-reveal='words'].is-in .word {
  opacity: 1;
  transform: none;
  filter: none;
}

/* --------------------------------------------------------------------------
   17. Opening curtain

   A veil the colour of the page, pierced by a pill-shaped hole that grows
   until nothing is left of it. The original runs 5.4s and holds the scroll;
   this one runs 1.2s and never blocks anything — see the README.
   -------------------------------------------------------------------------- */

.curtain {
  display: none;
}

.js .curtain {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 150;
  background: var(--cloud);
  pointer-events: none;
  mask-image: linear-gradient(#000, #000), url('../img/curtain-hole.svg');
  mask-repeat: no-repeat;
  mask-position: center, center;
  mask-composite: subtract;
  -webkit-mask-image: linear-gradient(#000, #000), url('../img/curtain-hole.svg');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center, center;
  -webkit-mask-composite: xor;
  mask-size: 100% 100%, 0 0;
  -webkit-mask-size: 100% 100%, 0 0;
  animation: curtain-open 1200ms var(--ease) 120ms forwards;
}

/* Once the veil is gone it must not sit over the page and swallow clicks
   in browsers that ignore `pointer-events`, so it removes itself. */
@keyframes curtain-open {
  0% {
    mask-size: 100% 100%, 220px 320px;
    -webkit-mask-size: 100% 100%, 220px 320px;
  }
  99% {
    mask-size: 100% 100%, 300vmax 300vmax;
    -webkit-mask-size: 100% 100%, 300vmax 300vmax;
  }
  100% {
    mask-size: 100% 100%, 300vmax 300vmax;
    -webkit-mask-size: 100% 100%, 300vmax 300vmax;
    visibility: hidden;
  }
}

/* --------------------------------------------------------------------------
   18. Reduced motion

   Delays included: a delay is movement spread over time. Everything lands
   on its final state at once, and the loops stop.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }

  .js [data-reveal],
  .js [data-reveal] .word {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }

  .curtain {
    display: none !important;
  }
}
