/* ═════════════════════════════════════════════════════════════════════════════ */

:root {
  --navy: #1a3c6e;
  --navy-dark: #12294c;
  --accent: #f0a500;
  --cta: #3e77b4;
  --cta-dark: #33678f;
  --ink: #1f2933;
  --muted: #5a6572;
  --line: #e4e8ee;
  --bg-soft: #f6f8fb;
  --radius: 14px;
  --max: 1080px;
}

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

/* ── IBM Plex ────────────────────────────────────────────────────────────── */
/*
 * Self-hosted from assets/fonts/ — run ./scripts/fetch-fonts.sh once to
 * populate it. A fonts.googleapis.com <link> would be fewer moving parts, but
 * it sends every visitor's IP to a third party on every page load, which this
 * project would rather not add to the Privacy Notice.
 *
 * IBM Plex Sans for Latin, Cairo for Arabic — two families, listed in that
 * order in the stack below. IBM Plex Sans contains no Arabic glyphs, so
 * Arabic text falls through to Cairo by itself: no `html[lang="ar"]` rule
 * needed, and a mixed string like "تعرّف على iDrive2" gets the right face on
 * each half.
 *
 * The order also means Cairo's own Latin glyphs are never reached, which is
 * why only its Arabic subset is downloaded.
 *
 * Plex Sans Arabic was here first and was replaced on the grounds that it
 * reads as a technical face — low contrast, angular joins — which suits IBM
 * and not a consumer marketplace. Cairo is the ordinary modern choice for
 * Arabic UI in the Gulf, which is the point: it should look unremarkable.
 *
 * `font-display: swap` on purpose: the system font shows immediately and is
 * replaced when Plex arrives. The alternative, invisible text for up to three
 * seconds, is worse on a slow connection than a brief reflow.
 */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/assets/fonts/ibm-plex-sans-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/assets/fonts/ibm-plex-sans-latin-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/assets/fonts/ibm-plex-sans-latin-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
/* 700 is the heaviest weight IBM Plex Sans ships. The stylesheet asks for 800
   in ten places; rather than chase those down, this entry claims 700-800 so
   the browser uses real Bold instead of synthesising a heavier one, which is
   what produces the smeared look. */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/assets/fonts/ibm-plex-sans-latin-700.woff2") format("woff2");
  font-weight: 700 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cairo";
  src: url("/assets/fonts/cairo-arabic-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Cairo";
  src: url("/assets/fonts/cairo-arabic-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Cairo";
  src: url("/assets/fonts/cairo-arabic-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Cairo";
  src: url("/assets/fonts/cairo-arabic-700.woff2") format("woff2");
  font-weight: 700 800;
  font-style: normal;
  font-display: swap;
}

/*
 * ── THE FONT SWITCH ───────────────────────────────────────────────────────
 *
 * Back on the OS stack, exactly as the site shipped before any webfont work:
 * SF Pro on Apple, Segoe UI on Windows, Roboto on Android. Arabic therefore
 * falls to whatever the OS supplies — Geeza Pro, Tahoma — which is the thing
 * that prompted the webfont work in the first place. This is a deliberate
 * pause, not a conclusion.
 *
 * The @font-face blocks above are left in place and are simply unreferenced,
 * so turning a face back on is ONE line: put its family at the front of this
 * stack. Nothing else has to move.
 *
 *   IBM Plex Sans + Cairo:   "IBM Plex Sans", "Cairo", system-ui, …
 *   Latin only:              "IBM Plex Sans", system-ui, …
 *
 * Whatever goes in front must have the matching files in assets/fonts/ —
 * ./scripts/fetch-fonts.sh puts them there, and build.py reports what is
 * missing.
 */
body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  color: var(--ink);
  line-height: 1.65;
  background: #fff;
}

html[lang="ar"] body {
  font-size: 1.05rem;
  line-height: 1.85;
}

img {
  max-width: 100%;
  height: auto;
}

a {
  color: var(--navy);
}

.wrap {
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: 20px;
}

/* ── Skip link ────────────────────────────────────────────────────────────── */
.skip {
  position: absolute;
  inset-inline-start: -9999px;
  top: 0;
  background: var(--navy);
  color: #fff;
  padding: 10px 16px;
  z-index: 100;
}
.skip:focus {
  inset-inline-start: 0;
}

/* ── Header ─────────────────────────────────────────────────────────────── */

header.site {
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(8px);
  z-index: 20;
}

header.site .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 12px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  color: var(--navy);
  text-decoration: none;
  font-size: 1.15rem;
}

.brand img {
  width: 34px;
  height: 34px;
}

.brand img.brand-wide {
  width: auto;
  height: 64px;
  max-inline-size: 320px;
}

nav.site a {
  margin-inline-start: 18px;
  text-decoration: none;
  color: var(--ink);
  font-weight: 600;
  font-size: 1.02rem;
}

nav.site a:hover {
  color: var(--navy);
}

nav.site a.lang-switch {
  /* 34px where every other link gets 18px: the extra 16 separates the two
     ACTIONS — switch language, get the app — from the six navigation links,
     which were reading as one undifferentiated run of items.
     margin-inline-start, so Arabic pushes them the other way.

     Safe to put on the base rule: the stacked mobile nav resets it with
     `header.site.js-nav nav.site a { margin-inline-start: 0 }`, which is
     (0,3,3) against this rule's (0,2,2) and therefore still wins. */
  margin-inline-start: 34px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 14px;
  font-weight: 700;
  font-size: 0.85rem;
  text-decoration: none;
  color: var(--navy);
}

/* ── Header: the mobile menu button ─────────────────────────────────────── */

.navtoggle {
  display: none;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 1px solid var(--line);
  border-radius: 11px;
  inline-size: 44px;
  block-size: 44px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--navy-dark);
  flex: none;
}

.navtoggle:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.navtoggle-bars {
  position: relative;
  display: block;
  inline-size: 19px;
  block-size: 2px;
  background: currentColor;
  border-radius: 2px;
}

.navtoggle-bars::before,
.navtoggle-bars::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inline-size: 19px;
  block-size: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .18s ease;
}

.navtoggle-bars::before { inset-block-start: -6px; }
.navtoggle-bars::after  { inset-block-start: 6px; }

header.site.nav-open .navtoggle-bars { background: transparent; }

header.site.nav-open .navtoggle-bars::before {
  transform: translateY(6px) rotate(45deg);
}

header.site.nav-open .navtoggle-bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
  .navtoggle-bars::before,
  .navtoggle-bars::after { transition: none; }
}

/* ── Header: narrow screens ─────────────────────────────────────────────── */

@media (max-width: 899px) {
  .navtoggle {
    display: inline-flex;
  }

  .brand img.brand-wide {
    height: 44px;
    max-inline-size: 230px;
  }

  header.site.js-nav nav.site {
    display: none;
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    background: #fff;
    border-block-end: 1px solid var(--line);
    box-shadow: 0 14px 26px rgba(18, 41, 76, 0.10);
    padding: 6px 20px 16px;
  }

  header.site.js-nav.nav-open nav.site {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  header.site.js-nav nav.site a {
    margin-inline-start: 0;
    padding-block: 13px;
    font-size: 1rem;
    border-block-end: 1px solid var(--line);
  }

  header.site.js-nav nav.site a.lang-switch {
    align-self: flex-start;
    margin-block-start: 12px;
    padding: 6px 14px;
    border: 1px solid var(--line);
  }

  header.site.js-nav nav.site a.nav-cta {
    margin-block-start: 12px;
    padding-block: 13px;
    text-align: center;
    border-block-end: none;
    font-size: 0.95rem;
  }
}

/* ── About page ─────────────────────────────────────────────────────────── */

/*
 * Only the pieces About needs that nothing else has. The pillars, value cards,
 * company panel and closing bar are the home page's .rsteps, .valuegrid,
 * .whybox and .readybar, reused unchanged.
 */

.abt-hero {
  background:
    radial-gradient(70rem 32rem at 88% -20%, #dfe9f8 0%, rgba(223, 233, 248, 0) 62%),
    linear-gradient(180deg, #f6f9fd 0%, #eaf1f9 100%);
  padding-block: 18px 56px;
  overflow: clip;
}

.abt-hero .crumbs {
  margin-block-end: 22px;
}

.abt-hero-grid {
  display: grid;
  gap: clamp(20px, 4vw, 48px);
  align-items: center;
  grid-template-columns: 1fr;
}

.abt-hero-art {
  display: none;
}

.abt-chips {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.abt-chips li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--navy-dark);
}

.abt-chips .ic {
  inline-size: 15px;
  block-size: 15px;
  color: #2f6fd0;
  flex: none;
}

.abt-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* The two audiences. min() on the track so a 2-up grid can still collapse
   below its own minimum on a narrow phone — see the entry in NOTES.md. */
.abt-sides {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}

.abt-side {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 20px;
}

.abt-side-art {
  background: var(--bg-soft);
  border-radius: 14px;
  margin-block-end: 16px;
  padding: 6px;
}

/*
 * Height-capped, not width-driven. The artwork is a 220×120 viewBox with
 * preserveAspectRatio="meet", so letting it take its natural height at a card
 * width of ~550px makes a 300px picture above two lines of text. Fixing the
 * block size letterboxes it instead, which is what the viewBox is for.
 */
.abt-side-art svg {
  display: block;
  inline-size: 100%;
  block-size: clamp(118px, 17vw, 158px);
}

.abt-side h3 {
  margin: 10px 0 6px;
  font-size: 1.15rem;
  color: var(--navy-dark);
}

.abt-side p {
  margin: 0;
  font-size: 0.88rem;
  color: var(--muted);
}

.abt-side .readylink {
  margin-block-start: 16px;
  margin-inline-start: 0;
}

.abt-co-p {
  margin: 0;
  color: var(--muted);
}

@media (min-width: 900px) {
  .abt-hero-grid {
    grid-template-columns: 1.15fr 0.85fr;
  }

  .abt-hero-art {
    display: block;
  }

  .abt-hero-art svg {
    display: block;
    inline-size: 100%;
    block-size: auto;
  }
}

/* ── Header: the band just above the hamburger ──────────────────────────── */

/*
 * 900–1099px is where the full nav and the 320px logo compete: the nav is a
 * flex item beside the brand, so a fifth link ("About") pushes it over and the
 * links wrap under each other. Trimming the link gap, the type and the logo
 * buys back ~90px, which is enough; below 900px the hamburger takes over.
 */
@media (min-width: 900px) and (max-width: 1099px) {
  nav.site a {
    margin-inline-start: 12px;
    font-size: 0.96rem;
  }

  /* Still separated, but by less: the row is already tight between 900 and
     1100, and the full 34px pushes the CTA into wrapping. */
  nav.site a.lang-switch {
    margin-inline-start: 22px;
  }

  .brand img.brand-wide {
    height: 52px;
    max-inline-size: 250px;
  }
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

/* ── Hero carousel ────────────────────────────────────────────────────────── */

/* ── Hero: the film plays behind everything ──────────────────────────────── */
/*
 * Dark band, light type, film underneath. The 25px rhythm is restated here
 * because `.hero` is a class and outranks the bare `section` selector.
 *
 * min-block-size, not a fixed height: the band has to be tall enough for the
 * film to be worth showing, but the tallest slide still decides, so nothing
 * is ever clipped in Arabic or at a narrow width.
 */
/*
 * HOW THE HERO FITS ONE SCREEN.
 *
 * It fits because the CONTENT is sized against the available height — not
 * because the band is capped and whatever sticks out is hidden.
 *
 * The first attempt did it the other way round: `max-block-size: 100svh -
 * header` with `overflow-y: auto` on the track inside. That technically kept
 * the carousel controls above the fold, and it was wrong. A scrollbar nested
 * inside a hero is a worse experience than the one it replaced — two scroll
 * contexts on one screen, a wheel gesture that does different things
 * depending on where the pointer is, and a hero that looks broken. A safety
 * valve that is visibly ugly is not a safety valve.
 *
 * So: no cap, no inner scroller. `--hero-fit` below shrinks the type and the
 * spacing as the viewport gets shorter, so the content genuinely gets
 * smaller and the band genuinely ends above the fold. On a freak window it
 * may run a little long, and then the PAGE scrolls — which is ordinary and
 * expected, unlike a box that scrolls inside itself.
 */
.hero {
  position: relative;
  background: #0c1830;
  color: #eaf1fb;
  padding-block: clamp(14px, 2.6svh, 25px);
  overflow: clip;
  display: grid;
  align-content: center;
  min-block-size: min(70vh, 560px);
}

/*
 * One number that everything inside the hero scales against, stepped by
 * viewport HEIGHT. Deliberately a few discrete steps rather than a formula:
 * a fluid version needs calc() to divide a length by a length, which is not
 * reliably supported, and a hero that silently computes to nothing is a
 * worse bug than one that steps.
 *
 * Height, not width: height is the dimension that runs out. A wide short
 * laptop window is the case the first attempt got wrong.
 */
.hero { --hero-fit: 1; }

@media (max-height: 860px) { .hero { --hero-fit: 0.94; } }
@media (max-height: 780px) { .hero { --hero-fit: 0.88; } }
@media (max-height: 700px) { .hero { --hero-fit: 0.82; } }
@media (max-height: 620px) { .hero { --hero-fit: 0.76; } }

/* ── The film ────────────────────────────────────────────────────────────── */

/*
 * STACKING: film 0, scrim 1, content 2. All positive, all explicit.
 *
 * This used to be `z-index: -2` on the film with `isolation: isolate` on the
 * hero, which is the tidier-looking trick and the reason the hero's content
 * could vanish behind the film. A negative z-index puts an element in a
 * separate paint layer BELOW the stacking context's in-flow content, and
 * whether a given element really is "in-flow content" stops being obvious as
 * soon as transforms, opacity transitions, backdrop-filter and a
 * cross-origin iframe are all in the same box. One of them promoting itself
 * is enough to reverse the order, and nothing reports it.
 *
 * Three positive layers cannot do that. If the content is ever invisible
 * again it is not the stacking order.
 */
.hero-film {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  /* The iframe must never take a click: YouTube's own player sits in there,
     and a click would navigate the visitor off the site. */
  pointer-events: none;
}

/*
 * The poster sits ABOVE the player, not below it, and that is the whole
 * trick for keeping YouTube's chrome off the screen.
 *
 * `controls: 0` removes the bottom bar but NOT the big centred
 * prev / play / next overlay, which YouTube paints over the picture whenever
 * the video is not actually playing — paused by the browser, buffering,
 * between loop passes, or restored from a background tab. No player flag
 * turns that off, and it sits dead centre so the scale() crop cannot reach
 * it.
 *
 * So instead of trying to hide the chrome, the film is only ever *revealed*
 * while the player reports PLAYING. Any other state drops `film-on` and this
 * opaque poster fades back over the top, covering whatever YouTube decided
 * to draw. z-index, not source order: the iframe is also absolutely
 * positioned, so without these the iframe would paint last and win.
 */
.hero-film-poster {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #0c1830 url("/assets/hero-car.jpg") center / cover no-repeat;
  opacity: 1;
  transition: opacity .6s ease;
}

.hero.film-on .hero-film-poster {
  opacity: 0;
}

/* 16:9 scaled to COVER a band that is wider and shorter than the film. The
   two max() terms are the same rule from each side: be at least as wide as
   the band, and at least as tall. Centring with the translate keeps the crop
   even top and bottom.

   The extra scale(1.35) is not about coverage — it is how YouTube's own
   chrome gets hidden. `controls: 0` and `modestbranding` do not remove the
   title bar and the share/watch-later buttons; those are drawn along the
   player's top and bottom edges whenever it loads or buffers. Blowing the
   player up past the container pushes those edges outside the clip box, so
   only the middle of the picture is ever visible.
   
   The cost is a tighter crop. That is the trade for a clean backdrop, and
   it is the standard one — there is no player flag that turns the overlay
   off. */
.hero-film iframe,
.hero-film-slot {
  position: absolute;
  z-index: 0;
  /*
   * `top`/`left`, NOT `inset-block-start`/`inset-inline-start`. This is the
   * second time a logical property has broken this hero in Arabic, and it is
   * the same mistake as `to inline-end` inside the scrim gradient.
   *
   * `inset-inline-start: 50%` resolves to `right: 50%` under RTL, but
   * `transform` has no logical form — `translate(-50%)` always moves towards
   * physical left. In English the two agree and the film centres. In Arabic
   * the anchor flips and the transform does not, so the film is offset by
   * the difference and a bare strip of the band shows down the left edge.
   *
   * A full-bleed background has no start or end. Centre it physically and it
   * is correct in both directions, with no second rule to keep in step.
   */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(1.35);
  inline-size: max(100%, 177.78vh);
  block-size: max(100%, 56.25vw);
  border: 0;
  opacity: 0;
  transition: opacity .8s ease;
}

.hero.film-on .hero-film iframe {
  opacity: 1;
}

/* Readability over moving pictures. Darker on the start side, where the copy
   is, so the film still shows through on the other. */
/* Readability over moving pictures: darker where the copy sits, lighter on
   the other side so the film still shows.

   `to right`, NOT `to inline-end`. Logical keywords are not allowed inside
   linear-gradient — one invalid layer invalidates the whole `background`
   declaration, so the first version of this rule painted nothing at all and
   the headline sat straight on the picture. The RTL flip is a second rule. */
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(8, 17, 36, .50) 0%, rgba(8, 17, 36, .74) 100%),
    linear-gradient(to right, rgba(8, 17, 36, .86) 0%, rgba(8, 17, 36, .72) 45%,
                              rgba(8, 17, 36, .56) 100%);
}

html[dir="rtl"] .hero-scrim {
  background:
    linear-gradient(to bottom, rgba(8, 17, 36, .50) 0%, rgba(8, 17, 36, .74) 100%),
    linear-gradient(to left, rgba(8, 17, 36, .86) 0%, rgba(8, 17, 36, .72) 45%,
                             rgba(8, 17, 36, .56) 100%);
}

/* No film: no reason to dim the poster as hard. */
@media (max-width: 899px), (prefers-reduced-motion: reduce) {
  .hero { min-block-size: auto; }
}

/* 0, not 20px. The slide sits INSIDE .hero, so its own padding stacked on top
   of the band's and the first section ended up with 36px above and 48px below
   while every other section had 25. */
.hero-slide {
  padding-block: 0;
}

/*
 * Before the script runs there is no .is-live, so every slide is in normal
 * flow — all three stacked down the page, at full height, over the film.
 * On a cold visit that is what paints first, and it collapses to one slide
 * the moment the carousel initialises. That flash is what "the text
 * disappears sometimes" was: nothing vanished, three slides' worth of text
 * appeared and then two of them were taken away.
 *
 * Showing only the first slide until the carousel takes over means the first
 * paint and the second agree.
 */
.hero-slide:not(:first-child) {
  display: none;
}

/* Positioned so the z-index above actually applies: a static element
   ignores z-index entirely, which is the other half of how content ends up
   underneath a backdrop. */
.hero-track,
.hero > .wrap {
  position: relative;
  z-index: 2;
}

.hero.is-live .hero-track {
  display: grid;
}

.hero.is-live .hero-slide:not(:first-child) {
  display: grid;
}

.hero.is-live .hero-slide {
  grid-area: 1 / 1;
  display: grid;
  align-content: stretch;
  visibility: hidden;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .35s ease, transform .35s ease;
  pointer-events: none;
}

.hero.is-live .hero-slide.is-active {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Belt and braces for the same failure the JS now guards against: if no slide
   ever gets `is-active` — a script error, a blocked file, an extension — the
   first one still shows. `:not(:has(...))` scopes it to the broken case only,
   so it never fights the carousel during normal operation. */
.hero.is-live .hero-track:not(:has(.is-active)) > .hero-slide:first-child {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .hero.is-live .hero-slide {
    transition: none;
    transform: none;
  }
}

/* ── Hero layout: copy on the start side, panel on the end side ──────────── */

.hero-slide > .wrap {
  inline-size: 100%;
}

.hero-grid {
  display: grid;
  gap: calc(var(--hero-fit, 1) * clamp(24px, 4vw, 48px));
  grid-template-columns: 1fr;
  align-items: center;
}

/* The hero's two-column rules all live in ONE place, the min-width: 900px
   block further down. There was a second block here at min-width: 980px
   setting `.hero-grid` to 1fr / 1.05fr; both matched above 980 and the 900 one
   came later in the file, so the 1.05 never applied and the real breakpoint
   was 900 — 80px away from where this block claimed it was. Merged. */

.hero-copy {
  margin-inline: 0;
  text-align: start;
}

/* ── The panels ──────────────────────────────────────────────────────────── */
/*
 * Glass, not white. A solid card over a moving picture reads as a hole cut in
 * the film; a translucent one keeps the footage visible underneath and still
 * carries dark text. backdrop-filter is the part doing the work — without it
 * these would need to be near-opaque to stay readable.
 */
.hero-panel {
  min-inline-size: 0;
}

/*
 * Only slide 2 uses cards. Slides 1 and 3 put their text straight on the
 * film with a light mark beside it, which is what the reference does and
 * what a card was getting in the way of: a white rectangle over footage
 * reads as a hole punched in the picture, and three of them in a row read as
 * a form.
 *
 * The cost of dropping the card is contrast, and it is paid in the scrim and
 * in text-shadow rather than by putting the rectangle back.
 */
/* Glass, matching the icon tiles on slides 1 and 3. These were near-opaque
   white with dark text, which made slide 2 the odd one out — a pair of solid
   panels in a hero that is otherwise text on film. */
/*
 * Frosted light: 78% white over a blur. Worth knowing why it is not higher.
 *
 * Transparency over dark footage drags any white towards grey — at 78% the
 * panel lands around #c9ccd2, not the near-white of a swatch sampled off a
 * pale page. Reaching that would need roughly 0.92 alpha, which is a solid
 * card with the blur doing nothing. 78% is the point where it still reads as
 * glass, the film still moves underneath, and the text can go back to navy.
 */
.aud {
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 18px;
  box-shadow: 0 18px 44px rgba(4, 12, 28, 0.32);
  backdrop-filter: blur(16px) saturate(120%);
  color: var(--ink);
}

@supports not (backdrop-filter: blur(4px)) {
  .aud { background: rgba(255, 255, 255, 0.93); }
}

/* Text that sits directly on the film. */
.hero-feats li,
.promise {
  color: #e8f0fb;
  text-shadow: 0 1px 14px rgba(5, 12, 26, .65);
}

.hero-feats strong,
.promise h3 {
  color: #fff;
}

/* ── Slide 1: phone beside what the app does ─────────────────────────────── */

.hero-app {
  display: grid;
  gap: clamp(18px, 2.5vw, 32px);
  grid-template-columns: 1fr;
  justify-items: center;
  align-items: center;
}

@media (min-width: 620px) {
  .hero-app {
    grid-template-columns: auto minmax(0, 1fr);
    justify-items: stretch;
  }
  /* Assigned explicitly rather than left to source order: the phone belongs
     on the start side with the feature rows beside it, and an auto-placed
     grid is one stray rule away from swapping them. Column numbers follow
     the writing direction, so Arabic mirrors without a second rule. */
  .hero-app .phone { grid-column: 1; }
  .hero-app .hero-feats { grid-column: 2; }
}

.hero-app .phone {
  inline-size: clamp(150px, 17vw, 196px);
  block-size: auto;
  /* Matches app-instructors.jpg exactly (720x1561). It used to be 170/320,
     which was close but not equal — harmless while the box did not clip, and
     a bug the moment `overflow: hidden` was added below, because the box was
     then 13% too short and quietly ate the app's bottom tab bar. An
     aspect-ratio that reserves space for an image has to be that image's. */
  aspect-ratio: 720 / 1561;
}

/*
 * The screenshot was landing on the film as a bare rectangle: square corners,
 * a hard cut at every edge, no relationship to the picture behind it. Three
 * things fix that, and the order they apply in matters.
 *
 * 1. A radius and a hairline ring, so it reads as a device rather than a
 *    pasted JPEG. The shot already contains the app's own rounded corners, so
 *    the radius here only needs to match them, not invent a bezel.
 * 2. drop-shadow rather than box-shadow, because a filter traces the actual
 *    masked shape; box-shadow would draw the full rectangle and put a hard
 *    edge back under the part that is meant to be dissolving.
 * 3. A mask that fades the bottom out. This is the part doing the real work —
 *    instead of the screenshot ending, it stops being there, and the film
 *    continues. Filters run BEFORE masking, so the shadow fades out with the
 *    image rather than outliving it, which is what makes the bottom look
 *    weightless instead of cut off.
 */
.hero-app .phone {
  position: relative;
  border-radius: 22px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
  filter: drop-shadow(0 22px 44px rgba(3, 10, 24, 0.55));
  -webkit-mask-image: linear-gradient(to bottom,
      #000 0, #000 72%, rgba(0, 0, 0, 0.35) 90%, transparent 100%);
  mask-image: linear-gradient(to bottom,
      #000 0, #000 72%, rgba(0, 0, 0, 0.35) 90%, transparent 100%);
}

.hero-app .phone-shot {
  display: block;
  inline-size: 100%;
  block-size: auto;
}

/* A touch of the hero's own blue laid over the shot, so it sits in the same
   light as the film instead of glowing white in front of it. Low enough that
   the app's UI stays legible — this is atmosphere, not a scrim. */
.hero-app .phone::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to bottom,
      rgba(12, 24, 48, 0.10) 0%,
      rgba(12, 24, 48, 0) 38%,
      rgba(12, 24, 48, 0.22) 100%);
}

.hero-feats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: calc(var(--hero-fit, 1) * 12px);
}

.hero-feats li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 2px 0;
}

/* Glass, not a white chip. A solid tile on a dark film reads as a bright
   sticker; a translucent one with a hairline edge keeps the footage showing
   through and lets the glyph itself be the bright thing. */
.feat-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.7);
  color: var(--navy);
  box-shadow: 0 8px 20px rgba(4, 12, 28, 0.25);
  backdrop-filter: blur(10px);
  flex: none;
}

.feat-glyph {
  inline-size: 21px;
  block-size: 21px;
}

.promise-glyph {
  inline-size: 26px;
  block-size: 26px;
}

@supports not (backdrop-filter: blur(4px)) {
  .feat-ic,
  .promise-badge,
  .aud-badge { background: #fff; }
}

.feat-txt {
  display: grid;
  gap: 2px;
  min-inline-size: 0;
}

.feat-txt strong {
  font-size: 1rem;
}

.feat-txt span {
  color: #c4d5ec;
  font-size: 0.88rem;
  line-height: 1.5;
}

/* ── Slide 2: the two audience cards ─────────────────────────────────────── */

.hero-auds {
  display: grid;
  gap: calc(var(--hero-fit, 1) * 16px);
  grid-template-columns: 1fr;
}

@media (min-width: 560px) {
  .hero-auds { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.aud {
  display: grid;
  justify-items: center;
  text-align: center;
  padding: 0 16px calc(var(--hero-fit, 1) * 18px);
}

.aud-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 54px;
  block-size: 54px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.7);
  color: var(--navy);
  margin-block-start: -27px;
  box-sizing: content-box;
  box-shadow: 0 8px 20px rgba(4, 12, 28, 0.25);
  backdrop-filter: blur(10px);
}

.aud-glyph {
  inline-size: 25px;
  block-size: 25px;
}

.aud h3 {
  margin: 10px 0 12px;
  font-size: 1rem;
  color: var(--navy-dark);
}

.aud ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 9px;
  text-align: start;
  inline-size: 100%;
}

.aud li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 0.88rem;
  color: var(--muted);
}

.tick-ic {
  color: #2f8f5b;
  margin-block-start: 2px;
}

/* ── Slide 3: the four promises ──────────────────────────────────────────── */

.hero-promises {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 1100px) {
  .hero-promises { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Slide 4 carries FIVE values, not four, so the fixed 4-column track above
   would leave the fifth stranded alone on a second row. Flex instead of grid:
   the tiles wrap into balanced rows and `justify-content: center` centres
   whatever ends up on the last one, which is the thing grid cannot do.

   The 170px basis is chosen to give 3 + 2 in this panel rather than 4 + 1 —
   a lone trailing tile reads as a mistake even when it is centred. */
.hero-s4 .hero-promises {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.hero-s4 .promise {
  flex: 1 1 170px;
  max-inline-size: 215px;
}

.promise {
  text-align: center;
  padding: calc(var(--hero-fit, 1) * 4px) 6px;
}

.promise-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 58px;
  block-size: 58px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.7);
  color: var(--navy);
  box-shadow: 0 10px 24px rgba(4, 12, 28, 0.28);
  backdrop-filter: blur(10px);
}

.promise h3 {
  margin: 12px 0 4px;
  font-size: 0.94rem;
}

.promise p {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: #c4d5ec;
}

/* The panels are the busiest thing on the slide. Below the two-column
   breakpoint they sit under the copy, where they still read, and the hero
   simply gets taller rather than cramming two columns into a phone. */
@media (max-width: 899px) {
  .hero-panel { inline-size: 100%; }
}

@media (min-width: 900px) {
  .hero.is-live .hero-copy {
    align-self: start;
  }
  /* The two-line reservation that used to live here is gone. It existed
     because slide 2's kicker ran to 35 characters and wrapped in that slide's
     narrower copy column, dragging its headline ~19px below the other two.
     The kicker is now short enough to hold one line down to the 900px
     breakpoint, so the reservation was only ever adding ~17px of empty space
     above every slide's kicker. If a kicker grows past ~25 characters this
     comes back — check all three slides at 900px before lengthening one. */
}

@media (min-width: 900px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  /* Slide 1 carries a phone, which is tall; give its copy a little less room
     so the phone and the feature rows are not squeezed. */
  .hero-s1 .hero-grid {
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.1fr);
  }
  .hero-s2 .hero-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  }
  .hero-s3 .hero-grid {
    grid-template-columns: minmax(0, 0.62fr) minmax(0, 1.38fr);
  }
  /* Slide 4 carries the same four-tile row as slide 3 but a much longer
     headline — "On Their Journey." against slide 3's "Clear." — so it needs a
     wider copy column. At slide 3's 0.62fr the second line broke again and the
     headline came out three lines deep. Keyed by class, not position. */
  .hero-s4 .hero-grid {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  }
  .hero-s2 .hero-h,
  .hero-s3 .hero-h,
  .hero-s4 .hero-h {
    font-size: clamp(1.8rem, 3.3vw, 2.5rem);
  }
  /* 19ch was cut for the three-line version ("Learners, Instructors" /
     "And Businesses." / "Connected In One Place.", longest line 23 chars).
     Dropping the businesses line merged the first two into "Learners And
     Instructors." at 25 — longer than anything the old cap had to hold, so
     the cap would have wrapped it and handed back the third line it just
     saved. Sized to the longest line now present, not to a round number. */
  .hero-s2 .hero-h { max-width: 26ch; }
  .hero-s3 .hero-h { max-width: 14ch; }
  /* "Your Brand." / "On Their Journey." — the break is explicit in the copy
     (the "|" in hero_s4_h1_a), so this only has to clear the longer line,
     17 characters. 18ch was not enough: `ch` is the width of "0", and this
     headline is bold display type whose letters run wider than that, so the
     second line broke again and the headline came out three deep. */
  .hero-s4 .hero-h { max-width: 22ch; }
  html[lang="ar"] .hero-s2 .hero-h { max-width: 23ch; }
  html[lang="ar"] .hero-s3 .hero-h { max-width: 18ch; }
  html[lang="ar"] .hero-s4 .hero-h { max-width: 20ch; }
}

/* ── Eyebrow ─────────────────────────────────────────────────────────────── */

.hero-eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 14px;
  font-size: 0.8rem;
  line-height: 1.35;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
}

html[lang="ar"] .hero-eyebrow {
  letter-spacing: 0;
  text-transform: none;
}

.hero-eyebrow::before {
  content: "";
  inline-size: 46px;
  block-size: 4px;
  border-radius: 2px;
  background: var(--accent);
  flex: none;
}

.hero-pos .sep {
  margin-inline: 3px;
  color: var(--muted);
  font-weight: 500;
}

/* The DEFAULT is the light-background blue, because "Explore iDrive2 your
   way" reuses .hero-eyebrow/.hero-kicker on a pale section. Recolouring the
   base rule for the dark hero quietly washed that heading out — same shape
   of mistake as .hero-lede, which needed the About page putting back.
   Scope anything the dark band needs to .hero. */
.hero-kicker {
  color: #2f6fd0;
}

.hero .hero-kicker {
  color: #8ec0ff;
}

/* ── Headline and lede ───────────────────────────────────────────────────── */

.hero-h {
  font-size: calc(var(--hero-fit, 1) * clamp(2rem, 4.6vw, 3.4rem));
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 16px;
  color: #ffffff;
  font-weight: 800;
  max-width: 16ch;
  /* The film behind can be bright in places; the shadow keeps the headline
     readable without darkening the scrim further and losing the picture. */
  text-shadow: 0 2px 18px rgba(5, 12, 26, .55);
}

html[lang="ar"] .hero-h {
  letter-spacing: 0;
  line-height: 1.3;
  max-width: 20ch;
}

.hero-h .accent {
  color: #7db2ff;
}

.hero-lede {
  font-size: calc(var(--hero-fit, 1) * 1.08rem);
  color: #c9d8ef;
  max-width: 46ch;
  margin: 0 0 calc(var(--hero-fit, 1) * 26px);
  text-shadow: 0 1px 12px rgba(5, 12, 26, .5);
}

/* The About page reuses .hero-lede on a LIGHT band, so it needs its own
   colour back — this is why the rule above is not simply `color: #fff`. */
.abt-hero .hero-lede {
  color: var(--muted);
  text-shadow: none;
}

.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.btn-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 26px;
  block-size: 26px;
  border-radius: 50%;
  border: 2px solid currentColor;
}

.btn-play .ic {
  inline-size: 13px;
  block-size: 13px;
}

.ic {
  inline-size: 18px;
  block-size: 18px;
  flex: none;
}

.ic-arrow {
  inline-size: 16px;
  block-size: 16px;
}

html[dir="rtl"] .ic-arrow {
  transform: scaleX(-1);
}

/* ── Controls ────────────────────────────────────────────────────────────── */

.hero-nav {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  margin-block-start: calc(var(--hero-fit, 1) * 26px);
  margin-inline: auto;
  padding: 8px 14px;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 999px;
  background: rgba(10, 20, 40, .55);
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .35);
}

.hero .wrap:has(.hero-nav) {
  display: flex;
  justify-content: center;
}

.hero-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 34px;
  block-size: 34px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .28);
  background: transparent;
  color: #eaf1fb;
  cursor: pointer;
}

.hero-arrow:hover {
  border-color: #fff;
}

html[dir="rtl"] .hero-arrow .ic {
  transform: scaleX(-1);
}

.hero-dots {
  display: inline-flex;
  gap: 8px;
}

.hero-dot {
  inline-size: 10px;
  block-size: 10px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .38);
  cursor: pointer;
}

.hero-dot.is-on {
  background: var(--accent);
}

.hero-pos {
  font-size: 0.85rem;
  color: #a9bdd9;
  font-variant-numeric: tabular-nums;
}

.hero-pos b {
  color: #fff;
}

.hero-arrow:focus-visible,
.hero-dot:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.btn {
  display: inline-block;
  padding: 13px 26px;
  border-radius: var(--radius);
  font-weight: 700;
  text-decoration: none;
  border: 2px solid transparent;
}

.btn-primary {
  background: var(--accent);
  color: #23282e;
}

.btn-ghost {
  border-color: rgba(255, 255, 255, 0.45);
  color: #fff;
}

/* ── Sections ───────────────────────────────────────────────────────────── */

/* 25px. Was 64, which on a page of six stacked sections spent most of a
   screen on nothing — the hero and the accordion carry their own spacing. */
/*
 * EVERY jump target clears the sticky header.
 *
 * header.site is position:sticky and roughly 90px tall, so #faq, #contact and
 * the accordion panels all landed UNDERNEATH it — the browser scrolled the
 * element to y=0, which is behind the bar. That is why the nav links appeared
 * not to go to the top of a section: they did, and the top was covered.
 *
 * scroll-margin is the property for this; it moves the scroll destination
 * without moving the element. The value tracks the header's own height, which
 * shrinks with the logo at the two breakpoints below.
 */
section[id],
.ex[id] {
  scroll-margin-block-start: 100px;
}

@media (max-width: 1099px) {
  section[id],
  .ex[id] { scroll-margin-block-start: 88px; }
}

@media (max-width: 899px) {
  section[id],
  .ex[id] { scroll-margin-block-start: 76px; }
}

section {
  padding-block: 25px;
}

section.soft {
  background: var(--bg-soft);
}

h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
  margin: 0 0 12px;
  color: var(--navy);
}

.section-lede {
  color: var(--muted);
  max-width: 62ch;
  margin: 0 0 34px;
}

.grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}

.card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}

.card h3 {
  margin: 0 0 8px;
  font-size: 1.1rem;
  color: var(--navy);
}

.card p {
  margin: 0;
  color: var(--muted);
}

.step-no {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-weight: 800;
  margin-bottom: 12px;
}

/* ── FAQ ───────────────────────────────────────────────────────────────── */

/* ── Footer ─────────────────────────────────────────────────────────────── */

footer.site {
  background: var(--navy-dark);
  color: #c7d3e4;
  padding-block: 44px 34px;
  font-size: 0.92rem;
}

footer.site a {
  color: #fff;
  text-decoration: none;
}

footer.site a:hover {
  text-decoration: underline;
}

.foot-grid {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  margin-bottom: 28px;
}

/* The brand column gets the extra room, because the logo is the thing being
   sized. Raising max-inline-size on .foot-logo-wide alone does NOTHING here:
   four equal auto-fit columns make the brand column about 240px wide, and
   the logo's `inline-size: 100%` caps it to that long before any max applies.
   The constraint was the column, not the image.

   Explicit tracks rather than auto-fit above the breakpoint, since auto-fit
   cannot be told that one of its columns matters more than the others. */
@media (min-width: 900px) {
  /* 1.7fr. This was tried at 2.4 and 3 to make the logos bigger and reverted,
     so the numbers are worth keeping rather than rediscovering:

     .wrap caps the footer at --max (1080px), so viewport width stops mattering
     past that and the share is fixed at 1080 - 40 padding - 3x28 gap = 956px.

       r = 1.7  ->  brand 346px, logos 53px tall, link columns 203px
       r = 2.4  ->  brand 425px, logos 66px tall, link columns 177px
       r = 3.0  ->  brand 478px, logos 72px tall, link columns 159px

     346px is exactly what DevTools reports, which is how the model was checked.

     What sent it back to 1.7: "To Promote Your Business" fits on ONE line in a
     203px column and wraps to two below that. Bigger logos cost that heading.
     If the trade is ever worth making, shorten the heading (under ~18 chars
     fits 159px) rather than just widening the track.

     Measure any of this at 1080px or wider, never at 1024. Below the cap the
     heading wraps at every ratio, which makes widening look free when it is
     not -- that mistake was made here once already. */
  .foot-grid {
    grid-template-columns: 1.7fr 1fr 1fr 1fr;
  }
}

.foot-grid h4 {
  color: #fff;
  margin: 0 0 10px;
  font-size: .92rem;
 /* text-decoration: underline;
  text-underline-offset: 6px; */
}

.foot-grid ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.foot-grid li {
  margin-bottom: 6px;
}

/* No rule here: the only horizontal line in the footer is the one above the
   copyright row. Two rules a few lines apart read as a mistake. */
/* GRID, not flex. The row carries three things — language switcher, the
   "powered by" credit, the legal links — and the credit has to sit in the
   middle of the ROW, not merely between the other two. `space-between` would
   centre it only if the switcher and the links were the same width, which
   they are not: it would drift left on English and further on Arabic.

   `1fr auto 1fr` pins the middle column to the row's centre whatever the
   outer two measure. The outer columns take the leftover equally, so the
   credit does not move when the legal links change length. */
.foot-bottom {
  padding-top: 4px;
  display: grid;
  gap: 10px 16px;
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
}

@media (min-width: 760px) {
  .foot-bottom {
    /* Two cells now, not three — the build credit that used to sit in the
       middle moved down to the copyright row. */
    grid-template-columns: 1fr auto;
    /* baseline, not center. The credit is 0.82rem and the links either side
       are 0.92rem, so centring their BOXES leaves the text sitting at three
       slightly different heights. Baseline puts them on one line, which is
       what the eye is actually checking. */
    align-items: baseline;
    text-align: start;
  }
  /* Logical properties, so Arabic mirrors without a second rule. */
  .foot-bottom > :first-child { justify-self: start; }
  .foot-bottom > :last-child { justify-self: end; }
}

/* ── Policy pages ───────────────────────────────────────────────────────── */

article.policy {
  max-width: 78ch;
  margin-inline: auto;
}

article.policy h1 {
  color: var(--navy);
  font-size: clamp(1.7rem, 4vw, 2.3rem);
  margin-bottom: 6px;
}

article.policy {
  line-height: 1.55;
}

article.policy h1 {
  margin-top: 0;
}

article.policy h2 {
  font-size: 1.18rem;
  margin-top: 24px;
  margin-bottom: 6px;
}

article.policy h3 {
  font-size: 1.02rem;
  margin-top: 16px;
  margin-bottom: 4px;
  color: var(--navy-dark);
}

article.policy p,
article.policy ul,
article.policy ol {
  margin-block: 0 10px;
}

article.policy li {
  margin-block-end: 3px;
}

article.policy blockquote {
  margin: 0 0 16px;
  padding: 10px 14px;
  background: var(--bg-soft);
  border-inline-start: 3px solid var(--accent);
  color: var(--muted);
  font-size: 0.9rem;
  border-radius: 0 var(--radius) var(--radius) 0;
}

html[dir="rtl"] article.policy blockquote {
  border-radius: var(--radius) 0 0 var(--radius);
}

article.policy table {
  width: 100%;
  border-collapse: collapse;
  margin-block: 12px;
  font-size: 0.92rem;
}

article.policy th,
article.policy td {
  border: 1px solid var(--line);
  padding: 8px 10px;
  text-align: start;
}

article.policy th {
  background: var(--bg-soft);
}

/* ── Overflow guard ─────────────────────────────────────────────────────── */

/* A flex or grid item defaults to min-width:auto, so it cannot shrink below
   its own content and pushes its container wider than the viewport instead.
   That is what made the instructors panel overflow on a phone: a nowrap
   placeholder inside flex:1, whose text-overflow:ellipsis could never fire. */
.flow-step > *,
.icard > *,
.ccard > *,
.rstep > *,
.aud > * {
  min-inline-size: 0;
}

/* ── Breadcrumbs ────────────────────────────────────────────────────────── */

section.doc {
  padding-block: 24px 56px;
}

.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-block-end: 18px;
  font-size: 0.88rem;
  color: var(--muted);
}

.crumbs a {
  color: var(--muted);
  text-decoration: none;
}

.crumbs a:hover {
  color: var(--navy);
  text-decoration: underline;
}

.crumb-sep {
  color: var(--line);
}

.crumb-pick {
  position: relative;
}

.crumb-pick > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  list-style: none;
  cursor: pointer;
  color: var(--navy-dark);
  font-weight: 700;
  border-radius: 8px;
  padding: 2px 6px;
}

.crumb-pick > summary::-webkit-details-marker { display: none; }
.crumb-pick > summary::marker { content: ""; }

.crumb-pick > summary:hover {
  background: var(--bg-soft);
}

.crumb-pick > summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.crumb-caret {
  inline-size: 0;
  block-size: 0;
  border-inline: 4px solid transparent;
  border-block-start: 5px solid currentColor;
}

.crumb-pick[open] .crumb-caret {
  transform: rotate(180deg);
}

.crumb-pick > ul {
  position: absolute;
  z-index: 30;
  inset-block-start: calc(100% + 6px);
  inset-inline-start: 0;
  margin: 0;
  padding: 6px;
  min-inline-size: 240px;
  max-inline-size: min(320px, 90vw);
  list-style: none;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 16px 30px rgba(18, 41, 76, 0.12);
}

.crumb-pick > ul a {
  display: block;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--ink);
  font-size: 0.9rem;
}

.crumb-pick > ul a:hover {
  background: var(--bg-soft);
  color: var(--navy);
  text-decoration: none;
}

/* The effective-date line above a policy: a note, not body copy. */
.doc-effective {
  margin: 0 0 14px;
  padding-block-end: 12px;
  border-block-end: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.88rem;
}

/* ── Legal index ────────────────────────────────────────────────────────── */

/*
 * Grouped cards rather than a flat list: the page carries two headed sections
 * and an enquiries block, so each card needs room for a one-line explanation
 * of what the document covers. The .policy-index pill grid it replaced had
 * nowhere to put that.
 */
.legal-h {
  font-size: 1.15rem;
  color: var(--navy-dark);
  margin: 30px 0 4px;
}

.legal-p {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 0.92rem;
}

.legalgrid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
}

.legal-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  text-decoration: none;
  transition: border-color .15s ease;
}

.legal-card:hover {
  border-color: var(--navy);
}

.legal-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 46px;
  block-size: 46px;
  border-radius: 50%;
  background: var(--bg-soft);
  flex: none;
}

.legal-ic .bg-ic {
  inline-size: 24px;
  block-size: 24px;
}

.legal-copy {
  display: block;
  min-inline-size: 0;
  flex: 1;
}

.legal-copy strong {
  display: block;
  font-size: 0.98rem;
  color: var(--navy-dark);
  margin-block-end: 3px;
}

.legal-copy span {
  display: block;
  font-size: 0.86rem;
  line-height: 1.4;
  color: var(--muted);
}

.legal-go {
  inline-size: 16px;
  block-size: 16px;
  flex: none;
  color: var(--muted);
  transition: transform .15s ease;
}

.legal-card:hover .legal-go { transform: translateX(2px); }

html[dir="rtl"] .legal-go { transform: scaleX(-1); }

html[dir="rtl"] .legal-card:hover .legal-go {
  transform: scaleX(-1) translateX(2px);
}

.legal-enq {
  margin-block-start: 30px;
  padding-block-start: 22px;
  border-block-start: 1px solid var(--line);
}

.legal-mail {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  background: var(--bg-soft);
  border-radius: 12px;
  text-decoration: none;
  color: var(--navy-dark);
  font-weight: 600;
  font-size: 0.95rem;
}

.legal-mail .ic {
  inline-size: 18px;
  block-size: 18px;
  flex: none;
}

.legal-mail:hover { text-decoration: underline; }

/* ── Footer: the copyright row ──────────────────────────────────────────── */

/*
 * Its own full-width row at the very bottom. It used to sit under the logo in
 * the first footer column, where it read as part of the brand block rather
 * than as the closing line of the page.
 */
/* Its own centred row rather than a third flex item in .foot-bottom — see
   the comment at the markup. */
/* margin: 0, not the 14px top it had when this was its own row. A <p> keeps
   its margin inside a grid cell, and `align-items: center` centres the BOX,
   margin included — so the text sat a few pixels below the switcher and the
   legal links either side of it. Nothing about the alignment was wrong; the
   margin was. */
.foot-powered {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: #a9b9d0;
}

.foot-powered a {
  color: #dbe5f2;
  text-decoration: none;
  border-block-end: 1px solid rgba(219, 229, 242, 0.35);
}

.foot-powered a:hover {
  color: #fff;
  border-block-end-color: #fff;
}

/* The last row: copyright and the build credit, one line on a wide screen.
   Stacked and centred below 640px, where the two together are too long. */
.foot-copy {
  margin: 16px 0 0;
  padding-block-start: 16px;
  border-block-start: 1px solid rgba(255, 255, 255, 0.15);
  font-size: 0.86rem;
  color: #c7d3e4;
  display: grid;
  gap: 6px;
  justify-items: center;
  text-align: center;
}

.foot-copy-text { margin: 0; }

@media (min-width: 640px) {
  .foot-copy {
    grid-template-columns: 1fr auto;
    /* baseline, not centre: the credit is 0.82rem against the copyright's
       0.86rem, so centring their boxes leaves the two texts a hair apart
       vertically — the same reason .foot-bottom uses baseline. */
    align-items: baseline;
    text-align: start;
  }
  /* Logical, so Arabic mirrors without a second rule: copyright leads, credit
     trails, in both directions. */
  .foot-copy > .foot-copy-text { justify-self: start; }
  .foot-copy > .foot-powered { justify-self: end; }
}

/* ── Print ──────────────────────────────────────────────────────────────── */

@media print {
  header.site,
  footer.site,
  .skip {
    display: none;
  }
  body {
    font-size: 11pt;
  }
}

/* ═════════════════════════════════════════════════════════════════════════════ */

.ex-eyebrow {
  margin-block-end: 6px;
}

.ex-title {
  font-size: clamp(1.9rem, 4vw, 3rem);
  letter-spacing: -0.02em;
  color: var(--navy-dark);
  font-weight: 800;
  margin: 0 0 8px;
}

html[lang="ar"] .ex-title {
  letter-spacing: 0;
}

.ex-list {
  display: grid;
  gap: 16px;
  margin-block-start: 28px;
}

/* ── The collapsed row ────────────────────────────────────────────────────── */

.ex {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 22px;
  box-shadow: 0 10px 30px rgba(26, 60, 110, 0.06);
  overflow: hidden;
}

.ex[open] {
  box-shadow: 0 16px 44px rgba(26, 60, 110, 0.1);
}

.ex-head {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 18px;
  padding: 22px 24px;
  cursor: pointer;
  list-style: none;
}

.ex-head::-webkit-details-marker {
  display: none;
}

.ex-headings {
  display: grid;
  gap: 4px;
  min-inline-size: 0;
}

.ex-kicker {
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
}

html[lang="ar"] .ex-kicker {
  letter-spacing: 0;
  text-transform: none;
}

.ex-h {
  font-size: clamp(1.25rem, 2.4vw, 1.9rem);
  font-weight: 800;
  color: var(--navy-dark);
  line-height: 1.15;
}

.ex-p {
  color: var(--muted);
  font-size: 0.95rem;
  max-inline-size: 52ch;
}

.ex-art {
  display: none;
}

.ex-art svg,
.ex-shot {
  inline-size: 100%;
  block-size: auto;
}

.ex-shot {
  border-radius: 14px;
  box-shadow: 0 10px 28px rgba(26, 60, 110, 0.12);
  /* The three panel heads carry different artwork — a 900x281 illustration on
     panel 1, a 900x471 screenshot on panel 2, CSS art on panel 3 — and left to
     themselves they stood at three different heights. One box for all of them.
     contain, not cover: cover would scale the 281-tall file by 1.3 and slice
     126px off each side of it. The letterbox it leaves is white on white. */
  aspect-ratio: 900 / 360;
  object-fit: contain;
}

@media (min-width: 900px) {
  .ex-head {
    grid-template-columns: 1fr minmax(180px, 300px) auto;
  }
  .ex-art {
    display: block;
    align-self: center;
  }
}

.ex-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  color: var(--navy);
  align-self: start;
  flex: none;
}

.ex[open] .ex-toggle {
  border-color: var(--navy);
}

.pm-v {
  transition: opacity .15s ease;
}

[open] > summary .pm-v,
[open] > .ex-head .pm-v {
  opacity: 0;
}

.ex-head:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: -3px;
}

/* ── The expanded body ────────────────────────────────────────────────────── */

.ex-body {
  padding: 0 24px 24px;
  display: grid;
  gap: 18px;
}

.jpanel {
  background: var(--bg-soft);
  border-radius: 20px;
  padding: 24px;
}

.jh {
  font-size: clamp(1.3rem, 2.6vw, 2rem);
  font-weight: 800;
  color: var(--navy-dark);
  line-height: 1.15;
  margin: 0 0 8px;
}

.jh .accent {
  color: #2f6fd0;
}

.jp {
  color: var(--muted);
  margin: 0 0 18px;
  max-inline-size: 62ch;
}

.jp-lead {
  font-size: 1.1rem;
  color: var(--ink);
}


.jhead {
  display: grid;
  gap: 14px;
  margin-block-end: 6px;
}

@media (min-width: 900px) {
  .jhead {
    grid-template-columns: 1.4fr 1fr;
    align-items: start;
    gap: 36px;
  }
}

.jaside {
  color: var(--muted);
  font-size: 0.92rem;
  margin: 0;
}

/* ── Journey steps ────────────────────────────────────────────────────────── */

.jsteps {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  counter-reset: none;
}

.jstep {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 18px;
  position: relative;
}

/* ── Real app screens inside the journey steps ───────────────────────────── */
/*
 * One screenshot per step, so the four cards are the same shape. Previously
 * only step 1 carried an image and that card stood a head taller than the
 * other three.
 *
 * `margin-block-start: auto` is the part that matters: .jstep is a flex
 * column, so the image is pushed to the bottom of the card and every
 * screenshot in the row lines up however long the copy above it runs.
 */
.jstep {
  display: flex;
  flex-direction: column;
}

.pshot {
  inline-size: 100%;
  max-inline-size: 240px;
  block-size: auto;
  /* A fixed box, not "whatever the file measures". Every step screenshot is a
     560x1214 full screen today, but pinning the ratio means one odd crop later
     cannot make its card taller than the three beside it. */
  aspect-ratio: 560 / 1214;
  object-fit: cover;
  object-position: top center;
  margin-block-start: auto;
  margin-inline: auto;
  padding-block-start: 14px;
  border-radius: 16px;
  /* The screenshots already include the phone's own rounded corners and
     status bar, so no device frame is drawn around them — a frame on top of
     a frame reads as a mistake. */
  filter: drop-shadow(0 14px 30px rgba(26, 60, 110, 0.18));
}

/* "How learners find you" carries one screen, not two: the result list, which
   is what the section is actually about. The filter sheet beside it made the
   pair read as a comparison and halved the size of both. One image, full panel
   width, cut to end on the gap below the first card so the bottom edge is a
   clean line rather than a card sliced through the middle. */
.findrow {
  margin-block: 6px 22px;
}

/* It is a cropped rectangle, not a whole phone screen, so it takes the card
   treatment used by .ex-shot — radius plus a cast shadow — rather than
   .pshot's drop-shadow, which traces a phone outline that is no longer there.
   Ratio pinned to the file so the box never changes shape. */
.findrow .pshot {
  max-inline-size: none;
  aspect-ratio: 820 / 930;
  margin-block-start: 0;
  padding-block-start: 0;
  border-radius: 16px;
  filter: none;
  box-shadow: 0 12px 32px rgba(26, 60, 110, 0.14);
}

.jstep h4 {
  margin: 0 0 6px;
  font-size: 1rem;
  color: var(--navy-dark);
}

.jstep p {
  margin: 0;
  font-size: 0.88rem;
  color: var(--muted);
}

/* ── The three-up flow strip ──────────────────────────────────────────────── */

.flow {
  list-style: none;
  margin: 0 0 18px;
  padding: 16px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}

.flow-step {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.flow-step b {
  display: block;
  font-size: 0.92rem;
  color: var(--navy-dark);
}

.flow-step span span {
  display: block;
  font-size: 0.82rem;
  color: var(--muted);
}

.flow-ic,
.why-ic,
.value-ic,
.rstep-ic,
.enq-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #eaf1fb;
  color: var(--navy);
  flex: none;
}

.flow-ic { inline-size: 40px; block-size: 40px; }
.why-ic { inline-size: 40px; block-size: 40px; }
.value-ic { inline-size: 52px; block-size: 52px; margin-block-end: 10px; }
.rstep-ic { inline-size: 48px; block-size: 48px; margin-block-end: 10px; }
.enq-ic { inline-size: 62px; block-size: 62px; background: #fdf3dd; color: #9a6c00; }

/* ── Buttons that only appear in this section ─────────────────────────────── */

.btn-navy {
  background: var(--navy);
  color: #fff;
}

.storemarks {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.storemarks .ic {
  inline-size: 20px;
  block-size: 20px;
}

/* ── Why instructors choose us ────────────────────────────────────────────── */

.whybox {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 20px;
  display: grid;
  gap: 18px;
  margin-block-end: 18px;
}

@media (min-width: 1000px) {
  .whybox {
    grid-template-columns: minmax(200px, 260px) 1fr;
    align-items: start;
    gap: 28px;
  }
}

.why-kicker {
  color: #2f6fd0;
  font-weight: 700;
  font-size: 0.85rem;
  margin: 0 0 4px;
}

.whybox-lead h4 {
  margin: 0;
  font-size: 1.15rem;
  color: var(--navy-dark);
  line-height: 1.25;
}

.whygrid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
}

.why {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.why h5 {
  margin: 0 0 4px;
  font-size: 0.92rem;
  color: var(--navy-dark);
}

.why p {
  margin: 0;
  font-size: 0.82rem;
  color: var(--muted);
}

/* ── Ready bar ────────────────────────────────────────────────────────────── */

.readybar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 18px 20px;
  border-radius: 16px;
  background: linear-gradient(90deg, #fdf3dd 0%, rgba(253, 243, 221, 0.35) 100%);
}

.readybar p {
  margin: 0;
  font-weight: 800;
  font-size: 1.1rem;
  color: var(--navy-dark);
}

.readylink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: 0.9rem;
  margin-inline-start: auto;
}

/* ── The search illustration ──────────────────────────────────────────────── */





/* The mock search stacks on a narrow screen: field over button.
   nowrap text is a min-content floor — the row could not shrink below the
   whole placeholder sentence, and it sized the grid column that both panels
   of the Instructors section share. Letting it wrap removes the floor;
   stacking keeps it looking like a search field rather than a tall sliver
   beside an oversized button. Normal word wrapping, NOT overflow-wrap:
   anywhere, which broke "instructor" across two lines. */
@media (max-width: 560px) {


}






/* ── Anonymous sample cards ───────────────────────────────────────────────── */

.sample-h {
  margin: 0 0 12px;
  font-size: 1rem;
  color: var(--navy-dark);
}

.icards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
}

/*
 * A button that is a direct child of a panel needs its own breathing room.
 * Everything else in .jpanel is a block element carrying a bottom margin, so
 * the rhythm looks automatic until you add an inline-flex <a> — which has no
 * margin and no margin-collapsing — straight after a list whose margin is 0.
 * It then sits flush against the cards above it, which is what happened to
 * "Discover Instructors in the app".
 *
 * 22px matches .findrow's bottom margin, so the panel keeps one spacing step.
 */
.jpanel > .btn {
  margin-block-start: 22px;
}

/* Now holds a cropped screenshot of a real card, so no padding, no border
   and no background — the crop already carries the card's own chrome. */
.icard {
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 10px 26px rgba(26, 60, 110, 0.12);
}

/*
 * All three files are now exactly 756x240 and contain nothing but card — no
 * page background, no padding — so the ratio here matches them exactly and
 * `cover` has nothing to crop.
 *
 * That framing is the whole fix. The previous crops were at the SAME
 * magnification (avatars measured 214, 216 and 216 px) but framed
 * differently: card 1 was cut tight to its edges while cards 2 and 3 carried
 * 17 and 19px of page background above them. Scaled into one box, that dead
 * space shrank the cards inside 2 and 3 by about 7%, and card 1 read as the
 * bigger one. Equal boxes do not give you equal-looking contents unless the
 * contents are framed equally.
 *
 * `object-position: top`: card 1 was clipped at the bottom in the original
 * screenshot, so it is 15px taller than the other two with no bottom corner.
 * Anchoring to the top takes that difference off the damaged edge rather than
 * off the name and the rating.
 */
.icard img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 756 / 240;
  object-fit: cover;
  object-position: top center;
}

.icard h5 {
  margin: 0 0 10px;
  font-size: 0.95rem;
  color: var(--navy-dark);
}

.icard ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.icard li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.84rem;
  color: var(--muted);
}

.icard li .ic {
  inline-size: 16px;
  block-size: 16px;
  color: var(--navy);
}

/* ── Advertiser value grid ────────────────────────────────────────────────── */

.valuegrid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  padding-block: 4px 8px;
}

.value h4 {
  margin: 0 0 6px;
  font-size: 1rem;
  color: var(--navy-dark);
}

.value p {
  margin: 0;
  font-size: 0.86rem;
  color: var(--muted);
}

/* ── Campaign flow steps ──────────────────────────────────────────────────── */
/*
 * `.plans` and `.plan` were removed here when the Featured Promotional Plans
 * list was replaced by the four cards at the top of the Partners page. Only
 * the plans-specific rules went; .rsteps and .rstep shared these selectors and
 * are still in use, which is why this was unpicked by hand rather than by
 * deleting the block.
 */

.rsteps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
}

.rsteps {
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
}

.rstep {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 20px;
}

.rstep h4 {
  margin: 0 0 6px;
  font-size: 1rem;
  color: var(--navy-dark);
}

.rstep p {
  margin: 0;
  font-size: 0.86rem;
  color: var(--muted);
}

.ticks {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.ticks li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.84rem;
  color: var(--ink);
}

.ticks .ic {
  inline-size: 16px;
  block-size: 16px;
  color: #2f6fd0;
}

/* ── Enquiry form ─────────────────────────────────────────────────────────── */

.enq {
  background: linear-gradient(120deg, #fdf3dd 0%, rgba(253, 243, 221, 0.4) 100%);
  border-radius: 20px;
  padding: 24px;
  display: grid;
  gap: 18px;
}

/* The form sits straight under the "Run Your Campaign" panel, and both are
   padded blocks with no margin of their own, so their rounded edges met with
   nothing between them. An adjacent-sibling rule rather than a margin on
   `.enq` itself: the gap belongs to the junction, so the form keeps a clean
   top edge if it is ever the first thing in its container. */
:is(.jpanel, .vwave) + .enq {
  margin-block-start: 20px;
}

.enq-lead {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.enq-lead h3 {
  margin: 0 0 4px;
  font-size: clamp(1.2rem, 2.4vw, 1.7rem);
  color: var(--navy-dark);
  font-weight: 800;
}

.enq-lead p {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  max-inline-size: 56ch;
}

.enq-fields {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
}

.enq label {
  display: grid;
  gap: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--navy-dark);
}

.enq input {
  font: inherit;
  font-weight: 400;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  min-inline-size: 0;
}

.enq input:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--navy);
}

.enq-hp {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.enq-send {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
}

.enq-send .btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

.enq-privacy {
  margin: 0;
  font-size: 0.76rem;
  color: var(--muted);
  /* ~68ch, not 48: the sentence is about 135 characters, so 48ch forced a
     third line with a short orphan on it. Half the sentence is ~68ch, which
     is what makes it two. Expanding "We'll" to "We will" lengthened it, so
     this was re-measured against the current wording. */
  max-inline-size: 68ch;
  /* Evens the two lines rather than filling the first and leaving the
     remainder on the second. Ignored by browsers that do not support it,
     which just means the old ragged break — no fallback needed. */
  text-wrap: balance;
}

.enq-msg {
  margin: 0;
  font-size: 0.88rem;
  font-weight: 600;
}

.enq-msg:empty {
  display: none;
}

.enq-msg.is-ok {
  color: #1d6b4f;
}

.enq-msg.is-bad {
  color: #a4303f;
}

/* ═════════════════════════════════════════════════════════════════════════════ */

/*
 * The SAME mark as .hero-eyebrow, deliberately. There are two eyebrow
 * systems in this stylesheet — .hero-eyebrow/.hero-kicker (hero, Explore)
 * and .secno/.secno-k (contact, FAQ, downloads, and all four About
 * sections) — and they had drifted: 0.8 vs 0.82rem, 14 vs 8px gap, and the
 * kicker blue vs var(--muted), which reads as near-black next to the blue
 * one. Matched here rather than merged, because the markup differs; if you
 * change one, change both.
 */
.secno {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 6px;
  font-size: 0.8rem;
  line-height: 1.35;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #2f6fd0;
}

html[lang="ar"] .secno {
  letter-spacing: 0;
  text-transform: none;
}

.secno::before {
  content: "";
  inline-size: 46px;
  block-size: 4px;
  border-radius: 2px;
  background: var(--accent);
  flex: none;
}

/* ── FAQ ──────────────────────────────────────────────────────────────────── */

.faq-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 26px;
  border-block-end: 1px solid var(--line);
  margin-block: 22px 18px;
}

.faq-tab {
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--muted);
  padding: 10px 2px;
  cursor: pointer;
  border-block-end: 3px solid transparent;
  margin-block-end: -1px;
}

.faq-tab[aria-current="true"] {
  color: var(--navy-dark);
  border-block-end-color: var(--navy);
}

.faq-tab:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.faq-search {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 6px 4px 14px;
  padding-inline: 14px 6px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  margin-block-end: 14px;
}

.faq-search-ic { color: var(--muted); display: inline-flex; }

.faq-search input {
  font: inherit;
  flex: 1;
  border: none;
  outline: none;
  padding: 11px 0;
  background: none;
  color: var(--ink);
  min-inline-size: 0;
}

.faq-count {
  margin: 0 0 10px;
  font-size: 0.84rem;
  color: var(--muted);
}

.faq-count:empty { display: none; }

.faq-list { display: grid; gap: 2px; }

.faq {
  border-block-end: 1px solid var(--line);
  border-radius: 14px;
}

.faq[open] { background: #eef3fa; }

.faq > summary {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  color: var(--navy-dark);
}

.faq > summary::-webkit-details-marker { display: none; }

.faq > summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: -3px;
}

.faq-q { flex: 1; min-inline-size: 0; }

.faq-toggle {
  display: inline-flex;
  color: var(--navy);
  flex: none;
}

.faq > p {
  margin: 0;
  /* Flush with the question, not indented under it. The inline-start was 72px,
     which cleared the number badge in the summary and set the answer well in
     from the edge of the card. Now 18px, matching the summary's own padding,
     so question and answer share a left edge.

     Both longhands, in this order: the physical one is the fallback and the
     logical one wins, which is what flips the inset under RTL. */
  padding: 0 18px 18px;
  padding-inline: 18px;
  color: var(--muted);
}

.faq-empty {
  margin: 18px 0;
  color: var(--muted);
}

.stillbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-block-start: 22px;
  padding: 18px 20px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
}

.stillbar h3 { margin: 0; font-size: 1.1rem; color: var(--navy-dark); }
.stillbar p { margin: 2px 0 0; color: var(--muted); font-size: 0.9rem; }
.stillbar .btn { margin-inline-start: auto; }

.still-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 48px;
  block-size: 48px;
  border-radius: 14px;
  background: #eaf1fb;
  color: var(--navy);
  flex: none;
}

/* ── Contact ──────────────────────────────────────────────────────────────── */

.contact-top {
  display: grid;
  gap: 24px;
  margin-block-end: 26px;
}

@media (min-width: 1000px) {
  .contact-top { grid-template-columns: 0.9fr 1.1fr; align-items: start; }
}

/*
 * THREE ACROSS, always, once there is room for them.
 *
 * auto-fit with a 180px minimum sounds like it would do that, but the cards
 * sit in the narrower half of .contact-top — at 1000–1300px that column is
 * around 560px, which fits two and wraps the third onto a row of its own.
 * An explicit three-column track is the only thing that holds the row
 * together, so the padding below shrinks to pay for it.
 */
.ccards {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
}

@media (min-width: 700px) {
  .ccards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.ccard {
  display: grid;
  gap: 2px;
  /* Tighter than the 18px it was: three of these share a column that used to
     hold two. */
  padding: 13px 12px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  text-decoration: none;
  box-shadow: 0 8px 24px rgba(26, 60, 110, 0.06);
}

.ccard:hover { border-color: var(--navy); }

.ccard-ic {
  inline-size: 36px;
  block-size: 36px;
  border-radius: 10px;
  background: var(--navy);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-block-end: 7px;
}

.ccard.is-wa .ccard-ic { background: #25d366; }

/* The WhatsApp mark is drawn filled, so it needs no stroke width and carries
   its own padding inside the 24-unit box — a touch smaller keeps its visual
   weight level with the two stroked glyphs beside it. */
.ccard.is-wa .ccard-ic .ic { inline-size: 17px; block-size: 17px; }

.ccard-h { font-size: 0.74rem; color: var(--muted); font-weight: 600; }

/* break-word, not break-all, and a size that lets info@idrive2app.com sit on
   one line in a third of the column. */
.ccard-v {
  font-weight: 800;
  font-size: 0.86rem;
  color: var(--navy-dark);
  word-break: break-word;
}

.ccard-n {
  font-size: 0.68rem;
  line-height: 1.3;
  color: var(--muted);
  margin-block-start: 3px;
}

/*
 * ONE column. This was 1.6fr 1fr, with the help box in the second — and when
 * that box went the track stayed, so the form kept 60% of the width and the
 * rest of the row was empty.
 *
 * It then carried `max-inline-size: 880px`, justified as "a single-column
 * enquiry form stretched across 1200px puts the name field a hand-span from
 * its label". That stopped being true when .sup-grid became two columns at
 * 760px: each field now sits in half the width with its label directly above
 * it, so there is no span to cross. All the cap did was leave an 880px form
 * hugging the start edge of a 1200px section, out of line with every band
 * above it.
 *
 * The constraint that mattered is still enforced, just one level up: .wrap
 * caps the whole page at --max.
 */
.contact-main {
  display: grid;
  gap: 18px;
}

.sup {
  background: var(--navy-dark);
  color: #fff;
  border-radius: 20px;
  padding: 26px;
}

.sup h3 { margin: 0 0 6px; font-size: clamp(1.3rem, 2.6vw, 1.9rem); color: #fff; }
.sup-lede { margin: 0 0 20px; color: #c6d4e8; font-size: 0.94rem; }

.sup-grid { display: grid; gap: 16px; }

@media (min-width: 760px) {
  .sup-grid { grid-template-columns: 1fr 1fr; }
}

.sup-col { display: grid; gap: 14px; align-content: start; }

.sup label { display: grid; gap: 6px; font-size: 0.85rem; font-weight: 700; }
.sup label small { font-weight: 400; color: #c6d4e8; font-size: 0.8rem; }

.sup input,
.sup select,
.sup textarea {
  font: inherit;
  font-weight: 400;
  padding: 11px 14px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  min-inline-size: 0;
}

.sup textarea { resize: vertical; }
.sup-msg { display: grid; gap: 4px; }
.sup-msg textarea { block-size: 100%; }

.sup input:focus-visible,
.sup select:focus-visible,
.sup textarea:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 1px;
}

.sup-send {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-block-start: 18px;
}

.sup-note { margin: 0; font-size: 0.78rem; color: #c6d4e8; flex: 1; min-inline-size: 180px; }
.sup-send .btn { margin-inline-start: auto; }
.sup-send .btn[disabled] { opacity: .55; cursor: not-allowed; }
.sup-privacy { margin: 14px 0 0; font-size: 0.74rem; color: #c6d4e8; }
.sup-privacy a { color: #fff; }
.sup .enq-msg.is-ok { color: #9ff0c8; }
.sup .enq-msg.is-bad { color: #ffb4bd; }

.helpbox {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 24px;
}

.helpbox h3 { margin: 0 0 8px; font-size: 1.4rem; color: var(--navy-dark); }
.helpbox p { margin: 0 0 18px; color: var(--muted); font-size: 0.92rem; }

.helplink {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px;
  border-radius: 14px;
  background: var(--bg-soft);
  text-decoration: none;
}

.helplink:hover { background: #eaf1fb; }
.helplink b { display: block; color: var(--navy-dark); font-size: 0.95rem; }
.helplink small { color: var(--muted); font-size: 0.76rem; }
.helplink > span:nth-child(2) { flex: 1; }
.helplink .ic-arrow { color: var(--navy); }

/* ── Downloads ────────────────────────────────────────────────────────────── */

.dlbar {
  display: grid;
  gap: 24px;
  padding: 28px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 22px;
}

@media (min-width: 900px) {
  .dlbar { grid-template-columns: 1.1fr 0.9fr; align-items: center; }
}

.dlstores {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
}

.store-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  text-decoration: none;
  font-weight: 700;
  color: var(--navy-dark);
  font-size: 0.9rem;
}

.store-tile:hover { border-color: var(--navy); }
.store-tile.is-off { opacity: .55; }
.store-mark svg { inline-size: 26px; block-size: 26px; }

/* ── Quick links ──────────────────────────────────────────────────────────── */

.qcards {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}

.qart {
  display: block;
  border-radius: 16px;
  overflow: hidden;
  background: #eaf1fb;
  margin-block-end: 14px;
}

.qart svg { inline-size: 100%; block-size: auto; display: block; }

.qkicker { margin: 0 0 2px; color: var(--muted); font-size: 0.86rem; }
.qcard h3 { margin: 0 0 6px; font-size: 1.15rem; color: var(--navy-dark); }
.qp { margin: 0 0 14px; color: var(--muted); font-size: 0.9rem; }

.qlink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  text-decoration: none;
  border-block-end: 3px solid var(--accent);
  padding-block-end: 3px;
}

/* ── Footer ───────────────────────────────────────────────────────────────── */

/* ── The footer's brand mark ─────────────────────────────────────────────── */

/* The <a> that wraps the footer logo. `block`, not `inline-block`, and it
   carries the width cap: the flex row inside is sized by this box, and an
   inline-block shrink-wraps to its content — which for two side-by-side
   images is their full 1004px natural width, straight off the screen. */
.foot-logo {
  display: block;
  text-decoration: none !important;
  /* 460px. Note this sits ABOVE the 346px brand column, so the column is what
     actually decides the logo size -- raising this alone does nothing. */
  max-inline-size: 460px;
}

/* 320px, not the 260px the iDrive2-only wordmark used: the joint lockup fits
   two brands and a divider into the same width, so at 260 the "Technologies"
   line and the Arabic stopped being legible. inline-size: 100% still caps it
   to the footer column on a narrow screen. */
/* The single-image fallback, if the split pair is ever removed. */
.foot-logo-wide {
  display: block;
  inline-size: 100%;
  max-inline-size: 420px;
  block-size: auto;
}

/*
 * The two footer logos, side by side on ONE row at every width.
 *
 * The trick is `flex-grow` set to each image's natural width. Both files are
 * exactly 180px tall, so growing them in proportion to their widths keeps
 * them at the SAME rendered height automatically, at any row width, with no
 * height declared anywhere. Give them equal flex and the wider iDrive2 mark
 * would be squashed shorter than the Condor one.
 *
 * `min-inline-size: 0` because a flex item will not shrink below its content
 * by default, and an image's content is its intrinsic width — without it the
 * row refuses to get narrower than 589 + 415px and overflows the phone.
 */
.foot-logos {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2.4vw, 18px);
}

.foot-logos-img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  min-inline-size: 0;
}

.foot-logo-idrive2 { flex: 615 1 0; }   /* = the file's width in px */
.foot-logo-condor { flex: 488 1 0; }   /* = the file's width in px */

/* Replaces the divider that used to be painted into the combined image. */
.foot-logos-rule {
  flex: none;
  inline-size: 1px;
  block-size: clamp(26px, 7vw, 46px);
  background: rgba(255, 255, 255, 0.22);
}

.foot-logo-square {
  display: block;
  inline-size: 44px;
  block-size: 44px;
}

.foot-logo-text {
  font-weight: 800;
  font-size: 1.15rem;
  color: #fff;
}

.foot-brand p { margin: 12px 0 0; font-size: 0.82rem; color: #c7d3e4; }

.socials { display: flex; gap: 10px; margin-block-start: 14px; }

.soc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 36px;
  block-size: 36px;
  border-radius: 50%;
  border: 1px solid var(--line);
  color: var(--navy);
}

.soc svg { inline-size: 18px; block-size: 18px; }
.soc:hover { border-color: var(--navy); }

.foot-sep { margin-inline: 10px; color: var(--line); }
.foot-legal a { margin: 0; }

.foot-lang .lang-on {
  color: #fff;
  font-weight: 700;
}

/* ── Native disclosure markers ──────────────────────────────────────────── */

summary::-webkit-details-marker {
  display: none;
}

summary::marker {
  content: "";
}

summary {
  list-style: none;
}

/* ── Hero: the blue call to action ────────────────────────────────────────── */

.hero .btn-primary {
  background: var(--cta);
  color: #fff;
}

.hero .btn-primary:hover {
  background: var(--cta-dark);
}

nav.site a.nav-cta {
  background: var(--cta);
  color: #fff;
  font-size: 0.93rem;
}

nav.site a.nav-cta:hover {
  background: var(--cta-dark);
  color: #fff;
}

/* ── The nav's one action ────────────────────────────────────────────────── */

.nav-cta {
  padding: 9px 16px;
  font-size: 0.9rem;
  border-radius: 10px;
  white-space: nowrap;
}

/* ── Hero film ────────────────────────────────────────────────────────────── */

.hero-film {
  padding: 0;
  overflow: hidden;
}

.hero-film video,
.hero-film img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
  .hero-film video {
    transition: none;
  }
}

/* `.jstep-shot img` lived here — the rule that predates .pshot, from when one
   step out of four carried an image. It set `margin-block-start: 14px`, which
   beat `.pshot { margin-block-start: auto }` on both specificity and source
   order and so cancelled the bottom alignment, leaving the four screenshots
   stepping down the row. Deleted, along with the class that selected it.
   Dead CSS for a component that has changed does not stay harmless. */

/* ── Narrow screens: swap slides rather than cross-fade them ──────────────── */

/*
 * SPECIFICITY, not source order, is what decides here — and getting it wrong
 * cost a 2400px-tall hero on every phone.
 *
 * Above, `.hero.is-live .hero-slide:not(:first-child)` sets `display: grid`.
 * `:not()` takes the specificity of its argument, so that selector is (0,4,0).
 * The obvious override below, `.hero.is-live .hero-slide`, is only (0,3,0),
 * and a media query adds nothing. So slides 2 and 3 kept their `display: grid`
 * and — with the track switched to `display: block` here — stacked one under
 * the other down the page. The visitor saw the first slide, then roughly
 * 1500px of nothing (the other two slides, invisible but occupying space),
 * then the carousel controls stranded at the bottom.
 *
 * So the hiding rule repeats the `:not(:first-child)` shape to tie at (0,4,0)
 * and wins on order, and `.is-active` is (0,4,0) too and comes last.
 */
@media (max-width: 899px) {
  .hero.is-live .hero-track {
    display: block;
  }
  .hero.is-live .hero-slide,
  .hero.is-live .hero-slide:not(:first-child) {
    display: none;
    grid-area: auto;
    opacity: 1;
    transform: none;
    transition: none;
  }
  .hero.is-live .hero-slide.is-active {
    display: block;
    visibility: visible;
  }
}

/* ── Phones: one slide, one screen ───────────────────────────────────────── */
/*
 * The hero is a carousel, and a carousel whose slide is taller than the
 * viewport is not a carousel — the visitor scrolls past the controls without
 * ever learning there are two more slides. At 390x844 the budget is:
 *
 *   header 69 + band padding 28 + copy ~215 + gap 16 + panel ~390 + nav 52
 *
 * which lands just inside one screen. Everything below is spending against
 * that budget, so measure before loosening any of it.
 */
@media (max-width: 699px) {
  .hero {
    padding-block: 14px 14px;
  }

  .hero-grid {
    gap: 16px;
  }

  /* Copy: the desktop clamp bottoms out at 2rem, which is three lines of
     headline on a 390px screen. 1.75rem holds it to two most of the time. */
  .hero-h {
    font-size: clamp(1.75rem, 7.6vw, 2.1rem);
    margin-block-end: 10px;
    max-width: 20ch;
  }

  .hero-lede {
    font-size: 0.97rem;
    margin-block-end: 16px;
  }

  .hero-eyebrow {
    margin-block-end: 10px;
  }

  /* Slide 1 — drop the phone mockup. It is a picture of a phone, shown to
     someone holding one; it costs ~300px of the budget and tells them nothing
     they cannot see by opening the app. The three feature rows carry the
     slide on their own. */
  .hero-app .phone {
    display: none;
  }

  .hero-feats {
    gap: 10px;
  }

  .hero-feats li {
    gap: 11px;
  }

  .feat-ic {
    inline-size: 38px;
    block-size: 38px;
    border-radius: 12px;
  }

  .feat-glyph {
    inline-size: 18px;
    block-size: 18px;
  }

  /* Slides 2 and 3 — same cards, tighter. Nothing is removed here: the
     audience lists and the promises are the argument the slide is making. */
  .aud {
    padding: 0 14px 14px;
  }

  .aud-badge {
    inline-size: 44px;
    block-size: 44px;
    margin-block-start: -22px;
  }

  .aud-glyph {
    inline-size: 21px;
    block-size: 21px;
  }

  .aud h3 {
    margin: 8px 0 9px;
    font-size: 0.95rem;
  }

  .aud ul {
    gap: 7px;
  }

  .aud li {
    font-size: 0.84rem;
  }

  .promise-badge {
    inline-size: 46px;
    block-size: 46px;
  }

  .promise-glyph {
    inline-size: 21px;
    block-size: 21px;
  }

  .promise h3 {
    margin: 8px 0 3px;
  }

  .promise p {
    font-size: 0.78rem;
  }

  /* The controls are the only affordance telling the visitor there is more
     than one slide, so they stay close to the content they belong to. */
  .hero-nav {
    margin-block-start: 14px;
  }
}

/* ── Short phones: spend the last 150px ──────────────────────────────────── */
/*
 * The block above fits all three slides on a 390x844 screen. A 360x640 one —
 * an older Android, still common enough to matter — is 200px shorter, and
 * slides 2 and 3 carry two or four cards rather than a list, so they ran over.
 *
 * Keyed on HEIGHT, not width, because height is the thing that ran out. A
 * tall narrow phone does not need any of this and does not get it.
 *
 * Nothing is hidden here except the eyebrow, which is decorative and repeats
 * the brand name the header already shows. The audience lists and the
 * promises are the argument the slide makes, so they stay and get tighter.
 */
@media (max-width: 699px) and (max-height: 740px) {
  .hero-eyebrow {
    display: none;
  }

  .hero-h {
    font-size: clamp(1.5rem, 6.6vw, 1.8rem);
    margin-block-end: 8px;
  }

  .hero-lede {
    font-size: 0.9rem;
    line-height: 1.45;
    margin-block-end: 13px;
  }

  .hero-grid {
    gap: 12px;
  }

  .hero-auds {
    gap: 11px;
  }

  .aud {
    padding: 0 12px 11px;
  }

  .aud-badge {
    inline-size: 38px;
    block-size: 38px;
    margin-block-start: -19px;
  }

  .aud-glyph {
    inline-size: 18px;
    block-size: 18px;
  }

  .aud h3 {
    margin: 6px 0 7px;
    font-size: 0.9rem;
  }

  .aud ul {
    gap: 5px;
  }

  .aud li {
    font-size: 0.8rem;
  }

  .hero-promises {
    gap: 10px;
  }

  .promise-badge {
    inline-size: 40px;
    block-size: 40px;
  }

  .promise h3 {
    margin: 6px 0 2px;
    font-size: 0.88rem;
  }

  .promise p {
    font-size: 0.75rem;
    line-height: 1.4;
  }

  .hero-feats {
    gap: 8px;
  }

  .hero-nav {
    margin-block-start: 10px;
    padding: 6px 12px;
  }
}

/* ── Slide entrances ─────────────────────────────────────────────────────── */
/*
 * Each slide's parts arrive in reading order rather than all at once, which
 * is what makes a carousel feel like it changed rather than just redrew.
 *
 * Scoped to `.hero.is-live .hero-slide.is-active` on purpose, and that scope
 * is load-bearing in two directions:
 *
 *   - `is-live` means the carousel JS ran. Without it these rules never match,
 *     so a page with broken or blocked JS shows its hero content plainly at
 *     full opacity. `animation-fill-mode: both` starts elements at opacity 0,
 *     and an element that is invisible until an animation that never runs is
 *     exactly the kind of failure this file has had before.
 *   - `is-active` is toggled on every slide change, which re-triggers the
 *     animation each time. No JS needed to replay it.
 */
@keyframes heroRise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes heroFade {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.hero.is-live .hero-slide.is-active .hero-eyebrow,
.hero.is-live .hero-slide.is-active .hero-h,
.hero.is-live .hero-slide.is-active .hero-lede,
.hero.is-live .hero-slide.is-active .hero-copy .btn {
  animation: heroRise .6s cubic-bezier(.22, .7, .3, 1) both;
}

.hero.is-live .hero-slide.is-active .hero-eyebrow   { animation-delay: .05s; }
.hero.is-live .hero-slide.is-active .hero-h         { animation-delay: .13s; }
.hero.is-live .hero-slide.is-active .hero-lede      { animation-delay: .21s; }
.hero.is-live .hero-slide.is-active .hero-copy .btn { animation-delay: .29s; }

/* The panel comes in as one object, slightly later and slightly softer than
   the copy — it is the supporting evidence, not the headline. */
.hero.is-live .hero-slide.is-active .hero-panel {
  animation: heroFade .7s cubic-bezier(.22, .7, .3, 1) .24s both;
}

/* Its own rows then stagger inside it. Capped at six children: beyond that
   the last item would arrive nearly a second after the first, which stops
   reading as one movement and starts reading as a slow page. */
.hero.is-live .hero-slide.is-active .hero-feats li,
.hero.is-live .hero-slide.is-active .hero-auds > *,
.hero.is-live .hero-slide.is-active .hero-promises > * {
  animation: heroRise .55s cubic-bezier(.22, .7, .3, 1) both;
}

.hero.is-live .hero-slide.is-active .hero-feats li:nth-child(1),
.hero.is-live .hero-slide.is-active .hero-auds > *:nth-child(1),
.hero.is-live .hero-slide.is-active .hero-promises > *:nth-child(1) { animation-delay: .34s; }

.hero.is-live .hero-slide.is-active .hero-feats li:nth-child(2),
.hero.is-live .hero-slide.is-active .hero-auds > *:nth-child(2),
.hero.is-live .hero-slide.is-active .hero-promises > *:nth-child(2) { animation-delay: .42s; }

.hero.is-live .hero-slide.is-active .hero-feats li:nth-child(3),
.hero.is-live .hero-slide.is-active .hero-auds > *:nth-child(3),
.hero.is-live .hero-slide.is-active .hero-promises > *:nth-child(3) { animation-delay: .50s; }

.hero.is-live .hero-slide.is-active .hero-feats li:nth-child(n+4),
.hero.is-live .hero-slide.is-active .hero-auds > *:nth-child(n+4),
.hero.is-live .hero-slide.is-active .hero-promises > *:nth-child(n+4) { animation-delay: .58s; }

/*
 * Reduced motion gets the content, not the choreography. `animation: none`
 * and not a shorter duration: fill-mode `both` would otherwise leave these at
 * opacity 0 for however long the animation lasts, and someone who has asked
 * for less motion should not be the one waiting for it.
 */
@media (prefers-reduced-motion: reduce) {
  .hero.is-live .hero-slide.is-active .hero-eyebrow,
  .hero.is-live .hero-slide.is-active .hero-h,
  .hero.is-live .hero-slide.is-active .hero-lede,
  .hero.is-live .hero-slide.is-active .hero-copy .btn,
  .hero.is-live .hero-slide.is-active .hero-panel,
  .hero.is-live .hero-slide.is-active .hero-feats li,
  .hero.is-live .hero-slide.is-active .hero-auds > *,
  .hero.is-live .hero-slide.is-active .hero-promises > * {
    animation: none;
  }
}

/* ── Partners page: the four placement cards ────────────────────────────── */
/*
 * Four panels in one contained band: photo, gradient scrim, copy over it.
 *
 * `position: relative` on the card with `absolute` art and scrim, rather
 * than a background-image: an <img> carries alt text, intrinsic width and
 * height (so the box is reserved before the photo lands, no reflow) and
 * loading="lazy". A CSS background gets none of that.
 */
.pcards {
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  margin-block: 26px 10px;
  /* The panels sit flush, so the rounding goes on the band and the band
     clips them — rounding each panel would put four notches in every seam. */
  border-radius: 16px;
  overflow: hidden;
}

@media (min-width: 700px) {
  .pcards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Two up on a tablet, four across on a desktop. Never three: there are four
   placements, and 3 + 1 leaves a lone card on a second row. */
@media (min-width: 1040px) {
  .pcards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.pcard {
  position: relative;
  display: block;
  overflow: hidden;
  /* A set height, CAPPED at 400px — not an aspect ratio, and not a vw-driven
     height either. The band stops widening at --max, so its height has to
     stop too; two earlier attempts tied height to vw and kept growing on a
     wide screen. */
  block-size: clamp(320px, 34vw, 400px);
  background: var(--navy-dark, #0d2342);
  isolation: isolate;
}

.pcard-art,
.pcard-scrim {
  position: absolute;
  inset: 0;
}

.pcard-img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}

/* Shown if a photo is ever missing. Same box as the image, so dropping a
   file in changes the picture and nothing else about the layout. */
.pcard-fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 90% at 70% 15%, rgba(79, 142, 221, 0.4), transparent 60%),
    linear-gradient(160deg, #16325c, #0b1d38);
}

.pcard-fallback b {
  font-size: 3.4rem;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.16);
  letter-spacing: 0.02em;
}

/* Bottom-weighted, and solid enough by mid-height to carry the whole copy
   box over a photo of any brightness. */
.pcard-scrim {
  background: linear-gradient(
    to top,
    rgba(6, 18, 36, 0.95) 0%,
    rgba(6, 18, 36, 0.90) 34%,
    rgba(6, 18, 36, 0.62) 50%,
    rgba(6, 18, 36, 0.18) 72%,
    transparent 100%
  );
}

.pcard-copy {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  /* Fixed box, content from the top: this is what makes the four headings
     line up. Bottom-anchored auto-height put each heading wherever its own
     description left it, so they landed at four different heights.

     215px, measured at the NARROWEST the panels get — a quarter of --max,
     about 250px. Column width drives how many lines the description takes,
     so this has to be sized for the tightest column, not the widest. */
  block-size: 215px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 18px 20px;
  color: #fff;
}

.pcard-copy h3 {
  margin: 0 0 8px;
  font-size: clamp(1.1rem, 1.6vw, 1.3rem);
  line-height: 1.25;
  color: #fff;
}

.pcard-copy p {
  margin: 0 0 14px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: rgba(235, 242, 252, 0.9);
}

/* What each placement gets you. Do NOT bottom-align these with `margin-top:
   auto` — that is a second alignment fighting the fixed box above, and it
   opens a gap in the shorter cards while pressing their text to the edge. */
.pcard-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.pcard-points li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.85rem;
  line-height: 1.4;
  color: rgba(235, 242, 252, 0.92);
}

.pcard-points .tick-ic {
  flex: none;
  inline-size: 15px;
  block-size: 15px;
  margin-block-start: 2px;
  color: var(--accent, #f0a500);
}

/* ── Placement cards: motion ─────────────────────────────────────────────── */
/*
 * The four panels rise into place once, staggered; and hovering one dims the
 * other three.
 *
 * The entrance is a plain CSS animation on load, not a scroll observer:
 * these sit near the top of the page and are nearly always in view already,
 * so a trigger would cost JavaScript and buy nothing — and it cannot leave a
 * panel permanently invisible if a script fails. `backwards` on the fill
 * matters, or the delayed panels flash at full opacity before starting.
 *
 * Dimming rather than lifting: the panels are flush in one band, so raising
 * one would tear a hole in the row.
 */
@keyframes pcard-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

.pcard {
  animation: pcard-rise 0.55s cubic-bezier(0.22, 0.75, 0.3, 1) backwards;
  transition: filter 0.35s ease;
}

.pcard:nth-child(1) { animation-delay: 0.04s; }
.pcard:nth-child(2) { animation-delay: 0.12s; }
.pcard:nth-child(3) { animation-delay: 0.20s; }
.pcard:nth-child(4) { animation-delay: 0.28s; }

.pcard-img { transition: transform 0.5s cubic-bezier(0.22, 0.75, 0.3, 1); }

/* Behind `(hover: hover)`: on a touch screen :hover sticks after a tap,
   which would strand three panels dimmed with no way to clear them. */
@media (hover: hover) {
  .pcards:hover .pcard { filter: brightness(0.45) saturate(0.85); }
  .pcards .pcard:hover { filter: none; }
  .pcards .pcard:hover .pcard-img { transform: scale(1.04); }
}

@media (prefers-reduced-motion: reduce) {
  .pcard { animation: none; transition: none; }
  .pcard-img { transition: none; }
  .pcards .pcard:hover .pcard-img { transform: none; }
}

/* ── Campaign flow: the step row (.ctl / .fstep) ────────────────────────── */
/*
 * Ringed markers in a row, a step number leading each ring and a chevron in
 * each gap, with title and description beneath.
 *
 * Its own names, NOT .rsteps/.rstep — those are the About page's three
 * pillars and restyling them would silently redesign a page nobody asked
 * about. And .ctl, not .flow: `.flow` is already the journey strip inside
 * the home page's accordion.
 */
.ctl {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: grid;
  gap: 22px;
  grid-template-columns: 1fr;
}

@media (min-width: 760px) {
  .ctl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1040px) {
  .ctl { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
}

.fstep {
  position: relative;
  text-align: center;
  padding: 4px 6px 6px;
  border-radius: 16px;
}

/* Number and ring on one line, the number leading. inline-flex plus source
   order rather than absolute offsets: the number then sits against its OWN
   ring at any column width, and mirrors for free in Arabic, where the
   leading side is the right. */
.fstep-mark {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-block-end: 14px;
}

/* The ring: a thick coloured circle round a white disc. */
.fstep-ring {
  position: relative;
  z-index: 1;
  display: inline-grid;
  place-items: center;
  inline-size: 104px;
  block-size: 104px;
  border-radius: 50%;
  background: #fff;
  border: 9px solid var(--fstep-colour, #1a3c6e);
  color: var(--fstep-colour, #1a3c6e);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.fstep-glyph { inline-size: 38px; block-size: 38px; }

.fstep:hover .fstep-ring {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(18, 41, 76, 0.16);
}

/* The step number, immediately before its own ring. One per step, the last
   one included — it labels the step it sits beside, it does not mark the gap
   to the next one. The CHEVRON is the thing that belongs to the gap, which
   is why that is :not(:last-child) and this is not. */
.fstep-num {
  display: none;
  font-size: 1.15rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fstep-colour, #1a3c6e);
}

@media (min-width: 1040px) {
  .fstep-num { display: block; }

  /* The chevron in the gap: a square showing only its top and right borders,
     rotated to point along the reading direction. */
  .fstep:not(:last-child) .fstep-mark::after {
    content: "";
    position: absolute;
    inset-inline-end: -34px;
    inset-block-start: 50%;
    inline-size: 22px;
    block-size: 22px;
    border-top: 4px solid var(--line, #e4e8ee);
    border-right: 4px solid var(--line, #e4e8ee);
    transform: translateY(-50%) rotate(45deg);
  }

  /* Rotate the other way; do not mirror. scaleX(-1) on top of the 45deg
     rotation flips the axes rather than the arrow and leaves it aimed up and
     to the left. */
  html[dir="rtl"] .fstep:not(:last-child) .fstep-mark::after {
    transform: translateY(-50%) rotate(-135deg);
  }
}

.fstep-copy h4 {
  margin: 0 0 6px;
  font-size: 1rem;
  color: var(--navy-dark, #12294c);
}

.fstep-copy p {
  margin: 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--muted, #5a6572);
}

/* A ramp across the brand rather than four unrelated colours. */
.fstep-1 { --fstep-colour: #f0a500; }
.fstep-2 { --fstep-colour: #4aa3df; }
.fstep-3 { --fstep-colour: #2f7fd1; }
.fstep-4 { --fstep-colour: #12294c; }

@media (prefers-reduced-motion: reduce) {
  .fstep-ring { transition: none; }
  .fstep:hover .fstep-ring { transform: none; }
}

/* ── Partners page: the five values as a serpentine ──────────────────────── */
/*
 * Round badges on a line, linked by arcs that bulge alternately below and
 * above it.
 *
 * Each arc is the ::before of the node it arrives at, reaching back one full
 * column to the previous badge. Drawn that way, not as separate connector
 * elements, because the arcs then cannot drift out of step with the badges
 * at any width — there is one element per step and the geometry is relative
 * to it.
 *
 * An arc is a box with one horizontal border removed and the remaining three
 * rounded into a half-ellipse. Elliptical rather than a true half-circle:
 * the gap between badges changes with the viewport while the arc height does
 * not, and a shape that stays attached is worth more than one that stays
 * perfectly circular.
 *
 * .vwave / .vnode were both checked against this file before use — `.flow`
 * and `.rsteps` were each already taken when this page's other sections were
 * built.
 */
.vwave {
  list-style: none;
  margin: 26px 0 10px;
  padding: 0;
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
}

.vnode {
  position: relative;
  text-align: center;
}

.vnode-badge {
  position: relative;
  z-index: 1;
  display: inline-grid;
  place-items: center;
  inline-size: 74px;
  block-size: 74px;
  border-radius: 50%;
  margin-block-end: 14px;
  color: #fff;
  background: var(--vnode-colour, #1a3c6e);
  /* Sits the badge on top of the arc ends rather than beside them. */
  box-shadow: 0 0 0 6px var(--bg-soft, #f6f8fb);
}

.vnode-glyph { inline-size: 30px; block-size: 30px; }

/* A ramp across the brand, so the five read as one family rather than five
   unrelated colours. */
.vnode-1 { --vnode-colour: #12294c; }
.vnode-2 { --vnode-colour: #f0a500; }
.vnode-3 { --vnode-colour: #2f7fd1; }
.vnode-4 { --vnode-colour: #1a3c6e; }
.vnode-5 { --vnode-colour: #4aa3df; }

.vnode-copy h4 {
  margin: 0 0 6px;
  font-size: 1rem;
  color: var(--navy-dark, #12294c);
}

.vnode-copy p {
  margin: 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--muted, #5a6572);
}

/* The wave itself only exists once all five sit on one row. Below that the
   grid wraps and a connector would point at a badge on another line. */
@media (min-width: 1000px) {
  .vwave { gap: 0; grid-template-columns: repeat(5, minmax(0, 1fr)); }

  .vnode:not(:first-child)::before {
    content: "";
    position: absolute;
    /* One full column back: from this badge's centre to the previous one's. */
    inset-inline-start: -50%;
    inline-size: 100%;
    block-size: 54px;
    /* Centred on the badge's own centre line. */
    inset-block-start: 37px;
    border: 9px solid var(--vnode-colour, #1a3c6e);
    pointer-events: none;
  }

  /* Odd arrivals dip below the line, even ones rise above it. */
  .vnode:nth-child(odd)::before {
    border-block-start-color: transparent;
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    border-end-start-radius: 50% 100%;
    border-end-end-radius: 50% 100%;
  }

  .vnode:nth-child(even)::before {
    border-block-end-color: transparent;
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    border-start-start-radius: 50% 100%;
    border-start-end-radius: 50% 100%;
    inset-block-start: -17px;
  }

  /* Clear of whichever way the arc bulges. */
  .vnode-copy { padding-block-start: 10px; }
}

/* ── Cookie consent banner ───────────────────────────────────────────────── */
/*
 * A bar at the bottom, not a modal. It asks about one optional thing, so it
 * takes no focus trap, dims nothing and blocks nothing — the page is fully
 * usable whether or not it is answered.
 *
 * `[hidden]` in the markup is what keeps it off the page without
 * JavaScript; this file must never override that, which is why there is no
 * bare `.ckb { display: ... }` rule.
 */
.ckb {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 60;
  background: #fff;
  border-block-start: 1px solid var(--line, #e4e8ee);
  box-shadow: 0 -10px 30px rgba(12, 28, 54, 0.12);
  padding: 16px clamp(16px, 4vw, 28px);
  animation: ckb-up 0.35s ease;
}

@keyframes ckb-up {
  from { transform: translateY(100%); }
  to   { transform: none; }
}

.ckb-in {
  max-inline-size: var(--max, 1080px);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 24px;
}

.ckb-copy { flex: 1 1 32ch; min-inline-size: 0; }

.ckb-copy strong {
  display: block;
  margin-block-end: 4px;
  color: var(--navy-dark, #12294c);
  font-size: 0.95rem;
}

.ckb-copy p {
  margin: 0;
  font-size: 0.84rem;
  line-height: 1.5;
  color: var(--muted, #5a6572);
}

.ckb-copy a { color: var(--navy, #1a3c6e); }

/* The two answers carry equal visual weight apart from the primary fill:
   same size, same row, neither hidden behind a "manage preferences" step.
   A decline that is harder to find than an accept is not a free choice. */
.ckb-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  flex: none;
}

.ckb-acts .btn {
  font-size: 0.88rem;
  padding: 9px 18px;
}

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