@charset "UTF-8";
/* ==========================================================================
   VOYRA SOLUTIONS — DESIGN SYSTEM
   --------------------------------------------------------------------------
   Two rules govern this file:

   1. DIRECTION IS NEVER HARD-CODED. There is no `left` or `right` anywhere in
      the layout. Everything uses CSS logical properties (inline-start/end,
      block-start/end), so Arabic mirrors by construction from a single `dir`
      attribute rather than from a pile of [dir="rtl"] overrides that rot the
      first time someone adds a component.

   2. COLOUR COMES FROM THE IDENTITY GUIDE. The four official colours are fixed.
      Additional steps exist only where a UI state needs them, and each is
      derived from an official colour — never introduced. The one place this
      matters most: turquoise #2CBFD5 scores about 2:1 on white, so it can never
      carry text on a light surface. --turq-ink is the darkened derivation used
      for links and small text; the pure identity turquoise is reserved for dark
      surfaces and non-text accents, where it is the hero it is meant to be.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
body { min-block-size: 100vh; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
img, picture, svg, video { display: block; max-inline-size: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
h1, h2, h3, h4, p, figure, blockquote { overflow-wrap: break-word; }
ul[class], ol[class] { list-style: none; padding: 0; }
a { color: inherit; }
:target { scroll-margin-block-start: 6rem; }

/* --------------------------------------------------------------------------
   2. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* -- Official identity palette (do not alter) ---------------------------- */
  --navy:       #1B3A57;
  --turquoise:  #2CBFD5;
  --gold:       #F7A440;
  --white:      #FFFFFF;

  /* -- Derived steps, for UI states only ---------------------------------- */
  --navy-950:   #0B1927;
  --navy-900:   #0E2134;
  --navy-800:   #142C43;
  --navy-700:   var(--navy);
  --navy-600:   #2B506F;
  --navy-400:   #3E6486;
  --ink-500:    #52697C;
  --ink-400:    #7B8FA0;
  --ink-300:    #A7B6C1;
  --ink-200:    #CBD5DC;
  --ink-100:    #E4EAEE;
  --ink-050:    #F2F5F7;

  --turq-ink:   #156F7C;   /* 5.84:1 on white, 5.38:1 on --turq-050 */
  --turq-600:   #1FA3B8;
  --turq-500:   var(--turquoise);
  --turq-200:   #A9E4EE;
  --turq-050:   #EBF8FB;

  --gold-ink:   #92590C;   /* 5.74:1 on white, 5.28:1 on --gold-050 */
  --gold-500:   var(--gold);
  --gold-200:   #FBD9A6;
  --gold-050:   #FEF4E7;

  /* -- Semantic ----------------------------------------------------------- */
  --surface:        var(--white);
  --surface-quiet:  var(--ink-050);
  --surface-deep:   var(--navy-900);
  --text:           var(--navy);
  --text-quiet:     var(--ink-500);
  --text-on-deep:   #E8EFF4;
  --text-on-deep-q: #9FB4C4;
  --rule:           var(--ink-100);
  --rule-deep:      rgb(255 255 255 / 0.14);
  --accent:         var(--turq-ink);
  --accent-bright:  var(--turquoise);

  /* -- Type --------------------------------------------------------------- */
  --font-display: "Montserrat", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-body:    "Open Sans", "Segoe UI", system-ui, -apple-system, sans-serif;

  /* Editorial scale, tightened. The previous top steps ran to 7rem and 10.5rem,
     which read as shouting rather than confident and pushed every section into
     a wall of oversized text. Display sizes now top out where a headline still
     commands the page without dominating it. */
  --step--2: clamp(0.70rem, 0.68rem + 0.08vw, 0.75rem);
  --step--1: clamp(0.80rem, 0.78rem + 0.10vw, 0.86rem);
  --step-0:  clamp(0.94rem, 0.92rem + 0.14vw, 1.02rem);
  --step-1:  clamp(1.06rem, 1.00rem + 0.28vw, 1.22rem);
  --step-2:  clamp(1.24rem, 1.13rem + 0.50vw, 1.55rem);
  --step-3:  clamp(1.50rem, 1.28rem + 0.95vw, 2.05rem);
  --step-4:  clamp(1.80rem, 1.45rem + 1.55vw, 2.70rem);
  --step-5:  clamp(2.15rem, 1.65rem + 2.20vw, 3.40rem);
  --step-6:  clamp(2.50rem, 1.80rem + 3.20vw, 4.40rem);

  /* -- Space -------------------------------------------------------------- */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;     --sp-7: 2.75rem;  --sp-8: 3.5rem;
  --sp-9: 5rem;     --sp-10: 7rem;    --sp-11: 9.5rem;  --sp-12: 13rem;

  --section-y: clamp(4.5rem, 3rem + 7vw, 11rem);
  --gutter:    clamp(1.25rem, 0.6rem + 3vw, 4rem);
  --measure:   66ch;
  --measure-tight: 46ch;

  /* -- Geometry ----------------------------------------------------------- */
  --radius:      2px;      /* one radius, used sparingly */
  --radius-lg:   4px;
  --hairline:    1px;
  --diagonal:    12deg;    /* the identity guide's 10–15° signature, fixed at 12 */
  --shell:       1440px;
  --shell-text:  760px;

  /* -- Motion ------------------------------------------------------------- */
  --ease:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out:  cubic-bezier(0.16, 1, 0.30, 1);
  --dur-1: 180ms;  --dur-2: 320ms;  --dur-3: 520ms;  --dur-4: 900ms;

  --z-nav: 100;  --z-menu: 200;  --z-skip: 300;
}

/* Arabic type stack. Letter-spacing is reset to normal everywhere in Arabic —
   tracking breaks the joining behaviour of the script and is a common and very
   visible mistake. Leading is opened up because Arabic carries more vertical
   detail than Latin at the same size. */
/* Per the brand manual: Cairo primary, Noto Kufi Arabic secondary, and never
   more than two families in one design. Headings take the Kufi at heavy weight
   - that is the manual's own secondary face and it gives Arabic headlines a
   distinct display voice - while body stays Cairo. Exactly two families render
   on any Arabic view, and no third face is introduced. */
:root:lang(ar), [lang="ar"] {
  --font-display: "Noto Kufi Arabic", "Cairo", "Segoe UI", system-ui, sans-serif;
  --font-body:    "Cairo", "Noto Kufi Arabic", "Segoe UI", system-ui, sans-serif;
}
/* Kufi is a wider, heavier construction than Cairo. At display sizes it needs
   more leading to breathe and must never be tracked - the script joins. */
[lang="ar"] h1, [lang="ar"] h2, [lang="ar"] h3, [lang="ar"] .display,
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] .display {
  /* Measured: Kufi's ascender/descender box runs ~17% taller than its line box
     at display size. At 1.5 the glyphs spilled past the element and collided
     with whatever sat beneath. 1.62 contains them. */
  line-height: 1.62;
  letter-spacing: normal;
  word-spacing: 0.02em;
}
[dir="rtl"] .hero__title { line-height: 1.42; }
[dir="rtl"] .band-dest__name { line-height: 1.55; }
[dir="rtl"] .route__name { line-height: 1.55; }

/* --------------------------------------------------------------------------
   3. BASE TYPOGRAPHY
   -------------------------------------------------------------------------- */
body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--text);
  background: var(--surface);
  font-feature-settings: "kern";
}
[lang="ar"] body, body[lang="ar"] { line-height: 1.9; }

h1, h2, h3, h4, .display {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.022em;
  text-wrap: balance;
}
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] h4, [dir="rtl"] .display,
[lang="ar"] h1, [lang="ar"] h2, [lang="ar"] h3, [lang="ar"] h4, [lang="ar"] .display {
  letter-spacing: normal;   /* never track Arabic */
  line-height: 1.35;
  /* NO font-weight here. This selector outranks .hero__title, so declaring a
     weight silently capped every Arabic headline at 700 and killed the weight
     contrast the design depends on. Weight belongs to the component. */
}

p { text-wrap: pretty; }

.u-kicker {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
[dir="rtl"] .u-kicker { letter-spacing: normal; text-transform: none; }

.u-lead      { font-size: var(--step-1); line-height: 1.5; color: var(--text-quiet); max-inline-size: var(--measure); }
[lang="ar"] .u-lead, [dir="rtl"] .u-lead { line-height: 1.85; }
.u-measure   { max-inline-size: var(--measure); }
.u-measure-t { max-inline-size: var(--measure-tight); }
.u-quiet     { color: var(--text-quiet); }
.u-center    { text-align: center; margin-inline: auto; }

/* --------------------------------------------------------------------------
   4. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.shell      { inline-size: min(100% - (var(--gutter) * 2), var(--shell)); margin-inline: auto; }
/* The atlas is the hero of its section, so it gets a wider measure than the
   text column it sits beside. */
.shell--wide { inline-size: min(100% - (var(--gutter) * 1.2), 1720px); margin-inline: auto; }
.shell-text { inline-size: min(100% - (var(--gutter) * 2), var(--shell-text)); margin-inline: auto; }
.section    { padding-block: var(--section-y); }
.section--tight { padding-block: clamp(3rem, 2rem + 4vw, 6rem); }

.section--deep {
  background: var(--surface-deep);
  color: var(--text-on-deep);
}
.section--deep .u-kicker   { color: var(--accent-bright); }
.section--deep .u-quiet,
.section--deep .u-lead     { color: var(--text-on-deep-q); }
.section--quiet { background: var(--surface-quiet); }

.stack > * + * { margin-block-start: var(--flow, var(--sp-5)); }
.stack-lg > * + * { margin-block-start: var(--sp-7); }

.grid { display: grid; gap: var(--sp-6); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr)); }

/* Editorial split: heading rail + content. Mirrors automatically. */
.split {
  display: grid;
  gap: clamp(var(--sp-6), 4vw, var(--sp-9));
  align-items: start;
}
@media (min-width: 62rem) {
  .split { grid-template-columns: minmax(14rem, 22rem) minmax(0, 1fr); }
  .split--wide  { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* The map needs the larger share: its labels are sized in viewBox units, so
     the narrower the column, the smaller they render on screen. */
  .split--map   { grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr); }
  .split__rail  { position: sticky; inset-block-start: 7rem; }
}

/* The brand diagonal. One angle, used as a section edge — the identity guide's
   10–15° rule, fixed at 12° so it is recognisable rather than decorative.
   It flips with direction so it always reads as the same gesture. */
.edge-diagonal { position: relative; }
.edge-diagonal::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: calc(-1 * clamp(2rem, 5vw, 5rem));
  block-size: clamp(2rem, 5vw, 5rem);
  background: inherit;
  clip-path: polygon(0 100%, 100% 0, 100% 100%);
}
[dir="rtl"] .edge-diagonal::before { clip-path: polygon(0 0, 100% 100%, 0 100%); }

/* --------------------------------------------------------------------------
   5. SKIP LINK / FOCUS
   -------------------------------------------------------------------------- */
.skip {
  position: fixed;
  inset-block-start: var(--sp-3);
  inset-inline-start: var(--sp-3);
  z-index: var(--z-skip);
  padding: var(--sp-3) var(--sp-5);
  background: var(--navy);
  color: var(--white);
  transform: translateY(-150%);
  transition: transform var(--dur-1) var(--ease);
}
.skip:focus-visible { transform: none; }

:focus-visible {
  outline: 2px solid var(--turq-600);
  outline-offset: 3px;
  border-radius: var(--radius);
}
.section--deep :focus-visible { outline-color: var(--turquoise); }

/* --------------------------------------------------------------------------
   6. NAVIGATION
   -------------------------------------------------------------------------- */
.nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-nav);
  transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
  border-block-end: var(--hairline) solid transparent;
}
.nav__inner {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  padding-block: var(--sp-4);
}
.nav__logo { display: flex; align-items: center; gap: var(--sp-3); flex: 0 0 auto; text-decoration: none; }

/* The supplied lockup, used as artwork rather than rebuilt from type — the
   identity manual fixes both the V-to-wordmark proportion and the space
   between them, so it is only ever scaled, never rearranged. */
.logo { display: inline-flex; align-items: center; }
.logo__img { block-size: 2.9rem; inline-size: auto; flex: 0 0 auto; }

/* The header sits transparent over the dark hero and turns solid white on
   scroll, so the lockup has to change with it. Both files ship and the header's
   own data-mode picks one; swapping src in JS would flash on the change. */
.logo__img--ondark  { display: none; }
.nav[data-mode="over"]  .logo__img--onlight { display: none; }
.nav[data-mode="over"]  .logo__img--ondark  { display: block; }
.footer__logo .logo__img { block-size: 3.1rem; }
@media (max-width: 40rem) { .logo__img { block-size: 2.4rem; } }
.nav__links {
  display: none;
  gap: clamp(var(--sp-4), 1.8vw, var(--sp-6));
  margin-inline-start: auto;
  align-items: center;
}
@media (min-width: 64rem) { .nav__links { display: flex; } }

/* The nav CTA is a compact variant — full button padding makes it wrap. */
.nav__links .btn { padding: var(--sp-3) var(--sp-5); white-space: nowrap; }

.nav__link {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  padding-block: var(--sp-2);
  position: relative;
  white-space: nowrap;
}
[dir="rtl"] .nav__link { letter-spacing: normal; }
.nav__link::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 1px;
  background: currentColor;
  transition: inline-size var(--dur-2) var(--ease);
}
.nav__link:hover::after, .nav__link[aria-current="page"]::after { inline-size: 100%; }

.nav__aside { display: flex; align-items: center; gap: var(--sp-4); margin-inline-start: auto; }
@media (min-width: 64rem) { .nav__aside { margin-inline-start: 0; } }

.nav__lang {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  text-decoration: none;
  padding: var(--sp-2) var(--sp-3);
  border: var(--hairline) solid currentColor;
  border-radius: var(--radius);
  opacity: 0.75;
  transition: opacity var(--dur-1) var(--ease);
}
.nav__lang:hover { opacity: 1; }

/* Transparent over the hero, solid once scrolled — set by a single data attribute. */
.nav[data-mode="over"]   { color: var(--white); }
.nav[data-mode="solid"]  {
  background: rgb(255 255 255 / 0.92);
  backdrop-filter: saturate(1.6) blur(14px);
  border-block-end-color: var(--rule);
  color: var(--navy);
}
@supports not (backdrop-filter: blur(1px)) {
  .nav[data-mode="solid"] { background: var(--white); }
}

.nav__burger {
  inline-size: 2.75rem; block-size: 2.75rem;
  display: grid; place-items: center;
  margin-inline-start: var(--sp-2);
}
.nav__burger span,
.nav__burger span::before,
.nav__burger span::after {
  content: ""; display: block;
  inline-size: 22px; block-size: 1.5px;
  background: currentColor;
  transition: transform var(--dur-2) var(--ease), opacity var(--dur-1) var(--ease);
}
.nav__burger span { position: relative; }
.nav__burger span::before { position: absolute; inset-block-start: -7px; inset-inline-start: 0; }
.nav__burger span::after  { position: absolute; inset-block-start:  7px; inset-inline-start: 0; }
.nav__burger[aria-expanded="true"] span { background: transparent; }
.nav__burger[aria-expanded="true"] span::before { transform: translateY(7px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span::after  { transform: translateY(-7px) rotate(-45deg); }

/* Declared after .nav__burger's own display:grid — an equal-specificity rule
   placed earlier would lose to it and leave the burger visible on desktop. */
@media (min-width: 64rem) { .nav__burger { display: none; } }

/* Mobile menu */
.menu {
  position: fixed; inset: 0; z-index: var(--z-menu);
  background: var(--navy-900); color: var(--text-on-deep);
  display: grid; align-content: center;
  padding: var(--gutter);
  opacity: 0; visibility: hidden;
  /* visibility is stepped, not eased: it flips instantly on open (so the menu
     is focusable on the very next frame) and is delayed on close until the
     fade has finished. Easing it in both directions leaves the panel
     unfocusable for the duration and breaks keyboard entry into the menu. */
  transition: opacity var(--dur-2) var(--ease), visibility 0s linear var(--dur-2);
}
.menu[data-open="true"] {
  opacity: 1; visibility: visible;
  transition: opacity var(--dur-2) var(--ease), visibility 0s linear 0s;
}
.menu__list { display: grid; gap: var(--sp-4); }
.menu__link {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 700;
  text-decoration: none;
  letter-spacing: -0.02em;
}
[dir="rtl"] .menu__link { letter-spacing: normal; }
.menu__close { position: absolute; inset-block-start: var(--sp-5); inset-inline-end: var(--gutter); font-size: var(--step-1); }
.menu__foot { margin-block-start: var(--sp-8); display: flex; flex-wrap: wrap; gap: var(--sp-5); font-size: var(--step--1); color: var(--text-on-deep-q); }

/* --------------------------------------------------------------------------
   7. BUTTONS
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-decoration: none;
  padding: var(--sp-4) var(--sp-6);
  border: var(--hairline) solid transparent;
  border-radius: var(--radius);
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-out);
  will-change: transform;
}
[dir="rtl"] .btn { letter-spacing: normal; }
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: none; }

.btn--primary { background: var(--navy); color: var(--white); }
.btn--primary:hover { background: var(--navy-800); }
.section--deep .btn--primary { background: var(--turquoise); color: var(--navy-950); }
.section--deep .btn--primary:hover { background: #4ACFE3; }

.btn--ghost { border-color: currentColor; color: inherit; }
.btn--ghost:hover { background: currentColor; }
.btn--ghost:hover > * { mix-blend-mode: difference; }

.btn--quiet { padding-inline: 0; border: 0; }
.btn--quiet .btn__arrow { transition: transform var(--dur-2) var(--ease-out); }
.btn--quiet:hover .btn__arrow { transform: translateX(4px); }
[dir="rtl"] .btn--quiet:hover .btn__arrow { transform: translateX(-4px); }

/* Arrow glyph flips with direction. */
.btn__arrow { display: inline-block; }
[dir="rtl"] .btn__arrow { scale: -1 1; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; }

/* --------------------------------------------------------------------------
   8. HERO — photographic, full bleed
   --------------------------------------------------------------------------
   The old hero was a coloured rectangle: no place, no people, no atmosphere,
   and half the RTL grid left empty. This one commits the first screen to one
   photograph and one action.

   Two things make a weak placeholder survive here:
   1. the scrim carries the contrast, not the picture, so type is legible over
      anything;
   2. `object-position` comes from the slot manifest, so a photograph shot as a
      group portrait can be cropped to behave as a landscape - the people sink
      into the scrim and the geology holds the frame.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-block-size: 100svh;
  display: grid;
  align-items: end;
  background: var(--navy-950);
  color: var(--white);
  overflow: hidden;
  padding-block: clamp(7rem, 14vh, 10rem) clamp(2rem, 5vh, 3.5rem);
  isolation: isolate;
}
.hero__img {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  z-index: -2;
  /* Desaturated and darkened so the brand colours stay the loudest thing on
     screen. The photograph sets mood; it does not compete with the identity. */
  filter: saturate(0.72) contrast(1.06) brightness(0.82);
}
/* The scrim. Deliberately asymmetric: heaviest at the bottom where the type
   sits, with a second wash from the inline-start so the headline block always
   has ground beneath it regardless of what the photograph is doing there. */
.hero__veil {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  /* Strengthened for the video hero. The old values were tuned against the
     Al-Qarah photograph, which is dark and even; the panel footage is bright
     and busy and left the eyebrow at 1.69:1. The upper reach of both gradients
     is raised - the bottom was already ample and is untouched - so the gain
     lands where the eyebrow and the top of the headline sit, and the rest of
     the frame stays open. */
  background:
    linear-gradient(to top,
      rgb(11 25 39 / 0.96) 0%,
      rgb(11 25 39 / 0.84) 26%,
      rgb(11 25 39 / 0.50) 55%,
      rgb(11 25 39 / 0.38) 100%),
    linear-gradient(to var(--veil-dir, left),
      rgb(11 25 39 / 0.78) 0%,
      rgb(11 25 39 / 0.26) 55%,
      transparent 100%);
}
[dir="rtl"] .hero { --veil-dir: left; }
[dir="ltr"] .hero { --veil-dir: right; }

/* The composition resolves on BOTH sides: the headline block holds one side,
   and a foot rail spans the full width beneath it carrying the scroll cue and
   the location of the photograph. No empty column. */
.hero__grid { position: relative; display: grid; gap: clamp(2.5rem, 6vh, 4.5rem); }
.hero__body { max-inline-size: min(100%, 44rem); }

.hero__eyebrow {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  /* --turq-200, not --turquoise. This line sits at the very top of the hero
     where the veil is thinnest, and #2CBFD5 over bright video measured
     1.69:1 - it cannot reach 4.5:1 without an overlay dense enough to hide
     the footage. The light tint carries the same accent and clears AA. The
     full-strength turquoise is unchanged everywhere else on the site. */
  color: var(--turq-200);
  margin-block-end: var(--sp-5);
}
[dir="rtl"] .hero__eyebrow { letter-spacing: normal; text-transform: none; font-weight: 700; }

.hero__title {
  font-size: var(--step-6);
  font-weight: 800;
  line-height: 0.94;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
/* Arabic gets the weight it was always specified at - 800, now that the
   direction rule no longer caps it - plus leading opened for the script and
   a touch of optical size correction at display scale. */
[dir="rtl"] .hero__title {
  letter-spacing: normal;
  line-height: 1.18;
  font-weight: 800;
}
.hero__title span { display: block; }
.hero__title .is-muted { color: var(--turquoise); }

.hero__sub {
  font-size: var(--step-1);
  max-inline-size: 34ch;
  color: rgb(255 255 255 / 0.82);
  line-height: 1.55;
  margin-block-start: var(--sp-5);
}
[lang="ar"] .hero__sub, [dir="rtl"] .hero__sub { line-height: 1.85; max-inline-size: 32ch; }
.hero__actions { margin-block-start: var(--sp-7); }

.hero__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); flex-wrap: wrap;
  padding-block-start: var(--sp-5);
  border-block-start: var(--hairline) solid rgb(255 255 255 / 0.16);
}
.hero__scroll {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--step--2);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.6);
}
[dir="rtl"] .hero__scroll { letter-spacing: normal; text-transform: none; }
.hero__scroll i {
  display: block; inline-size: 2.5rem; block-size: 1px;
  background: linear-gradient(to var(--veil-dir, left), rgb(255 255 255 / 0.6), transparent);
}
/* The photograph names itself. First appearance of the data-as-design voice
   that Phase 3 builds out across destinations and programmes. */
.hero__credit {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.5);
}
[dir="rtl"] .hero__credit { letter-spacing: normal; text-transform: none; }

/* A bigger, more committed primary action. One CTA, given room. */
.btn--lg { padding: var(--sp-5) var(--sp-8); font-size: var(--step-0); }

@media (max-width: 40rem) {
  .hero__body { max-inline-size: none; }
  .hero__title { font-size: clamp(2.3rem, 9vw, 3.2rem); }
}
/* --------------------------------------------------------------------------
   9. FIGURES — the editorial image system
   --------------------------------------------------------------------------
   The library is 93% portrait phone photography of real school groups. It is
   used at its native ratio, never stretched into a cinematic crop it was not
   shot for, and always under a navy scrim that unifies wildly varying source
   quality into one visual system.

   `.figure--protected` carries a heavier scrim and is applied wherever a
   parental media release is not yet on file. It reduces prominence; it is not
   a substitute for consent.
   -------------------------------------------------------------------------- */
.figure { position: relative; overflow: hidden; background: var(--navy-900); }
.figure img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  filter: saturate(0.88) contrast(1.04);
  transition: transform var(--dur-4) var(--ease-out), filter var(--dur-3) var(--ease);
}
.figure::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgb(11 25 39 / 0.72) 0%, rgb(11 25 39 / 0.18) 45%, rgb(11 25 39 / 0.06) 100%);
  transition: opacity var(--dur-3) var(--ease);
  pointer-events: none;
}
.figure--protected::after {
  background:
    linear-gradient(to top, rgb(11 25 39 / 0.80) 0%, rgb(11 25 39 / 0.42) 50%, rgb(11 25 39 / 0.30) 100%);
}
.figure--plain::after { display: none; }
a:hover > .figure img, .figure--zoom:hover img { transform: scale(1.035); }

/* Card photography sits at 3:2. Portrait cards stacked five across turned every
   listing page into a column of oversized images. */
.figure--photo     { aspect-ratio: 3 / 2; }
.figure--empty     { background: linear-gradient(150deg, #142C43, #0B1927); }
/* No forced ratio: the picture keeps whatever shape it was taken in. Used
   where a page shows ONE photograph rather than a grid of them - a targeted
   destination's landmark - because there is no neighbour for it to line up
   with, and forcing a 2:1 panorama into a 3:4 card threw away 63% of it. */
.figure--auto { aspect-ratio: auto; }
.figure--auto img { block-size: auto; object-fit: contain; }
.figure--portrait  { aspect-ratio: 3 / 4; }
.figure--tall      { aspect-ratio: 2 / 3; }
.figure--landscape { aspect-ratio: 4 / 3; }
.figure--wide      { aspect-ratio: 16 / 9; }

.figure__caption {
  position: absolute;
  inset-block-end: 0; inset-inline: 0;
  padding: var(--sp-5);
  color: var(--white);
}
.figure__caption h3 { font-size: var(--step-2); }
.figure__meta {
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--turquoise);
  margin-block-end: var(--sp-2);
}
[dir="rtl"] .figure__meta { letter-spacing: normal; text-transform: none; }

/* Offset editorial pair — deliberately not a grid of equal cards. */
.editorial { display: grid; gap: var(--sp-6); }
@media (min-width: 52rem) {
  .editorial { grid-template-columns: 1fr 1fr; align-items: end; }
  .editorial > :nth-child(odd)  { margin-block-end: clamp(2rem, 6vw, 5rem); }
}

/* --------------------------------------------------------------------------
   10. CARDS
   -------------------------------------------------------------------------- */
.cards {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}
.card {
  display: block; text-decoration: none; color: inherit;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--white);
  transition: border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-out);
}
.card:hover { border-color: var(--turq-500); transform: translateY(-3px); }
.section--deep .card { background: rgb(255 255 255 / 0.04); border-color: var(--rule-deep); }
.card--soon { opacity: 0.78; }
.card--soon:hover { transform: none; border-color: var(--rule); }
.card__body { padding: var(--sp-5); }
.card__title { font-size: var(--step-1); margin-block-end: var(--sp-2); line-height: 1.3; }
[dir="rtl"] .card__title { line-height: 1.55; }
.card__text { color: var(--text-quiet); font-size: var(--step--1); line-height: 1.65; }

.badge {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.3em 0.7em;
  border-radius: 999px;
  vertical-align: middle;
  margin-inline-start: var(--sp-2);
}
[dir="rtl"] .badge { letter-spacing: normal; text-transform: none; }
.badge--soon { background: var(--gold-050); color: var(--gold-ink); }
.section--deep .badge--soon { background: rgb(247 164 64 / 0.16); color: var(--gold); }
.section--deep .card__text { color: var(--text-on-deep-q); }
.card:hover .card__title { color: var(--accent); }
.section--deep .card:hover .card__title { color: var(--accent-bright); }

/* Numbered list-item rows, used for services and reasons. */
.rows { border-block-start: var(--hairline) solid var(--rule); }
.section--deep .rows, .section--deep .row { border-color: var(--rule-deep); }
.row {
  display: grid;
  gap: var(--sp-3) var(--sp-6);
  padding-block: var(--sp-6);
  border-block-end: var(--hairline) solid var(--rule);
  align-items: baseline;
}
@media (min-width: 48rem) { .row { grid-template-columns: 4rem minmax(0, 18rem) minmax(0, 1fr); } }
.row__num {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.1em;
}
[dir="rtl"] .row__num { letter-spacing: normal; }
.section--deep .row__num { color: var(--accent-bright); }
.row__title { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); line-height: 1.25; }
[dir="rtl"] .row__title { line-height: 1.5; }
.row__text { color: var(--text-quiet); }
.section--deep .row__text { color: var(--text-on-deep-q); }

/* --------------------------------------------------------------------------
   The six-stage method, as cards rather than a text list.
   The numbers are load-bearing here: this genuinely is a sequence, and a school
   reads it to find out what happens when.
   -------------------------------------------------------------------------- */
.steps {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
  counter-reset: step;
}
/* Fixed 3 x 2 rather than auto-fit: auto-fit produced a 4 + 2 row that read as
   a mistake rather than a sequence. */
@media (min-width: 40rem) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62rem) { .steps { grid-template-columns: repeat(3, 1fr); } }
.step {
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  padding: var(--sp-6);
  background: var(--white);
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  transition: border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-out);
}
.step:hover { border-color: var(--turq-500); transform: translateY(-3px); }
.section--deep .step, .section--quiet .step { background: var(--white); }
.section--deep .step { background: rgb(255 255 255 / 0.04); border-color: var(--rule-deep); }

.step__top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.step__icon {
  display: grid; place-items: center;
  inline-size: 2.6rem; block-size: 2.6rem;
  border-radius: 999px;
  background: var(--turq-050);
  color: var(--turq-ink);
  flex: 0 0 auto;
}
.section--deep .step__icon { background: rgb(44 191 213 / 0.14); color: var(--turquoise); }
.step__icon svg { inline-size: 1.35rem; block-size: 1.35rem; }
.step__num {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 800;
  line-height: 1;
  color: var(--ink-200);
  font-variant-numeric: tabular-nums;
  direction: ltr;
}
.section--deep .step__num { color: rgb(255 255 255 / 0.22); }
.step__title { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); line-height: 1.3; }
[dir="rtl"] .step__title { line-height: 1.55; }
.step__text { font-size: var(--step--1); color: var(--text-quiet); line-height: 1.7; }
.section--deep .step__text { color: var(--text-on-deep-q); }

/* Chips — the "bring us any one of these" set. */
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.chip {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  padding: var(--sp-3) var(--sp-5);
  border: var(--hairline) solid var(--ink-200);
  border-radius: 999px;
  color: var(--text);
  background: var(--white);
}
.section--deep .chip { border-color: var(--rule-deep); color: var(--text-on-deep); background: transparent; }
.chip--accent { border-color: var(--turq-500); color: var(--turq-ink); background: var(--turq-050); }

/* --------------------------------------------------------------------------
   11. THE COMPARISON (Vision → Design → Experience → Impact)
   -------------------------------------------------------------------------- */
.compare { display: grid; gap: var(--sp-7); }
@media (min-width: 54rem) { .compare { grid-template-columns: 1fr 1fr; gap: var(--sp-9); } }
.compare__col { padding-block-start: var(--sp-5); border-block-start: 2px solid var(--rule); }
.compare__col--voyra { border-block-start-color: var(--turquoise); }
.compare__label {
  font-family: var(--font-display);
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-quiet);
  margin-block-end: var(--sp-6);
}
[dir="rtl"] .compare__label { letter-spacing: normal; text-transform: none; }
.compare__col--voyra .compare__label { color: var(--accent); }
.section--deep .compare__col--voyra .compare__label { color: var(--accent-bright); }
.compare__steps { display: grid; gap: var(--sp-4); }
.compare__step {
  display: flex; align-items: center; gap: var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--step-2); font-weight: 700;
  line-height: 1.2;
}
.compare__step::before {
  content: "";
  flex: 0 0 auto;
  inline-size: 0.5rem; block-size: 0.5rem;
  border-radius: 999px;
  background: var(--ink-200);
}
.compare__col--voyra .compare__step::before { background: var(--turquoise); }
.compare__note { margin-block-start: var(--sp-6); color: var(--text-quiet); font-size: var(--step-0); }
.section--deep .compare__note { color: var(--text-on-deep-q); }

/* --------------------------------------------------------------------------
   12. TESTIMONIALS
   -------------------------------------------------------------------------- */
.quote-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}
.quote {
  display: grid;
  gap: var(--sp-4);
  align-content: start;
  padding: var(--sp-6);
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--white);
}
.section--deep .quote { background: rgb(255 255 255 / 0.04); border-color: var(--rule-deep); }
/* The turquoise rule ties the card to the identity without an ornament. */
.quote { border-block-start: 2px solid var(--turq-500); }
.quote__text {
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  margin: 0;
  quotes: "\201C" "\201D";
}
.quote__text::before { content: open-quote; }
.quote__text::after  { content: close-quote; }
[dir="rtl"] .quote__text, [lang="ar"] .quote__text { letter-spacing: normal; line-height: 1.75; }
.quote__original {
  font-size: var(--step--1);
  line-height: 1.8;
  color: var(--text-quiet);
  direction: rtl;
  text-align: start;
  font-family: "Cairo", "Noto Kufi Arabic", system-ui, sans-serif;
  padding-block-start: var(--sp-3);
  border-block-start: var(--hairline) solid var(--rule);
}
.section--deep .quote__original { color: var(--text-on-deep-q); border-color: var(--rule-deep); }
.quote__attr {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--turq-ink);
}
.section--deep .quote__attr { color: var(--turquoise); }
[dir="rtl"] .quote__attr { letter-spacing: normal; text-transform: none; }
.quote__tag {
  font-size: var(--step--2);
  color: var(--text-on-deep-q);
  opacity: 0.75;
}

/* --------------------------------------------------------------------------
   13. IMPACT FIGURE
   -------------------------------------------------------------------------- */
.figure-stat { text-align: center; }
.figure-stat__num {
  font-family: var(--font-display);
  font-size: var(--step-6);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.04em;
  background: linear-gradient(135deg, var(--turquoise) 0%, var(--gold) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
[dir="rtl"] .figure-stat__num { letter-spacing: normal; direction: ltr; }
.figure-stat__label {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 500;
  margin-block-start: var(--sp-4);
}

/* --------------------------------------------------------------------------
   14. THE ATLAS — hub and spoke
   --------------------------------------------------------------------------
   The map is the hero of its section, not a sidebar graphic: near full width,
   Kingdom dead centre, everything radiating outward. Colour carries the site
   rule — ORANGE = delivered / live, turquoise = targeted.
   -------------------------------------------------------------------------- */
.atlas { display: grid; gap: clamp(var(--sp-6), 4vw, var(--sp-8)); }
/* The panel is a column, not an overlay. Floating it over the map looked
   tempting, but this projection has destinations in every quadrant — any
   corner it sat in buried three of them. A column keeps the map unobstructed
   and still leaves it ~70% of a very wide shell, which is the point. */
.atlas__stage { position: relative; display: grid; gap: clamp(var(--sp-5), 2vw, var(--sp-7)); }
@media (min-width: 62rem) {
  .atlas__stage { grid-template-columns: minmax(0, 1fr) minmax(0, 21rem); align-items: start; }
  /* Explicit placement. Left to auto-flow the panel landed in column one and
     squeezed the map to a quarter of its width. */
  .atlas__svg    { grid-column: 1; grid-row: 1; }
  .focus         { grid-column: 2; grid-row: 1 / span 2; }
  .atlas__legend { grid-column: 1; grid-row: 2; }
}
/* Geography is pinned LTR and must never mirror. The rail and focus panel
   beside it stay RTL — that split is the whole RTL story for this component. */
.atlas__svg { direction: ltr; inline-size: 100%; block-size: auto; overflow: visible; }

.map__land { pointer-events: none; }
.map__land path { fill: rgb(255 255 255 / 0.05); stroke: rgb(255 255 255 / 0.11); stroke-width: 0.7; }
.map__land--inset path { fill: rgb(255 255 255 / 0.08); stroke: rgb(255 255 255 / 0.2); stroke-width: 1.4; }

/* Routes. Delivered is the confident primary layer: solid, orange, brighter.
   Targeted is dashed and quiet — a proposal, not a claim. */
.map__arc {
  fill: none;
  stroke: rgb(44 191 213 / 0.34);
  stroke-width: 1;
  stroke-dasharray: 0.012 0.016;
  vector-effect: non-scaling-stroke;
  transition: stroke var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease);
}
.map__arc--live { stroke: rgb(247 164 64 / 0.55); stroke-width: 1.6; stroke-dasharray: none; }

/* Home. The Kingdom is a place, not a dot: a slow pulse ring marks the origin
   every journey departs from. */
.map__homeDot  { r: 5.5; fill: var(--gold); }
.map__homeRing { r: 5.5; fill: none; stroke: var(--gold); stroke-width: 1.2; opacity: 0.5;
                 transform-origin: center; transform-box: fill-box; animation: homePulse 3.6s var(--ease-out) infinite; }
@keyframes homePulse { 0% { r: 6; opacity: 0.55; } 70% { r: 22; opacity: 0; } 100% { r: 22; opacity: 0; } }
.map__homeLabel {
  font-family: var(--font-display); font-size: 15px; font-weight: 700;
  fill: var(--gold); letter-spacing: 0.1em;
  paint-order: stroke; stroke: var(--navy-950); stroke-width: 5px; stroke-linejoin: round;
}

.map__pin { cursor: pointer; }
.map__dot { r: 4.5; fill: none; stroke: var(--turquoise); stroke-width: 1.8;
            transition: r var(--dur-2) var(--ease-out); }
.map__pin.is-live .map__dot { fill: var(--gold); stroke: var(--gold); }
.map__halo { r: 0; fill: rgb(44 191 213 / 0.18); transition: r var(--dur-3) var(--ease-out); }
.map__pin.is-live .map__halo { fill: rgb(247 164 64 / 0.22); }
.map__pin:hover .map__dot, .map__pin:focus-visible .map__dot, .map__pin[data-active] .map__dot { r: 7; }
.map__pin:hover .map__halo, .map__pin:focus-visible .map__halo, .map__pin[data-active] .map__halo { r: 17; }

.map__label {
  font-family: var(--font-display); font-size: 15px; font-weight: 600;
  fill: rgb(255 255 255 / 0.86);
  paint-order: stroke; stroke: var(--navy-950); stroke-width: 4.5px; stroke-linejoin: round;
  pointer-events: none; transition: fill var(--dur-2) var(--ease);
}
.map__label--inset { font-size: 16px; }
.map__pin.is-live .map__label { fill: #fff; }
.map__pin:hover .map__label, .map__pin[data-active] .map__label { fill: var(--gold); }

/* The inset is a deliberate cartographic object: framed, labelled, and tied to
   the Kingdom's true position by a connector so the eye reads "this is that,
   magnified". Its corner is cut on the identity's diagonal. */
.map__insetFrame { fill: rgb(11 25 39 / 0.86); stroke: rgb(255 255 255 / 0.22); stroke-width: 1.2; }
.map__connector  { stroke: rgb(247 164 64 / 0.45); stroke-width: 1; stroke-dasharray: 3 4; }
.map__insetTitle {
  font-family: var(--font-display); font-size: 12px; font-weight: 700;
  fill: var(--gold); letter-spacing: 0.12em; opacity: 0.85;
}
[dir="rtl"] .map__insetTitle, [dir="rtl"] .map__homeLabel { letter-spacing: normal; }

/* Focus: one journey at a time. Sits over the map's inline-end side, where the
   projection leaves open ocean. It is the reach statement until a journey is
   focused, so it is never an empty box. */
.focus {
  align-self: start;
  /* The panel must NEVER be sized by its own content on hover.
     Two earlier attempts reserved a measured height - 512px, then 34rem - and
     each one held only until something changed the metrics under it. The fix
     is structural instead: see FOCUS PANEL - THE STACK at the end of this
     file. Every panel occupies one shared grid cell, so the box is already
     the height of the tallest of them and swapping which is visible moves
     nothing. Height here stays auto because the stack, not this rule, is what
     makes it constant. */
  position: relative;
  block-size: auto;
  padding: var(--sp-6);
  background: rgb(11 25 39 / 0.9);
  backdrop-filter: blur(6px);
  border: var(--hairline) solid rgb(255 255 255 / 0.16);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
.focus__eyebrow {
  font-family: var(--font-display); font-size: var(--step--2); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--turquoise);
  margin-block-end: var(--sp-5);
}
[dir="rtl"] .focus__eyebrow { letter-spacing: normal; text-transform: none; }

/* The reach block: the section title stated as a fact, in big figures. */
.reach { display: grid; gap: var(--sp-5); }
.reach__item { display: flex; align-items: baseline; gap: var(--sp-3); }
.reach__n {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(2rem, 1.2rem + 2.2vw, 3.1rem); line-height: 0.9;
  color: var(--white); font-variant-numeric: tabular-nums;
}
[dir="rtl"] .reach__n { letter-spacing: normal; }
.reach__l { font-size: var(--step--1); color: var(--text-on-deep-q); }


.atlas__legend { display: flex; flex-wrap: wrap; gap: var(--sp-5); margin-block-start: var(--sp-4); }
.atlas__key { display: inline-flex; align-items: center; gap: var(--sp-3);
              font-size: var(--step--1); color: var(--text-on-deep-q); }
.atlas__key i { inline-size: 0.7rem; block-size: 0.7rem; border-radius: 999px; flex: 0 0 auto; }
.atlas__key--live i { background: var(--gold); }
.atlas__key--soon i { border: 1.5px solid var(--turquoise); }

/* Rail: a light grouped index. Detail lives in the focus panel, but travel
   time stays here so the list is complete with JavaScript off. */
.rail { display: grid; gap: var(--sp-7); }
@media (min-width: 48rem) { .rail { grid-template-columns: 1fr 1fr; gap: var(--sp-8); } }
.rail__head {
  font-family: var(--font-display); font-size: var(--step--2); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--turquoise);
  padding-block-end: var(--sp-3); border-block-end: var(--hairline) solid var(--rule-deep);
}
[dir="rtl"] .rail__head { letter-spacing: normal; text-transform: none; }
.rail__rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr)); gap: 0 var(--sp-5); }
.rail__row {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "dot name" ". travel";
  gap: 0 var(--sp-3); align-items: baseline;
  padding-block: var(--sp-3);
  border-block-end: var(--hairline) solid rgb(255 255 255 / 0.07);
  text-decoration: none;
  transition: background var(--dur-1) var(--ease);
}
.rail__row:hover, .rail__row[data-active] { background: rgb(255 255 255 / 0.05); }
.rail__dot { grid-area: dot; inline-size: 0.45rem; block-size: 0.45rem; border-radius: 999px;
             border: 1.5px solid var(--turquoise); }
.rail__row.is-live .rail__dot { background: var(--gold); border-color: var(--gold); }
.rail__name { grid-area: name; font-family: var(--font-display); font-weight: 700;
              font-size: var(--step--1); color: var(--text-on-deep); }
.rail__travel { grid-area: travel; font-size: var(--step--2); color: var(--text-on-deep-q);
                font-variant-numeric: tabular-nums; }

/* Below 62rem the focus panel stops floating — there is no open ocean to sit
   in once the map is narrow — and becomes a block beneath it. */
@media (max-width: 62rem) {
  .focus { clip-path: none; }
  .reach { grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--sp-4); }
  .reach__item { flex-direction: column; gap: var(--sp-1); }
}

/* Motion with meaning: the focused route draws itself, once, quickly. Every
   other arc dims so one journey is legible at a time. */
.js .atlas[data-focused] .map__arc { opacity: 0.18; }
.js .atlas[data-focused] .map__arc[data-active] { opacity: 1; }
.js .map__arc[data-active] { animation: drawArc 620ms var(--ease-out) both; }
@keyframes drawArc { from { stroke-dasharray: 1; stroke-dashoffset: 1; } to { stroke-dasharray: 1; stroke-dashoffset: 0; } }
.js .map__arc--live[data-active] { stroke: rgb(247 164 64 / 0.95); }
.js .map__arc[data-active]:not(.map__arc--live) { stroke: rgb(44 191 213 / 0.9); }

@media (prefers-reduced-motion: reduce) {
  .map__homeRing { animation: none; opacity: 0.4; }
  .js .map__arc[data-active] { animation: none; }
}
/* Destination index lists */
.dest-group + .dest-group { margin-block-start: var(--sp-9); }
.dest-group__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-4); margin-block-end: var(--sp-6); }
.dest-group__note { font-size: var(--step--1); color: var(--text-quiet); }
.section--deep .dest-group__note { color: var(--text-on-deep-q); }

.tag {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.35em 0.75em;
  border-radius: var(--radius);
}
[dir="rtl"] .tag { letter-spacing: normal; text-transform: none; }
.tag--delivered { background: var(--turq-050); color: var(--turq-ink); }
.tag--targeted  { background: var(--gold-050); color: var(--gold-ink); }
.section--deep .tag--delivered { background: rgb(44 191 213 / 0.16); color: var(--turquoise); }
.section--deep .tag--targeted  { background: rgb(247 164 64 / 0.14); color: var(--gold); }

/* --------------------------------------------------------------------------
   15. FORM
   -------------------------------------------------------------------------- */
.form { display: grid; gap: var(--sp-8); }
.form__section { display: grid; gap: var(--sp-5); }
.form__legend {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  padding-block-end: var(--sp-4);
  border-block-end: var(--hairline) solid var(--rule);
  inline-size: 100%;
}
.form__grid { display: grid; gap: var(--sp-5); }
@media (min-width: 42rem) { .form__grid { grid-template-columns: 1fr 1fr; } .form__grid .is-full { grid-column: 1 / -1; } }

.field { display: grid; gap: var(--sp-2); }
.field__label {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  display: flex; gap: var(--sp-3); align-items: baseline; flex-wrap: wrap;
}
.field__opt { font-weight: 400; color: var(--ink-400); font-size: var(--step--2); }
.field__help { font-size: var(--step--1); color: var(--text-quiet); }

.input, .select, .textarea {
  inline-size: 100%;
  padding: var(--sp-4);
  background: var(--white);
  border: var(--hairline) solid var(--ink-200);
  border-radius: var(--radius);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-300); }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--turq-600);
  box-shadow: 0 0 0 3px rgb(44 191 213 / 0.18);
  outline: none;
}
.textarea { min-block-size: 7rem; resize: vertical; }
/* Native select arrow is direction-aware in browsers; padding must be too. */
.select { padding-inline-end: var(--sp-8); appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-400) 50%), linear-gradient(135deg, var(--ink-400) 50%, transparent 50%);
  background-position: right 1.1rem top 55%, right 0.72rem top 55%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
[dir="rtl"] .select {
  background-position: left 0.72rem top 55%, left 1.1rem top 55%;
  background-image: linear-gradient(135deg, transparent 50%, var(--ink-400) 50%), linear-gradient(45deg, var(--ink-400) 50%, transparent 50%);
}

.radios { display: grid; gap: var(--sp-3); }
.radio { display: flex; align-items: flex-start; gap: var(--sp-3); cursor: pointer; padding: var(--sp-3) var(--sp-4); border: var(--hairline) solid var(--ink-200); border-radius: var(--radius); transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease); }
.radio:hover { border-color: var(--turq-500); background: var(--turq-050); }
.radio input { accent-color: var(--turq-600); margin-block-start: 0.3em; flex: 0 0 auto; }

/* The escape hatch — the strategic core of this form, given visual weight. */
.escape {
  padding: var(--sp-5);
  border: var(--hairline) dashed var(--turq-500);
  border-radius: var(--radius);
  background: var(--turq-050);
}
.escape label { display: flex; align-items: flex-start; gap: var(--sp-3); cursor: pointer; font-weight: 600; font-family: var(--font-display); font-size: var(--step--1); }
.escape input { accent-color: var(--turq-600); margin-block-start: 0.25em; flex: 0 0 auto; }
.escape__note { font-size: var(--step--2); color: var(--turq-ink); margin-block-start: var(--sp-2); font-weight: 400; }

.field.is-invalid .input, .field.is-invalid .select, .field.is-invalid .textarea { border-color: #C2413B; }
.field__error { font-size: var(--step--2); color: #C2413B; }
.form__status { padding: var(--sp-5); border-radius: var(--radius); background: var(--turq-050); border: var(--hairline) solid var(--turq-200); }

/* --------------------------------------------------------------------------
   16. FOOTER
   -------------------------------------------------------------------------- */
.footer { background: var(--navy-950); color: var(--text-on-deep); padding-block: clamp(3rem, 5vw, 4.5rem) var(--sp-5); }
.footer a { text-decoration: none; }
.footer a:hover { color: var(--turquoise); }
.footer__top { display: grid; gap: var(--sp-6); }
@media (min-width: 58rem) { .footer__top { grid-template-columns: minmax(0, 1.3fr) repeat(2, minmax(0, 1fr)); gap: var(--sp-7); } }
.footer__logo svg { block-size: 2.6rem; inline-size: auto; }
.footer__tag { color: var(--text-on-deep-q); margin-block-start: var(--sp-4); max-inline-size: 32ch; }
.footer__h {
  font-family: var(--font-display);
  font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--turquoise);
  margin-block-end: var(--sp-4);
}
[dir="rtl"] .footer__h { letter-spacing: normal; text-transform: none; }
.footer__list { display: grid; gap: var(--sp-3); font-size: var(--step--1); }
.footer__social { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-block-start: var(--sp-5); }
.footer__social a { display: grid; place-items: center; inline-size: 2.4rem; block-size: 2.4rem; border: var(--hairline) solid var(--rule-deep); border-radius: 999px; transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease); }
.footer__social a:hover { border-color: var(--turquoise); background: rgb(44 191 213 / 0.12); }
.footer__social svg { inline-size: 1.05rem; block-size: 1.05rem; fill: currentColor; }
.footer__bottom {
  margin-block-start: var(--sp-6); padding-block-start: var(--sp-5);
  border-block-start: var(--hairline) solid var(--rule-deep);
  display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6);
  align-items: center; justify-content: space-between;
  font-size: var(--step--2); color: var(--text-on-deep-q);
}

/* WhatsApp: an inline channel, never a floating bubble. */
.channel { display: inline-flex; align-items: center; gap: var(--sp-3); text-decoration: none; }
/* Phone numbers and email addresses are LTR runs. Without isolation the bidi
   algorithm reorders the digit groups and throws the leading + to the far end. */
bdi { unicode-bidi: isolate; }
.channel bdi { font-variant-numeric: tabular-nums; }
.channel svg { inline-size: 1.1rem; block-size: 1.1rem; fill: currentColor; flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   17. MOTION
   --------------------------------------------------------------------------
   Six behaviours, each with a job. Everything is opt-in via [data-reveal] and
   everything stops entirely under prefers-reduced-motion.
   -------------------------------------------------------------------------- */
/* Hiding is gated on the `js` class, which is set by an inline script in <head>.
   With JavaScript disabled the class is never added, nothing is ever hidden,
   and the page renders complete — rather than blank, which is what happens if
   you put opacity:0 in the stylesheet unconditionally. */
.js [data-reveal] { opacity: 0; transform: translateY(18px); }
/* Fade-only variant. A transform on an ancestor becomes the containing block
   for any position:fixed descendant, which silently broke the map's sheet on
   touch - it resolved against the wrapper and landed a screenful below the
   viewport. The atlas wrapper therefore reveals by opacity alone, and never
   holds a transform at any point in the transition. */
.js [data-reveal="fade"] { transform: none; }
[data-reveal="fade"].is-in { transform: none; }
[data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* Hero entrance: one sequence, ~1.6s total, then the page is still. */
.js .hero [data-enter] { opacity: 0; transform: translateY(26px); }
.hero.is-ready [data-enter] {
  opacity: 1; transform: none;
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
  transition-delay: var(--enter-delay, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal], .hero [data-enter] { opacity: 1 !important; transform: none !important; }
  .figure img { transition: none; }
}

/* --------------------------------------------------------------------------
   18. PRINT
   -------------------------------------------------------------------------- */
@media print {
  .nav, .menu, .hero__scroll, .footer__social { display: none; }
  .hero, .section--deep { background: #fff !important; color: #000 !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}

/* --------------------------------------------------------------------------
   TRUST BAND — Phase 2
   --------------------------------------------------------------------------
   The first thing after the photograph is evidence. White Desert opens with
   IAATO and Carbon Neutral; a school does not care about either. This is the
   same gesture in the currency schools actually buy on: how long we have been
   doing it, how many students, how far, and who is standing with them.
   -------------------------------------------------------------------------- */
.band {
  background: var(--white);
  color: var(--navy);
  padding-block: clamp(var(--sp-7), 5vw, var(--sp-9));
  border-block-end: var(--hairline) solid var(--rule);
}
/* The band's own claim, set above the evidence it rests on. Display face, but
   held at a size that reads as a statement rather than competing with the
   section headings further down the page. */
.band__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-1);
  line-height: 1.35;
  color: var(--navy);
  margin-block-end: clamp(var(--sp-5), 2.5vw, var(--sp-7));
  max-inline-size: 42ch;
}
.band__grid {  display: grid;
  gap: var(--sp-6) clamp(var(--sp-5), 3vw, var(--sp-8));
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  align-items: start;
}
.band__item { display: grid; gap: var(--sp-2); align-content: start; }
/* A hairline rule on the inline-start edge — mirrors correctly, and gives the
   row rhythm without drawing boxes around anything. */
.band__item + .band__item {
  padding-inline-start: clamp(var(--sp-5), 3vw, var(--sp-8));
  border-inline-start: var(--hairline) solid var(--rule);
}
.band__fig {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 0.9;
  display: flex; align-items: baseline; gap: var(--sp-2);
  color: var(--navy);
}
.band__pre {
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--turq-ink);
}
/* Figures are Latin and tabular in both languages — they are read by
   comparison, which is the whole point of the band. */
.band__n {
  font-size: clamp(2.2rem, 1.3rem + 3vw, 4rem);
  font-variant-numeric: tabular-nums;
  direction: ltr;
}
.band__label { font-size: var(--step--1); color: var(--text-quiet); line-height: 1.5; max-inline-size: 22ch; }
/* The fourth item is a claim, not a number. It gets the turquoise weight the
   others get from their figure, so the row still scans as four equals. */
.band__item--claim .band__label {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-2);
  color: var(--navy);
  line-height: 1.2;
}
[dir="rtl"] .band__item--claim .band__label { line-height: 1.45; }
.band__note { font-size: var(--step--2); color: var(--turq-ink); }

/* --------------------------------------------------------------------------
   SPEC STRIP — Phase 3, data as design
   --------------------------------------------------------------------------
   The buying information a school actually reads — how far, how long, who is
   with the students — set as headline material rather than a table. Values
   large in the display face, labels small beneath. Unknowns are dimmed rather
   than hidden, so a school can see what is still to come instead of wondering
   whether it was omitted.
   -------------------------------------------------------------------------- */
.spec {
  display: grid;
  gap: var(--sp-5) clamp(var(--sp-5), 3vw, var(--sp-8));
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  margin-block-start: clamp(var(--sp-7), 4vw, var(--sp-9));
  padding-block-start: var(--sp-6);
  border-block-start: 2px solid var(--turq-500);
}
.spec__cell { display: grid; gap: var(--sp-2); align-content: start; }
.spec__v {
  font-family: var(--font-display);
  /* Pending values are distinguished by WEIGHT, not by fading the colour.
     Dimming to --ink-300 scored 2.08:1 on white — well under AA — and this is
     real information, not decoration. */
  font-weight: 500;
  font-size: var(--step-1);
  line-height: 1.25;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
[dir="rtl"] .spec__v { line-height: 1.5; }
.spec__v.is-known { color: var(--navy); font-weight: 800; }
.spec__k {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--turq-ink);
}
[dir="rtl"] .spec__k { letter-spacing: normal; text-transform: none; }
.section--deep .spec__v { color: var(--text-on-deep-q); }
.section--deep .spec__v.is-known { color: #fff; }
.section--deep .spec__k { color: var(--turquoise); }
/* --------------------------------------------------------------------------
   THE SIGNATURE — Phase 4
   --------------------------------------------------------------------------
   Vision > Design > Experience > Impact, the strongest idea in the brand, was
   a bulleted list. It is now the centrepiece.

   The connective line between stages is the identity diagonal at 12deg, doing
   structural work rather than sitting in a corner as decoration. The
   conventional route is deliberately quiet — smaller, greyed, unnumbered — so
   the comparison is made by weight rather than by criticising anyone.
   -------------------------------------------------------------------------- */
.routes { display: grid; gap: clamp(var(--sp-8), 5vw, var(--sp-10)); }
@media (min-width: 62rem) {
  .routes { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: start; }
}
.route__label {
  font-family: var(--font-display);
  font-size: var(--step--2); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--turq-ink);
  padding-block-end: var(--sp-4);
  border-block-end: 2px solid var(--turq-500);
  margin-block-end: var(--sp-7);
}
[dir="rtl"] .route__label { letter-spacing: normal; text-transform: none; }

.route__list { display: grid; gap: 0; }
.route__stage {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  padding-block: clamp(var(--sp-5), 2.5vw, var(--sp-7));
}
/* The diagonal connector. It runs between one stage's number and the next,
   leaning at the identity's 12deg, and flips with direction so the gesture
   reads the same way in both languages. */
.route__stage:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-block-start: 3.6rem;
  inset-inline-start: 1.15rem;
  block-size: calc(100% - 2.6rem);
  inline-size: 2px;
  background: var(--ink-200);
  transform: rotate(var(--diagonal));
  transform-origin: top center;
  transition: background var(--dur-3) var(--ease);
}
[dir="rtl"] .route__stage:not(:last-child)::after { transform: rotate(calc(var(--diagonal) * -1)); }

.route__n {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  direction: ltr;
  inline-size: 2.3rem; block-size: 2.3rem;
  display: grid; place-items: center;
  border-radius: 999px;
  border: 2px solid var(--ink-200);
  color: var(--ink-400);
  background: var(--white);
  transition: color var(--dur-3) var(--ease), border-color var(--dur-3) var(--ease),
              background var(--dur-3) var(--ease);
}
.route__name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-3);
  line-height: 1.1;
  color: var(--ink-400);
  transition: color var(--dur-3) var(--ease);
}
[dir="rtl"] .route__name { line-height: 1.35; }
.route__note { font-size: var(--step--1); color: var(--text-quiet); margin-block-start: var(--sp-2); max-inline-size: 34ch; }
.route__close { margin-block-start: var(--sp-6); font-size: var(--step--1); color: var(--text-quiet); max-inline-size: 40ch; }

/* Lit state. Stages arrive one at a time as the sequence enters view. */
.route__stage.is-on .route__n {
  color: var(--white); background: var(--navy); border-color: var(--navy);
}
.route__stage.is-on .route__name { color: var(--navy); }
.route__stage.is-on::after { background: var(--turq-500); }

/* The quiet counterpoint. */
.route--conv { padding-block-start: var(--sp-2); }
.route--conv .route__label { color: var(--ink-400); border-block-end-color: var(--ink-200); }
.route__plain { display: grid; gap: var(--sp-4); }
.route__plain li {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  /* --ink-400 measured 3.05:1 on the quiet surface at semibold, which needs
     4.5:1. Quiet must still be legible. */
  color: var(--ink-500);
  padding-inline-start: var(--sp-5);
  border-inline-start: 2px solid var(--ink-100);
  padding-block: var(--sp-1);
}

/* Without JS every stage is simply lit — the sequence is content, not an
   effect, so it must never depend on the observer running. */
.route__stage { }
html:not(.js) .route__stage .route__n { color: var(--white); background: var(--navy); border-color: var(--navy); }
html:not(.js) .route__stage .route__name { color: var(--navy); }
html:not(.js) .route__stage::after { background: var(--turq-500); }

@media (prefers-reduced-motion: reduce) {
  .route__stage, .route__n, .route__name { transition: none; }
}
/* --------------------------------------------------------------------------
   EDITORIAL BANDS — Phase 5
   --------------------------------------------------------------------------
   The eight delivered destinations were eight identical bordered rectangles in
   a grid. They are now editorial bands: a wide image against a typographic
   half, alternating side down the page. Cards survive only for the targeted
   list, where being visually subordinate is the correct signal — those are
   proposals, not evidence.
   -------------------------------------------------------------------------- */
.band-dests { display: grid; gap: clamp(var(--sp-8), 6vw, var(--sp-11)); }
.band-dest { display: grid; gap: clamp(var(--sp-5), 3vw, var(--sp-7)); align-items: center; }
@media (min-width: 62rem) {
  .band-dest { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
  /* Alternating the image side is the whole rhythm of the page. It is done by
     column order, not by direction, so it reads identically in RTL. */
  .band-dest--flip .band-dest__media { order: 2; }
}
.band-dest__media { display: block; }
.band-dest__body { display: grid; gap: var(--sp-3); align-content: center; }
.band-dest__index {
  font-family: var(--font-display);
  font-size: var(--step--2); font-weight: 800;
  letter-spacing: 0.2em;
  color: var(--gold-ink);
  font-variant-numeric: tabular-nums; direction: ltr;
}
[dir="rtl"] .band-dest__index { letter-spacing: normal; }
.band-dest__name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-4);
  line-height: 1.05;
}
[dir="rtl"] .band-dest__name { line-height: 1.3; }
.band-dest__name a { text-decoration: none; transition: color var(--dur-2) var(--ease); }
.band-dest:hover .band-dest__name a { color: var(--turq-ink); }
.band-dest__line { font-size: var(--step-1); color: var(--text-quiet); line-height: 1.5; max-inline-size: 38ch; }
[dir="rtl"] .band-dest__line { line-height: 1.8; }
.band-dest__meta {
  font-family: var(--font-display);
  font-size: var(--step--2); font-weight: 600;
  color: var(--turq-ink);
  font-variant-numeric: tabular-nums;
  padding-block-start: var(--sp-3);
  border-block-start: var(--hairline) solid var(--rule);
  margin-block-start: var(--sp-2);
  max-inline-size: 38ch;
}
.band-dest__go { margin-block-start: var(--sp-3); color: var(--navy); font-weight: 700; }
.band-dest:hover .band-dest__go .btn__arrow { transform: translateX(4px); }
[dir="rtl"] .band-dest:hover .band-dest__go .btn__arrow { transform: translateX(-4px); }
/* --------------------------------------------------------------------------
   DEPTH AND THE THREE STREAMS — Phase 6
   --------------------------------------------------------------------------
   Flat navy panels were the clearest "template" tell on the site. Every deep
   section now carries one duotoned photograph at low opacity plus a diagonal
   wash, so the darkness has material in it. The image is published once as a
   custom property; no section needs to know which picture it is.
   -------------------------------------------------------------------------- */
.section--deep { position: relative; isolation: isolate; }
.section--deep::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background-image: var(--deep-texture);
  background-size: cover;
  background-position: center;
  opacity: 0.09;
  /* Duotoned toward the identity rather than left as a colour photograph. */
  filter: grayscale(1) contrast(1.15);
  mix-blend-mode: luminosity;
  pointer-events: none;
}
/* The map is line art on a dark ground, and a photograph behind it - even at
   9% - competes with the coastlines instead of sitting under them. Its section
   keeps the diagonal wash for depth and drops the picture. Placed AFTER
   .section--deep::before deliberately: the two selectors carry equal
   specificity, so this only wins by coming later. */
.section--map::before { content: none; }
/* A wash along the identity diagonal, so the depth has direction rather than
   being an even fog. Flips with reading direction. */
.section--deep::after {
  content: "";
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(calc(90deg + var(--diagonal)),
              rgb(44 191 213 / 0.07) 0%, transparent 55%, rgb(247 164 64 / 0.05) 100%);
}
[dir="rtl"] .section--deep::after {
  background: linear-gradient(calc(90deg - var(--diagonal)),
              rgb(44 191 213 / 0.07) 0%, transparent 55%, rgb(247 164 64 / 0.05) 100%);
}

/* THREE STREAMS, ONE IDENTITY.
   Same palette, three temperatures — the differentiation is which brand colour
   leads, never a new colour. Domestic runs warm (orange, the Kingdom), the
   international streams run cool (turquoise, distance), and the accent appears
   as a top rule so the cards stay a set rather than becoming three designs. */
.card[data-stream] { border-block-start: 3px solid transparent; }
.card[data-stream="domestic"]     { border-block-start-color: var(--gold-500); }
.card[data-stream="winter"]       { border-block-start-color: var(--gold-500); }
.card[data-stream="international"]{ border-block-start-color: var(--turq-500); }
.card[data-stream="summer"]       { border-block-start-color: var(--turq-500); }
.card[data-stream="conference"]   { border-block-start-color: var(--ink-200); }
.card[data-stream="domestic"]:hover, .card[data-stream="winter"]:hover { border-color: var(--gold-500); }
.card[data-stream="international"]:hover, .card[data-stream="summer"]:hover { border-color: var(--turq-500); }
/* The warm streams carry a faint warm ground on their image, the cool ones a
   cool one — visible as a set, never as three different card designs. */
.card[data-stream="domestic"] .figure::after,
.card[data-stream="winter"] .figure::after   { background: linear-gradient(to top, rgb(247 164 64 / 0.22), transparent 62%); }
.card[data-stream="international"] .figure::after,
.card[data-stream="summer"] .figure::after   { background: linear-gradient(to top, rgb(44 191 213 / 0.22), transparent 62%); }
/* --------------------------------------------------------------------------
   CONTACT CHANNELS — each its own tappable row
   --------------------------------------------------------------------------
   Phone and email were sitting on one line, cramped and hard to hit on a
   phone. Each is now a labelled row with its own target well over the 44px
   minimum, and the number keeps Latin digits inside <bdi dir="ltr"> so the
   leading + and the grouping survive the right-to-left run.
   -------------------------------------------------------------------------- */
.channels { display: grid; gap: var(--sp-3); margin-block-start: var(--sp-5); }
.channels .channel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-4);
  min-block-size: 3rem;
  padding: var(--sp-3) var(--sp-4);
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--white);
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.channels .channel:hover { border-color: var(--turq-500); background: var(--turq-050); }
.channels .channel svg { inline-size: 1.15rem; block-size: 1.15rem; color: var(--turq-ink); }
.channel__text { display: grid; gap: 0.1rem; min-inline-size: 0; }
.channel__label {
  font-family: var(--font-display);
  font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--turq-ink);
}
[dir="rtl"] .channel__label { letter-spacing: normal; text-transform: none; }
.channel__value {
  font-size: var(--step--1);
  color: var(--navy);
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}
/* --------------------------------------------------------------------------
   PAGE HEAD
   --------------------------------------------------------------------------
   These classes were being emitted with no stylesheet behind them at all, so
   every interior page rendered its title with zero top padding and slid under
   the fixed header. It also fixes the "empty column" the critique flagged: the
   heading and its standfirst share a two-column grid that resolves on both
   sides instead of leaving half the row blank.
   -------------------------------------------------------------------------- */
.page-head {
  /* Clears the fixed header at every size — it is ~77px tall at desktop. */
  padding-block: clamp(7.5rem, 6rem + 6vw, 10rem) clamp(2.5rem, 2rem + 2vw, 4rem);
  background: var(--surface);
}
.page-head__grid {
  display: grid;
  gap: clamp(var(--sp-5), 3vw, var(--sp-8));
  align-items: end;
}
@media (min-width: 62rem) {
  .page-head__grid { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
}
.page-head__h {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-5);
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin-block-start: var(--sp-4);
  text-wrap: balance;
}
/* Kufi at display size needs room; it is also never tracked. */
[dir="rtl"] .page-head__h { line-height: 1.62; letter-spacing: normal; }
.page-head__lead {
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--text-quiet);
  max-inline-size: 46ch;
  padding-block-end: var(--sp-2);
}
[dir="rtl"] .page-head__lead { line-height: 1.9; }
/* --------------------------------------------------------------------------
   FOCUS PANEL
   --------------------------------------------------------------------------
   Once a stack of seventeen panels sharing one grid cell, with a close button
   and a phone sheet-mode, all of it serving a card that appeared on hover.
   That card is gone - it updated off-screen on desktop and it had to swallow
   the first touch on a phone, which broke scrolling. What remains is a single
   static panel stating the reach, so it needs no height reservation, no
   visibility swapping and no dismiss affordance.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   FLOATING WHATSAPP
   --------------------------------------------------------------------------
   Persistent on every page. Three decisions worth recording:

   1. It is NOT the stock green bubble. That colour belongs to another company
      and lands on our pages as a foreign object. Navy shell, white glyph,
      turquoise hairline - it reads as part of the site.
   2. It is pinned with logical insets, so it sits bottom-LEFT in Arabic and
      bottom-RIGHT in English off one declaration, always on the trailing side
      away from the reading edge.
   3. It sits BELOW the menu overlay (--z-nav, not --z-menu). Floating over an
      open full-screen menu is exactly the kind of thing that ends up covering
      a close button.

   Collapsed it is a 3rem circle. Pointer users get the label on hover; on
   touch, where hover does not exist, it stays a circle so it can never grow
   across a CTA. Below the tablet breakpoint it is smaller still.
   -------------------------------------------------------------------------- */
.wafloat {
  position: fixed;
  inset-block-end: clamp(1rem, 2.5vw, 1.75rem);
  inset-inline-end: clamp(1rem, 2.5vw, 1.75rem);
  z-index: var(--z-nav);
  display: inline-flex;
  align-items: center;
  gap: 0;
  block-size: 3rem;
  padding-inline: 0.75rem;
  border-radius: 999px;
  /* Gold body, turquoise ring. Navy read as a utility chip against a navy
     site; gold is the identity's one accent and it separates from every
     surface here - white, navy, photograph and video alike. The glyph is navy
     on gold: 6.2:1, where white on gold would have been 1.9:1 and illegible.
     The ring is a shadow rather than a border so it can sit outside the shape
     without changing its size on hover. */
  background: var(--gold);
  border: 0;
  box-shadow:
    0 0 0 2px rgb(44 191 213 / 0.75),
    0 0 0 6px rgb(44 191 213 / 0.18),
    0 0.5rem 1.5rem rgb(11 25 39 / 0.35);
  color: var(--navy-950);
  text-decoration: none;
  transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease),
              box-shadow var(--dur-2) var(--ease);
}
.wafloat svg { inline-size: 1.5rem; block-size: 1.5rem; fill: currentColor; flex: 0 0 auto; }
/* The label is width-animated rather than display-toggled so the circle grows
   into a pill instead of jumping. max-inline-size, not inline-size: the text
   is a different length in each language and must not be measured here. */
.wafloat__t {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 700;
  white-space: nowrap;
  max-inline-size: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-inline-size var(--dur-3) var(--ease-out),
              opacity var(--dur-2) var(--ease),
              margin-inline-start var(--dur-3) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .wafloat:hover, .wafloat:focus-visible {
    background: #FFB45C;
    box-shadow:
      0 0 0 2px var(--turquoise),
      0 0 0 8px rgb(44 191 213 / 0.26),
      0 0.65rem 1.75rem rgb(11 25 39 / 0.42);
  }
  .wafloat:hover .wafloat__t, .wafloat:focus-visible .wafloat__t {
    max-inline-size: 10rem;
    opacity: 1;
    margin-inline-start: 0.5rem;
  }
}
.wafloat:focus-visible { outline: 3px solid var(--navy); outline-offset: 4px; }
@media (max-width: 47.99rem) {
  /* calc, not max: the home-indicator inset must be ADDED to the gap, not
     compared with it, or on an iPhone the button sits on the indicator. */
  .wafloat { block-size: 3rem; padding-inline: 0.7rem;
             inset-block-end: calc(1rem + env(safe-area-inset-bottom, 0px));
             inset-inline-end: calc(1rem + env(safe-area-inset-right, 0px)); }
  .wafloat svg { inline-size: 1.375rem; block-size: 1.375rem; }
}
@media (prefers-reduced-motion: reduce) {
  .wafloat, .wafloat__t { transition: none; }
}
@media print { .wafloat { display: none; } }

/* ==========================================================================
   DESTINATION FACTS CARD
   ==========================================================================
   Replaces a six-column strip that spread the same six facts across the full
   page width. At that spacing the eye had to travel to pair a label with its
   value, and three cells reading "to confirm" made the set look unfinished
   rather than pending.

   It is ONE card divided into cells, not six boxes. The dividers are the
   grid's own gap letting the container colour through - which is why they stay
   exactly one hairline, never double at a junction, and re-flow correctly when
   the column count changes. It also means the component contains no
   directional border at all, so RTL needs no separate rule: the grid mirrors
   itself and the dividers land wherever the columns do.
   ========================================================================== */
/* Three items now, not six. The old rule reflowed 3 -> 2 -> 1 because six
   cells needed it; with three the middle step is pointless - two-up leaves a
   lone cell hanging - so it goes straight from one row to a stack. */
.facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--hairline);
  margin-block-start: clamp(var(--sp-6), 3vw, var(--sp-8));
  background: var(--rule);          /* shows through the gap as the divider */
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  overflow: hidden;                 /* keeps the cells inside the radius */
  box-shadow: 0 1px 2px rgb(27 58 87 / 0.04);
}
.facts__item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: clamp(var(--sp-5), 2.2vw, var(--sp-6));
  background: var(--surface);
}
/* The icon sits on a tinted disc so it reads as a mark, not as a stray
   glyph beside the text. Turquoise here is --turq-ink, the AA-safe
   derivation; #2CBFD5 on white is 2.0:1 and would fail even the 3:1 that
   non-text graphics need. */
.facts__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border-radius: 999px;
  background: var(--turq-050);
  color: var(--turq-ink);
}
.facts__icon .icon { inline-size: 1.125rem; block-size: 1.125rem; }
.facts__text { min-inline-size: 0; }
/* The label is the heading of the cell now: bigger, navy, display face. */
.facts__k {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.35;
}
[dir="rtl"] .facts__k { letter-spacing: normal; }
/* The value is the supporting line: smaller, quieter, body face. Arabic
   travel times run long ("نحو ١ س ٤٥ د طيرانًا من الرياض"), so this wraps
   rather than shrinking to fit. */
.facts__v {
  margin: 0;
  margin-block-start: 0.3rem;
  font-family: var(--font-body);
  font-size: var(--step--1);
  /* A pending figure is the SAME colour as a known one and differs only in
     weight. Greying it out is what made the old strip read as broken data. */
  font-weight: 500;
  color: var(--navy);
  line-height: 1.45;
  overflow-wrap: break-word;
}
.facts__v { color: var(--text-quiet); font-weight: 500; }
.facts__v.is-known { color: var(--text-quiet); font-weight: 600; }
@media (max-width: 47.99rem) {
  .facts { grid-template-columns: minmax(0, 1fr); }
  .facts__item { padding: var(--sp-5); align-items: center; }
}

/* ==========================================================================
   VISION AND MISSION
   ==========================================================================
   Same two-up structure as before; the two blocks are now paired panels with
   a shared inner rhythm so neither reads as longer than the other when the
   copy lengths differ. Equal height comes from the grid, not from a fixed
   size, so nothing clips at any width.
   ========================================================================== */
.vm {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--sp-5), 3vw, var(--sp-7));
  align-items: stretch;
}
.vm__card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: clamp(var(--sp-6), 3vw, var(--sp-8));
  background: rgb(255 255 255 / 0.04);
  border: var(--hairline) solid var(--rule-deep);
  border-radius: var(--radius-lg);
  /* The identity's diagonal, once per card and only on the leading corner. */
  border-start-start-radius: 0;
}
.vm__k {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--turquoise);
}
[dir="rtl"] .vm__k { letter-spacing: normal; text-transform: none; font-size: var(--step--1); }
.vm__t {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 500;
  line-height: 1.55;
  color: var(--text-on-deep);
  max-inline-size: 34ch;
}
@media (max-width: 47.99rem) {
  .vm { grid-template-columns: minmax(0, 1fr); }
  .vm__t { font-size: var(--step-0); max-inline-size: none; }
}

/* ==========================================================================
   VALUES
   ==========================================================================
   These were .chip elements - small, bordered, tinted pills. On a page of
   statements they read as filter controls, and a filter you cannot click is
   worse than no affordance at all. They are cards now: icon, name, line.

   Five items into a three-column grid leaves an orphan row of two. Rather
   than stretch them, the last two are centred under the first three by
   offsetting the fourth card half a column - so the second row reads as
   deliberate rather than as a grid that ran out.
   ========================================================================== */
.values {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(var(--sp-4), 2vw, var(--sp-6));
  margin-block-start: clamp(var(--sp-6), 3vw, var(--sp-7));
}
.values > .value { grid-column: span 2; }
.values > .value:nth-child(4) { grid-column: 2 / span 2; }
.values > .value:nth-child(5) { grid-column: 4 / span 2; }
.value {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: clamp(var(--sp-5), 2.4vw, var(--sp-6));
  background: var(--surface);
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  /* Not a link, so no pointer, no lift and no shadow at rest. */
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}
.value__icon {
  display: grid;
  place-items: center;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border-radius: 999px;
  background: var(--turq-050);
  color: var(--turq-ink);
  margin-block-end: var(--sp-2);
}
.value__icon .icon { inline-size: 1.25rem; block-size: 1.25rem; }
.value__h {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.4;
}
.value__t {
  font-size: var(--step--1);
  color: var(--text-quiet);
  line-height: 1.65;
}
/* Gold is the accent, so it appears once: a hairline that answers the hover
   rather than a colour wash. Pointer devices only - on touch a permanent
   hover state sticks after the tap. */
@media (hover: hover) and (pointer: fine) {
  .value:hover { border-color: var(--gold-200); background: var(--ink-050); }
  .value:hover .value__icon { background: var(--gold-050); color: var(--gold-ink); }
}
@media (max-width: 61.99rem) {
  .values { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .values > .value,
  .values > .value:nth-child(4),
  .values > .value:nth-child(5) { grid-column: span 2; }
}
@media (max-width: 40rem) {
  .values { grid-template-columns: minmax(0, 1fr); }
  .values > .value,
  .values > .value:nth-child(4),
  .values > .value:nth-child(5) { grid-column: auto; }
}

/* ==========================================================================
   TARGETED DESTINATIONS, SPLIT INTO TWO GROUPS
   ==========================================================================
   International and local, inside one section. Identical card, identical
   grid, identical image ratio: the moment the local half gets a smaller
   treatment it reads as the lesser list. The only difference is the accent
   on the group heading's rule - turquoise for international, gold for local -
   which is enough to separate them without implying a hierarchy.
   ========================================================================== */
.tgroup + .tgroup { margin-block-start: clamp(var(--sp-8), 5vw, var(--sp-9)); }
/* An EXPLICIT three-track grid, not the shared auto-fit .grid--3. Auto-fit
   sizes tracks to the item count, so the six international cards packed into
   four columns while the two local ones stretched to half the shell each -
   twice the width, twice the image height, and a local half that no longer
   matched the international one. Fixed tracks keep every card in this section
   identical and simply leave the empty tracks empty. */
.tgroup__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-6);
  align-items: stretch;
}
@media (max-width: 61.99rem) { .tgroup__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem)    { .tgroup__grid { grid-template-columns: minmax(0, 1fr); } }
.tgroup__h {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 800;
  color: var(--navy);
  margin-block-end: clamp(var(--sp-5), 2.5vw, var(--sp-6));
}
/* The rule runs to the end of the line and mirrors with the text direction,
   because it is flex order rather than a float. */
.tgroup__h::after {
  content: "";
  flex: 1 1 auto;
  block-size: 2px;
  border-radius: 2px;
  background: var(--turq-200);
}
.tgroup--local .tgroup__h::after { background: var(--gold-200); }
@media (max-width: 40rem) {
  .tgroup__h { font-size: var(--step-0); }
}

/* ==========================================================================
   HERO VIDEO
   ==========================================================================
   Approved 2026-08-21. Three vertical panels, twelve clips, four destinations.
   The Al-Qarah photograph is still built and still in the library; this
   replaces it as the hero, it does not remove it.

   The <img> underneath is not decoration. It is the LCP element and it paints
   first, carrying srcset and intrinsic dimensions. The video sits on top at
   opacity 0 and only fades in once the browser reports it can actually play,
   so a stalled or refused autoplay leaves a finished-looking hero rather than
   a black rectangle. The poster is the video's own first frame, which is why
   the hand-off is invisible.
   -------------------------------------------------------------------------- */
.hero__video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* The panels are a composition, not a photograph: centring is correct here,
     and unlike the old crop there is no subject to keep in frame. */
  object-position: center center;
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-out);
  pointer-events: none;
  /* MUST be -2, level with .hero__img. The veil is at -1, so anything above
     that renders OVER the scrim and the headline loses its ground - measured
     2.66:1 on the panel footage before this was corrected. Sitting at -2 and
     later in the DOM puts the video above the still and below the veil, which
     is the only ordering that works. */
  z-index: -2;
}
.hero__video.is-playing { opacity: 1; }

/* THIS RULE USED TO BE display:none AND IT IS WHY THE VIDEO DID NOT PLAY ON
   IPHONE. The reasoning was sound - a 16:9 triptych on a 9:16 screen shows
   about a fifth of one panel - but the remedy was wrong: hiding the element
   and refusing to load it looked identical to a codec or server fault.
   Phones now get voyra-hero-portrait.mp4, a portrait cut of the same approved
   footage, so the element stays visible and object-position moves to the top
   where a vertical frame carries its subject. */
@media (max-width: 47.99rem) {
  .hero__video { object-position: center 42%; }
}

/* Reduced motion: never show it, whatever the script does. */
@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none !important; }
}

/* Printing a video frame is meaningless; the poster prints. */
@media print { .hero__video { display: none; } }

/* Shown only when autoplay is actually refused - iOS Low Power Mode does this
   unconditionally, whatever the markup says. The poster stays put behind it,
   so the hero still looks finished; this just gives the visitor a way to act
   on it. Injected by script, so it never appears when autoplay works. */
.hero__play {
  position: absolute;
  inset-block-end: clamp(1.25rem, 5vw, 2.5rem);
  inset-inline-end: clamp(1.25rem, 5vw, 2.5rem);
  z-index: 3;
  inline-size: 3.25rem;
  block-size: 3.25rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: var(--hairline) solid rgb(255 255 255 / 0.55);
  border-radius: 999px;
  background: rgb(11 25 39 / 0.55);
  backdrop-filter: blur(6px);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.hero__play svg { inline-size: 1.5rem; block-size: 1.5rem; fill: currentColor; }
.hero__play:hover { background: rgb(11 25 39 / 0.78); border-color: #fff; }
.hero__play:focus-visible { outline: 2px solid var(--turquoise); outline-offset: 3px; }

/* ==========================================================================
   PER-IMAGE FOCAL POINTS
   ==========================================================================
   Every figure crops. A 3:2 photograph inside a 3:4 card loses a third of its
   frame, and the middle is only the right third by accident - the Clock Tower
   starts at the top of its picture, a lone figure in the Madinah plaza sits
   near the bottom. --focus is set per image from content/image-art.json.

   The property is read here rather than written as an inline object-position
   so the rule lives in the stylesheet and the markup carries only data. An
   image with no entry falls back to 50% 50%, which is exactly what the site
   did before this existed.
   ========================================================================== */
.figure img { object-position: var(--focus, 50% 50%); }

/* The destination bands are 16:9 beside their text on a wide screen, which is
   right there. On a phone the text moves below and the picture takes the whole
   width - and a 16:9 window onto a 3:4 photograph is a letterbox slit through
   the middle of it, discarding roughly 70% of the frame. At that breakpoint the
   band relaxes to 4:5 and <source media> swaps in the mobile rendition, so the
   taller picture has somewhere to go. */
@media (max-width: 47.99rem) {
  .band-dest .figure--wide { aspect-ratio: 4 / 5; }
}

/* <picture> wraps the hero image now. It is a non-rendering grouping element,
   but it still generates an inline box, so it must not sit between the hero
   and its absolutely-positioned image. */
.hero__picture { display: contents; }

/* ==========================================================================
   PATH COMPARISON
   ==========================================================================
   Replaces .routes, where VOYRA had four numbered, described, connected
   stages and the conventional route had three bare words in a box a third the
   height. One column read as a considered process and the other as a stub
   floating beside it - which is not a comparison, it is a straw man that also
   looked broken.

   Both sides are now the same component: a numbered track with a connector,
   a title and a line of explanation per step. The difference is carried by
   colour and by what the steps SAY. The conventional route is not mocked; it
   is simply shorter, and being shorter is the whole point.
   ========================================================================== */
.compare {
  display: grid;
  gap: clamp(var(--sp-6), 3vw, var(--sp-8));
  align-items: start;
}
@media (min-width: 62rem) {
  /* Equal columns, and the two tracks share ROWS through subgrid so the
     comparison actually lines up: destination beside vision, booking beside
     design, trip beside experience. Unequal widths and free-floating rows were
     hiding the entire argument - which is the fourth row, where VOYRA has
     "impact" and the conventional path has run out. That gap is the point of
     the section, so it is now a deliberate, visible hole rather than the
     accident of one column being shorter. */
  .compare {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto repeat(4, auto) auto;
  }
  .compare > .track {
    grid-row: 1 / -1;
    display: grid;
    grid-template-rows: subgrid;
  }
  .compare > .track > .track__head  { grid-row: 1; }
  .compare > .track > .track__list  { grid-row: 2 / 6; display: grid; grid-template-rows: subgrid; }
  .compare > .track > .track__close { grid-row: 6; }

  /* The empty fourth slot, marked rather than left blank so it reads as
     "nothing happens here" instead of a layout fault. */
  .compare > .track--conv > .track__list::after {
    content: "";
    grid-row: 4 / 5;
    align-self: center;
    block-size: 2px;
    inline-size: 3rem;
    margin-inline-start: 0.35rem;
    background: repeating-linear-gradient(90deg, var(--rule) 0 6px, transparent 6px 12px);
  }
}

.track {
  display: flex;
  flex-direction: column;
  padding: clamp(var(--sp-5), 2.5vw, var(--sp-7));
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--surface);
  block-size: 100%;
}
.track--voyra {
  border-color: var(--turq-200);
  background: linear-gradient(180deg, var(--turq-050) 0%, var(--surface) 42%);
}
.track--conv { background: var(--ink-050); }

.track__head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding-block-end: var(--sp-5);
  margin-block-end: var(--sp-5);
  border-block-end: var(--hairline) solid var(--rule);
}
.track__label {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.3;
}
.track--conv .track__label { color: var(--text-quiet); }

.track__list { list-style: none; display: grid; gap: 0; flex: 1 1 auto; }

/* The connector is drawn on the step, not as a separate element, so it can
   never fall out of alignment with the numbers it joins - which is what
   happened to the old diagonal at small widths. The last step draws none. */
.track__step {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4);
  padding-block-end: var(--sp-6);
}
.track__step:last-child { padding-block-end: 0; }
.track__step::before {
  content: "";
  position: absolute;
  inset-block-start: 2.25rem;
  inset-block-end: 0.35rem;
  inset-inline-start: 1.09rem;      /* the number's centre line */
  inline-size: 2px;
  background: var(--rule);
}
.track__step:last-child::before { display: none; }
.track--voyra .track__step::before { background: var(--turq-200); }

.track__n {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  background: var(--ink-100);
  color: var(--text-quiet);
}
[dir="rtl"] .track__n { letter-spacing: normal; }
.track--voyra .track__n { background: var(--turq-ink); color: #fff; }

.track__body { min-inline-size: 0; padding-block-start: 0.2rem; }
.track__name {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 700;
  color: var(--navy);
  line-height: 1.4;
}
.track--conv .track__name { color: var(--ink-500); font-weight: 600; }
.track__note {
  margin-block-start: 0.35rem;
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-quiet);
  max-inline-size: 46ch;
}
.track__close {
  margin-block-start: var(--sp-6);
  padding-block-start: var(--sp-5);
  border-block-start: var(--hairline) solid var(--rule);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.65;
  color: var(--text-quiet);
}
.track--voyra .track__close { color: var(--turq-ink); }

@media (max-width: 40rem) {
  .track__step { gap: var(--sp-3); padding-block-end: var(--sp-5); }
  .track__n { inline-size: 2rem; block-size: 2rem; }
  .track__step::before { inset-inline-start: 0.97rem; inset-block-start: 2rem; }
}

/* The section heading was the same size as its own standfirst's neighbours and
   lost to the comparison below it. Up one step, with the kicker pulled down
   and the lead given room, so label -> title -> intro reads as three levels
   rather than two. Clamped so it does not overpower on a phone. */
.route-section .section__h {
  font-size: clamp(1.9rem, 1.1rem + 3.2vw, 3.35rem);
  line-height: 1.18;
  margin-block-start: var(--sp-3);
  max-inline-size: 20ch;
}
[dir="rtl"] .route-section .section__h { line-height: 1.32; }
.route-section .u-kicker { margin-block-end: var(--sp-2); }
.route-section .u-lead { margin-block-start: var(--sp-5); max-inline-size: 62ch; }

/* ==========================================================================
   TRUST BAR - three items, the number in the middle
   ==========================================================================
   Order is destinations, students, supervision. 250+ is the strongest figure
   so it holds the centre; leading with it left the strip front-loaded and the
   third item reading as an afterthought.

   The centre gets weight from SIZE and a tinted ground, not from shrinking its
   neighbours - all three keep the same box and the same rhythm. The third item
   has no figure, so its title takes the figure's slot and its supporting line
   sits underneath, which keeps the three baselines aligned.
   ========================================================================== */
@media (min-width: 48rem) {
  .band__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
  .band__item { padding-block: var(--sp-2); }
  .band__item--lead .band__n { font-size: clamp(2.6rem, 1.4rem + 3.4vw, 4.1rem); color: var(--turq-ink); }
  .band__item--lead {
    padding-inline: clamp(var(--sp-5), 3vw, var(--sp-8));
    background: linear-gradient(180deg, var(--turq-050), transparent 78%);
    border-radius: var(--radius-lg);
  }
}
/* A no-figure item would otherwise start half a line lower than its
   neighbours; the title stands in for the figure and holds the baseline. */
.band__item--claim .band__label {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.25;
  max-inline-size: none;
}
.band__item--claim .band__note {
  margin-block-start: 0.4rem;
  font-size: var(--step--1);
  color: var(--text-quiet);
  line-height: 1.6;
  max-inline-size: 34ch;
}

/* Below the three-up breakpoint the items stack as full-width rows with a
   rule between them, rather than three columns squeezed to a third of a
   phone. The lead item keeps its tint so the hierarchy survives the stack. */
@media (max-width: 47.99rem) {
  .band__grid { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .band__item + .band__item {
    padding-inline-start: 0;
    border-inline-start: 0;
    border-block-start: var(--hairline) solid var(--rule);
  }
  .band__item { padding-block: var(--sp-5); }
  .band__item--lead {
    padding-inline: var(--sp-5);
    background: linear-gradient(180deg, var(--turq-050), transparent);
    border-radius: var(--radius-lg);
  }
  .band__item--lead .band__n { color: var(--turq-ink); }
  .band__label { max-inline-size: none; }
}

/* The local group holds two cards in a three-track grid, so they sat in the
   first two columns with an empty third beside them - reading as a row that
   had lost a card rather than as a deliberate pair. Auto-flow centring keeps
   the card WIDTH identical to the international grid (the tracks are still a
   third of the shell) while placing the pair in the middle. */
@media (min-width: 40rem) {
  .tgroup--local .tgroup__grid {
    grid-template-columns: repeat(2, minmax(0, calc((100% - 2 * var(--sp-6)) / 3)));
    justify-content: center;
  }
}

/* ==========================================================================
   DELIVERED DESTINATIONS - one link, one target, one visual system
   ==========================================================================
   The block used to hold two anchors plus a <span class="btn"> that looked
   like a button and did nothing. It is now a single <a> wrapping the whole
   card: one tab stop, one destination, and the entire image is a click area
   on touch. Every child is inline-level because they live inside an anchor.

   The alternating editorial layout is kept - it gives the page rhythm the
   card grids cannot - but everything else is aligned with the targeted-
   destination cards: the same tag component, the same image ratio behaviour,
   the same hover language.
   ========================================================================== */
.band-dest__link {
  display: grid;
  gap: clamp(var(--sp-5), 3vw, var(--sp-7));
  align-items: center;
  text-decoration: none;
  color: inherit;
  border-radius: var(--radius-lg);
}
@media (min-width: 62rem) {
  .band-dest__link { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
  /* The flip alternates which side the picture sits on. Explicit placement,
     because source order must stay image-then-text for a screen reader. */
  .band-dest--flip .band-dest__media { grid-column: 2; grid-row: 1; }
  .band-dest--flip .band-dest__body  { grid-column: 1; grid-row: 1; }
}
.band-dest__media { display: block; min-inline-size: 0; overflow: hidden; border-radius: var(--radius-lg); }
.band-dest__body  { display: block; min-inline-size: 0; }

.band-dest__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-block-end: var(--sp-4);
}
.band-dest__index {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--ink-300);
}
[dir="rtl"] .band-dest__index { letter-spacing: normal; }

.band-dest__name {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1rem + 1.9vw, 2.35rem);
  font-weight: 800;
  line-height: 1.25;
  color: var(--navy);
}
[dir="rtl"] .band-dest__name { line-height: 1.4; }
.band-dest__line {
  display: block;
  margin-block-start: var(--sp-4);
  font-size: var(--step-0);
  line-height: 1.75;
  color: var(--text-quiet);
  max-inline-size: 48ch;
}
.band-dest__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  margin-block-start: var(--sp-5);
  font-size: var(--step--1);
  color: var(--text-quiet);
}
.band-dest__meta .icon { inline-size: 1rem; block-size: 1rem; color: var(--turq-ink); flex: 0 0 auto; }

/* Reads as a link and behaves as one, but it is a <span> inside the card's
   single anchor - a nested <a> would be invalid and would split the tab
   order in two. */
.band-dest__go {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  margin-block-start: var(--sp-5);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--turq-ink);
  border-block-end: 2px solid transparent;
  padding-block-end: 2px;
  transition: border-color var(--dur-2) var(--ease), gap var(--dur-2) var(--ease);
}
/* The arrow is mirrored for RTL by the same rule that mirrors every other
   arrow on the site, so it always points along the reading direction. */
.band-dest__go .btn__arrow { transition: transform var(--dur-2) var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
  .band-dest__link:hover .band-dest__go { border-block-end-color: var(--turq-ink); gap: var(--sp-4); }
  .band-dest__link:hover .band-dest__go .btn__arrow { transform: translateX(0.2rem); }
  [dir="rtl"] .band-dest__link:hover .band-dest__go .btn__arrow { transform: translateX(-0.2rem); }
  .band-dest__link:hover .figure img { transform: scale(1.04); }
  .band-dest__link:hover .band-dest__name { color: var(--turq-ink); }
}
.band-dest__link .figure img { transition: transform var(--dur-3) var(--ease-out); }

/* One focus ring around the whole card, which is the whole target. */
.band-dest__link:focus-visible {
  outline: 3px solid var(--turq-600);
  outline-offset: 6px;
}

/* The gap between bands was set for a layout with a floating index number
   above each one; without it the rhythm can tighten considerably. */
.band-dests { display: grid; gap: clamp(var(--sp-8), 6vw, var(--sp-9)); }

/* ==========================================================================
   LEGAL PAGES
   ==========================================================================
   Privacy, terms and cookies. These are read under stress - a parent checking
   what happens to their child's photograph, a school bursar checking a refund
   deadline - so they are set for reading, not for skimming: one column, a
   generous measure, numbered sections so a lawyer can cite one.
   ========================================================================== */
.legal { max-inline-size: 68ch; }
.legal__updated {
  font-size: var(--step--1);
  color: var(--text-quiet);
  padding-block-end: var(--sp-5);
  margin-block-end: var(--sp-7);
  border-block-end: var(--hairline) solid var(--rule);
}
.legal__sec + .legal__sec { margin-block-start: clamp(var(--sp-7), 4vw, var(--sp-8)); }
.legal__h {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 800;
  line-height: 1.35;
  color: var(--navy);
  margin-block-end: var(--sp-4);
}
.legal__n {
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--turq-ink);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
[dir="rtl"] .legal__n { letter-spacing: normal; }
.legal__body p {
  font-size: var(--step-0);
  line-height: 1.85;
  color: var(--text-quiet);
}
.legal__body p + p { margin-block-start: var(--sp-4); }
/* The [[ ]] markers are unresolved facts, not copy. They are meant to be
   impossible to miss during review and must all be gone before launch. */
.legal__body p:has(+ p) { }

/* Footer legal block: links, copyright, registration, image credits. */
.footer__legal { display: grid; gap: var(--sp-3); margin-block-start: var(--sp-5); }
.footer__legalnav { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); }
.footer__legalnav a {
  font-size: var(--step--1);
  color: var(--text-on-deep-q);
  text-decoration: none;
  border-block-end: var(--hairline) solid transparent;
}
.footer__legalnav a:hover { color: #fff; border-block-end-color: currentColor; }
.footer__cr, .footer__credits {
  font-size: var(--step--2);
  color: var(--text-on-deep-q);
  line-height: 1.7;
}
.footer__credits a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* A single photograph standing alone on a destination page. Centred, capped so
   a wide panorama cannot run edge to edge on a large screen, and rounded to
   match the grid cards it replaces. */
.figure-solo { max-inline-size: 60rem; margin-inline: auto; }

/* --------------------------------------------------------------------------
   FOOTER — REORGANISED
   --------------------------------------------------------------------------
   Three changes, all about weight. The two direct channels moved up under the
   social row so the identity block carries everything a visitor might contact
   us through. WhatsApp joined the social icons instead of sitting alone on a
   line halfway down. And the bottom strip became two halves rather than one
   centred stack of five items, which had been giving a licence footnote the
   same prominence as the copyright.
   -------------------------------------------------------------------------- */
.footer__channels {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-6);
  margin-block-start: var(--sp-5);
  font-size: var(--step--1);
}
.footer__channels .channel { color: var(--text-on-deep-q); }
.footer__channels .channel:hover { color: #fff; }

/* WhatsApp reads as a channel among channels, with just enough tint to be
   findable without becoming the loudest thing in the footer. */
.footer__social--wa { border-color: var(--turq-ink) !important; }
.footer__social--wa:hover { border-color: var(--turquoise) !important; }

.footer__bottom {
  align-items: start;
  gap: var(--sp-5) var(--sp-8);
}
.footer__legal { margin-block-start: 0; }
.footer__registry {
  display: grid; gap: var(--sp-2);
  text-align: end;
  margin-inline-start: auto;
}
.footer__rights { margin: 0; }
@media (max-width: 47.99rem) {
  /* Stacked, both halves read from the same edge - a right-aligned block under
     a left-aligned one looks like a mistake rather than a column. */
  .footer__registry { text-align: start; margin-inline-start: 0; }
}

/* --------------------------------------------------------------------------
   BACK TO TOP
   --------------------------------------------------------------------------
   Stacked directly above the WhatsApp float on the same trailing edge, so the
   two read as one column of utilities rather than two things fighting for a
   corner. Quiet by design: an outline chip on the page's own navy, because it
   is a convenience and WhatsApp is the call to action - only one of them
   should be gold.

   It stays out of the way until it is useful. The script unsets [hidden] once
   the visitor is roughly a screen and a half down; offered before that, a
   "back to top" is just clutter over the hero.
   -------------------------------------------------------------------------- */
.totop {
  position: fixed;
  inset-block-end: calc(clamp(1rem, 2.5vw, 1.75rem) + 3.75rem);
  inset-inline-end: clamp(1rem, 2.5vw, 1.75rem);
  z-index: var(--z-nav);
  inline-size: 3rem; block-size: 3rem;
  display: grid; place-items: center;
  padding: 0;
  border: 1.5px solid rgb(255 255 255 / 0.28);
  border-radius: 999px;
  background: rgb(11 25 39 / 0.72);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.totop[hidden] { display: none; }
.totop.is-in { opacity: 1; transform: none; }
.totop:hover { border-color: var(--turquoise); background: rgb(11 25 39 / 0.9); }
.totop:focus-visible { outline: 2px solid var(--turquoise); outline-offset: 3px; }
.totop svg { inline-size: 1.15rem; block-size: 1.15rem; }

@media (max-width: 47.99rem) {
  .totop { inline-size: 2.6rem; block-size: 2.6rem; inset-block-end: calc(clamp(1rem, 2.5vw, 1.75rem) + 3.25rem); }
}
/* While the map sheet is open it owned the corner; nothing else may sit there. */
html[data-map-sheet] .totop { display: none; }
@media (prefers-reduced-motion: reduce) {
  .totop { transition: opacity var(--dur-1) var(--ease); transform: none; }
}


/* --------------------------------------------------------------------------
   DELIVERED DESTINATIONS — GRID
   --------------------------------------------------------------------------
   Was eight alternating left/right bands. As a list of announcements that
   worked; as a way to compare eight places at a glance it did not, because
   the eye had to find a new starting edge on every row. The targeted section
   below was already a grid and read better, so delivered now uses the same
   card, four across instead of three.

   Four, then three, then two, then one. Eight cards divide cleanly into 4+4
   on a desktop and 2+2+2+2 on a tablet, so no row is ever left with a single
   orphan card.
   -------------------------------------------------------------------------- */
.dgrid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-6);
  align-items: stretch;
}
@media (max-width: 74rem)    { .dgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 56rem)    { .dgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 34rem)    { .dgrid { grid-template-columns: minmax(0, 1fr); } }

/* The two things a delivered card carries that a targeted one does not. */
.card--dest .card__body { display: flex; flex-direction: column; gap: var(--sp-3); }
.card--dest .tag { align-self: flex-start; }
.card--dest .card__title { margin: 0; }
.card--dest .card__text { margin: 0; flex: 1 1 auto; }
.card__meta {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--step--2);
  color: var(--text-quiet);
  padding-block-start: var(--sp-3);
  border-block-start: var(--hairline) solid var(--rule);
}
.card__meta .icon { inline-size: 1rem; block-size: 1rem; flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   CARD IMAGES — NO SCRIM
   --------------------------------------------------------------------------
   The scrim on .figure exists so white text can sit ON a photograph and stay
   legible, and .figure--protected darkens further still. Neither job applies
   to a card: its title, standfirst and meta all sit in the body BELOW the
   picture, never over it.

   So on cards the gradient was doing nothing but dimming every photograph by
   30% at the top and 80% at the bottom - which is why the destination grid
   read as a wall of murky night shots when the originals are bright.

   Removed only where there is no overlaid text. Bands, heroes and any figure
   that does carry a caption keep their scrim untouched.
   -------------------------------------------------------------------------- */
.card .figure::after,
.dgrid .figure::after,
.tgroup__grid .figure::after { background: none; }
