/* ==========================================================================
   Lalasoy — travel marketplace, category standard at full craft.
   Craft bar: exoticca.com/us. Mobile-first. No build step.
   ========================================================================== */

:root {
  /* Ground. Warm-neutral, not blue-grey: the page is almost colourless so the
     one hue and the photography carry all the colour. */
  --white:      #FFFFFF;
  --bg-soft:    #F1F1F1;
  --bg-tint:    #E6E6E6;

  /* Ink. Four steps, all AA on both --white and --bg-soft. */
  --black:      #121212;   /* headings, dark grounds, primary CTA */
  --head-dark:  #121212;   /* the header's ground once it sticks — the reference
                              operator's own bar colour, and the same black */
  --ink:        #303030;   /* 13.2:1 on white */
  --muted:      #5E5E5E;   /* 6.5:1 on white, 5.7:1 on --bg-soft */
  --faint:      #6B6B6B;   /* 5.3:1 on white, 4.7:1 on --bg-soft */

  /* THE ONE HUE. --hue is a fill, not a text colour: it clears 3.4:1 on white,
     so nothing small is ever set in it. Black on --hue is 5.5:1, which is how
     it is meant to be used — a flash of colour carrying dark text.
     --hue-ink is the same hue darkened until it passes as text and as a
     button ground (5.6:1 both ways); it is what links and controls use. */
  --hue:           #2596BE;
  --hue-lift:      #3FA9D0;   /* the hue on a dark ground, lifted for hover */
  --hue-ink:       #17708C;
  --hue-ink-dark:  #115569;
  --hue-soft:      #DFF0F6;

  /* The route map's own three colours. The sea is the hue at its lightest —
     the map is the one place on the site where a whole surface is coloured,
     and it stays inside the palette rather than borrowing a tile service's
     blue. The coastline is tinted from that sea, not grey: a neutral hairline
     on a tinted ground reads as dirt. */
  --map-sea:    #A8D3E4;   /* water, at the depth a printed map gives it */
  --map-shelf:  #CDE7F0;   /* the pale band along every coast */
  --map-land:   #EFE7D5;   /* the neighbours: warm paper, present, not the subject */
  --map-focus:  #DCE9C8;   /* the countries this route actually visits */
  --map-coast:  #B9A98A;   /* the hairline, tinted from the land it divides */
  --map-route:  #0F5468;   /* the line the trip runs along */
  --map-ink:    #4A4132;   /* a name on the land */

  /* Commerce. The price is black and the CTA is black — the hue does the
     flashing, the neutrals do the selling. */
  --price:      #121212;
  --cta:        #121212;
  --cta-hover:  #303030;

  /* --gold is the one colour outside the system, and it carries a meaning:
     provisional / awaiting real data. Darkened to 4.9:1 so the note under a
     price is readable as small text. Nothing else may add a hue. */
  --gold:       #8A6D00;
  --gold-lift:  #C79E12;   /* the same signal on a dark ground (7.9:1 on the footer) */
  --gold-soft:  #FDF7E8;   /* the same signal as a ground: --gold on it is 4.6:1 */

  /* --alert is the site's third colour, and like --gold it exists for a
     meaning rather than for a mood: THE MONEY DID NOT MOVE. A declined card
     and a field that stops a payment are the only two things allowed to use
     it — nothing decorative, nothing merely "important", and nothing outside
     the checkout. It is 7.2:1 on white and 6.3:1 on its own tint, so a refusal
     is readable at the size a refusal is written. */
  --alert:      #A8231A;
  --alert-soft: #FCECEA;

  --line:       #DBDBDB;
  --line-soft:  #EDEDED;
  --line-hover: #ABABAB;   /* control border on hover, logo-slot dashes */
  --line-card:  #C6C6C6;   /* card border on hover */

  /* Text tints for dark grounds. Neutral, like the grounds they sit on. */
  --on-dark:      #C6C6C6; /* text on the dark bands */
  --on-dark-soft: #CFCFCF; /* CTA band body */
  --on-dark-foot: #B0B0B0; /* footer body on --footer-ground */
  --on-dark-mute: #8A8A8A; /* one step under footer body: the register's descriptive lines (5.7:1) */
  --on-black-num: #ABABAB; /* count inside an active chip */

  --footer-ground: #0A0A0A; /* one step darker than --black, closes the page */

  /* Hero scrim. One colour at three alphas, layered in two directions. */
  --scrim:      12 12 12;

  --scroll-thumb:       #C6C6C6;
  --scroll-thumb-hover: #ABABAB;

  /* Type */
  --display: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --text:    "Open Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Space */
  --s1: .25rem; --s2: .5rem;  --s3: .75rem; --s4: 1rem;
  --s5: 1.25rem; --s6: 1.5rem; --s8: 2rem;  --s10: 2.5rem;
  --s12: 3rem;  --s16: 4rem;  --s20: 5rem;

  --r-xs: 4px;
  --r-sm: 6px;
  --r:    10px;
  --r-lg: 16px;
  --r-pill: 999px;

  --shadow-sm: 0 1px 2px rgb(18 18 18 / .06), 0 2px 6px rgb(18 18 18 / .06);
  --shadow:    0 2px 6px rgb(18 18 18 / .07), 0 10px 24px -8px rgb(18 18 18 / .16);
  --shadow-lg: 0 4px 12px rgb(18 18 18 / .09), 0 22px 44px -14px rgb(18 18 18 / .26);
  /* The stuck header's own separation, and deliberately not --shadow: a black
     bar over white content needs a whisper, not a grade. The reference draws
     the same one under its own bar. */
  --head-shadow: 0 0 8px rgb(18 18 18 / .08);

  --ease: cubic-bezier(.2, .7, .3, 1);

  /* The header's own height, so the hero knows how far to run up under it. */
  --head-h: 60px;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--text);
  font-size: 1rem;
  line-height: 1.6;
  /* deliberately no overflow-x:hidden — it masks real overflow and made the
     390px audit unable to see an overflowing child */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

/* Browser surfaces carry the design too. */
::selection { background: var(--hue-soft); color: var(--black); }
:root { accent-color: var(--hue-ink); caret-color: var(--hue-ink); scrollbar-color: var(--scroll-thumb) var(--bg-soft); scrollbar-width: thin; }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--bg-soft); }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border: 3px solid var(--bg-soft); border-radius: var(--r-pill); }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); }

/* The blue ring is ~1.5:1 on navy, i.e. invisible on the CTA
   band and the footer. Those grounds get a light ring instead. */
:focus-visible { outline: 3px solid var(--hue-ink); outline-offset: 2px; border-radius: var(--r-xs); }
.cta :focus-visible,
.foot :focus-visible,
.hero :focus-visible,
.tile:focus-visible { outline-color: #FFFFFF; }
/* ...except on the hero's own white surface, where a white ring is nothing. */
.hsearch :focus-visible { outline-color: var(--hue-ink); }

/* A skip link nobody can see is not a skip link. */
.vh--focusable:focus {
  position: fixed; inset-block-start: var(--s2); inset-inline-start: var(--s2);
  width: auto; height: auto; margin: 0; overflow: visible; clip-path: none;
  z-index: 100; background: var(--white); color: var(--black);
  font-family: var(--display); font-weight: 700; font-size: .9375rem;
  padding: var(--s3) var(--s4); border-radius: var(--r); box-shadow: var(--shadow-lg);
}

#main:focus { outline: none; }

img { max-width: 100%; display: block; }
a { color: var(--hue-ink); text-underline-offset: .18em; }

h1, h2, h3, h4 {
  font-family: var(--display);
  color: var(--black);
  line-height: 1.18;
  letter-spacing: -0.015em;
  margin: 0;
  font-weight: 700;
  text-wrap: balance;
}

p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
/* dd carries a 40px inline-start margin in every UA stylesheet, which inside a
   centred cell pushes the value half that distance off the axis its own label
   sits on. The register was the first description list in the project; the
   reset had never had reason to cover one. */
dl, dd { margin: 0; }

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

.shell { width: 100%; max-width: 1220px; margin-inline: auto; padding-inline: var(--s4); }

/* The header is sticky, so an in-page anchor must stop short of it. The offset
   is derived from --head-h rather than typed as a number: the token is
   load-bearing (the immersive hero is pulled up by exactly it), and a hardcoded
   76px would silently stop matching the day the bar changes height.
   .cta carries it too — #contact is an anchor target from six places on the
   home page, and it is the one scroll target that is not a .section. */
.section, .cta { scroll-margin-block-start: calc(var(--head-h) + var(--s2)); }
.section { padding-block: var(--s12); }
.section--soft { background: var(--bg-soft); }

.section-head { display: grid; gap: var(--s2); margin-block-end: var(--s8); max-width: 44rem; }
.section-head h2 { font-size: clamp(1.6rem, 5.5vw, 2.25rem); }
.section-head p { color: var(--muted); }

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

/* The header follows the reference operator's immersive pattern: transparent at
   rest over the hero footage, then a solid dark bar for the whole of the rest of
   the page. The content is white in both states, so the colour rules live on the
   base selectors below and only the bar's own ground changes. The elevation is a
   shadow, not a border, so it never adds to --head-h — the immersive hero is
   pulled up by exactly that height and a 1px border would leave a strip of the
   page showing above it.

   The rule for when the ground arrives is the reference's own, measured off its
   live site: the bar takes it at the exact pixel its resting position passes the
   top edge. The reference's bar rests 81px down, under a promo strip, so it
   spends those 81px travelling with the page before it pins; this one rests at
   the top, so that same rule fires on the first pixel of scroll. Non-immersive
   pages (the tour page) never had a transparent state and open on the dark bar,
   the way the reference's own package pages do. */
.head {
  position: sticky; top: 0; z-index: 50;
  background: var(--head-dark);
  box-shadow: var(--head-shadow);
}
.head__row {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: var(--s3); min-height: var(--head-h);
}
.head__left { display: flex; align-items: center; gap: var(--s6); justify-self: start; }

/* An immersive page opens with no ground under the bar. The transparent state is
   the page's own default rather than a class a script adds, so there is no dark
   frame between first paint and the observer's first report; .head--stuck is
   what arrives, and it arrives once.

   The fade is deliberately one-directional, and this is the whole readability of
   the thing. The search pill rests 10px under the bar, so on any real flick it is
   inside the header within a frame or two — a ground that takes .3s to arrive is
   a ground the pill passes through, and what the visitor reads is the pill, the
   wordmark and the call icon on top of each other. So the ground snaps on: the
   transition lives on the transparent state, which means it governs the way back
   to transparent and not the way to dark. Going down there is content arriving
   underneath and the ground has to beat it; coming back up the content has
   already left and nothing is racing the fade, so the footage is uncovered over
   the reference's own .3s ease-in-out. */
body[data-immersive] .head {
  background: transparent; box-shadow: none;
  transition: background-color .3s ease-in-out;
}
body[data-immersive] .head--stuck {
  background: var(--head-dark); box-shadow: var(--head-shadow);
  transition: none;
}
/* Over footage the controls need their own ground; over the dark bar they do not,
   and a blur there would only cost a compositor layer. */
.head > .shell { position: relative; z-index: 1; }
body[data-immersive] .head::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: 0;
  height: calc(var(--head-h) + var(--s6)); pointer-events: none;
  background: linear-gradient(to bottom, rgb(var(--scrim) / .42), rgb(var(--scrim) / 0));
  transition: opacity .3s ease-in-out;
}
body[data-immersive] .head--stuck::before { opacity: 0; transition: none; }

/* The scroll threshold as a DOM object rather than a number inside a handler: a
   single pixel at the very top of the document, which the viewport loses the
   moment the page moves at all. A rubber-band overscroll at the top pulls it
   further into view rather than out of it, so a bounce cannot flicker the bar. */
.head__sentinel {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  width: 1px; height: 1px; pointer-events: none;
}
.head :focus-visible { outline-color: #FFFFFF; }

/* The wordmark is sized by its height and left to find its own width, so a
   redrawn lockup of a different proportion drops in without a number changing.
   38px on the phone and 42 above it, which are not the reference's own 32 and
   36: only 47% of this artwork's height is letters — the swash rises above them
   and the y and the swoosh fall below — so matching the reference on image
   height would have set the letters two thirds the size of its own. Matched on
   letter size instead, and the mark lands within four pixels of the
   reference's width at both breakpoints. */
.brand { display: flex; align-items: center; text-decoration: none; justify-self: center; min-width: 0; }
.brand__slot { display: block; height: 38px; }
.brand__slot img { display: block; height: 100%; width: auto; max-width: min(52vw, 15rem); object-fit: contain; }

/* The set word is what the link falls back to while the file is missing, and
   what it shows if the file ever fails to load. JS flips the flag on error;
   until then the slot is what shows, so a delivered logo needs no script. */
.brand__word {
  display: none; font-family: var(--display); font-size: 1.375rem;
  font-weight: 700; color: var(--white); letter-spacing: -0.02em;
}
.brand[data-nomark] .brand__slot { display: none; }
.brand[data-nomark] .brand__word { display: block; }

.mainnav { display: none; gap: var(--s6); }
.mainnav a {
  font-family: var(--display); font-size: .9375rem; font-weight: 600;
  color: rgb(255 255 255 / .82); text-decoration: none; padding-block: var(--s2);
  border-block-end: 2px solid transparent; transition: color .16s var(--ease), border-color .16s var(--ease);
}
.mainnav a:hover { color: var(--white); border-block-end-color: var(--white); }

.head__actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--s2); justify-self: end; }

/* Two matched controls, not one boxed and one bare: the call icon and the
   burger are the whole of the header's right side now. 40px rather than the 44
   they were: the client asked for a tenth off, and the marks inside came down
   with the boxes so the controls did not tighten. It stays well clear of the
   24px WCAG 2.2 AA target minimum, and is the one place in the system that sits
   under the 44px comfort mark. */
.burger, .callbtn, .langbtn {
  appearance: none; background: none; border: 0; padding: 0;
  width: 40px; height: 40px; display: grid; place-items: center;
  cursor: pointer; color: var(--white); border-radius: var(--r-sm);
  transition: opacity .16s var(--ease);
}
.burger:hover, .callbtn:hover, .langbtn:hover { opacity: .7; }
.callbtn[aria-expanded="true"], .langbtn[aria-expanded="true"] { opacity: .7; }
/* Nothing is drawn around these now, so the focus ring is the only frame they
   ever get and it needs to clear the glyph. */
.head :focus-visible { outline-offset: 3px; }
.burger { justify-self: start; }
.callbtn { justify-self: end; }

/* Hidden until the burger goes, because below that width the menu sheet is
   the language switch and the system allows exactly one at a time. */
.langbtn { display: none; }

/* Sheets ------------------------------------------------------------------
   Both header controls answer with the same object: a panel that rises from
   the bottom edge. The phone is the primary device and both triggers are
   reached with the thumb, so the answer arrives where the thumb already is
   rather than dropping from the top of the screen. The two sheets are told
   apart by what is inside them and by how far they rise, not by direction.

   Geometry, scrim, body lock, drag-to-dismiss and the close plumbing are
   shared; .sheet--menu and .sheet--card only change the size they settle at.
   ------------------------------------------------------------------------ */

.sheet { position: fixed; inset: 0; z-index: 80; }
.sheet[hidden] { display: none; }

.sheet__scrim {
  position: absolute; inset: 0; background: rgb(18 18 18 / .45);
  opacity: 0; transition: opacity .24s var(--ease);
}
.sheet.is-open .sheet__scrim { opacity: 1; }

.sheet__panel {
  position: absolute; inset-block-end: 0; inset-inline: 0;
  max-height: 92%; background: var(--white);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow-lg); display: flex; flex-direction: column;
  /* The grab area and the close button both live in this padding. */
  padding-block-start: var(--s16);
  transform: translateY(100%);
  transition: transform .34s var(--ease);
  will-change: transform;
}
.sheet.is-open .sheet__panel { transform: none; }
/* While a finger is on it the panel follows the finger, not a curve. */
.sheet__panel.is-dragging { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .sheet__scrim, .sheet__panel { transition: none; }
}

/* The whole top padding is the drag target, so the gesture does not have to
   find a 4px bar; the bar is the sign that the zone is there. Restricted to
   the padding so the sheet's own scrolling is never fighting a drag. */
.sheet__grab {
  position: absolute; inset-block-start: 0; inset-inline: 0; height: var(--s16);
  touch-action: none; cursor: grab;
}
.sheet__grab::before {
  content: ""; position: absolute; inset-block-start: var(--s3);
  inset-inline-start: 50%; translate: -50% 0;
  width: 40px; height: 4px; border-radius: var(--r-pill); background: var(--line-card);
}
.sheet__grab:active { cursor: grabbing; }

/* The menu's own name, set on the close button's line so the sheet's top
   band carries something besides a close. The contact sheet titles itself
   inside its scroll at the display step; this one is a navigation, so it
   takes the card-title step and stays chrome. */
.sheet__title {
  position: absolute; inset-block-start: var(--s5); inset-inline: 0;
  display: flex; align-items: center; justify-content: center;
  height: 40px; margin: 0;
  font-family: var(--display); font-size: 1.125rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--black);
}

.sheet__close {
  position: absolute; inset-block-start: var(--s5); inset-inline-end: var(--s5);
  appearance: none; border: 0; color: var(--black);
  width: 40px; height: 40px; display: grid; place-items: center; cursor: pointer;
  border-radius: var(--r-pill); background: var(--bg-soft);
  transition: background .16s var(--ease);
}
.sheet__close:hover { background: var(--bg-tint); }

/* The panel, not the page, scrolls: the body is locked while it is open. The
   phone's home indicator lives in the last few points of the screen, so the
   final row is lifted clear of it. */
.sheet__scroll {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 0 var(--s5) calc(var(--s6) + env(safe-area-inset-bottom, 0px));
}
/* The menu's actions are a pinned footer and carry the safe-area inset
   themselves, so the scrolling list above them stops at plain spacing. */
.sheet--menu .sheet__scroll { padding-block-end: var(--s4); }

.sheet__group { display: grid; }
.sheet__group--minor { border-block-start: 1px solid var(--line-soft); padding-block-start: var(--s2); margin-block-start: var(--s2); }

.sheet__row {
  appearance: none; background: none; border: 0; width: 100%;
  font-family: var(--display); font-size: 1.125rem; font-weight: 600;
  color: var(--black); text-decoration: none; text-align: start;
  padding-block: var(--s4); cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
}
.sheet__row--minor { font-size: 1rem; font-weight: 600; color: var(--ink); }
.sheet__rowlead { display: inline-flex; align-items: center; gap: var(--s3); min-width: 0; }
.sheet__rowlead svg { flex-shrink: 0; color: var(--faint); }
.sheet__row:hover { color: var(--hue-ink); }
.sheet__chev { color: var(--faint); flex-shrink: 0; transition: transform .2s var(--ease); }
.sheet__row[aria-expanded="true"] .sheet__chev { transform: rotate(180deg); }

.sheet__panelbody { display: grid; padding-block-end: var(--s3); }
.sheet__panelbody[hidden] { display: none; }
/* Also worn by the language <button>s, which otherwise arrive with the UA's
   grey ground and border. */
.sheet__sub {
  appearance: none; background: none; border: 0; width: 100%; cursor: pointer;
  font: inherit; text-align: start;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
  color: var(--ink); text-decoration: none; font-size: .9375rem;
  padding: var(--s3) 0 var(--s3) var(--s5);
}
.sheet__sub:hover { color: var(--hue-ink); }
.sheet__sub[aria-current="true"] { font-weight: 700; color: var(--black); }
.sheet__sub-n { color: var(--faint); font-size: .8125rem; font-variant-numeric: tabular-nums; }

/* Flags ---------------------------------------------------------------------
   Colour arrives on this page through photography, and a flag is the same
   kind of thing: content, not palette. It is the one place the One Hue Rule
   is set aside, and only at 28px, only for a country. One 3:2 box for all
   four so the names line up; the hairline is an ::after because an inset
   shadow would sit under the artwork rather than over it, and Russia's white
   band needs an edge on a white sheet. */
.flag {
  position: relative; flex-shrink: 0; display: block;
  width: 28px; height: 19px; border-radius: var(--r-xs); overflow: hidden;
}
.flag svg { display: block; width: 100%; height: 100%; }
.flag::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(18 18 18 / .16);
}

/* The current language, in the header row. Round because it is the value in
   force rather than one of the choices — the same distinction the tour cards
   draw between a badge and a chip. The flag is 3:2, so it is scaled to cover
   the circle instead of being squeezed into it. */
.flag--round { width: 20px; height: 20px; border-radius: var(--r-pill); }
.flag--round svg { width: 150%; margin-inline-start: -25%; }

/* Language rows ------------------------------------------------------------
   The one list in the menu that is a set of choices rather than a set of
   destinations, so it is drawn as cards rather than as text rows: each has a
   hit area a thumb can miss the middle of and still hit. */
.sheet__panelbody--lang, .langlist { gap: var(--s2); }
.sheet__panelbody--lang { padding-block: var(--s2) var(--s4); }
.langlist { display: grid; }

.langrow {
  appearance: none; width: 100%; cursor: pointer; text-align: start;
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4); min-height: 52px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
  font-family: var(--display); font-size: 1rem; font-weight: 600; color: var(--ink);
  transition: border-color .16s var(--ease), background-color .16s var(--ease), color .16s var(--ease);
}
.langrow:hover { border-color: var(--line-hover); background: var(--bg-soft); color: var(--hue-ink); }
.langrow__name { flex: 1 1 auto; min-width: 0; }

/* Selected: the black hairline the active chip uses, without the filled
   ground — a row of solid black bars would read as four disabled controls.
   The check carries it for anyone who cannot see the border weight. */
.langrow[aria-current="true"] {
  border-color: var(--black); color: var(--black); font-weight: 700;
}
.langrow[aria-current="true"]:hover { background: var(--white); color: var(--black); }
.langrow__check { flex-shrink: 0; color: var(--black); }

.sheet__expert {
  display: flex; align-items: center; gap: var(--s3);
  padding-block: var(--s5); border-block-start: 1px solid var(--line-soft);
}
.sheet__expert-ico {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: var(--r-pill);
  background: var(--hue-soft); color: var(--hue-ink); display: grid; place-items: center;
}
.sheet__expert-txt { display: grid; font-size: .8125rem; color: var(--muted); }
.sheet__expert-txt a { font-family: var(--display); font-size: 1rem; font-weight: 700; color: var(--black); }

/* The two actions are the last thing the thumb reaches and the sheet's only
   filled controls, so they stay put while the list above them scrolls. */
.sheet__actions {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3);
  padding: var(--s4) var(--s5) calc(var(--s4) + env(safe-area-inset-bottom, 0px));
  border-block-start: 1px solid var(--line-soft); background: var(--white);
}

/* The menu's band carries a title as well as a close, and the list scrolls
   under it: at the shared padding the first visible row was clipped four
   pixels below the title's own baseline box and read as a collision. The
   larger band buys a real gap between the title and the scroll's top edge —
   permanent, because it sits outside the scrolling area. */
.sheet--menu .sheet__panel { padding-block-start: var(--s20); }
.sheet--menu .sheet__grab { height: var(--s20); }

/* Both sheets stop where their content stops, and the shared 92% ceiling
   catches the menu once its groups are open. A fixed-height menu left a blank
   half-screen under the last row; the height difference between a screen-tall
   navigation and a three-row contact card is then real, not declared. */

body.is-locked { overflow: hidden; }

/* Contact sheet ------------------------------------------------------------
   The bottom-sheet geometry above is shared with the menu; what follows is
   only what is inside this one. */

.callsheet__head { display: grid; gap: var(--s2); margin-block-end: var(--s5); max-width: 26rem; }
/* The documented display step, same as a section heading — the sheet gets a
   real heading, not a size invented for it. */
.callsheet__head h2 { font-size: clamp(1.6rem, 5.5vw, 2.25rem); }
.callsheet__head p { color: var(--muted); font-size: .9375rem; }

/* The number is the sheet's reason to exist, so it gets the one filled
   surface here and the largest type after the heading. */
.callcard {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s4) var(--s5); border-radius: var(--r-lg);
  background: var(--bg-soft); color: inherit; text-decoration: none;
  transition: background .16s var(--ease);
}
.callcard:hover { background: var(--bg-tint); }
.callcard__ico {
  flex-shrink: 0; width: 42px; height: 42px; border-radius: var(--r-pill);
  background: var(--hue-soft); color: var(--hue-ink); display: grid; place-items: center;
}
.callcard__txt { display: grid; gap: 1px; min-width: 0; }
.callcard__lbl { font-size: .8125rem; color: var(--muted); }
/* The price step: this is the sheet's headline figure, and the ramp already
   has a size for a headline figure. */
.callcard__num {
  font-family: var(--display); font-size: 1.375rem; font-weight: 700;
  color: var(--black); letter-spacing: -.01em; font-variant-numeric: tabular-nums;
}

.callsheet__more { margin-block-start: var(--s6); padding-block-start: var(--s6); border-block-start: 1px solid var(--line-soft); }
.callsheet__more h3 { font-size: 1.125rem; }
.callsheet__more p { color: var(--muted); font-size: .875rem; margin-block-start: var(--s1); }

/* Rows sit in the panel's own gutter, so the hover ground reaches past the
   text without the list looking inset. */
.chanlist { display: grid; margin-block-start: var(--s3); margin-inline: calc(var(--s3) * -1); }
.chan {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3); border-radius: var(--r);
  font-family: var(--display); font-size: 1rem; font-weight: 600;
  color: var(--black); text-decoration: none;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.chan svg { flex-shrink: 0; color: var(--faint); }
.chan__name { flex: 1 1 auto; min-width: 0; }
.chan__go { color: var(--line-hover); }
a.chan:hover { background: var(--bg-soft); color: var(--hue-ink); }
a.chan:hover svg { color: var(--hue-ink); }

/* A channel with no address yet: shown and named, marked in the same gold
   language as a pending price — never a link that goes nowhere. */
.chan.is-pending { color: var(--faint); }
.chan.is-pending .chan__note { font-size: .8125rem; font-style: italic; color: var(--gold); }

/* Once there is room, the sheet stops spanning the screen and becomes the card
   it always was: a full-width band of three short rows across a desktop window
   is a sheet that forgot to stop growing. It keeps rising from the bottom, so
   the gesture reads the same on a tablet as on a phone. */
@media (min-width: 48rem) {
  .sheet--card .sheet__panel {
    inset-block-end: var(--s10); max-width: 27rem; margin-inline: auto;
    border-radius: var(--r-lg); max-height: calc(100% - var(--s20));
  }
  .sheet--card .sheet__scroll { padding-block-end: var(--s6); }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  appearance: none; font-family: var(--display); font-size: .9375rem; font-weight: 700;
  border: 1px solid transparent; border-radius: var(--r); cursor: pointer;
  padding: .8rem 1.35rem; min-height: 48px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  text-decoration: none; line-height: 1;
  transition: background-color .18s var(--ease), border-color .18s var(--ease),
              color .18s var(--ease), box-shadow .18s var(--ease), transform .18s var(--ease);
}
.btn--primary { background: var(--cta); color: var(--white); box-shadow: var(--shadow-sm); }
.btn--primary:hover { background: var(--cta-hover); box-shadow: var(--shadow); transform: translateY(-1px); }
.btn--hue { background: var(--hue-ink); color: var(--white); box-shadow: var(--shadow-sm); }
.btn--hue:hover { background: var(--hue-ink-dark); box-shadow: var(--shadow); transform: translateY(-1px); }
.btn--ghost { background: var(--white); color: var(--black); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--hue-ink); color: var(--hue-ink); }
/* The hero's action. White on footage, and pill-shaped because the hero is
   where this system speaks in pills — the search bar sets that register. */
.btn--light { background: var(--white); color: var(--black); box-shadow: var(--shadow); }
.btn--light:hover { background: var(--bg-soft); box-shadow: var(--shadow-lg); transform: translateY(-1px); }
.btn--pill { border-radius: var(--r-pill); padding-inline: 1.6rem; }
.btn--sm { min-height: 40px; padding: .55rem 1rem; font-size: .875rem; }
.btn:active { transform: translateY(0); }

/* --------------------------------------------------------------------------
   Form controls — the tour page's booking card. The hero's own pill fields are
   a different shape and carry their own rules under Hero.
   -------------------------------------------------------------------------- */

.field { display: grid; gap: var(--s2); min-width: 0; }
/* A field can be absent rather than empty — the booking card's date list is
   not drawn at all for a route with no published departures. `display: grid`
   would otherwise win over the attribute. */
.field[hidden] { display: none; }
.field > label { font-family: var(--display); font-size: .75rem; font-weight: 700; color: var(--black); letter-spacing: .02em; }

.select-wrap { position: relative; display: block; }
.select-wrap > svg {
  position: absolute; inset-inline-end: var(--s3); inset-block-start: 50%;
  transform: translateY(-50%); pointer-events: none; color: var(--hue-ink);
}
.select-wrap__lead {
  position: absolute; inset-inline-start: var(--s3); inset-block-start: 50%;
  transform: translateY(-50%); pointer-events: none; color: var(--faint);
}
select.control, input.control {
  appearance: none; width: 100%; font: inherit; font-size: 1rem; color: var(--black);
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
  padding: .8rem 2.5rem .8rem 2.6rem; min-height: 50px; cursor: pointer;
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
/* The note field. Same ground, border and radius as the selects, but no icon
   gutter to indent past and a text caret rather than a pointer — it is typed
   into, not picked from. Three lines tall to start, and growable by the
   handle only: an auto-growing box would move the total and the button under
   the visitor's thumb while they are still writing. */
/* The select's padding leaves room for the icon in its gutter. A plain text
   input has no icon, so it starts where its own label starts. */
input.control--plain { padding-inline: var(--s4); cursor: text; }

textarea.control {
  appearance: none; width: 100%; font: inherit; font-size: 1rem; line-height: 1.5;
  color: var(--black); background: var(--white);
  border: 1px solid var(--line); border-radius: var(--r);
  padding: .7rem var(--s4); min-height: 88px; resize: vertical; cursor: text;
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
.control::placeholder { color: var(--faint); opacity: 1; }
select.control:hover, input.control:hover, textarea.control:hover { border-color: var(--line-hover); }
select.control:focus-visible, input.control:focus-visible, textarea.control:focus-visible { border-color: var(--hue-ink); box-shadow: 0 0 0 3px var(--hue-soft); outline: none; }

/* --------------------------------------------------------------------------
   Hero — the reference's immersive pattern: footage to the top of the frame,
   the search floating over it as one pill, the promise against the bottom-left.
   -------------------------------------------------------------------------- */

.hero {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--black);
  /* The reference runs 520px on the phone and 640px on the desktop. The svh
     guard is for a short landscape phone, where a fixed 34rem would bury the
     whole page below the fold. */
  min-height: min(33rem, 88svh);
}
/* Only the page that flags itself immersive pulls the hero up under the header;
   the tour page keeps its solid bar. */
body[data-immersive] .hero { margin-block-start: calc(var(--head-h) * -1); }

.hero__media { position: absolute; inset: 0; overflow: hidden; }
.hero__video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Three scrims, painted top down. The first is the header band and is measured
   in pixels, because it answers the header's height rather than the frame's:
   this clip opens on a bright sky, and white nav over it measured 1:1. The
   second shapes the frame as a whole and closes the bottom under the campaign.
   The third protects the text column on the left. Every value here was set by
   sampling the composited pixels — against the poster frame, which is the worst
   case, the first thing painted, and all a reduced-motion visitor ever sees. */
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      rgb(var(--scrim) / .82) 0,
      rgb(var(--scrim) / .60) 78px,
      rgb(var(--scrim) / .30) 165px,
      rgb(var(--scrim) / 0) 260px),
    linear-gradient(180deg,
      rgb(var(--scrim) / .34) 0%,
      rgb(var(--scrim) / .26) 38%,
      rgb(var(--scrim) / .52) 72%,
      rgb(var(--scrim) / .86) 100%),
    linear-gradient(90deg,
      rgb(var(--scrim) / .62) 0%,
      rgb(var(--scrim) / .30) 42%,
      rgb(var(--scrim) / 0) 72%);
}

.hero__top { position: relative; z-index: 1; padding-block-start: var(--s4); }
body[data-immersive] .hero__top { padding-block-start: calc(var(--head-h) + var(--s3)); }

.hsearch {
  display: flex; align-items: center; gap: var(--s4);
  max-width: 45rem; margin-inline: auto;
  background: var(--white); border-radius: var(--r-pill);
  padding: 5px 5px 5px var(--s5);
  box-shadow: var(--shadow-lg);
}

.hfield { display: flex; align-items: center; gap: var(--s3); flex: 1 1 0; min-width: 0; }
.hfield__ico { flex-shrink: 0; display: grid; place-items: center; color: var(--faint); }
.hfield__body { display: grid; gap: 1px; min-width: 0; flex: 1 1 auto; }
.hfield__body > label {
  font-family: var(--display); font-size: .75rem; font-weight: 600;
  color: var(--muted); letter-spacing: .01em; line-height: 1.3;
}
.hfield__pick { position: relative; display: flex; align-items: center; min-width: 0; }
.hfield__pick > svg { position: absolute; inset-inline-end: 0; pointer-events: none; color: var(--faint); }

select.hcontrol {
  appearance: none; width: 100%; min-width: 0; margin: 0;
  font-family: var(--text); font-size: .9375rem; line-height: 1.45;
  color: var(--black); background: transparent; border: 0; border-radius: var(--r-xs);
  padding: 0 1.1rem 0 0; cursor: pointer;
  text-overflow: ellipsis; white-space: nowrap;
}
select.hcontrol:disabled { color: var(--faint); cursor: not-allowed; }
.hfield:has(select:disabled) .hfield__ico,
.hfield:has(select:disabled) .hfield__pick > svg { color: var(--line-hover); }

/* The two segments the phone drops, and the rules that separate them. */
.hsearch__div { flex: 0 0 1px; align-self: center; width: 1px; height: 34px; background: var(--line); }
.hfield--wide, .hsearch__div { display: none; }

.hsearch__go {
  appearance: none; border: 0; flex: 0 0 auto; cursor: pointer;
  width: 48px; height: 48px; border-radius: var(--r-pill);
  background: var(--cta); color: var(--white);
  display: grid; place-items: center;
  transition: background-color .16s var(--ease), transform .12s var(--ease);
}
.hsearch__go:hover { background: var(--cta-hover); }
.hsearch__go:active { transform: scale(.94); }

/* The gold advisory belongs to the month control, so it appears where that
   control does — from 48rem up. */
.hsearch__note {
  display: none; align-items: center; justify-content: center; gap: var(--s2);
  max-width: 45rem; margin: var(--s3) auto 0;
  font-size: .8125rem; color: var(--white); text-align: center;
}
.hsearch__note svg { flex-shrink: 0; color: var(--gold-lift); }
.hsearch__note[hidden] { display: none; }

/* Campaign block ----------------------------------------------------------- */

.hero__inner {
  position: relative; z-index: 1; margin-block-start: auto;
  display: grid; justify-items: start; gap: var(--s4);
  padding-block: var(--s10) var(--s8);
}
/* Two rows, one per half of the sentence. The cap is wide enough that the
   longest of the four languages still breaks after the first half rather than
   inside it. */
.hero__title { display: grid; color: var(--white); font-size: clamp(1.9rem, 7.5vw, 3.4rem); letter-spacing: -0.025em; max-width: min(100%, 49rem); }
/* The one accented line. --hue-lift is the token for the hue on a dark ground;
   gold is spoken for, it means "not real data yet". */
.hero__em { color: var(--hue-lift); }
.hero__sub { color: #E8E8E8; font-size: 1.0625rem; max-width: 34rem; }
.hero__act { margin-block-start: var(--s1); }
.hero__foot { color: #CFCFCF; font-size: .875rem; line-height: 1.5; max-width: 36rem; }

/* The bottom line of the frame: the proof on the left, what the footage is and
   how to stop it on the right. In flow rather than pinned to the corner, so a
   three-line Russian footnote can never run underneath the controls. */
.hero__base {
  width: 100%; margin-block-start: var(--s5);
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: var(--s4);
}
.hero__meta { display: flex; align-items: center; gap: var(--s3); margin-inline-start: auto; }

/* The stop sits where the reference puts its carousel dots. The script un-hides
   it only once the footage is genuinely running. */
.hero__toggle {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--r-pill); cursor: pointer;
  display: grid; place-items: center;
  background: rgb(255 255 255 / .16); border: 1px solid rgb(255 255 255 / .42);
  color: var(--white); backdrop-filter: blur(8px);
  transition: background-color .16s var(--ease), border-color .16s var(--ease);
}
.hero__toggle:hover { background: rgb(255 255 255 / .3); border-color: var(--white); }
.hero__toggle[hidden] { display: none; }
.hero__toggle-play { display: none; }
.hero__toggle[aria-pressed="true"] .hero__toggle-pause { display: none; }
.hero__toggle[aria-pressed="true"] .hero__toggle-play { display: block; }

/* --------------------------------------------------------------------------
   Trust bar
   -------------------------------------------------------------------------- */

.trust { border-block-end: 1px solid var(--line); background: var(--white); }
/* One column on the phone. Two-up was the default here, and at 375px it left
   each label 112px of measure — about fourteen characters — so three of the
   four titles broke across two lines and every description ran to three, on
   the proof strip directly under the headline. The 4-up rule below already
   reasons this way ("only once Russian's longer strings still fit"); this is
   the same test applied at the bottom of the range, where 2-up fails it.
   Two columns return at 35rem, and that number is set by the same test the
   4-up rule uses: at 32rem the columns are 230px, which is enough for the
   Azerbaijani labels but still breaks Russian's longest — "Сервис на четырёх
   языках" — across two lines. 35rem is where it fits. */
.trust__grid { display: grid; gap: var(--s5); grid-template-columns: minmax(0, 1fr); padding-block: var(--s8); }

@media (min-width: 35rem) {
  .trust__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.trust__item { display: flex; gap: var(--s3); align-items: flex-start; }
.trust__icon { flex-shrink: 0; width: 38px; height: 38px; border-radius: var(--r-pill); background: var(--hue-soft); color: var(--hue-ink); display: grid; place-items: center; }
/* Not a heading. Four reassurance labels between the h1 and the first real
   section put four entries in the document outline and skipped a level to do
   it; they name nothing a reader would navigate to. They keep the display
   face and the weight, and give the outline back. */
/* Scoped to .trust__item so it outranks the sibling `.trust__item p` rule
   below, which would otherwise pull the label down to the description's
   13px — the h3 this replaced won on element specificity for free. */
.trust__item .trust__t {
  font-family: var(--display); font-weight: 700; color: var(--black);
  font-size: .9375rem; line-height: 1.18; letter-spacing: -0.015em;
  margin-block-end: 2px;
}
.trust__item p { font-size: .8125rem; color: var(--muted); line-height: 1.45; }

/* --------------------------------------------------------------------------
   Filter chips
   -------------------------------------------------------------------------- */

/* Wraps rather than scrolls: a hidden-scrollbar carousel put a whole
   destination off-screen at phone width with nothing indicating it existed. */
.chips { display: flex; flex-wrap: wrap; gap: var(--s2); margin-block-end: var(--s4); }
.chip {
  appearance: none; font-family: var(--display); font-size: .875rem; font-weight: 600;
  background: var(--white); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: .5rem 1rem; cursor: pointer; white-space: nowrap;
  transition: background-color .16s var(--ease), border-color .16s var(--ease), color .16s var(--ease);
}
.chip:hover { border-color: var(--hue-ink); color: var(--hue-ink); }
.chip[aria-pressed="true"] { background: var(--black); border-color: var(--black); color: var(--white); }
.chip__n { color: var(--muted); margin-inline-start: .35rem; font-variant-numeric: tabular-nums; }
.chip[aria-pressed="true"] .chip__n { color: var(--on-black-num); }

/* --------------------------------------------------------------------------
   Tour cards
   -------------------------------------------------------------------------- */

/* On the phone the grid is a swipe rail: one card holds the screen and the
   next one peeks past the right edge, so the gesture is visible before it is
   tried. The rail bleeds through .shell's padding to both screen edges — a
   card sits flush with the text above it while the peek still reaches the
   bezel — and snaps card to card. It is a real grid again from 34rem, where
   two cards fit side by side and there is nothing left to swipe. */
.cards {
  --peek: 3.25rem;            /* next card + gap left on screen */
  display: flex;
  gap: var(--s4);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;   /* the swipe never becomes a back gesture */
  scroll-snap-type: x mandatory;
  scroll-padding-inline-start: var(--s4);
  margin-inline: calc(var(--s4) * -1);
  padding-inline: var(--s4);
  padding-block-end: var(--s1);
  /* The platform scrollbar is 12px of undesigned chrome under every card;
     .railbar below draws the same information from the palette instead. */
  scrollbar-width: none;
}
.cards::-webkit-scrollbar { display: none; }
@media (prefers-reduced-motion: no-preference) { .cards { scroll-behavior: smooth; } }

.card {
  position: relative;
  flex: 0 0 calc(100% - var(--peek));
  scroll-snap-align: start;
  /* One route left after a filter: nothing to peek at, so the card takes the
     screen rather than leaving a lopsided margin where the next one was. */
  display: grid; grid-template-rows: auto 1fr;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; text-decoration: none; color: inherit;
  transition: box-shadow .22s var(--ease), transform .22s var(--ease), border-color .22s var(--ease);
}
.card:hover { box-shadow: var(--shadow-lg); transform: translateY(-3px); border-color: var(--line-card); }
/* Inside the rail the lift has nowhere to go — the scroller clips it — and a
   phone has no pointer to hover with. The border still answers. */
.cards .card:hover { transform: none; box-shadow: none; }
.cards.is-single .card { flex-basis: 100%; }

/* Rail position. --w is the thumb's share of the track and --x its travel as
   a fraction of its own width; both are written by the scroll handler, so the
   bar tracks the finger rather than animating after it. */
.railbar {
  --w: 1; --x: 0;
  height: 3px; margin-block-start: var(--s5);
  background: var(--line); border-radius: var(--r-pill); overflow: hidden;
}
.railbar::after {
  content: ""; display: block; height: 100%; border-radius: inherit;
  background: var(--hue-ink);
  width: calc(var(--w) * 100%);
  transform: translateX(calc(var(--x) * 100%));
}

/* The card's button is its link; this makes the whole card the hit area
   without nesting an anchor around one.

   The button must carry no transform of its own. --hue's hover lift resolves
   to a matrix that outlives the pointer (the transition leaves an identity
   matrix, never `none`), and any transform makes the button the containing
   block for its own ::after — which collapses the hit area back to the button
   the moment the card is first hovered or tapped. The whole card already
   lifts, so the button loses nothing. */
.card__cta, .card__cta:hover { transform: none; }
.card__cta::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-lg); }
.card:focus-within { border-color: var(--line-card); }

.card__media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-tint); }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.card:hover .card__media img { transform: scale(1.045); }

/* The region badge matches the card's "Ətraflı" button: the darkened
   --hue-ink ground carrying white text (5.6:1). No blur — the fill is
   opaque, so the label stays legible over any photograph. */
.card__badge {
  position: absolute; inset-block-start: var(--s3); inset-inline-start: var(--s3);
  background: var(--hue-ink); color: var(--white); font-family: var(--display);
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: .3rem .6rem; border-radius: var(--r-sm);
}


.card__body { display: grid; grid-template-rows: auto auto 1fr auto; gap: var(--s3); padding: var(--s5); }
.card__title { font-size: 1.125rem; }
/* Clamped: the 11-stop Dubai route otherwise dictates row height for the
   whole grid and leaves a void beside its row partners. */
.card__stops {
  font-size: .875rem; color: var(--muted); line-height: 1.5;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}

.tours__count { font-size: .875rem; color: var(--muted); margin-block-end: var(--s5); }

.noscript-list { display: grid; gap: var(--s2); margin-block-end: var(--s4); }
.noscript-list li { padding: var(--s3); border: 1px solid var(--line); border-radius: var(--r); }

.card__meta { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); align-self: start; }
.card__metaitem { display: inline-flex; align-items: center; gap: var(--s2); font-size: .8125rem; color: var(--muted); }
.card__metaitem svg { flex-shrink: 0; color: var(--faint); }
/* Gold, not grey: this is the commonest instance of the pending signal on the
   whole site (every card with no night count), and it was the one place that
   spoke it in a different colour from the dashed rule under the price
   directly beneath it. One card, one honesty language. Gold is 4.9:1 on the
   card's white ground. */
.card__metaitem.is-pending { color: var(--gold); font-style: italic; }

.card__foot { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s3); padding-block-start: var(--s3); border-block-start: 1px solid var(--line-soft); }
.card__pricewrap { display: grid; gap: 1px; }
.card__from { font-size: .75rem; color: var(--muted); }
.card__price { font-family: var(--display); font-size: 1.375rem; font-weight: 700; color: var(--price); font-variant-numeric: tabular-nums; line-height: 1.1; }

/* Provisional figure — marked in the same gold language as the pending nights,
   so the loudest number on the card is not also the least true one. */
.card__price.is-provisional { border-block-end: 2px dashed var(--gold); padding-block-end: 1px; }
.card__per { font-size: .6875rem; color: var(--faint); }

.cards__empty {
  display: none; text-align: center; padding: var(--s16) var(--s4);
  border: 1px dashed var(--line); border-radius: var(--r-lg); background: var(--bg-soft);
}
.cards__empty h3 { font-size: 1.125rem; margin-block-end: var(--s2); }
.cards__empty p { color: var(--muted); margin-block-end: var(--s4); }
.cards.is-empty ~ .cards__empty { display: block; }

/* --------------------------------------------------------------------------
   Destination tiles
   -------------------------------------------------------------------------- */

.deck-wrap {
  /* Only bites once the deck is taller than roughly three rows; four
     destinations never scroll, a dozen do. */
  max-height: 74vh; overflow-y: auto; overscroll-behavior: contain;
  margin-inline: calc(var(--s1) * -1); padding-inline: var(--s1);
}
.deck { display: grid; gap: var(--s4); grid-template-columns: repeat(2, minmax(0, 1fr)); }

.tile {
  position: relative; display: grid; place-items: center; aspect-ratio: 1 / 1;
  border-radius: var(--r-lg); overflow: hidden; text-decoration: none;
  box-shadow: var(--shadow-sm); isolation: isolate;
}
.tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .55s var(--ease); }
.tile:hover img { transform: scale(1.06); }
/* Darker than the old bottom-only wash: the name sits in the middle of the
   photo now, so the whole frame has to carry white text.
   The stops are monotonic on purpose. The previous curve dipped to .12 at 45%
   — its thinnest point was exactly the band the centred label sits in, which
   measured 2.42:1 on the Türkiyə tile against a 3:1 threshold. The scrim now
   only ever deepens down the frame, so the label band can never be the
   lightest part of it, and the floor under the label is ~.47 whatever
   photograph lands here. This is the one gradient in the system that has to
   hold white text over an image nobody has chosen yet, so it is tuned for the
   worst case rather than for the current placeholders. */
.tile::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgb(var(--scrim) / .34) 0%, rgb(var(--scrim) / .46) 45%, rgb(var(--scrim) / .66) 100%);
}
.tile__label { position: relative; z-index: 2; display: grid; justify-items: center; gap: var(--s2); padding: var(--s3); text-align: center; }
.tile__label strong {
  font-family: var(--display); font-size: clamp(1.0625rem, 4.4vw, 1.375rem); font-weight: 700;
  color: var(--white); letter-spacing: -0.015em; line-height: 1.15;
  text-shadow: 0 1px 10px rgb(18 18 18 / .45);
}
.tile__count {
  background: var(--white); color: var(--black); border-radius: var(--r-pill);
  font-family: var(--display); font-size: .8125rem; font-weight: 700;
  padding: .3rem .8rem; box-shadow: var(--shadow-sm); white-space: nowrap;
}

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

/* The hero carousel. The swipe is the browser's own: a scroll-snapping
   scroller, so it carries native momentum and rubber-banding on a phone and
   stays keyboard-scrollable. No drag handling, no library. */
.hero-gal { position: relative; background: var(--bg-tint); }
.hero-gal__track {
  display: flex; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.hero-gal__track::-webkit-scrollbar { display: none; }
.hero-gal__track:focus-visible { outline: 2px solid var(--hue-ink); outline-offset: -4px; }

.hero-gal__slide {
  flex: 0 0 100%; margin: 0; position: relative;
  aspect-ratio: 4 / 3; scroll-snap-align: center; scroll-snap-stop: always;
}
.hero-gal__slide img { width: 100%; height: 100%; object-fit: cover; display: block; }


.hero-gal .card__badge {
  position: absolute; inset-block-start: var(--s4); inset-inline-start: var(--s4);
  z-index: 2; pointer-events: none;
}

/* Dots sit on the photo, over a soft gradient so they read on a bright sky
   as well as a dark mountain. */
.hero-gal__dots {
  position: absolute; inset-block-end: 0; inset-inline: 0; z-index: 2;
  display: flex; justify-content: center; gap: 0;
  padding: var(--s5) var(--s3) var(--s3);
  background: linear-gradient(to top, rgb(var(--scrim) / .35), transparent);
}

/* The dot the eye reads is 8px; the button the thumb hits is 24px square.
   WCAG 2.2 AA (2.5.8) asks for 24px, and its spacing exception cannot save an
   8px dot here — it needs 24px between centres, which is more than the gap the
   dots were drawn with. So the target carries the space instead of the gap:
   pitch is exactly 24px, the dots keep the size and rhythm they were designed
   at, and nothing overlaps. Nine dots come to 216px, which still sits inside
   the narrowest phone with room either side. */
.hero-gal__dot {
  width: 1.5rem; height: 1.5rem; padding: 0; border: 0;
  background: none; cursor: pointer;
  display: grid; place-items: center;
}
.hero-gal__dot::before {
  content: ''; width: .5rem; height: .5rem; border-radius: 50%;
  background: rgba(255, 255, 255, .5);
  transition: background .2s ease, transform .2s ease;
}
.hero-gal__dot[aria-current="true"]::before { background: var(--white); transform: scale(1.25); }
.hero-gal__dot:focus-visible { outline: 2px solid var(--white); outline-offset: -2px; border-radius: 50%; }

/* Arrows. A phone swipes; a pointer has nothing to swipe with, so from 48rem
   the carousel carries two controls. White ground rather than a translucent
   one: the slides run from bright sky to dark mountain and a glass circle
   reads on neither. Hidden below that width — the gesture is the control
   there, and a 44px target over the photo would only be in the way. */
.hero-gal__nav {
  display: none;
  position: absolute; inset-block-start: 50%; z-index: 2;
  width: 44px; height: 44px; padding: 0;
  transform: translateY(-50%);
  align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 50%;
  background: rgba(255, 255, 255, .94); color: var(--ink);
  box-shadow: 0 2px 10px rgb(18 18 18 / .18);
  cursor: pointer;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease, opacity .18s ease;
}
.hero-gal__nav--prev { inset-inline-start: var(--s4); }
.hero-gal__nav--next { inset-inline-end: var(--s4); }
.hero-gal__nav:hover { background: var(--white); box-shadow: 0 4px 14px rgb(18 18 18 / .22); }
.hero-gal__nav:focus-visible { outline: 3px solid var(--white); outline-offset: 2px; }
/* At an end the control is really unavailable, so it says so and stops
   taking the pointer, rather than looking live and doing nothing. */
.hero-gal__nav[disabled] { opacity: .38; cursor: default; box-shadow: none; }

@media (min-width: 48rem) {
  .hero-gal__nav:not([hidden]) { display: flex; }
}

/* One photo: nothing to swipe, so the scroller stops behaving like one. */
.hero-gal.is-single .hero-gal__track { overflow-x: hidden; }

@media (prefers-reduced-motion: reduce) {
  .hero-gal__track { scroll-behavior: auto; }
  .hero-gal__dot::before { transition: none; }
  .hero-gal__nav { transition: none; }
}

/* Title, price and the route's standing marks, in that order — the reference's
   own sequence, and the order a buyer reads them in. */
.tour__head { padding-block: var(--s6) var(--s8); display: grid; gap: var(--s3); }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); font-size: .8125rem; }
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--hue-ink); text-decoration: underline; }
.crumbs span { color: var(--line-hover); }

.tour__head h1 { font-size: clamp(1.75rem, 7vw, 2.75rem); letter-spacing: -0.025em; }
.tour__sub { color: var(--muted); font-size: 1rem; }

.tour__pricerow { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2); margin-block-start: var(--s1); }
.tour__from { font-size: .875rem; color: var(--muted); }
.tour__price { font-family: var(--display); font-size: clamp(1.5rem, 6vw, 2rem); font-weight: 700; color: var(--price); font-variant-numeric: tabular-nums; }
.tour__price.is-provisional { border-block-end: 2px dashed var(--gold); }
.tour__per { font-size: .8125rem; color: var(--faint); }

/* Price by age. A ruled list rather than a run-on sentence, because three
   bands and three rules is a table however it is punctuated — and because a
   family scanning for the word "pulsuz" finds it on its own line. It stacks
   on the phone, where "полная цена" needs the width, and becomes three
   columns at the breakpoint where the width exists. */
.agerule { display: grid; gap: var(--s3); margin-block-start: var(--s4); }
.agerule__title {
  font-family: var(--display); font-size: .75rem; font-weight: 700;
  letter-spacing: .02em; color: var(--black);
}
.agerule__list {
  display: grid; width: 100%; max-width: 34rem;
  border: 1px solid var(--line); border-radius: var(--r);
}
.agerule__item {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3); padding: .6rem var(--s4); min-width: 0;
}
.agerule__item + .agerule__item { border-block-start: 1px solid var(--line-soft); }
.agerule__band { font-size: .875rem; color: var(--muted); }
.agerule__rule {
  font-family: var(--display); font-size: .875rem; font-weight: 700; color: var(--black);
}
.agerule__note { font-size: .8125rem; color: var(--muted); margin: 0; }

@media (min-width: 34rem) {
  .agerule__list { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .agerule__item { display: grid; gap: 2px; align-content: start; padding: var(--s3) var(--s4); }
  .agerule__item + .agerule__item {
    border-block-start: 0; border-inline-start: 1px solid var(--line-soft);
  }
}

.tour__marks { display: grid; gap: var(--s2); margin-block-start: var(--s2); }
.tour__marks .card__metaitem { font-size: .875rem; }

.tour__layout { display: grid; gap: var(--s10); padding-block-end: var(--s12); }
.tour__main { display: grid; gap: var(--s10); min-width: 0; }
.tour__section { display: grid; gap: var(--s5); scroll-margin-block-start: 90px; }
.tour__section h2 { font-size: clamp(1.375rem, 5vw, 1.75rem); }
.tour__prose { color: var(--ink); font-size: 1.0625rem; }

/* Route map. Authored SVG on real coastlines — see routeMap() in the script
   for why it is drawn rather than fetched. It is a picture, not a control:
   nothing in it takes a pointer or the keyboard, and the numbered list under
   it carries every stop the map may have merged into one pin.

   --u is the bridge between the two scales at work. The geography is drawn in
   the SVG's own units and stretches with the frame; the pins, the names and
   the route line are sized in --u so they measure the same on a phone as on a
   desktop. The script measures it and keeps it current. */
.routemap {
  --u: 2.2;
  position: relative;
  margin: 0 0 var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--map-sea);
}
.routemap__svg { display: block; width: 100%; aspect-ratio: 25 / 14; }
.routemap__sea { fill: var(--map-sea); }
/* The shelf: the same coastlines, stroked wide and pale under the land, the
   way a printed map lightens the water at the shore. It is what keeps a flat
   blue rectangle from reading as a hole cut in the page. */
.routemap__shelf path {
  fill: none;
  stroke: var(--map-shelf);
  stroke-width: calc(var(--u) * 9px);
  stroke-linejoin: round;
}
/* The countries the route visits are the page the trip is written on; the
   neighbours are the margin. One step of value between them is enough. */
.routemap__land path.is-visited { fill: var(--map-focus); }
.routemap__land path {
  fill: var(--map-land);
  stroke: var(--map-coast);
  stroke-width: 1;
  stroke-linejoin: round;
  /* The coastline is a hairline at every zoom: the geometry stretches with
     the frame, the line it is drawn with does not. */
  vector-effect: non-scaling-stroke;
}
/* Country names. Two weights, one job each: the countries the route visits
   are read, the neighbours are only placed. Each name is knocked out of the
   land it stands on rather than boxed — the halo is the ground colour, so a
   name crossing a border stays legible without drawing a shape of its own. */
.routemap__place {
  fill: var(--map-ink);   /* 6.9:1 on the neighbours' paper */
  font-family: var(--display);
  font-weight: 600;
  font-size: calc(var(--u) * 11px);
  letter-spacing: .05em;
  text-anchor: middle;
  paint-order: stroke fill;
  stroke: var(--map-land);
  stroke-width: calc(var(--u) * 3px);
  stroke-linejoin: round;
}
.routemap__place.is-visited {
  fill: var(--black);
  font-weight: 700;
  font-size: calc(var(--u) * 12.5px);
  letter-spacing: .04em;
  stroke: var(--map-focus);
}
/* The route, drawn the way a road is drawn on a map: a pale casing under a
   dark line, so it stays legible whether it crosses water, paper or the
   green of a country the trip actually enters. */
.routemap__casing {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: calc(var(--u) * 5.4px);
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .75;
}
.routemap__line {
  fill: none;
  stroke: var(--map-route);
  stroke-width: calc(var(--u) * 2.4px);
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* A pin is a control: it stands on its coordinate and, pressed, says which
   stop it is. Placement and optical size are one transform so the two never
   fight; the focus ring is drawn rather than outlined, because an outline on
   an SVG group is measured off a bounding box and lands nowhere near the
   mark. */
.routemap__pin {
  fill: var(--black);
  cursor: pointer;
  transform: translate(calc(var(--x) * 1px), calc(var(--y) * 1px)) scale(calc(var(--u) * 1.15));
  transition: fill .18s ease-out;
}
.routemap__core { fill: var(--white); }
.routemap__ring { fill: none; stroke: none; stroke-width: 2.4; }
.routemap__pin:hover,
.routemap__pin[aria-current] { fill: var(--map-route); }
/* The ring shows on plain :focus, not only :focus-visible — an SVG group is
   not a form control and browsers disagree about when it earns the visible
   variant, and a focus a keyboard user cannot see is the one failure this
   must not have. It doubles as the mark on the pin currently being read. */
.routemap__pin:focus { outline: none; }
.routemap__pin:focus .routemap__ring { stroke: var(--map-route); }
.routemap__pin:focus { fill: var(--map-route); }
.routemap__pins { filter: drop-shadow(0 calc(var(--u) * 1px) calc(var(--u) * 1.5px) rgb(18 18 18 / .3)); }

/* The name a pressed pin shows. It sits over the map rather than in it, so it
   is set in the site's own face at a size the map's scale cannot touch. It
   never takes the pointer: hovering the name must not count as leaving the
   pin. */
.routemap__tip {
  position: absolute;
  left: 0; top: 0;
  z-index: 2;
  pointer-events: none;
  max-width: min(16rem, 76%);
  transform: translate(calc(-50% + var(--slip, 0px)), calc(-100% - 38px));
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: 0 6px 18px rgb(18 18 18 / .16);
  padding: .34rem .6rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: .8125rem;
  line-height: 1.3;
  color: var(--black);
  text-align: center;
}
/* The stem. Two squares, one white over the border colour, so the join with
   the sheet stays a single hairline. */
.routemap__tip::after {
  content: "";
  position: absolute;
  left: calc(50% - var(--slip, 0px)); bottom: -4px;
  width: 7px; height: 7px;
  margin-inline-start: -3.5px;
  background: var(--white);
  border-inline-end: 1px solid var(--line);
  border-block-end: 1px solid var(--line);
  transform: rotate(45deg);
}
.routemap__tip.is-below { transform: translate(calc(-50% + var(--slip, 0px)), 10px); }
.routemap__tip.is-below::after {
  bottom: auto; top: -4px;
  border: 0;
  border-inline-start: 1px solid var(--line);
  border-block-start: 1px solid var(--line);
}

/* The tour page's one authored moment: the route draws itself as it comes
   into view and the pins land along it, once. Everything starts from the
   finished position, so a browser that never runs the script — or a visitor
   who asked for less motion — gets the whole map and no performance. */
@media (prefers-reduced-motion: no-preference) {
  .routemap__line, .routemap__casing {
    stroke-dasharray: var(--len);
    stroke-dashoffset: var(--len);
  }
  .routemap.is-drawn .routemap__line,
  .routemap.is-drawn .routemap__casing {
    transition: stroke-dashoffset 1.1s cubic-bezier(.2,.7,.3,1) .12s;
    stroke-dashoffset: 0;
  }
  .routemap__pin { opacity: 0; }
  .routemap.is-drawn .routemap__pin {
    opacity: 1;
    transition: opacity .38s ease-out;
    transition-delay: calc(220ms + var(--i) * 90ms);
  }
}

/* Stops. The route's own data, numbered — the closest honest equivalent of
   the reference's photo highlights until the operator's photography lands. */
.stops { display: grid; gap: var(--s2); }
.stops__item {
  display: flex; align-items: center; gap: var(--s4);
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--s4);
}
.stops__n {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: var(--r-pill);
  background: var(--hue-soft); color: var(--hue-ink);
  font-family: var(--display); font-weight: 700; font-size: .875rem;
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
}
.stops__name { font-family: var(--display); font-weight: 600; color: var(--black); }

.ticks { display: grid; gap: var(--s3); }
.ticks__item { display: flex; align-items: flex-start; gap: var(--s3); font-size: .9375rem; }
.ticks__item svg { flex-shrink: 0; color: var(--hue-ink); margin-block-start: .18em; }

/* Accordion — itinerary days and the additional-information rows. */
.acc { display: grid; border-block-start: 1px solid var(--line-soft); }
.acc__item { border-block-end: 1px solid var(--line-soft); }
.acc__head {
  appearance: none; background: none; border: 0; width: 100%; cursor: pointer;
  display: flex; align-items: center; gap: var(--s3); text-align: start;
  padding-block: var(--s4); font-family: var(--display); font-size: 1rem;
  font-weight: 600; color: var(--black);
}
.acc__head:hover { color: var(--hue-ink); }
.acc__n {
  flex-shrink: 0; width: 26px; height: 26px; border-radius: var(--r-pill);
  border: 1px solid var(--line); color: var(--muted); font-size: .8125rem;
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
}
.acc__title { flex: 1; min-width: 0; }
.acc__chev { color: var(--faint); flex-shrink: 0; transition: transform .2s var(--ease); }
.acc__head[aria-expanded="true"] .acc__chev { transform: rotate(180deg); }
.acc__body { padding-block-end: var(--s4); color: var(--muted); font-size: .9375rem; }
.acc__body[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Departure calendar. The whole of the tour page's Hərəkət tarixləri section,
   replacing a list that repeated one identical price and one identical button
   on every row. Deliberately flat: no card, no shadow, no ruled cells. The
   only ink it spends is on the days that are actually open, which is the
   entire message.
   -------------------------------------------------------------------------- */

.cal { display: grid; gap: var(--s3); }
.cal__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
.cal__month { font-family: var(--display); font-size: 1rem; font-weight: 700; color: var(--black); }
.cal__nav {
  inline-size: 38px; block-size: 38px; flex-shrink: 0; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--white); color: var(--black); cursor: pointer;
  transition: border-color .16s var(--ease), color .16s var(--ease);
}
.cal__nav:hover:not(:disabled) { border-color: var(--line-hover); }
.cal__nav:disabled { color: var(--line-hover); border-color: var(--line-soft); cursor: default; }

.cal__week, .cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal__week span {
  font-family: var(--display); font-size: .6875rem; font-weight: 700; letter-spacing: .02em;
  text-align: center; color: var(--faint);
}
/* Every cell holds its place in the week whether or not it carries a day, so
   the columns stay under their own weekday from the first row to the last. */
.cal__day, .cal__pad { aspect-ratio: 1; min-block-size: 38px; }
.cal__day {
  display: grid; place-items: center; border: 0; background: none; padding: 0;
  border-radius: var(--r-pill); font-family: var(--display); font-size: .875rem;
  font-variant-numeric: tabular-nums; color: var(--faint);
}
/* An open day is the only thing in the grid that can be pressed, so it is the
   only thing drawn as though it could be — and it is a real button, while a
   day the operator never offered is plain text. */
.cal__day.is-open {
  background: var(--hue-soft); color: var(--hue-ink); font-weight: 700; cursor: pointer;
  transition: background-color .16s var(--ease), color .16s var(--ease);
}
.cal__day.is-open:hover { background: var(--hue-ink); color: var(--white); }
.cal__day.is-on, .cal__day.is-on:hover { background: var(--black); color: var(--white); }

/* The choice, stated in words. It shares the quote total's rule and rhythm,
   because it is the same kind of line: what the controls above it add up to. */
.cal__pick {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  margin: 0; padding-block-start: var(--s3); border-block-start: 1px solid var(--line-soft);
}
.cal__picked { font-family: var(--display); font-size: .9375rem; font-weight: 700; color: var(--black); }
.cal__picked.is-any { font-family: var(--text); font-weight: 400; color: var(--muted); }
.cal__clear {
  flex-shrink: 0; border: 0; background: none; padding: 0; cursor: pointer; font: inherit;
  font-size: .8125rem; color: var(--hue-ink); text-decoration: underline; text-underline-offset: 3px;
}
.cal__clear:hover { color: var(--hue-ink-dark); }

/* It has a whole column to itself, so it stops growing before the days turn
   into paving slabs. */
.cal--wide { max-inline-size: 27rem; }

/* The slim ruled line, at the system's own weight: Shapes allows one hairline
   and no coloured side-border heavier than 1px, so the signal is carried by
   the gold itself rather than by a thick tab. Full-strength --gold because a
   45%-alpha rule disappears entirely once it is 1px wide. */
/* What the route is still missing, said once at the end of its sections.
   It is a peer of the sections above it, not a note inside one, so it takes
   their heading step and their full width — a whisper repeated five times was
   what it replaced, and a whisper once would be missed. */
.pendingbox {
  border: 1px solid rgb(138 109 0 / .35); background: rgb(138 109 0 / .06);
  border-radius: var(--r); padding: var(--s5); display: grid; gap: var(--s3);
  justify-items: start;
}
.pendingbox h2 { font-size: 1.125rem; color: var(--gold); }
.pendingbox p { color: var(--muted); font-size: .9375rem; max-width: 62ch; }
/* On a reading page the panel is not an aside — it carries the clause itself.
   On the refund page that clause is the cancellation scale, and shipping the
   one paragraph about a visitor's money a step quieter than the prose around
   it undoes the honesty it is written with. Same panel, prose weight. */
.legal__prose .pendingbox p { color: var(--ink); font-size: 1rem; }
/* Two ways to reach the same team, side by side rather than stacked: neither
   is a fallback for the other. */
.pendingbox__acts { display: flex; flex-wrap: wrap; gap: var(--s3); }

/* Booking card */
.bookcard {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow); padding: var(--s5); display: grid; gap: var(--s4);
  scroll-margin-block-start: 90px;
}
.bookcard__title { font-size: clamp(1.375rem, 5vw, 1.75rem); line-height: 1.15; }
.bookcard__body { font-size: .875rem; color: var(--muted); }
/* Sits under the action rather than above it: it answers what the button
   does, and an answer belongs after the question. */
.bookcard__note { font-size: .8125rem; color: var(--muted); line-height: 1.5; margin: 0; }

/* Travellers. Three ruled rows in one bordered block, matching the price-by-
   age table above them so the count and the rule read as the same object. */
.party { display: grid; gap: var(--s3); }
.party__title {
  font-family: var(--display); font-size: .75rem; font-weight: 700;
  letter-spacing: .02em; color: var(--black);
}
.party__rows { display: grid; border: 1px solid var(--line); border-radius: var(--r); }
.party__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); padding: var(--s2) var(--s3) var(--s2) var(--s4);
}
.party__row + .party__row { border-block-start: 1px solid var(--line-soft); }
.party__who { display: grid; gap: 1px; min-width: 0; }
.party__name {
  font-family: var(--display); font-size: .9375rem; font-weight: 700; color: var(--black);
}
.party__band { font-size: .8125rem; color: var(--muted); }
.party__rule { font-family: var(--display); font-weight: 700; color: var(--black); }

/* Full 44px targets, unlike the header's tightened controls: this is the one
   place on the page a visitor presses repeatedly, and it is pressed with a
   thumb while the other hand holds nothing. */
.stepper { display: flex; align-items: center; gap: var(--s1); flex-shrink: 0; }
.stepper__btn {
  inline-size: 44px; block-size: 44px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--white); color: var(--black); cursor: pointer;
  transition: border-color .16s var(--ease), color .16s var(--ease);
}
.stepper__btn:hover:not(:disabled) { border-color: var(--line-hover); }
.stepper__btn:disabled { color: var(--line-hover); border-color: var(--line-soft); cursor: default; }
.stepper__n {
  min-inline-size: 1.5rem; text-align: center; font-family: var(--display);
  font-size: 1rem; font-weight: 700; color: var(--black); font-variant-numeric: tabular-nums;
}

/* The rule, applied. Each counted band gets a line and the discount shows as
   a number, because a stated percentage and a charged one are different
   promises. The sum carries the same dashed gold underline the price above it
   does, for the same reason: it is built from a provisional figure. */
.quote { display: grid; gap: var(--s3); }
.quote__lines { display: grid; gap: var(--s1); }
.quote__line {
  display: flex; justify-content: space-between; gap: var(--s3);
  font-size: .8125rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.quote__total {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  margin: 0; padding-block-start: var(--s3); border-block-start: 1px solid var(--line-soft);
  font-size: .875rem; color: var(--muted);
}
/* The label is set at the figure's own weight and size: this is the line the
   whole card adds up to, and a muted caption beside a black total read as an
   aside rather than as the answer. */
.quote__label {
  font-family: var(--display); font-size: 1.25rem; font-weight: 700; color: var(--black);
}
.quote__sum {
  font-family: var(--display); font-size: 1.25rem; font-weight: 700;
  color: var(--price); font-variant-numeric: tabular-nums;
}
.quote__sum.is-provisional { border-block-end: 2px dashed var(--gold); }
.quote__note { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--muted); }
.quote__note.is-pending { color: var(--gold); font-style: italic; }

.bookcard .btn { width: 100%; }
.bookcard .btn--primary { font-size: 1.0625rem; min-height: 54px; }
.bookcard__call {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: var(--display); font-weight: 700; color: var(--black); text-decoration: none;
  font-size: .9375rem;
}
.bookcard__call:hover { color: var(--hue-ink); }

/* Sticky price bar. Bottom-anchored on the phone, where the aside is far
   above the fold; it retires at the desktop breakpoint where the booking
   card is always in view. */
.pricebar {
  position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 60;
  background: var(--white); border-block-start: 1px solid var(--line);
  box-shadow: 0 -6px 20px -10px rgb(18 18 18 / .3);
  padding-block: var(--s3);
  padding-block-end: calc(var(--s3) + env(safe-area-inset-bottom, 0px));
}
.pricebar[hidden] { display: none; }
/* Stood down while the booking card is on screen — the bar and the card carry
   the same action in the same words, and only one of them should be asking.
   It leaves downward rather than fading, so the card is what remains. */
.pricebar { transition: transform .3s var(--ease), opacity .3s var(--ease); }
.pricebar.is-stood-down {
  transform: translateY(100%); opacity: 0; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .pricebar { transition: none; } }
.pricebar__row { display: flex; align-items: center; gap: var(--s3); }
/* The thumb's copy of the card's action, and it carries the same weight of
   voice: the bar is what most of this page's visitors will actually press. */
.pricebar .btn--sm { font-size: 1rem; min-height: 46px; padding-inline: 1.15rem; }
.pricebar__price { display: grid; flex: 1; min-width: 0; line-height: 1.15; }
.pricebar__from { font-size: .6875rem; color: var(--muted); }
.pricebar__price strong { font-family: var(--display); font-size: 1.25rem; color: var(--price); font-variant-numeric: tabular-nums; }
.pricebar__call {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: var(--r-pill);
  border: 1px solid var(--line); color: var(--black);
  display: grid; place-items: center; text-decoration: none;
}
.pricebar__call:hover { border-color: var(--hue-ink); color: var(--hue-ink); }

/* The bar floats over the page end; the footer needs room to clear it. */
body:has(.pricebar:not([hidden])) .foot { padding-block-end: calc(var(--s6) + 76px); }

/* --------------------------------------------------------------------------
   Why us
   -------------------------------------------------------------------------- */

.why__grid { display: grid; gap: var(--s8); }
.why__media { border-radius: var(--r-lg); overflow: hidden; position: relative; aspect-ratio: 4 / 3; box-shadow: var(--shadow); }
.why__media img { width: 100%; height: 100%; object-fit: cover; }
.why__points { display: grid; gap: var(--s5); }
.why__point { display: flex; gap: var(--s4); align-items: flex-start; }
/* Blue, not green: OWN-WORLD names one deep blue plus coral, and a fifth hue
   here was cited by nothing. Matches the trust-bar icon treatment. */
.why__ico { flex-shrink: 0; width: 44px; height: 44px; border-radius: var(--r); background: var(--hue-soft); color: var(--hue-ink); display: grid; place-items: center; }
.why__point h3 { font-size: 1.0625rem; margin-block-end: var(--s1); }
.why__point p { color: var(--muted); font-size: .9375rem; }

/* --------------------------------------------------------------------------
   CTA band
   -------------------------------------------------------------------------- */

.cta { background: var(--black); color: var(--white); }
.cta__inner { padding-block: var(--s12); display: grid; gap: var(--s5); max-width: 40rem; }
.cta h2 { color: var(--white); font-size: clamp(1.6rem, 5.5vw, 2.25rem); }
.cta p { color: var(--on-dark-soft); }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--s3); }

/* A black button on the black band would disappear, so the primary action
   inverts to the one hue carrying black text (5.5:1). Together with the card
   badge this is the only other place the hue appears as a fill. */
.cta .btn--primary { background: var(--hue); color: var(--black); box-shadow: none; }
.cta .btn--primary:hover { background: var(--hue-lift); box-shadow: none; }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.foot { background: var(--footer-ground); color: var(--on-dark-foot); font-size: .875rem; padding-block: var(--s12) var(--s6); }
.foot__grid { display: grid; gap: var(--s8); }
/* The footer keeps the badge and the name set beside it — the header took the
   wordmark, this column did not. Mark and word share one row; the blurb wraps
   to the full width beneath them. */
.foot__brand { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--s3); }
.foot__mark { display: block; width: 64px; height: 64px; flex: none; }
.foot__mark img { width: 100%; height: 100%; object-fit: contain; }
.foot__word { font-family: var(--display); font-size: clamp(1.75rem, 6vw, 2.25rem); font-weight: 700; color: var(--white); letter-spacing: -0.02em; }
/* h2, not h4. The footer's columns are top-level sections of the footer
   landmark, and as h4s they skipped a level under the CTA band's h2. The size
   is unchanged — outline depth and type size are separate decisions. */
.foot__grid h2 { color: var(--white); font-size: .9375rem; margin-block-end: var(--s3); }
.foot a { color: var(--on-dark-foot); text-decoration: none; }
.foot a:hover { color: var(--white); text-decoration: underline; }
.foot__links { display: grid; gap: var(--s2); }
/* The list's last row is the way to the full grid, not another route: a hair
   of space above it, brighter than the names, and a chevron that sits with
   the text baseline. */
.foot__all { margin-block-start: var(--s2); }
.foot__all a { display: inline-flex; align-items: center; gap: var(--s1); color: var(--white); font-weight: 600; }
.foot__all svg { flex: none; }
.foot__brand .foot__word { color: var(--white); }
.foot__brand p { flex-basis: 100%; margin-block-start: var(--s4); max-width: 30rem; font-size: 1.0625rem; line-height: 1.65; }

/* The register — the company's public record, and the page's last word.
   Structured after the reference's own closing band: a descriptive line in the
   quiet tint with the credential itself under it, set in the display face and
   full white, with air around each one. The centring is load-bearing rather
   than decorative — the link columns above are a left-aligned grid, so the
   change of axis is what tells a reader the register is a different kind of
   statement from the navigation. The reference anchors its band with a trade
   association's mark; Lalasoy holds no membership, so the entity's own legal
   name takes that position and nothing is implied that does not exist. */
.reg {
  border-block-start: 1px solid rgb(255 255 255 / .1);
  margin-block-start: var(--s8); padding-block-start: var(--s10);
  text-align: center;
}
.reg__entity {
  font-family: var(--display); font-weight: 700; font-size: 1.0625rem;
  letter-spacing: -.01em; text-wrap: balance;
  color: var(--white); max-width: 30rem; margin-inline: auto;
}
/* Capped and centred rather than spread across the full shell: three
   credentials sitting a third of a page apart read as scattered facts, and the
   band only reads as one seal when they are held close enough to be taken in
   together. */
.reg__list { display: grid; gap: var(--s6); margin-block-start: var(--s8); max-width: 58rem; margin-inline: auto; }
.reg__item { display: grid; gap: var(--s1); justify-items: center; }
.reg__item dt { font-size: .8125rem; color: var(--on-dark-mute); }
.reg__item dd {
  font-family: var(--display); font-weight: 700; font-size: .9375rem;
  color: var(--white); font-variant-numeric: tabular-nums;
  text-wrap: balance; max-width: 20rem;
}
.reg__note {
  margin-block-start: var(--s8); max-width: 40rem; margin-inline: auto;
  font-size: .8125rem; line-height: 1.6; color: var(--on-dark-mute);
  text-wrap: pretty;
}

.foot__bar { border-block-start: 1px solid rgb(255 255 255 / .1); margin-block-start: var(--s8); padding-block-start: var(--s5); display: flex; flex-wrap: wrap; gap: var(--s3); justify-content: space-between; font-size: .8125rem; }

/* --------------------------------------------------------------------------
   Motion — one authored moment: cards rise as the field is filtered.
   Content is visible by default.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .card.is-entering { animation: card-in .42s var(--ease) both; animation-delay: calc(var(--i, 0) * 45ms); }
  @keyframes card-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
}

.card[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Wider
   -------------------------------------------------------------------------- */

@media (min-width: 34rem) {
  .shell { padding-inline: var(--s6); }
  /* Back to a grid: no rail, no bleed, no snap, no bar. */
  .cards {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s5);
    overflow: visible; scroll-snap-type: none;
    margin-inline: 0; padding-inline: 0; padding-block-end: 0;
  }
  .card { flex: none; }
  .cards .card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
  .railbar { display: none; }
  .deck { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .foot__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 48rem) {
  /* The pill opens out to the reference's two live segments, and the note that
     explains the dead month control comes with them. A party-size select stood
     third until it was removed: nothing read it, and a control that filters
     nothing is a promise the grid cannot keep. */
  .hfield--wide, .hsearch__div { display: flex; }
  .hsearch__note { display: flex; }
  .hsearch { gap: var(--s5); padding-inline-start: var(--s6); }
  /* 4-up only once Russian's longer strings still fit; 2-up before that. */
  .trust__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* The register's three credentials go side by side once there is width for
     the Russian address to sit on two lines rather than four. */
  .reg__list { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s6) var(--s8); align-items: start; }
  /* Subgrid because Russian's "Идентификационный номер налогоплательщика"
     takes two lines where Azerbaijani takes one: without a shared row the
     longest label pushes its own credential below the other two and the band
     stops reading as one line of record. The rule degrades to the
     top-aligned columns above wherever subgrid is missing. */
  @supports (grid-template-rows: subgrid) {
    .reg__list { grid-template-rows: auto auto; }
    .reg__item { grid-row: span 2; grid-template-rows: subgrid; }
  }
}

/* 68rem, not 62rem: at 992-1088 the Russian nav plus "Забронировать" left
   .mainnav as the only shrinkable item, and it cannot shrink below content. */
@media (min-width: 68rem) {
  .mainnav { display: flex; }
  /* The switch changes hands here. The nav is on screen from this width, so
     the burger would only duplicate it — and its one unique payload, the
     language list, moves to a control that shows the flag in force instead of
     hiding it three levels down. Exactly two controls are ever on screen, and
     exactly one language switch: the two swap at the same breakpoint. */
  .langbtn { display: grid; }
  .burger { display: none; }
  .brand__slot { height: 42px; }
  .brand__slot img { max-width: 15rem; }
  /* The booking card is on screen from the top here, so the bar is noise. */
  .pricebar { display: none; }
  body:has(.pricebar:not([hidden])) .foot { padding-block-end: var(--s6); }
  .deck { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 62rem) {
  .section { padding-block: var(--s20); }

  .hero { min-height: min(40rem, 88svh); }
  .hero__inner { padding-block: var(--s12) var(--s12); }
  .hero__sub { font-size: 1.125rem; }
  .hero__base { margin-block-start: var(--s6); flex-wrap: nowrap; }

  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .why__grid { grid-template-columns: 1fr 1fr; align-items: center; gap: var(--s16); }

  .hero-gal__slide { aspect-ratio: 21 / 9; }
  .tour__layout { grid-template-columns: minmax(0, 1.7fr) minmax(300px, 1fr); align-items: start; }
  .tour__aside { position: sticky; inset-block-start: 92px; }
  .stops { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot__grid { grid-template-columns: 1.6fr 1fr 1.4fr; }
}

/* ==========================================================================
   Legal pages
   A reading surface, not a selling one: one measured column, a contents rail
   that says where you are, and nothing on the page competing with the text.
   The register, the storage table and the gold panel are the same three
   devices the rest of the site already uses to state facts, reused here so a
   policy page reads as part of the site rather than as pasted boilerplate.
   ========================================================================== */

.legal { padding-block: var(--s10) var(--s16); }

.legal__head {
  display: grid; gap: var(--s4); max-width: 46rem;
  padding-block-end: var(--s8); border-block-end: 1px solid var(--line);
}
.legal__head h1 { font-size: clamp(1.75rem, 7vw, 2.75rem); letter-spacing: -0.025em; }
.legal__lede { color: var(--muted); font-size: 1.0625rem; max-width: 58ch; }
/* Metadata, so it sits under the sentence it dates rather than over the
   title. Tabular figures because the date is a number the eye scans. */
.legal__updated {
  display: flex; flex-wrap: wrap; gap: .5em; margin: 0;
  font-family: var(--display); font-weight: 600; font-size: .8125rem;
  letter-spacing: .05em; text-transform: uppercase; color: var(--faint);
}
.legal__updated time { color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: .02em; }

.legal__body { display: grid; gap: var(--s10); padding-block-start: var(--s8); }

/* Contents. On a phone it is a card of twelve short entries in two columns —
   it costs one screen and saves twelve. On a desktop it loses the card and
   becomes a rail that tracks the reading position. */
.legal__toc {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--bg-soft); padding: var(--s5);
}
.legal__toc-title {
  font-size: .75rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); margin: 0 0 var(--s3);
}
/* Two columns by flow, not by grid: a grid row is as tall as its tallest
   entry, which left ragged holes between one-line and three-line clauses.
   Columns pack them, and the reading order stays 1-6 then 7-12. */
.legal__toc-list {
  list-style: none; margin: 0; padding: 0; counter-reset: toc;
  columns: 2; column-gap: var(--s5);
}
.legal__toc-list li { break-inside: avoid; }
.legal__toc-list a {
  display: block; padding-block: var(--s2); padding-inline-start: var(--s3);
  margin-inline-start: -2px; border-inline-start: 2px solid transparent;
  color: var(--muted); font-size: .875rem; line-height: 1.35; text-decoration: none;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.legal__toc-list a::before {
  counter-increment: toc; content: counter(toc) ". ";
  color: var(--faint); font-variant-numeric: tabular-nums;
}
.legal__toc-list a:hover { color: var(--black); }
.legal__toc-list a.is-current { color: var(--black); font-weight: 600; border-inline-start-color: var(--black); }
.legal__toc-list a.is-current::before { color: var(--black); }
@media (prefers-reduced-motion: reduce) { .legal__toc-list a { transition: none; } }

.legal__prose { display: grid; gap: var(--s12); max-width: 68ch; }

.legal__sec {
  display: grid; gap: var(--s4); justify-items: start;
  scroll-margin-block-start: calc(var(--head-h) + var(--s6));
}
.legal__sec > h2 {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .55em;
  align-items: baseline; font-size: clamp(1.1875rem, 4vw, 1.4375rem);
}
/* The clause number is here so a reader can quote one back to us; it is set
   quieter than the heading it belongs to, not as a graphic. */
.legal__num { color: var(--faint); font-size: .78em; font-weight: 600; font-variant-numeric: tabular-nums; }
.legal__sec h3 { font-size: 1rem; margin-block-start: var(--s2); }
.legal__sec p { margin: 0; }
.legal__sec ul { margin: 0; padding-inline-start: 1.2em; display: grid; gap: var(--s2); }
.legal__sec li::marker { color: var(--line-hover); }

/* The register of company facts — the footer's device, in daylight. */
.legal__dl { margin: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; width: 100%; }
.legal__dl > div { display: grid; gap: var(--s1); padding: var(--s4) var(--s5); }
.legal__dl > div + div { border-block-start: 1px solid var(--line-soft); }
.legal__dl dt { font-size: .8125rem; color: var(--faint); }
.legal__dl dd { margin: 0; font-family: var(--display); font-weight: 700; color: var(--black); }

.legal__tablewrap { width: 100%; overflow-x: auto; }
.legal__table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.legal__table th, .legal__table td {
  text-align: start; vertical-align: top; padding: var(--s3) var(--s4);
  border-block-end: 1px solid var(--line-soft);
}
.legal__table thead th {
  font-family: var(--display); font-weight: 700; font-size: .75rem;
  letter-spacing: .05em; text-transform: uppercase; color: var(--faint);
  border-block-end: 1px solid var(--line); white-space: nowrap;
}
.legal__table td:first-child { padding-inline-start: 0; }
.legal__table th:first-child { padding-inline-start: 0; }
/* A real stored key, so it is set as one — this is the site's only monospace. */
.legal__key {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: .875em; color: var(--black); background: var(--bg-soft);
  padding: .15em .4em; border-radius: var(--r-xs);
}

.legal__contact {
  display: grid; gap: var(--s4); width: 100%;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--bg-soft); padding: var(--s6);
}
.legal__contact-entity { font-family: var(--display); font-weight: 700; color: var(--black); margin: 0; }
.legal__chans { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.legal__chan { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s3); align-items: center; }
.legal__chan-ico { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--r-pill); background: var(--white); border: 1px solid var(--line); color: var(--ink); }
.legal__chan-lbl { display: block; font-size: .75rem; letter-spacing: .05em; text-transform: uppercase; color: var(--faint); }
.legal__chan a, .legal__chan span:not(.legal__chan-lbl) { font-family: var(--display); font-weight: 600; color: var(--black); text-decoration: none; }
.legal__chan a:hover { color: var(--hue-ink-dark); text-decoration: underline; }

/* The footer's legal row: a second line under the copyright, not a fourth
   column — one link should not read as a section of the site. */
.foot__legal { display: flex; flex-wrap: wrap; gap: var(--s4); }
.foot__legal a { color: var(--on-dark-foot); text-decoration: none; }
.foot__legal a:hover { color: var(--white); text-decoration: underline; }

@media (max-width: 39.99rem) {
  /* One row of four facts does not survive a 375px column, so the table
     becomes the same four labelled lines it would have been in prose. */
  .legal__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .legal__table tr { display: grid; gap: var(--s2); padding-block: var(--s4); border-block-end: 1px solid var(--line); }
  .legal__table td { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); gap: var(--s3); padding: 0; border: 0; }
  .legal__table td::before {
    content: attr(data-label); font-family: var(--display); font-weight: 700;
    font-size: .75rem; letter-spacing: .05em; text-transform: uppercase;
    color: var(--faint); padding-block-start: .15em;
  }
}

@media (min-width: 40rem) {
  .legal__dl > div { grid-template-columns: 17rem minmax(0, 1fr); align-items: baseline; gap: var(--s4); }
}

@media (min-width: 64rem) {
  .legal { padding-block: var(--s12) var(--s20); }
  .legal__body { grid-template-columns: 15rem minmax(0, 1fr); gap: var(--s16); align-items: start; }
  .legal__toc { position: sticky; inset-block-start: calc(var(--head-h) + var(--s5)); background: none; border: 0; padding: 0; }
  .legal__toc-list { columns: 1; }
}

/* ==========================================================================
   CHECKOUT AND THE PAYMENT RESULT

   The two surfaces where money moves. They are Operate surfaces in a site
   that is otherwise Persuade: nothing here is trying to sell the trip any
   more — that argument was won on the tour page — so the job is to make what
   is about to be charged unmissable and everything else quiet.

   No new visual world. The order summary is the booking card's own object,
   the fields are the booking card's own fields, and the quote block is
   literally the same class, because the figure a visitor agreed to on the
   tour page must look identical to the figure they are charged.
   ========================================================================== */

.co { padding-block: var(--s8) var(--s16); }

/* The way out, above the title rather than beside it: a visitor who arrived
   here by mistake should find the exit before they find the form. */
.co__back {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-block-size: 44px; font-family: var(--display); font-weight: 600;
  font-size: .9375rem; color: var(--muted); text-decoration: none;
}
.co__back:hover { color: var(--black); }
.co__back svg { flex: none; }

.co__head { display: grid; gap: var(--s3); max-width: 46rem; margin-block-end: var(--s8); }
.co__head h1 { font-size: clamp(1.75rem, 7vw, 2.75rem); letter-spacing: -0.025em; }
.co__lede { color: var(--muted); font-size: 1.0625rem; max-width: 52ch; }

/* On the phone the summary comes first and the fields follow it, which is the
   order of the decision: what am I buying, then who is buying it. The DOM is
   written in that order, and only the desktop reorders — so a page read
   linearly, by a screen reader or with styles off, still reads correctly. */
.co__layout { display: grid; gap: var(--s8); align-items: start; }
/* `display: grid` wins over the hidden attribute, so every block this page
   shows or hides needs the guard spelled out — the same trap the booking
   card's date field already carries. */
.co__layout[hidden], .co__head[hidden], .co__gone[hidden] { display: none; }
.co__form { display: grid; gap: var(--s5); min-width: 0; }

.co__sec { font-family: var(--display); font-size: 1.125rem; font-weight: 700; color: var(--black); }
.co__secbody { margin: calc(var(--s5) * -1) 0 0; font-size: .875rem; color: var(--muted); }

/* --------------------------------------------------------------- summary */

/* The one card on the page. The fields around it sit on the page's own ground
   rather than in a second card: two bordered boxes side by side would make the
   order and the form look like alternatives to each other. */
.co__sum {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow); padding: var(--s5); display: grid; gap: var(--s4);
}
.cosum__title {
  font-family: var(--display); font-size: .75rem; font-weight: 700;
  letter-spacing: .02em; color: var(--black);
}
.cosum__route { display: flex; gap: var(--s3); align-items: center; }
.cosum__thumb {
  inline-size: 96px; block-size: 72px; object-fit: cover; flex: none;
  border-radius: var(--r); background: var(--bg-tint);
}
.cosum__id { display: grid; gap: 2px; min-width: 0; }
.cosum__name {
  font-family: var(--display); font-size: 1.0625rem; font-weight: 700;
  line-height: 1.25; color: var(--black); text-wrap: balance;
}
.cosum__meta { font-size: .8125rem; color: var(--muted); }

.cosum__facts { display: grid; gap: var(--s2); }
.cosum__facts > div {
  display: flex; justify-content: space-between; gap: var(--s3);
  padding-block: var(--s2); border-block-start: 1px solid var(--line-soft);
}
.cosum__facts dt { font-size: .8125rem; color: var(--muted); }
.cosum__facts dd {
  margin: 0; font-family: var(--display); font-size: .875rem; font-weight: 700;
  color: var(--black); text-align: end;
}

/* Text, not a button: it goes back to a page the visitor has already seen,
   and a filled control here would compete with the one that pays. */
.cosum__change {
  justify-self: start; min-block-size: 44px; display: inline-flex; align-items: center;
  font-family: var(--display); font-weight: 600; font-size: .875rem;
  color: var(--hue-ink); text-decoration: underline; text-underline-offset: 3px;
}
.cosum__change:hover { color: var(--hue-ink-dark); }

/* ------------------------------------------------------------ the action */

/* The label on the left and the figure on the right, inside one full-width
   control: on a phone the summary is a scroll away by the time the thumb
   reaches this, and the amount has to be on the thing that commits to it. */
.co__pay {
  inline-size: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); min-block-size: 56px; font-size: 1.0625rem;
}
.co__paysum { font-variant-numeric: tabular-nums; font-weight: 700; }
.co__pay.is-working { cursor: progress; }
.co__pay.is-working .co__paysum { font-size: .9375rem; font-weight: 600; }

.co__secure {
  display: flex; align-items: flex-start; gap: var(--s2);
  margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--muted);
}
.co__secure svg { flex: none; margin-block-start: 2px; color: var(--hue-ink); }

.co__rules { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--muted); }
.co__rules a { color: var(--hue-ink); text-decoration: underline; text-underline-offset: 3px; }
.co__rules a:hover { color: var(--hue-ink-dark); }

/* A whole attempt that failed. Tinted ground and alert text, no coloured bar
   down the side: the colour is already carrying the message and a 4px rule
   would only be saying it twice. */
.co__alert {
  margin: 0; padding: var(--s3) var(--s4); border-radius: var(--r);
  background: var(--alert-soft); color: var(--alert);
  font-size: .9375rem; line-height: 1.5;
}

/* One field's own problem, said under that field. */
.field__err { font-size: .8125rem; line-height: 1.4; color: var(--alert); }
.field__err[hidden] { display: none; }
.control.is-bad { border-color: var(--alert); }
.control.is-bad:focus-visible { border-color: var(--alert); box-shadow: 0 0 0 3px var(--alert-soft); }

/* Arrived with nothing to buy. Not a form with its fields removed — a short
   statement and the one way forward. */
.co__gone { display: grid; gap: var(--s4); justify-items: start; max-width: 40rem; padding-block: var(--s10); }
.co__gone h2 { font-size: clamp(1.375rem, 5vw, 1.75rem); }
.co__gone p { color: var(--muted); font-size: 1.0625rem; }
.co__goneacts { margin: 0; }

/* ==========================================================================
   The result. One card, one verdict, and the loudest use of --alert on the
   site. Where else it may appear is the Alert Rule's business, not this
   block's: the checkout's field errors and its whole-attempt failure carry it
   too, and nothing outside the checkout ever does.
   ========================================================================== */

.pr { padding-block: var(--s12) var(--s16); }
.pr__card {
  max-width: 34rem; margin-inline: auto;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow); padding: var(--s8) var(--s6);
  display: grid; gap: var(--s4); justify-items: center; text-align: center;
}

/* The mark answers before the sentence does, so it is the one element on the
   page allowed to be large and coloured. Three grounds, three meanings, and
   each is a colour the system already uses for exactly that meaning: the hue
   for something that is now true, gold for something not settled yet, alert
   for money that did not move. */
.pr__mark {
  inline-size: 60px; block-size: 60px; border-radius: var(--r-pill);
  display: grid; place-items: center; flex: none;
}
.pr__mark--ok   { background: var(--hue-soft);  color: var(--hue-ink); }
.pr__mark--bad  { background: var(--alert-soft); color: var(--alert); }
/* An abandoned payment is not an unsettled value — it is money that did not
   move, which is alert's job and not gold's. Painting it gold would have given
   gold a second meaning, and a signal with two meanings has none. Only the
   waiting state is gold, and it is gold correctly: nothing is settled yet. */
.pr__mark--stop { background: var(--alert-soft); color: var(--alert); }
.pr__mark--wait { background: var(--gold-soft);  color: var(--gold); }

/* The heading carries the verdict too, not just the disc. Success and failure
   were otherwise one screen — the same card, the same black title, two pale
   discs a few points apart in lightness — with the whole outcome resting on
   the two letters between "alındı" and "alınmadı". A visitor who misreads that
   arrives at a bus with no seat. `--alert` measures 7.2:1 on white and this is
   large text twice over, so the loudest available signal is also the legal one. */
.pr__card.is-bad .pr__title,
.pr__card.is-stop .pr__title { color: var(--alert); }

/* The page's one authored moment: the verdict lands rather than appearing.
   It runs once, on the state that resolves, and never on the waiting state —
   a spinner that keeps re-entering says the page is anxious. */
@keyframes pr-land {
  from { transform: scale(.82); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}
.pr__card.is-ok .pr__mark,
.pr__card.is-bad .pr__mark,
.pr__card.is-stop .pr__mark { animation: pr-land .42s var(--ease) both; }

/* Waiting is a real state and it moves, slowly, so the page reads as working
   rather than stuck. */
@keyframes pr-breathe { 50% { opacity: .5; } }
.pr__card.is-wait .pr__mark { animation: pr-breathe 1.8s ease-in-out infinite; }

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

/* The documented `page-title` step, not a new one a shade under it: this is
   the h1 of a page that holds one sentence, which is exactly the job that step
   already has. An off-ramp size here would have been drift, not a decision. */
.pr__title { font-size: clamp(1.75rem, 7vw, 2.75rem); letter-spacing: -0.025em; text-wrap: balance; }
.pr__body { color: var(--ink); font-size: 1.0625rem; line-height: 1.6; max-width: 40ch; }

/* The receipt. Left-aligned inside a centred card, because a column of
   label-and-value is read down its own edge and centring it would leave every
   line starting somewhere different. */
.pr__facts {
  inline-size: 100%; text-align: start; display: grid;
  border-block-start: 1px solid var(--line-soft); margin-block-start: var(--s2);
}
.pr__facts > div {
  display: flex; justify-content: space-between; gap: var(--s4);
  padding-block: var(--s3); border-block-end: 1px solid var(--line-soft);
}
.pr__facts dt { font-size: .8125rem; color: var(--muted); flex: none; }
.pr__facts dd {
  margin: 0; font-family: var(--display); font-size: .875rem; font-weight: 700;
  color: var(--black); text-align: end; font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.pr__keep { margin: 0; font-size: .8125rem; color: var(--muted); line-height: 1.5; max-width: 42ch; }

.pr__acts { display: flex; flex-wrap: wrap; gap: var(--s3); justify-content: center; margin: var(--s2) 0 0; }
.pr__card.is-lost { gap: var(--s5); }

/* ==========================================================================
   The booking card's second action, and the one thing that can stop its first.
   ========================================================================== */

/* The enquiry, stepped down rather than removed. Text under the filled button,
   because a second filled control beside the first would ask the visitor to
   choose between two things that look equally like the way forward. */
.bookcard__alt {
  justify-self: center; text-align: center; min-block-size: 44px;
  display: inline-flex; align-items: center;
  font-family: var(--display); font-weight: 600; font-size: .875rem;
  color: var(--hue-ink); text-decoration: underline; text-underline-offset: 3px;
}
.bookcard__alt:hover { color: var(--hue-ink-dark); }
.bookcard__alt[hidden] { display: none; }

/* Said above the button it blocks, so the eye meets it on the way back up
   from the press that did nothing. */
.bookcard__hint { margin: 0; font-size: .875rem; line-height: 1.5; color: var(--alert); }
.bookcard__hint[hidden] { display: none; }

@media (min-width: 62rem) {
  /* The fields lead and the summary keeps pace beside them: explicit
     placement rather than source order, since the phone wants the opposite. */
  .co__layout { grid-template-columns: minmax(0, 1.5fr) minmax(320px, 1fr); gap: var(--s10); }
  /* A name is not 880 pixels long. Left uncapped these ran the full column and
     promised an answer nobody has; the note field keeps the width because a
     note genuinely uses it. */
  .co__form .field { max-width: 30rem; }
  .co__form .field--wide { max-width: none; }
  .co__form  { grid-column: 1; grid-row: 1; }
  .co__aside { grid-column: 2; grid-row: 1; position: sticky; inset-block-start: 92px; }
  .pr { padding-block: var(--s16) var(--s20); }
}
