/* ==========================================================================
   ESNAD — Alesnad Al-Taqni for Services
   Shared stylesheet (LTR base). RTL overrides live in rtl.css.
   Colours are PLACEHOLDERS — swap the hex values in :root when confirmed.
   ========================================================================== */

:root {
  /* B2: the header tile highlight, sampled from the rendered animation
     peak (rgba(74,144,217,0.52) over white). Single source of truth —
     B6 (section backgrounds) and B13 (logo cards) must use this token,
     not a re-sampled or approximated value. */
  --color-tile-blue: #A1C5EB;
  /* B6: section backgrounds. A 70% white tint of --color-tile-blue —
     same hue family, but body text (#42505f) measures 7.02:1 on it
     (AAA) where the full-strength tile blue is only 4.60:1. Headings
     in navy measure 9.98:1. */
  /* B1: restated as the rgba that composites to exactly #E3EEF9
     over white -- same approved B6 colour, but no longer opaque,
     so the fixed E watermark carries across the tinted bands. */
  --color-section-tint: rgba(161, 197, 235, 0.298);

  /* --- Brand palette (placeholder; dark blue aligned to the logo navy) --- */
  --color-dark-blue: #0E3A5F;   /* primary / headers / footer (matches logo) */
  --color-dark-blue-800: #0a2c49;
  --color-dark-blue-600: #14507f;
  --color-light-blue: #4A90D9;  /* accent / links / buttons */
  --color-light-blue-600: #3a7bc0;
  --color-light-blue-100: #e8f1fb;

  /* --- Neutrals --- */
  /* B10: was #1a2230, a neutral slate that read as black. Now the brand
     navy itself. 11.74:1 on white, 9.98:1 on the section tint. */
  --color-ink: #0E3A5F;
  /* B10: was #3f4a5a. Same lightness, re-cut on the navy hue.
     7.86:1 on white, 6.68:1 on the tint -- both clear AA body text. */
  --color-body: #2C5577;
  /* B10: was #6b7688. Same lightness on the navy hue. 5.38:1 on white,
     4.58:1 on the tint -- still AA, which the old grey only just was. */
  --color-muted: #476E90;
  --color-line: #e3e8ef;
  --color-bg: #ffffff;
  /* B6: was #f5f7fb (grey). Now the approved tint so no grey band
     remains anywhere. Single token — see --color-section-tint. */
  --color-bg-alt: rgba(161, 197, 235, 0.298);   /* B1: as above */
  /* B19: one reading measure for body copy site-wide. Measured line lengths
     before this ran 38ch (cards) to 134ch (About/Products intros); 66-75 is
     the readable band, so 72ch sits at the wide end of it -- generous, but
     without the long-line drift the client flagged. */
  /* D7 (supersedes B19's 72ch). The client's report is that standalone
     paragraphs still leave uneven whitespace -- which they did: a 72ch
     paragraph in a 1140px container left the whole remainder as a gutter on
     one side. They have asked for standalone copy to use the available space.
     100% is the content column, and because max-width is a CEILING every
     narrower context is untouched automatically: cards, copy beside an image
     and the Mission/Vision panels all keep the width their container gives
     them, exactly as the brief asks.
     NOTE FOR THE CLIENT: this puts long paragraphs at roughly 95 characters a
     line, past the 66-75 usually considered most comfortable. It is what was
     asked for and it is a single token to dial back -- set it to 80ch or 72ch
     here and everything follows. */
  --measure: 100%;
  --color-white: #ffffff;

  /* --- Utility --- */
  --color-whatsapp: #25D366;

  /* --- Typography --- */
  --font-base: "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
  --font-heading: "Segoe UI", system-ui, -apple-system, Arial, sans-serif;

  /* --- Spacing / layout --- */
  --container: 1200px;
  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 6px 24px rgba(27, 42, 107, 0.08);
  --shadow-lg: 0 14px 40px rgba(27, 42, 107, 0.14);
  --header-h: 76px;
  --transition: 0.25s ease;
}

/* --------------------------------- Reset -------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-base);
  color: var(--color-body);
  background: var(--color-bg);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  color: var(--color-ink);
  line-height: 1.25;
  margin: 0 0 0.6em;
  font-weight: 700;
}
h1 { font-size: clamp(2rem, 4vw, 3rem); }
h2 { font-size: clamp(1.6rem, 3vw, 2.25rem); }
h3 { font-size: 1.25rem; }
p { margin: 0 0 1em; }
a { color: var(--color-light-blue-600); text-decoration: none; transition: color var(--transition); }
a:hover { color: var(--color-dark-blue); }
img { max-width: 100%; display: block; }
ul { margin: 0; padding: 0; list-style: none; }

/* ------------------------------- Layout --------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 24px;
}
.section { position: relative; padding: clamp(48px, 8vw, 96px) 0; }
.section--alt { background: var(--color-bg-alt); }

/* Section separation, take two.
   The hairline rule read as a hard divider and reintroduced the "stacked
   boxes" feel it was meant to solve. Replaced with breathing room plus a very
   soft wash at the top of each section — enough to register a change of
   subject, with no line and no colour block. */
.section + .section,
.hero-slides + .section,
.page-head + .section { padding-top: clamp(64px, 9vw, 120px); }

.section + .section::before,
.hero-slides + .section::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 34px;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(14, 58, 95, 0.030), rgba(14, 58, 95, 0));
}
.section__head { max-width: 720px; margin-bottom: 48px; }
.eyebrow {
  display: inline-block;
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--color-light-blue-600);
  margin-bottom: 12px;
}
.lead { font-size: 1.15rem; color: var(--color-muted); }

/* ------------------------------- Buttons -------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 26px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.98rem;
  cursor: pointer;
  border: 2px solid transparent;
  transition: all var(--transition);
  white-space: nowrap;
}
.btn--primary { background: var(--color-light-blue); color: #fff; }
.btn--primary:hover { background: var(--color-light-blue-600); color: #fff; transform: translateY(-2px); }
.btn--ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,0.5); }
.btn--ghost:hover { background: rgba(255,255,255,0.12); color: #fff; }
.btn--dark { background: var(--color-dark-blue); color: #fff; }
.btn--dark:hover { background: var(--color-dark-blue-600); color: #fff; transform: translateY(-2px); }

/* ------------------------------- Header --------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--color-line);
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: var(--header-h);
}
/* ---- Header logo: horizontal, as it originally was ----------------------
   Emblem on the LEFT, ESNAD and WE PROTECT stacked to its RIGHT. The vertical
   lockup tried in the previous round is reverted -- that layout belongs to the
   page-transition loader, not the header.

   The ONE thing borrowed from the loader is the SIZE RATIO between the two
   pieces of text. Measured off the loader artwork (esnad-wm.png): the
   WE PROTECT band is 0.288x the height of the ESNAD band. Nothing else about
   the loader's layout or alignment is carried over. */
.brand { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.brand__logo { height: 42px; width: auto; }
.brand__name {
  font-weight: 800;
  font-size: 1.15rem;
  color: var(--color-dark-blue);
  letter-spacing: 0.02em;
}
/* The loader's ratio is 0.288, and the header WAS set to exactly that -- it has
   not drifted. But a ratio alone does not carry across a size change: the
   loader's ESNAD is 50.8px of ink so 0.288 leaves WE PROTECT at 14.6px, while
   the header's ESNAD is 13.2px so the identical ratio produced 3.8px, which is
   below the size at which the letterforms hold together.
   0.38 is the middle ground: clearly smaller than ESNAD, comfortably readable.
   The tracking is set so the strip still spans 0.920 of the ESNAD width, which
   is what actually makes it read as the same lockup.
   NB the tracking was retuned when the weight went to 700: bolder glyphs are
   wider, which had pushed the strip out to 0.942. Size is untouched. */
/* Bold, size unchanged. At 7px the 500 weight was too light to hold against
   the tiled header; 700 thickens the strokes without altering the metrics,
   so the 0.380 size ratio and 0.920 width ratio both still hold.
   Colour also moved off --color-muted to the body navy: muted is a light
   grey-blue that was costing contrast on the tiled background. */
.brand__name small { display: block; font-size: 0.437rem; font-weight: 700; color: var(--color-body, #2C5577); letter-spacing: 0.247em; }

/* Nav — always a single row; labels never wrap to two lines */
.main-nav ul { display: flex; align-items: center; gap: 2px; flex-wrap: nowrap; }
.main-nav a {
  position: relative;
  display: block;
  padding: 8px 10px;
  color: var(--color-ink);
  font-weight: 500;
  font-size: 0.88rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
/* Base appearance. The hover behaviour is defined ONCE, further down, in a
   single universal rule -- see "nav hover, single source of truth". There were
   four overlapping hover rules here across previous rounds; they happened to
   resolve correctly but any future edit could have flipped that by accident. */
.main-nav a {
  color: var(--color-dark-blue);
  background: transparent;
}
.main-nav a.is-active { color: var(--color-dark-blue); font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
  .main-nav a { transition: none; }
}

/* ---- PHASE 1c: header balance -------------------------------------------
   With only one language option left, space-between pushed the nav off centre
   and left a gap where the second flag used to sit. Letting the nav take the
   free space and centre inside it keeps brand / nav / language balanced. */
.main-nav { flex: 1 1 auto; display: flex; justify-content: center; min-width: 0; }
.header__actions { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }

/* Language switcher */
.lang-switch { position: relative; }
.lang-switch__toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-sm);
  background: #fff;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--color-ink);
  cursor: pointer;
}
.lang-switch__toggle:hover { border-color: var(--color-light-blue); }
.lang-switch__menu {
  position: absolute;
  top: calc(100% + 8px);
  inset-inline-end: 0;
  min-width: 150px;
  background: #fff;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 6px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: all var(--transition);
}
.lang-switch.is-open .lang-switch__menu { opacity: 1; visibility: visible; transform: translateY(0); }
.lang-switch__menu a {
  display: block;
  padding: 9px 12px;
  border-radius: 4px;
  color: var(--color-ink);
  font-size: 0.92rem;
}
.lang-switch__menu a:hover { background: var(--color-light-blue-100); }
.lang-switch__menu a.is-current { color: var(--color-light-blue-600); font-weight: 600; }

/* Mobile nav toggle */
.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  width: 42px;
  height: 42px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-sm);
  background: #fff;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--color-dark-blue);
  transition: var(--transition);
}

/* -------------------------------- Hero ---------------------------------- */
.hero {
  position: relative;
  background: linear-gradient(135deg, var(--color-dark-blue) 0%, var(--color-dark-blue-600) 100%);
  color: #fff;
  overflow: hidden;
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 85% 15%, rgba(74,144,217,0.35), transparent 45%),
    radial-gradient(circle at 10% 90%, rgba(74,144,217,0.2), transparent 40%);
  pointer-events: none;
}
.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 48px;
  align-items: center;
  /* same rhythm as every other section, so the gap below the hero matches
     the rest of the page (it measured 200px against 179px elsewhere).
     NB: padding-block, not `padding: x 0` — the shorthand would zero
     .container's side gutter and run the hero text into the screen edge. */
  padding-block: clamp(56px, 7vw, 96px);
}
.hero h1 { color: #fff; }
.hero p { color: rgba(255,255,255,0.85); font-size: 1.15rem; max-width: 46ch; }
.hero__cta { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 28px; }
.hero__visual { display: flex; justify-content: center; align-items: center; }

/* --------------------------- Cards / grids ------------------------------ */
.grid { display: grid; gap: 24px; }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }

.card {
  background: #fff;
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
  padding: 30px 26px;
  transition: transform var(--transition), box-shadow var(--transition);
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
.card__icon {
  width: 52px;
  height: 52px;
  border-radius: var(--radius-sm);
  background: var(--color-light-blue-100);
  color: var(--color-light-blue-600);
  display: grid;
  place-items: center;
  margin-bottom: 18px;
}
.card__icon svg { width: 26px; height: 26px; }
.card h3 { margin-bottom: 8px; }
.card p { color: var(--color-muted); font-size: 0.96rem; margin: 0; }

/* Stats strip */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; text-align: center; }
.stat__num { font-size: clamp(2rem, 4vw, 2.8rem); font-weight: 800; color: var(--color-dark-blue); }
.stat__label { color: var(--color-muted); font-size: 0.95rem; }

/* CTA band */
.cta-band {
  background: linear-gradient(135deg, var(--color-light-blue) 0%, var(--color-light-blue-600) 100%);
  color: #fff;
  border-radius: var(--radius);
  padding: clamp(36px, 6vw, 64px);
  text-align: center;
}
.cta-band h2 { color: #fff; }
.cta-band p { color: rgba(255,255,255,0.9); }

/* PHASE 4: compact page title, replacing the video hero on inner pages.
   Deliberately light rather than a dark band, so it sits inside the same
   continuous white surface Phase 3 established. */
.page-head { position: relative; padding: clamp(30px, 4.5vw, 54px) 0 clamp(22px, 3.5vw, 38px); }
.page-head .eyebrow { color: var(--color-light-blue-600); }
.page-head h1 {
  margin: 6px 0 12px;
  font-size: clamp(1.85rem, 3.8vw, 2.7rem);
  line-height: 1.18;
  color: var(--color-dark-blue);
}
.page-head p { max-width: 760px; margin: 0; color: var(--color-body); font-size: 1.02rem; line-height: 1.7; }
.page-head::after {
  content: "";
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  width: min(var(--container), 92vw); height: 1px;
  background: linear-gradient(90deg, transparent, var(--color-line) 14%, var(--color-line) 86%, transparent);
}
/* the title already provides separation, so suppress the generic rule after it */
.page-head + .section::before { display: none; }

/* PHASE 3: hero -> slideshow blend. The hero ends dark and the slideshow began
   abruptly at full brightness. A short dark-to-transparent wash across the top
   of the slideshow carries the hero's tone down into the photography instead of
   cutting hard. Sits above the slides but below the caption and controls. */
.hero-slides::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 110px;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to bottom,
              rgba(10, 44, 73, 0.55) 0%,
              rgba(10, 44, 73, 0.22) 45%,
              rgba(10, 44, 73, 0) 100%);
}

/* ---- EXPERIMENT (off by default) --------------------------------------
   Faint transmission-line motif behind the whole page. Enable by adding
   class="bg-lines" to <body>; remove the class to switch it off. Kept behind a
   class so the site is never shipped with an unreviewed background. */
body.bg-lines::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: url(../images/bg-transmission.svg) center 30% / 1600px auto repeat-x;
  opacity: 0.045;
}
body.bg-lines > * { position: relative; z-index: 1; }

/* ------------------------------- Footer --------------------------------- */
.site-footer {
  background: var(--color-dark-blue-800);
  color: rgba(255,255,255,0.75);
  padding: 64px 0 28px;
  font-size: 0.94rem;
}
.site-footer h4 { color: #fff; font-size: 1rem; margin-bottom: 18px; }
.footer__grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
  gap: 40px;
  padding-bottom: 40px;
  border-bottom: 1px solid rgba(255,255,255,0.12);
}
.site-footer a { color: rgba(255,255,255,0.75); }
.site-footer a:hover { color: #fff; }
.footer__brand .brand__name { color: #fff; }
.footer__links li { margin-bottom: 10px; }
.footer__contact li { margin-bottom: 12px; display: flex; gap: 10px; align-items: flex-start; }
/* One consistent icon colour across the footer: the brand sky blue reads
   clearly on the navy panel and marks the icons as accents rather than text.
   Fixed box + 1px nudge keeps each icon optically centred on its first line,
   including the multi-line address. */
.footer__contact .fic { flex: 0 0 18px; width: 18px; height: 18px; margin-top: 1px;
  color: #8fbaf0; display: inline-flex; align-items: center; justify-content: center; }
.footer__contact .fic svg { width: 16px; height: 16px; display: block; }
.footer__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding-top: 24px;
  flex-wrap: wrap;
  font-size: 0.88rem;
}

/* --------------------------- WhatsApp button ---------------------------- */
.wa-float {
  position: fixed;
  bottom: 24px;
  inset-inline-end: 24px;
  z-index: 200;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: var(--color-whatsapp);
  color: #fff;
  display: grid;
  place-items: center;
  box-shadow: 0 8px 24px rgba(37,211,102,0.4);
  transition: transform var(--transition);
}
.wa-float:hover { transform: scale(1.08); color: #fff; }
.wa-float svg { width: 30px; height: 30px; }
.wa-float::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--color-whatsapp);
  animation: wa-pulse 2.2s infinite;
}
@keyframes wa-pulse {
  0% { transform: scale(1); opacity: 0.7; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* ------------------------------ Responsive ------------------------------ */
@media (max-width: 960px) {
  .hero__inner { grid-template-columns: 1fr; text-align: center; }
  .hero p { margin-inline: auto; }
  .hero__cta { justify-content: center; }
  .hero__visual { order: -1; }
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
}
/* Collapse to hamburger while there isn't room for the full one-line nav */
@media (max-width: 1024px) {
  .nav-toggle { display: flex; }
  .main-nav {
    position: fixed;
    top: var(--header-h);
    inset-inline-start: 0;
    width: 100%;
    background: #fff;
    border-bottom: 1px solid var(--color-line);
    transform: translateY(-120%);
    transition: transform var(--transition);
    box-shadow: var(--shadow);
  }
  .main-nav.is-open { transform: translateY(0); }
  /* Sit above every section, and stay reachable on a short screen. */
  .main-nav { z-index: 200; max-height: calc(100vh - var(--header-h)); overflow-y: auto; }
  /* backdrop-filter would make the header the containing block for this
     fixed panel, which is what broke it before. An opaque bar looks the
     same at these widths and keeps `fixed` meaning the viewport. */
  .site-header { backdrop-filter: none; background: #fff; }
  .main-nav ul { flex-direction: column; align-items: stretch; padding: 12px; gap: 2px; }
  .main-nav { display: block; }
  .main-nav a { padding: 12px 14px; }
  .stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .grid--3, .grid--4, .grid--2 { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: 1fr; gap: 28px; }
  .brand__name small { display: none; }
}

/* ==========================================================================
   Branded page transition
   Outbound: the overlay fades in and the ESNAD mark plays, then we navigate.
   Inbound : an inline <head> script sets .pt-entering before first paint, so
             the new page is covered from the very first frame and no flash of
             content shows through. Fades out once the page is ready.
   The emblem layers are the same files the header already loads, so the
   overlay costs one extra request (the navy wordmark) and nothing else.
   ========================================================================== */
.pt {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  background: var(--color-bg, #fff);
  opacity: 0;
  visibility: hidden;
  transition: opacity .20s ease, visibility 0s linear .20s;
}
.pt.is-on { opacity: 1; visibility: visible; transition: opacity .16s ease; }

/* first paint of an incoming page: visible immediately, no transition */
html.pt-entering .pt { opacity: 1; visibility: visible; transition: none; }
html.pt-entering .pt.pt-out { opacity: 0; transition: opacity .22s ease; }

/* The loader is fixed brand motion, not layout: it must play identically in
   both languages. rtl.css sets `direction: rtl` on <body>, which inherits here
   and made .pt__bar span grow its width from the RIGHT edge on Arabic pages —
   the bar appeared to run backwards. Pinning the component to LTR fixes the
   direction without touching any other RTL behaviour (nav, text, alignment all
   stay as they are). The wordmark is Latin script in both languages anyway. */
.pt { direction: ltr; }
.pt__logo { display: flex; flex-direction: column; align-items: center; --pt-em: 116px; }
.pt__em { position: relative; width: var(--pt-em); aspect-ratio: 759 / 751; display: block; }
.pt__em img { position: absolute; inset: 0; width: 100%; height: 100%; }
.pt__wm { width: calc(var(--pt-em) * 1.95); height: auto; margin-top: calc(var(--pt-em) * 0.16); display: block; }

/* The mark does not animate here and there is no sound — it is simply present,
   in full brand colour, with a progress line beneath it doing the work. */

/* Progress line. It cannot report true cross-navigation load progress, so it is
   split across the two halves of the transition: it fills to ~68% while the
   outgoing page is still on screen, then completes on the incoming page before
   the cover clears. The effect is one continuous fill. */
.pt__bar {
  width: calc(var(--pt-em) * 1.95);
  height: 2px;
  margin-top: 20px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.10);
  overflow: hidden;
}
/* D2: the bar animates TRANSFORM, not width.
   Width is a layout property, so every frame of the old animation forced a
   reflow on the main thread -- the same thread that is busy parsing the
   document and decoding images while the loader is on screen. That contention
   is what was left of the stutter after the start-position fix: the animation
   itself was competing with page load for the thread. A scaleX transform is
   handled by the compositor and keeps running smoothly no matter how busy the
   main thread gets. The element is full width and scaled down instead. */
.pt__bar span {
  display: block;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
  height: 100%;
  border-radius: 2px;
  background: #2a2a2a;
}
/* Outbound (leaving a page): fill quickly to 68% while we navigate away. */
.pt.is-on .pt__bar span { animation: ptFill 340ms cubic-bezier(.25,.8,.3,1) forwards; }
/* NB .pt is forced to direction:ltr for the Arabic pages, so a left origin is
   correct in both languages -- the bar must always fill left to right. */
/* Inbound: .pt-entering is applied before first paint, so anything hung off it
   starts immediately. Previously that was the FINISH animation, which meant the
   bar read as complete about 200ms in while the page was still loading. Now it
   creeps toward 72% and waits there — an honest "still working" state — and
   only runs the finish once .pt-loaded is added on window load. */
html.pt-entering .pt__bar span { animation: ptCreep 2600ms cubic-bezier(.15,.75,.25,1) forwards; }
html.pt-entering.pt-loaded .pt__bar span { animation: ptFinish 240ms cubic-bezier(.25,.8,.3,1) forwards; }
@keyframes ptFill { from { transform: scaleX(0); } to { transform: scaleX(.68); } }
/* --pt-from is handed over by the page you just left, so the bar picks up
   where it stopped instead of snapping backwards. .08 is the fallback for
   a cold visit, where there is no previous page. */
@keyframes ptCreep { from { transform: scaleX(var(--pt-from, .08)); }
                     to   { transform: scaleX(.92); } }
@keyframes ptFinish { from { transform: scaleX(.72); } to { transform: scaleX(1); } }

/* Reduced motion: the transition is skipped entirely in JS, but if the overlay
   is ever shown, present it plainly rather than animating. */
@media (prefers-reduced-motion: reduce) {
  .pt, .pt.is-on, html.pt-entering .pt { transition: none; }
  .pt__bar span { animation: none !important; transform: scaleX(1); }
}

/* ------------------------- Phones: hero sizing --------------------------
   At 390px the h1 clamp floors at 2rem and .hero__inner keeps 56px of
   padding, so the hero alone filled ~58% of the screen before the visitor
   saw any content. These floors are phone-specific and deliberately below
   the clamp minimums above. */
@media (max-width: 560px) {
  .hero__inner { padding-block: 28px 32px; gap: 22px; }
  .hero h1 { font-size: clamp(1.45rem, 6.4vw, 1.8rem); line-height: 1.18; }
  .hero p { font-size: 0.95rem; line-height: 1.55; }
  .hero__cta { margin-top: 16px; gap: 8px; }
  /* 1 1 0, not 1 1 auto: the two buttons then split the row evenly instead of
     sizing to their own label lengths, which is what made them look mismatched
     side by side. */
  .hero__cta .btn { flex: 1 1 0; justify-content: center; text-align: center; }
  .page-head { padding: 26px 0 20px; }
  /* applies wherever the h1 sits — Projects moved its h1 into a section head */
  h1, .page-head h1 { font-size: clamp(1.5rem, 6.4vw, 1.9rem); }
  .section { padding: 40px 0; }
}

/* ======================= Feedback round 1 — layout ======================= */

/* Two-column text + image. Replaces the `max-width: 820px` columns that left a
   wide empty gutter on desktop (flagged as unbalanced whitespace), and gives
   the client the image slot they asked for beside "Who we are". */
.split { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(28px, 4vw, 56px); align-items: center; }
.split__text > :first-child { margin-top: 0; }
.split__text > :last-child { margin-bottom: 0; }
.split__media { margin: 0; border-radius: 14px; overflow: hidden;
  background: var(--color-surface, #f4f8fd);
  box-shadow: 0 18px 40px rgba(14,58,95,0.10);
  /* Match the height of the text column beside it — top-aligning left a void
     under the photo, which the client marked up.

     NB: NO aspect-ratio here. With align-self: stretch the height is fixed by
     the row, and an aspect-ratio would then compute the WIDTH from that height
     instead of obeying the grid column — which made the figure 677px wide in a
     522px column, overhanging the content edge by 153px and running 249px past
     the right of the screen at 1024px. width: 100% keeps the column in charge
     of the width and the row in charge of the height. The stacked layout below
     is the mirror case and does want a ratio. */
  align-self: stretch; width: 100%; min-height: 300px; }
.split__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  /* the source is a 2:1 frame; this keeps the helmet/vest in shot once the box
     is cropped narrower than that */
  object-position: 58% center; }
/* the form card is tall, so pin the columns to the top rather than centring */
.split--form { align-items: start; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
@media (max-width: 860px) {
  .split, .split--form { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  /* Stacked, the row height comes from the content, so `align-self: stretch`
     would leave aspect-ratio to drive the WIDTH instead — which pushed the
     homepage 167px past the viewport. Let the ratio set the height from the
     column width, as it does everywhere else. */
  .split__media { aspect-ratio: 16 / 9; align-self: start; min-height: 0; }
}

/* centred section heading (careers "Current Openings") */
.section__head--center { text-align: center; margin-inline: auto; max-width: 680px; }

/* ticked list on the careers page */
.ticks { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 14px; }
.ticks li { display: grid; grid-template-columns: 24px 1fr; gap: 12px;
  align-items: start; font-size: 0.95rem; color: var(--color-body, #42505f); }
.ticks .tick { width: 24px; height: 24px; border-radius: 50%; display: grid;
  place-items: center; background: rgba(74,144,217,0.14);
  color: var(--color-light-blue-600, #2b6cb8); }
.ticks .tick svg { width: 12px; height: 12px; }

/* raised card that holds the CV form */
.formcard { background: #fff; border: 1px solid var(--color-line, #e3e8ef);
  border-radius: 16px; padding: clamp(20px, 3vw, 34px);
  box-shadow: 0 22px 50px rgba(14,58,95,0.09); }
.formcard h3 { margin: 0 0 6px; font-size: clamp(1.2rem, 2.2vw, 1.5rem); }
.formcard__lead { margin: 0 0 18px; color: var(--color-body, #42505f); font-size: 0.92rem; }
.formcard__note { margin: 12px 0 0; text-align: center; font-size: 0.8rem; color: #7a8798; }
.formcard .frm { max-width: none; margin-top: 0; }
.req { color: #c2410c; font-weight: 700; }
.btn--block { width: 100%; justify-content: center; }

/* file field styled as a drop zone; the input itself covers the box so a tap
   anywhere opens the picker and a real drag-and-drop still lands on it */
.drop { position: relative; }
.drop input[type="file"] { position: absolute; inset: auto 0 0 0; height: 96px;
  opacity: 0; cursor: pointer; z-index: 2; }
.drop__box { display: grid; place-items: center; gap: 2px; height: 96px;
  border: 1px dashed #c6d2e2; border-radius: 12px; background: #f8fafd;
  text-align: center; padding: 8px; transition: border-color .18s, background .18s; }
.drop:hover .drop__box { border-color: var(--color-light-blue, #4A90D9); background: #f2f7fd; }
.drop__arrow svg { width: 20px; height: 20px; color: var(--color-dark-blue, #0E3A5F); }
.drop__main { font-size: 0.9rem; font-weight: 700; color: var(--color-dark-blue, #0E3A5F); }
.drop__sub { font-size: 0.76rem; color: #7a8798; font-weight: 600; }
.drop.has-file .drop__box { border-style: solid; border-color: var(--color-light-blue, #4A90D9); }

/* Even rhythm between sections. The feedback showed a thin band above one
   section and a deep one below the next; these two rules make every gap the
   same regardless of which backgrounds happen to meet. */
.section { padding-block: clamp(56px, 7vw, 96px); }
.section + .section,
.hero-slides + .section,
.page-head + .section { padding-top: clamp(56px, 7vw, 96px); }

/* Nothing should scroll past the footer — no rubber-band, no trailing gap.

   NB: there is deliberately no `overflow-x` guard on <body> here. Per CSS
   Overflow 3, when one axis is `clip`/`hidden` and the other is `visible`, the
   visible axis computes to `auto` — which turns <body> into a scroll container
   in its own right. On <body> that interacts with viewport scroll propagation
   and is a known source of a phantom second scroll area below the content,
   engine- and device-dependent. Measured horizontal overflow across
   320/360/375/390/428/768 is zero, so the guard bought nothing and carried
   that risk. If a page ever does overflow sideways, fix the offending element
   rather than reinstating this. */
html { overscroll-behavior-y: none; }

/* Phones: hero copy reads left, not centred over the video. */
@media (max-width: 860px) {
  .hero__inner { text-align: left; }
  .hero p { margin-inline: 0; }
  .hero__cta { justify-content: flex-start; }
  [dir="rtl"] .hero__inner { text-align: right; }
}

/* keep a required marker on the same line as its label text — .frm label is a
   grid, so a bare sibling span would take a row of its own */
.frm label > .lbl { display: block; }

/* ---- A13: even desktop rhythm -----------------------------------------
   Two things made the gaps uneven between pages:
     - a .section__head that is the section's ONLY child still carried its
       48px bottom margin on top of the section padding (careers "Current
       Openings" measured 205-227px against 179px elsewhere)
     - .page-head's bottom padding is a title-band value (38px), so the gap
       from a page title to the first section was 128px against 179px between
       sections further down
   Measured spread on the homepage is now ~20px; these bring the inner pages
   into the same band. */
.section__head:last-child { margin-bottom: 0; }
/* Give the page title band the same top and bottom breathing room a section
   gets, so every page starts its content at the same distance below the
   header. Measured: pages with a title band opened at 57px while pages whose
   first block is a normal section opened at 90px. */
.page-head { padding-block: clamp(56px, 7vw, 96px); }
/* Trailing margins on the last element inside a heading block leak into the
   section gap, which is where the remaining 191/198px outliers came from
   against a 179px rhythm. */
.section__head > :last-child,
.page-head > .container > :last-child { margin-bottom: 0; }
/* NB: the full-bleed band's rhythm lives in logo.css — `.hero-slides { margin: 0 }`
   there loads later and would override anything set here. */
@media (max-width: 560px) {
  /* keep the phone title band compact — the desktop value is too airy here */
  .page-head { padding-bottom: 26px; }
}

/* ---- .intro: replacement copy with no image ----------------------------
   Services, Products and About carry supplied copy and, per the client, no
   photograph. A left-aligned column would leave the wide empty gutter they
   flagged as unbalanced whitespace, so the column is constrained to a
   readable measure and centred — balanced on both sides, nothing added. */
.intro:not(.intro--art) { max-width: var(--measure); margin-inline: auto; }
.intro > .eyebrow { margin-bottom: 4px; }
.intro > h1, .intro > h2 { margin-top: 0; }
.intro > p { margin: 0 0 18px; }
.intro > p:last-child { margin-bottom: 0; }
.intro > p:first-of-type { font-size: 1.08rem; color: var(--color-dark-blue); }
@media (max-width: 560px) {
  .intro > p:first-of-type { font-size: 1rem; }
}

/* ---- item 2: hero text scrim (mobile) ---------------------------------
   The text sat straight on the video with only a text-shadow. This puts a
   soft panel behind the TEXT BLOCK rather than darkening the whole frame —
   and the full-frame overlay is eased back at the same widths, so more of the
   video actually shows than before. */
@media (max-width: 860px) {
  /* THE MOBILE HERO PANEL BUG.
     The panel used to hang off .hero__content. On desktop that element is the
     LEFT COLUMN of a two-column grid, about 48% of the hero, so the panel sat
     behind the text with the video visible beside it -- the intended look.
     Below this breakpoint the grid collapses to a single 1fr column, so
     .hero__content becomes the full width, and with -18px side insets on top
     the panel reached past the gutters to the hero's edges. Measured: 35% of
     the hero's area on desktop, 76% on mobile. That is the "solid box covering
     the whole video".

     The panel now hangs off .hero__lede -- the heading and paragraph only --
     so it hugs the text, stops short of the buttons, and leaves the video
     visible above, below and at the sides. */
  .hero__bg::after {
    background: linear-gradient(180deg, rgba(0,0,0,0.30) 0%, rgba(0,0,0,0.14) 52%, rgba(0,0,0,0.26) 100%);
  }
  .hero__content { position: relative; }
  .hero__lede > :first-child { margin-top: 0; }
  .hero__lede > :last-child { margin-bottom: 0; }
  /* THE BUTTON REGRESSION.
     Moving the panel off the buttons left .btn--ghost -- transparent, with a
     50%-alpha white border -- sitting directly on moving video. Over a dark
     frame the border showed; over a bright one it vanished, so it read as a
     broken, half-drawn outline. It also no longer matched the solid primary
     button's weight.
     The ghost variant is given its own translucent ground on mobile so it is
     legible regardless of what is behind it, and the border is taken to near
     full strength. Both buttons now carry the same shadow and the same visual
     weight. */
  .hero__cta .btn { box-shadow: 0 4px 14px rgba(0,0,0,0.32); }
  .hero__cta .btn--ghost {
    background: rgba(6, 26, 44, 0.58);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    border-color: rgba(255, 255, 255, 0.85);
  }

  /* The panel could only ever cover most of the hero while the hero was sized
     to its own text: the copy runs seven lines on a phone, so there was almost
     no hero left for the video to show in. Giving the hero a minimum height
     and centring the content creates real space above and below the text --
     which is where the video now reads. */
  /* The card sits at the TOP of the hero on mobile, not centred: the visitor
     reads it immediately instead of scrolling past dead space, and the video
     then fills everything below it. Scoped to this media query, so the desktop
     hero is untouched. */
  /* HERO HEIGHT (mobile).
     Measured at 390x844 the hero ran 625px with the copy ending at 493 --
     209px of empty video below the buttons, which is what read as "taller
     than it needs to be".

     The band under the buttons is set by PADDING, not by the viewport height,
     and that is the important part. A pure svh floor gives a different band on
     every phone because the copy reflows: measured at 66svh it left 178px of
     video at 430x932 but only 38px at 360x800, where the paragraph runs two
     lines longer. The video read as a sliver on exactly the phones with least
     room. Padding-bottom is measured from the END of the copy, so every phone
     gets the same ~100px of footage regardless of how the text wraps; the
     min-height is now just a floor for the widest screens, where the copy is
     short enough that the hero would otherwise collapse.

     Net effect: the hero gets shorter where it was too tall (640 -> 520 at
     430px wide) and keeps its band where it was already tight, even though
     the text block itself grew. */
  .hero { min-height: min(62svh, 520px); display: grid; align-items: start; }
  .hero__inner { padding-block: 18px 100px; }

  /* HERO TEXT SPACING (mobile).
     The three parts -- headline, paragraph, buttons -- were 15px and 16px
     apart with a 1.55 line inside the paragraph, so the whole thing read as
     one dense block. Each rule below beats its phone-query counterpart on
     source order at equal specificity (this block comes later in the file);
     none of them exists outside this media query, so desktop is untouched. */
  .hero h1 { margin-bottom: 24px; }
  .hero p { line-height: 1.78; }
  .hero__cta { margin-top: 30px; }
  /* NO PANEL ON MOBILE.
     Every card/scrim behind the hero copy is gone at this breakpoint -- the
     text, the paragraph and the buttons sit straight on the video, so the
     footage is visible across the whole hero. Legibility is carried entirely
     by a shadow on the GLYPHS (see logo.css, which loads after this file and
     therefore owns the .hero .hero__content text-shadow -- setting it here
     would lose on source order at equal specificity).

     Nothing in this block exists outside the media query, so the desktop hero
     keeps its diagonal scrim and its own text-shadow untouched. */

  /* THE BUTTON REGRESSION, again.
     With no card behind them, .btn--ghost is transparent with a 50%-alpha
     white border sitting directly on moving video: over a dark frame the
     border shows, over a bright one it vanishes, so it reads as a broken
     half-drawn outline. A button's own fill is not a panel behind the text
     block, so the ghost variant keeps a light translucent ground and both
     buttons keep a drop shadow to lift them off the footage. */
  .hero__cta .btn { box-shadow: 0 4px 14px rgba(0,0,0,0.38); }
  .hero__cta .btn--ghost {
    background: rgba(6, 26, 44, 0.45);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    border-color: rgba(255, 255, 255, 0.85);
  }
}

/* lead line demoted from a page heading (see fb5_headings.py) */
.lead--intro { font-size: 1.08rem; color: var(--color-dark-blue); margin-top: 6px; }

/* ---- text width: use the container, don't sit in a narrow column ------
   The three caps below were leaving a wide empty gutter to the right of every
   lead paragraph. Measured at 1280 (container inner 1152px): lifting them puts
   the Clients and Partners leads on one line each and roughly halves the line
   count of the About copy. Long paragraphs do end up with a long measure —
   that is the trade the brief asks for, to remove the gap. */
.section__head { max-width: none; }
/* B19: was `max-width: none` from the same widening round as .intro, which
   let the Partners page-head paragraph run to 131 characters a line. */
.page-head p { max-width: var(--measure); }
/* B19: this used to be `max-width: none`, added when the Products illustration
   was dropped and the copy was asked to fill the space. It applied to EVERY
   .intro though, so About and Products ran to 124-134 characters a line while
   other pages sat at 57-67. One measure now governs both. Note this is still
   WIDER than the 62ch column the copy had when the illustration was there.
   :not(--art) matters: .intro--art is a two-column grid holding the copy AND
   the illustration, so capping the grid itself crushed the Services copy to
   33ch. That variant caps its own text column instead. */
.intro:not(.intro--art) { max-width: var(--measure); margin-inline: auto; }

/* ---- intro with a line-art illustration beside it ---------------------
   Services and Products only. The text keeps a readable measure here because
   the empty space is being filled by artwork rather than by longer lines. */
.intro--art {
  display: grid;
  /* even split: the copy is capped at 62ch anyway, so the extra room goes to
     the illustration. At 1280 this takes the art column from 484px to ~544px,
     which is what stops the scene reading small beside the text. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: center;
}
.intro--art .intro__text { max-width: 62ch; }
.intro--art .intro__text > :first-child { margin-top: 0; }
.intro--art .intro__text > :last-child { margin-bottom: 0; }
.intro__art { margin: 0; display: flex; align-items: center; justify-content: center; }
.intro__art svg { width: 100%; height: auto; display: block; }
/* Isometric scene beside the copy. align-self: stretch makes the figure span
   the exact height of the text column so their top and bottom edges line up;
   object-fit keeps the artwork centred inside that box without distorting it. */
.intro__art--scene { align-self: stretch; position: relative; min-height: 280px; }
/* Absolutely positioned so the image contributes NO intrinsic height: the row
   is then sized purely by the text column, stretch makes the figure match it
   exactly (top and bottom edges flush), and object-fit centres the artwork
   inside without distorting it. Letting the img size the figure made the art
   26-66px taller than the text and pushed the two out of alignment. */
.intro__art--scene img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; display: block; }
@media (max-width: 860px) {
  .intro--art { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .intro--art .intro__text { max-width: none; }
  /* stacked: the scene becomes a band above the copy, not a side panel, so it
     goes back to flowing normally and sizing itself */
  .intro__art--scene { align-self: auto; position: static; min-height: 0;
    max-width: 420px; margin-inline: auto; }
  .intro__art--scene img { position: static; height: auto; }
}

/* ---- Projects: tighten the run from slideshow to timeline -------------
   Item 9. The slideshow, the intro and the timeline should read as one
   sequence, not three separated blocks. */
.projects-intro { padding-block: clamp(34px, 4vw, 52px) clamp(24px, 3vw, 36px); }
/* This used to pull the section up over the slideshow's bottom margin, which
   was a page-specific workaround for the white band. Item 5b removed that
   margin at source (see .hero-slides--page in logo.css), so the pull is not
   only redundant, it now drags the section 88px OVER the slideshow. */
.projects-intro + .section { padding-top: clamp(20px, 2.4vw, 32px); }

/* page heads with nothing but the title: no rule beneath, and the content
   below moves up to close the gap the removed elements left (items 12, 13) */
/* the rule is drawn by .page-head::after, not a border */
.page-head--bare::after { display: none; }
.page-head--bare { padding-bottom: clamp(24px, 3vw, 40px); }
.page-head--bare + .section { padding-top: clamp(24px, 3vw, 40px); }

/* About page: the same width fix as the intro copy, applied to the remaining
   prose blocks the client listed (Mission/Vision and Company Milestones). The
   Values and Goals cards are grid columns, not capped prose — they already
   fill the row, so they are left exactly as they are. */
.mv-wrap { max-width: none; margin: 0; }
/* NB: .milestones and .goals-tagline are capped in logo.css, which loads after
   this file — their overrides have to live there or they lose the cascade. */

/* ---- products: one row of large thin-line isometric icons --------------
   CURRENTLY UNUSED — the row was removed from solutions.html on request
   ("remove the icons for now"). Kept here because restoring it is just
   re-running _work/fb8_products.py, which regenerates the markup. Delete this
   block if the icons are dropped for good.
   Same drawing language as the footer icons (stroke only, currentColor, round
   caps) but isometric and much larger. Sits under the full-width copy; there
   are no captions because the paragraph above already names the categories. */
.iconrow {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(16px, 4vw, 56px);
  margin-top: clamp(30px, 4vw, 48px);
  /* span the same width as the copy above, so the row reads as part of that
     block rather than a cluster hugging the left edge */
  color: var(--color-dark-blue, #0E3A5F);
}
.iconrow svg { width: clamp(78px, 10vw, 132px); height: auto; flex: 0 0 auto;
  opacity: 0.92; }
@media (max-width: 560px) {
  /* keep them on one line at phone widths — they are the point of the row */
  .iconrow { gap: 10px; justify-content: space-around; }
  .iconrow svg { width: clamp(58px, 19vw, 78px); }
}

/* ---- B7: collapsed section headings ------------------------------------
   The small label and the big heading are now a single heading. Both variants
   carry the label's colour (--color-light-blue-600), which is what B7 asked
   for; --label additionally renders the text uppercase because the label was
   uppercase by style, not in the source text.
   NB this deliberately overrides the site-wide navy heading colour from B3 for
   these specific headings — see the note in the report. */
.heading--accent,
.heading--label { color: var(--color-light-blue-600, #3a7bc0); }
/* D6: the heading FONT never changed -- --font-heading has been Segoe UI in
   every build. What changed was this rule: B7 promoted the small labels to
   headings and rendered them UPPERCASE with added letter-spacing, and set in
   caps at heading size they read as a different typeface. The transform is
   removed so the headings render in the normal face again; the B7 size and
   colour are deliberately kept, as instructed. */
.heading--label { text-transform: none; letter-spacing: normal; }

/* ---- B1: fixed E watermark ----------------------------------------------
   Large, faint, and visually still while the page scrolls, fading out as the
   footer arrives. position:fixed does the "still" part; the negative z-index
   keeps it behind every piece of content including non-positioned text. */
.esnad-watermark {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity .45s ease;
}
/* Sized against the SMALLER viewport axis so it stays whole on a phone in
   portrait and on a wide desktop alike, never cropped by the viewport. */
.esnad-watermark img {
  width: min(58vw, 58vh, 660px);
  height: auto;
  opacity: 0.055;
}
/* The footer is in view: the mark has done its job and gets out of the way. */
.esnad-watermark.is-off { opacity: 0; }

@media (max-width: 640px) {
  /* Slightly stronger on a phone: the mark is smaller relative to the text
     around it, so at 5.5% it read as a printing artefact rather than a mark. */
  .esnad-watermark img { width: min(72vw, 46vh); opacity: 0.07; }
}
@media (prefers-reduced-motion: reduce) {
  .esnad-watermark { transition: none; }
}
@media print {
  .esnad-watermark { display: none; }
}

/* ---- B19: consistent paragraph measure ---------------------------------
   Applies to body copy only. Narrower contexts (cards at 38ch, the hero at
   46ch) already sit inside this and are unaffected -- max-width is a ceiling,
   not a width. Paragraphs are only re-centred where their heading block is
   centred; under a left-aligned heading they stay left-aligned. */
main p { max-width: var(--measure); }
.section__head--center p,
.page-head--center p,
.section__head--center .lead,
.page-head--center .lead { margin-inline: auto; }


/* ======================================================================
   ROUND 5 — header reverted
   ======================================================================
   The Round 4 block that lived here is gone: the utility bar, the
   `.esnad-floor--header { display: none }` that killed the tiled background,
   the `.site-header { background:#fff }` and the whole navy nav strip. The
   tiled light-blue header and the original nav rules (navy text, navy pill +
   white text on hover) are therefore live again untouched -- they were only
   ever being overridden, never removed, so nothing had to be rebuilt.

   The one thing kept from Round 4 is D3's "text grows slightly on hover",
   which the client did not ask to lose. It uses transform, not font-size:
   the nav is a single no-wrap row and resizing text would reflow every
   sibling. */
/* ---- nav hover, single source of truth ---------------------------------
   ONE rule governs hover for every nav item, active or not. Both selectors are
   listed explicitly so an active item can never fall through to a different
   branch of the cascade -- hovering "About Us" from the homepage now renders
   identically to hovering "Home" from the homepage.

   `color` is deliberately NOT transitioned. The background is, so the pill
   fades in, but the text flips to white on the first frame. Transitioning both
   put the text mid-way between navy and white while the navy pill was already
   half-opaque, which is a genuinely low-contrast moment even if brief. */
.main-nav a { transition: background-color .16s ease, transform .16s ease; }
/* The hover declarations are NOT here. They live in logo.css, immediately
   after the `a:not(.btn):hover` rule that was overriding them -- see the long
   note there. Putting them back in this file will break the nav again. */

@media (prefers-reduced-motion: reduce) {
  .main-nav a, .main-nav a:hover, .main-nav a:focus-visible { transform: none; }
}
@media (max-width: 1024px) {
  /* The panel is white again with navy links, as it was before Round 4, and
     sits directly under the header now that the utility bar is gone. */
  .main-nav a:hover, .main-nav a:focus-visible, .main-nav a.is-active:hover { transform: none; }
}

/* ---- D7: even line lengths -------------------------------------------
   Widening alone does not fix "lines of inconsistent length" -- the ragged
   right edge and the one-word last line are what read as uneven.
   text-wrap: pretty makes the browser look at the whole paragraph rather than
   breaking line by line, which removes orphans and evens the rag. Headings
   get `balance`, which is the equivalent for short blocks.
   Both degrade silently to normal wrapping where unsupported. */
p, li, .lead, dd { text-wrap: pretty; }
h1, h2, h3, h4, .pyear__year { text-wrap: balance; }

/* ======================================================================
   ROUND 5 — footer rebalance, QR lightbox, watermark emblem
   ====================================================================== */

/* ---- 4: footer rebalance ------------------------------------------------
   The brand column carried the DUNS mark as well as the logo, which left the
   logo looking small beside the amount of content next to it. DUNS now has
   its own column on the right and the logo is free to grow. */
.footer__grid { grid-template-columns: 1.7fr 1fr 1fr 1.2fr auto; }

/* Sized so the logo block reads at the same weight as the "Get in touch"
   column beside it -- it was 187px against that column's 293px. */
.footer__brand .site-logo { --lem: clamp(170px, 19vw, 260px); }

.footer__duns {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  text-align: end;
  padding-inline-start: 20px;
}
.footer__duns-txt { margin: 0; display: flex; flex-direction: column; gap: 3px; line-height: 1.3; }
.footer__duns .duns__label {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em;
  font-weight: 600; color: rgba(255, 255, 255, 0.65);
}
.footer__duns .duns__num {
  font-size: 1rem; font-weight: 700; letter-spacing: 0.03em; color: #fff;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;          /* the number was clipping to "98-646-453" */
}
.footer__duns .duns__label { white-space: nowrap; }
/* Enough room for the longest line, so the column never squeezes the number. */
.footer__duns { min-width: 190px; }

/* The QR is a real button: it opens the lightbox, so it must be reachable by
   keyboard and announce itself. Styled to look like the plate, not a button. */
.duns-qr {
  appearance: none;
  border: 0;
  padding: 6px;
  border-radius: 8px;
  background: #fff;
  line-height: 0;
  cursor: zoom-in;
  transition: transform .16s ease, box-shadow .16s ease;
}
/* Sized against the footer logo beside it (--lem, 170-260px) rather than the
   96px chip it was: at that size it left an obvious empty gap in the column.
   Deliberately a little smaller than the logo so the logo still leads. */
.duns-qr img { display: block; width: clamp(120px, 13vw, 190px); height: auto; aspect-ratio: 1; }
.duns-qr:hover, .duns-qr:focus-visible { transform: scale(1.04); box-shadow: 0 8px 24px rgba(0,0,0,0.35); }
.duns-qr:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

@media (max-width: 1024px) {
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .footer__duns { align-items: flex-start; text-align: start; padding-inline-start: 0; }
}
@media (max-width: 640px) {
  .footer__grid { grid-template-columns: 1fr; }
}

/* ---- 2: QR lightbox -----------------------------------------------------
   Expands in place over the dimmed page. Not a navigation, so the visitor
   never leaves the footer they were looking at. */
.qrbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(6, 20, 33, 0.72);
  backdrop-filter: blur(3px);
  animation: qrIn .18s ease-out both;
}
.qrbox[hidden] { display: none; }
@keyframes qrIn { from { opacity: 0; } to { opacity: 1; } }
.qrbox__img {
  width: min(78vw, 78vh, 460px);
  height: auto;
  background: #fff;
  padding: 18px;
  border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}
.qrbox__close {
  position: absolute;
  top: 18px;
  inset-inline-end: 18px;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 1.7rem;
  line-height: 1;
  cursor: pointer;
}
.qrbox__close:hover, .qrbox__close:focus-visible { background: rgba(255, 255, 255, 0.28); }
.qrbox__close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .qrbox { animation: none; } }

/* ---- 5: watermark is the real emblem ------------------------------------
   Was a single layer, which rendered as a plain E. The mark is two layers --
   the ring/crescent plate and the E over it -- exactly as the loader and the
   footer logo stack them. Icon only: no wordmark, no tagline. */
.esnad-watermark__em {
  position: relative;
  display: block;
  width: min(58vw, 58vh, 660px);
  aspect-ratio: 759 / 751;
}
.esnad-watermark__em img { position: absolute; inset: 0; width: 100%; height: 100%; }
@media (max-width: 640px) {
  .esnad-watermark__em { width: min(72vw, 46vh); }
}

/* ---- "View More Info": a plain text link, not a button ------------------ */
.prod__more {
  margin-top: auto;
  align-self: flex-start;
  background: none;
  border: 0;
  padding: 0;
  color: var(--color-light-blue-600, #3a7bc0);
  font-weight: 600;
  font-size: 0.92rem;
  text-decoration: none;
}
/* Item 3: this held a literal 0x11 control byte followed by "92" -- the CSS
   escape \2192 (a right arrow) had lost its backslash, so the browser drew
   a tofu box and the digits. Written as the real character now, so there is
   no escape sequence left that can break. */
.prod__more::after { content: " →"; }
.prod__more:hover, .prod__more:focus-visible { text-decoration: underline; color: var(--color-dark-blue); }

/* The product card is the scroll target of a deep link, and the header is
   sticky -- without this the card lands underneath it. */
.prod { scroll-margin-top: calc(var(--header-h) + 24px); }

}
