/* =========================================================
   RAISSY — CATENARY: The Live Conductor
   Motif kit: THREAD · NODE · GRID · GHOST NUMERAL
   Rule: LIGHT = ENERGY. Light only lives on the thread.
   ========================================================= */

@font-face { font-family:"Plex AR"; src:url("../fonts/plex-ar-400.woff2") format("woff2"); font-weight:400; font-display:swap; }
@font-face { font-family:"Plex AR"; src:url("../fonts/plex-ar-500.woff2") format("woff2"); font-weight:500; font-display:swap; }
@font-face { font-family:"Plex AR"; src:url("../fonts/plex-ar-600.woff2") format("woff2"); font-weight:600; font-display:swap; }
@font-face { font-family:"Plex AR"; src:url("../fonts/plex-ar-700.woff2") format("woff2"); font-weight:700; font-display:swap; }
@font-face { font-family:"Plex LA"; src:url("../fonts/plex-la-400.woff2") format("woff2"); font-weight:400; font-display:swap; }
@font-face { font-family:"Plex LA"; src:url("../fonts/plex-la-500.woff2") format("woff2"); font-weight:500; font-display:swap; }
@font-face { font-family:"Plex LA"; src:url("../fonts/plex-la-600.woff2") format("woff2"); font-weight:600; font-display:swap; }
@font-face { font-family:"Plex LA"; src:url("../fonts/plex-la-700.woff2") format("woff2"); font-weight:700; font-display:swap; }

:root{
  /* ===== Raissy brand identity — sampled from the official logo ===== */
  --royal:#162EBD;        /* RAISSY wordmark + right block — PRIMARY */
  --royal-600:#2A45D6;    /* royal hover */
  --cyan:#0E99E1;         /* icon left block — technical / active highlight */
  --cyan-bright:#54BFF0;  /* energy peak */
  /* grounds (deep navy helper, never pure black) */
  --void:#07123A; --graphite:#0B1A4A; --slate:#13266A; --hairline:#243C77;
  --paper:#F3F6FC; --paper-sink:#E6EDF9;   /* clean cool off-white */
  /* text */
  --offwhite:#EAF1FB; --mist-cool:#9AACD2; --mist-warm:#4A5C80; --ink:#0C1A45;
  /* signal roles (all mapped to brand blue family — no gold/brass) */
  --steel:#3E63C9; --glow:var(--cyan); --plant:var(--cyan-bright);
  --brass:var(--cyan); --brass-dk:var(--royal); --steel-dk:#1B3A8A;
  --line-paper:rgba(12,26,69,.12);

  --fl:"Plex LA","Segoe UI",Arial,sans-serif;
  --fa:"Plex AR","Segoe UI",Tahoma,sans-serif;
  --font:var(--fa);

  /* Widened from 1280px (2026-09-15): on the client's wide screens every
     section sat in a narrow middle band and its copy stacked into tall
     columns. Nothing changes at 1440px and below, where .wrap is already
     the full width. */
  --wrap:1680px;
  --pad:clamp(22px,5.5vw,96px);
  --hd-h:clamp(88px,7vh,104px);   /* approx unscrolled header height: 54px logo + 2×20px pad */
  --sec:clamp(44px,5.2vw,80px);
  /* One type scale (2026-09-15): a section's name is its title, the line that
     follows it is a subtitle, and every run of content copy shares one size. */
  --fs-title:clamp(1.7rem,2.6vw,2.5rem);
  --fs-sub:clamp(1.08rem,1.35vw,1.28rem);
  --fs-body:1.0625rem;
  --lh-body:1.85;
  --ease:cubic-bezier(.19,.7,.25,1);
  --ease2:cubic-bezier(.22,1,.36,1);  /* premium scroll-reveal easing */
}
html[lang="en"]{--font:var(--fl);}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;}
body{font-family:var(--font);background:var(--paper);color:var(--ink);font-size:16px;line-height:1.7;-webkit-font-smoothing:antialiased;overflow-x:hidden;}
img{display:block;max-width:100%;}
a{color:inherit;text-decoration:none;}
button{font-family:inherit;background:none;border:none;cursor:pointer;color:inherit;}
ol,ul{list-style:none;}
::selection{background:var(--plant);color:var(--void);}

h1,h2,h3{font-weight:600;line-height:1.12;}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum";}
.u{color:var(--brass);font-size:.82em;font-weight:600;}

.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--pad);position:relative;z-index:2;}
.sec{position:relative;overflow:hidden;padding-block:var(--sec);}
/* Two adjacent sections each pay the full --sec, so the gap between them is
   twice a section's own breathing room — on a page like /quality, which is
   four short sections stacked, that reads as a page of empty bands. The
   client called it out in the 2026-08-26 review, and again on 2026-09-15,
   when --sec itself came down by about a third. A section that FOLLOWS
   another keeps half of its leading pad, without touching the space above
   the first section or below the last. */
.sec + .sec{padding-block-start:calc(var(--sec) * .5);}
.sec[data-ground="paper"]{background:var(--paper);color:var(--ink);--gl:rgba(12,26,69,.05);}
.sec[data-ground="void"]{background:var(--void);color:var(--offwhite);--gl:rgba(234,241,251,.06);}
.sec[data-ground="graphite"]{background:var(--graphite);color:var(--offwhite);--gl:rgba(234,241,251,.05);}
/* Sections now alternate white / navy (2026-09-15), and the same partial can
   sit on either ground — so the label, its subtitle and the handful of
   components that hardcoded one ground take their colour from the section's
   ground instead of from a --dark/--light class. */
.sec[data-ground="paper"] .label{color:var(--ink);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .label{color:var(--offwhite);}
.sec[data-ground="paper"] .label ~ :is(.h-section,.contact__title){color:var(--mist-warm);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .label ~ :is(.h-section,.contact__title){color:var(--mist-cool);}
.sec[data-ground="paper"] .h-section--light{color:inherit;}
/* sectors on navy */
.sec[data-ground="void"] .sector{border-top-color:var(--hairline);}
.sec[data-ground="void"] .sector:last-child{border-bottom-color:var(--hairline);}
.sec[data-ground="void"] .sector__t{color:var(--mist-cool);}
.sec[data-ground="void"] .sector:hover .sector__t{color:var(--offwhite);}
.sec[data-ground="void"] .sector.active .sector__t{color:var(--glow);}
.sec[data-ground="void"] .sector__node{border-color:var(--mist-cool);}
.sec[data-ground="void"] .sector .ic{stroke:var(--mist-cool);}
.sec[data-ground="void"] .sector.active .ic{stroke:var(--glow);}
.sec[data-ground="void"] .sectors__stage{background:var(--slate);}
.sec[data-ground="void"] .stage__desc{color:var(--mist-cool);}
.sec[data-ground="void"] .stage__points li{color:var(--offwhite);}
/* projects on white */
.sec[data-ground="paper"] .ptabs{border-block-end-color:var(--line-paper);}
.sec[data-ground="paper"] .ptab{color:var(--mist-warm);}
.sec[data-ground="paper"] .ptab:hover,.sec[data-ground="paper"] .ptab[aria-selected="true"]{color:var(--ink);}
.sec[data-ground="paper"] .pscroll__btn{border-color:var(--line-paper);color:var(--ink);}
/* clients on navy: the logos keep a light tile, since most are dark marks on transparent */
/* Several marks are JPGs on pure white, so the tile is pure white too — no box shows around them. */
/* contact on white */
.sec[data-ground="paper"] .contact__title{color:var(--ink);}
.sec[data-ground="paper"] .contact__list li{border-top-color:var(--line-paper);}
.sec[data-ground="paper"] .contact__list li:last-child{border-bottom-color:var(--line-paper);}
.sec[data-ground="paper"] .contact__k{color:var(--mist-warm);}
.sec[data-ground="paper"] .contact__v{color:var(--ink);}

/* ---------- 12-column engineering grid (vertical lines removed per request) ---------- */
.grid-cols{display:none;}

/* ---------- INSTRUMENTATION LABEL ---------- */
/* The label names the section, so it sets as the section's title. */
.label{display:inline-flex;align-items:center;gap:14px;font-size:var(--fs-title);font-weight:700;line-height:1.3;letter-spacing:-.01em;color:var(--ink);}
html[lang="ar"] .label{letter-spacing:0;}
.label i{width:28px;height:2px;background:var(--brass);flex-shrink:0;}
.label--dark{color:var(--offwhite);}
/* In a page hero the <h1> is the title, so the label there stays a kicker. */
.phero .label{gap:10px;font-size:.72rem;font-weight:600;line-height:inherit;letter-spacing:.22em;text-transform:uppercase;color:var(--mist-cool);}
html[lang="ar"] .phero .label{font-size:.85rem;letter-spacing:.03em;text-transform:none;}
.phero .label i{width:18px;height:1px;}

/* ---------- ICON ---------- */
/* App\Support\Icons' marks: 24×24 line work, drawn stroke-only so the whole set
   takes its colour and weight from here. Brass is what the label's rule and the
   tag row's tick already carry on either ground. Sized in em, so a mark tracks
   the type it sits beside — 24px against body copy, 19px against a .8rem tag —
   and holds one optical hairline weight at both. The flex row it sits in places
   it with its own gap, so there is no physical margin to flip in RTL. */
.ic{width:1.5em;height:1.5em;flex-shrink:0;fill:none;stroke:var(--brass);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;}

/* ---------- THE THREAD (catenary) ---------- */
.thread{position:absolute;inset:0;width:100%;height:100%;display:block;overflow:visible;pointer-events:none;}
/* The rail draws in with a clip rather than a stroke-dash. Under
   non-scaling-stroke, Chrome measures dash lengths in screen pixels and
   ignores pathLength, so a 1000 dash covered only the first 1000px of a seam
   that spans the whole viewport — on a wide screen the line stopped halfway
   and left a gap. A clip is unit-free: it reveals the full width everywhere. */
.thread .rail{fill:none;stroke:var(--steel);stroke-width:1;vector-effect:non-scaling-stroke;opacity:.55;
  clip-path:inset(-4px 100% -4px 0);transition:clip-path 1.2s var(--ease);}
.thread.drawn .rail{clip-path:inset(-4px 0 -4px 0);}
.thread .pulse{fill:none;stroke:var(--plant);stroke-width:1.5;vector-effect:non-scaling-stroke;
  stroke-dasharray:12 1000;stroke-dashoffset:1012;filter:drop-shadow(0 0 3px rgba(84,191,240,.7));opacity:0;}
.thread.drawn .pulse{opacity:.95;animation:flow 8s linear infinite;}
@keyframes flow{from{stroke-dashoffset:1012}to{stroke-dashoffset:12}}

/* 44px, not 74: sections that follow another start ~40px down, and a deeper
   curve ran through their headings. The path is drawn preserveAspectRatio=none,
   so it simply flattens. */
.seam{position:absolute;inset-block-start:-2px;inset-inline:0;height:44px;z-index:1;}

/* =========================================================
   BUTTONS
   ========================================================= */
.btn{display:inline-flex;align-items:center;gap:10px;padding:15px 30px;font-size:.92rem;font-weight:600;letter-spacing:.01em;
  border:1px solid transparent;transition:background .4s var(--ease),color .4s,border-color .4s,transform .4s var(--ease);position:relative;}
.btn--solid{background:var(--royal);color:#fff;}
.btn--solid:hover{background:var(--cyan);color:var(--void);transform:translateY(-2px);}
.btn--line{border-color:var(--line-paper);color:var(--ink);}
.sec[data-ground="paper"] .btn--solid{background:var(--royal);color:#fff;}
.sec[data-ground="paper"] .btn--solid:hover{background:var(--royal-600);color:#fff;}
.btn--line{border-color:rgba(234,241,251,.28);color:var(--offwhite);}
.btn--line:hover{border-color:var(--glow);color:var(--glow);transform:translateY(-2px);}
.btn--full{width:100%;justify-content:center;}

/* =========================================================
   HEADER
   ========================================================= */
.hd{position:fixed;inset-block-start:0;inset-inline:0;z-index:90;padding-block:20px;border-bottom:1px solid transparent;
  transition:background .5s var(--ease),padding .4s var(--ease),border-color .5s;}
.hd__inner{display:flex;align-items:center;gap:20px;z-index:2;}
.hd__logo{height:54px;width:auto;filter:brightness(0) invert(1);transition:filter .5s,height .4s;}
.hd.scrolled{background:rgba(7,18,58,.88);backdrop-filter:blur(10px) saturate(1.2);padding-block:12px;border-color:var(--hairline);}
.hd__nav{display:flex;gap:clamp(14px,1.6vw,24px);margin-inline-start:auto;}
.hd__nav a{font-size:.92rem;font-weight:500;color:rgba(234,241,251,.82);position:relative;padding-block:6px;transition:color .3s;}
.hd__nav a::after{content:"";position:absolute;inset-block-end:0;inset-inline-start:0;width:0;height:1px;background:var(--glow);transition:width .4s var(--ease);box-shadow:0 0 6px rgba(14,153,225,.6);}
.hd__nav a:hover{color:var(--offwhite);}
.hd__nav a.active{color:var(--offwhite);}
.hd__nav a.active::after{width:100%;}
.hd__right{display:flex;align-items:center;gap:16px;}
.hd__profile{display:inline-flex;align-items:center;gap:8px;white-space:nowrap;padding:8px 15px;border:1px solid var(--hairline);border-radius:999px;font-size:.86rem;font-weight:500;color:rgba(234,241,251,.9);transition:color .3s,border-color .3s,background .3s;}
.hd__profile .ic{width:1.05em;height:1.05em;stroke:currentColor;}
.hd__profile:hover{color:var(--offwhite);border-color:var(--glow);background:rgba(14,153,225,.08);}
.lang{display:inline-flex;align-items:center;gap:9px;}
.lang button{font-size:.82rem;font-weight:600;color:rgba(234,241,251,.78);transition:color .3s;}
.lang button.is-active{color:var(--glow);}
.lang__sep{width:1px;height:12px;background:rgba(234,241,251,.3);}
.burger{display:none;flex-direction:column;gap:6px;width:28px;}
.burger span{height:1.5px;width:100%;background:var(--offwhite);transition:transform .4s var(--ease),opacity .3s;}
.burger.open span:nth-child(1){transform:translateY(3.7px) rotate(45deg);}
.burger.open span:nth-child(2){transform:translateY(-3.7px) rotate(-45deg);}

/* light header when over a paper section (scrolled) handled by .scrolled keeping dark glass; logo stays white on dark glass */

/* ---------- MOBILE NAV ---------- */
.mnav{position:fixed;inset:0;z-index:85;background:var(--void);color:var(--offwhite);display:flex;flex-direction:column;justify-content:center;padding:var(--pad);
  opacity:0;visibility:hidden;transition:opacity .5s var(--ease),visibility .5s;}
.mnav.open{opacity:1;visibility:visible;}
.mnav nav{display:flex;flex-direction:column;}
.mnav a{display:flex;align-items:baseline;gap:14px;font-size:clamp(1.7rem,7vw,2.4rem);font-weight:600;color:var(--offwhite);padding-block:14px;border-bottom:1px solid var(--hairline);
  opacity:0;transform:translateY(18px);transition:opacity .5s var(--ease) var(--rd,0s),transform .5s var(--ease) var(--rd,0s),color .3s;}
.mnav.open a{opacity:1;transform:none;}
.mnav a:hover{color:var(--glow);}
/* The profile PDF link is an action, not a page: override the big full-width
   .mnav a treatment into a self-sized pill matching the header's. Needs 0-2-0
   specificity to beat `.mnav a` (0-1-1). It keeps the .mnav.open reveal. */
.mnav .mnav__profile{align-self:flex-start;gap:10px;margin-top:28px;padding:12px 22px;font-size:clamp(1rem,3.6vw,1.15rem);font-weight:500;border:1px solid var(--hairline);border-bottom:1px solid var(--hairline);border-radius:999px;}
.mnav .mnav__profile::before{content:none;}
.mnav .mnav__profile .ic{width:1.1em;height:1.1em;stroke:currentColor;align-self:center;}
.mnav__foot{display:flex;flex-direction:column;gap:6px;margin-top:36px;color:var(--mist-cool);font-size:.9rem;}
body.lock{overflow:hidden;}

/* =========================================================
   HERO — 4 layers
   ========================================================= */
/* --hstrip-h is the sector strip's band at the base of the hero. Every
   bottom-anchored piece below measures from it rather than from a hard-coded
   offset, so the strip can change height in one place. --mask-aside is the
   inverse of --mask-lin: the slide photograph is masked AWAY from the text
   side, and the aside photograph is masked TO it. */
.hero{position:relative;min-height:100svh;padding-block-start:var(--hd-h);background:var(--graphite);color:var(--offwhite);overflow:hidden;display:flex;align-items:flex-end;
  --gl:rgba(234,241,251,.055);--bloom-x:30%;--mask-lin:linear-gradient(to right,#000 0,#000 16%,transparent 72%);
  --mask-aside:linear-gradient(to left,#000 0,#000 10%,transparent 46%);
  --hstrip-h:clamp(104px,13vh,140px);}
html[dir="ltr"] .hero{--bloom-x:70%;--mask-lin:linear-gradient(to left,#000 0,#000 16%,transparent 72%);
  --mask-aside:linear-gradient(to right,#000 0,#000 10%,transparent 46%);}

/* The gutter photograph. Much dimmer than .hero__layer — it sits UNDER the
   headline, not beside it, so it has to read as a shadow of the work rather
   than as a second picture competing with the type. No ken-burns and no
   transition: it never changes with the slides. */
.hero__aside{position:absolute;inset:0;z-index:0;background:var(--img) center/cover no-repeat;
  filter:brightness(.28) contrast(1.05) saturate(.5);opacity:.46;
  -webkit-mask-image:var(--mask-aside);mask-image:var(--mask-aside);}
/* The same navy rake .hero__media wears, so both photographs sit in one tonal
   family and the seam between them is the ground, not an edge. */
.hero__aside::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,var(--void) 4%,rgba(7,18,58,.55) 30%,transparent 62%);}
.hero .grid-cols{--gl:rgba(234,241,251,.055);}

.hero__media{position:absolute;inset:0;z-index:0;
  -webkit-mask-image:var(--mask-lin),radial-gradient(60% 60% at var(--bloom-x) 55%,#000 30%,transparent 78%);
  -webkit-mask-composite:source-over; mask-image:var(--mask-lin),radial-gradient(60% 60% at var(--bloom-x) 55%,#000 30%,transparent 78%); mask-composite:add;}
.hero__layer{position:absolute;inset:0;background:var(--img) center/cover no-repeat;opacity:0;transform:scale(1.06);
  filter:brightness(.52) contrast(1.03) saturate(.9);transition:opacity 1.2s var(--ease);}
.hero__layer.is-active{opacity:1;animation:kenburns 24s var(--ease) infinite alternate;}
@keyframes kenburns{from{transform:scale(1.06) translateY(0)}to{transform:scale(1.11) translateY(-1.6%)}}
.hero__media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,var(--void) 2%,rgba(7,18,58,.5) 26%,transparent 54%),
             linear-gradient(125deg,rgba(22,46,189,.38),rgba(14,153,225,.12) 55%,transparent 82%);}

.hero__bloom{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(38% 44% at var(--bloom-x) 56%,rgba(84,191,240,.3),transparent 72%);}

.hero__bracket{position:absolute;width:26px;height:26px;z-index:2;}
.hero__bracket--tr{inset-block-start:96px;inset-inline-start:var(--pad);border-block-start:1px solid var(--steel);border-inline-start:1px solid var(--steel);}
.hero__bracket--bl{inset-block-end:calc(var(--hstrip-h) + 34px);inset-inline-end:var(--pad);border-block-end:1px solid var(--steel);border-inline-end:1px solid var(--steel);}

/* measured moment (default slide only) */

.hero__thread{position:absolute;inset:0;z-index:3;}

.hero__content{position:relative;z-index:5;width:100%;max-width:min(1180px,100%);padding-block:0 calc(var(--hstrip-h) + clamp(64px,8vh,96px));}
.hero__kicker{display:inline-flex;align-items:center;gap:10px;font-size:.74rem;font-weight:600;letter-spacing:.18em;text-transform:uppercase;
  color:var(--glow);margin-bottom:22px;padding:7px 14px;border:1px solid rgba(14,153,225,.3);background:rgba(7,18,58,.35);backdrop-filter:blur(2px);}
html[lang="ar"] .hero__kicker{letter-spacing:.02em;font-size:.86rem;}
.hero__kicker i{width:14px;height:1px;background:var(--brass);}
.hero__title{font-weight:700;font-size:clamp(2.4rem,5.4vw,5rem);line-height:1.06;letter-spacing:-.02em;color:var(--offwhite);text-wrap:balance;}
html[lang="ar"] .hero__title{letter-spacing:0;line-height:1.12;}
/* English words are much longer than Arabic, so at the Arabic-tuned size the
   hero titles stack into 5-6 short lines and tower into the header. A smaller
   English-only cap keeps them to 2-3 lines, matching the Arabic rhythm. */
html[lang="en"] .hero__title{font-size:clamp(2rem,3.6vw,3.4rem);}
.hero__title .w{display:inline-block;transition:color .5s var(--ease),text-shadow .5s var(--ease);}
.hero__title .w.anim{opacity:0;transform:translateY(16px);transition:opacity .6s var(--ease),transform .6s var(--ease),color .5s var(--ease),text-shadow .5s var(--ease);}
.hero__title .w.anim.show{opacity:1;transform:none;}
.hero__title .w.lit{color:var(--plant);text-shadow:0 0 18px rgba(84,191,240,.55);}
.hero__lead{font-size:clamp(1.02rem,1.5vw,1.28rem);font-weight:400;color:rgba(234,241,251,.8);max-width:72ch;margin-block:24px 36px;
  opacity:0;transform:translateY(14px);transition:opacity .8s var(--ease) .35s,transform .8s var(--ease) .35s;}
.hero__lead.go{opacity:1;transform:none;}
.hero__actions{display:flex;gap:14px;flex-wrap:wrap;opacity:0;transform:translateY(14px);transition:opacity .8s var(--ease) .5s,transform .8s var(--ease) .5s;}
.hero__actions.go{opacity:1;transform:none;}

.hero__nav{position:absolute;z-index:6;inset-block-start:50%;transform:translateY(-50%);inset-inline-end:var(--pad);display:flex;flex-direction:column;gap:16px;}
.hero__dot{display:flex;align-items:center;gap:11px;color:var(--mist-cool);font-size:.68rem;font-weight:600;letter-spacing:.08em;transition:color .4s;font-variant-numeric:tabular-nums;}
.hero__dot .bar{width:30px;height:1px;background:rgba(234,241,251,.28);position:relative;overflow:hidden;}
.hero__dot.is-active{color:var(--offwhite);}
.hero__dot.is-active .bar::after{content:"";position:absolute;inset:0;inset-inline-end:auto;width:0;background:var(--glow);box-shadow:0 0 6px var(--glow);animation:barfill 7s linear forwards;}
@keyframes barfill{to{width:100%}}

/* The word ticker that shared this bar was replaced by the sector strip
   below, so the bar carries the scroll cue alone and sits directly above the
   strip rather than at the very base of the hero. */

/* --- HERO SECTOR STRIP -----------------------------------------------------
   The band that replaced the word ticker: one card per sector the client has
   opted into the hero, each a photograph and a name, each a link to that
   sector's page.

   The track is printed twice in the markup and the loop is a plain -50%
   translate, so the seam is invisible. That only holds if the two halves are
   byte-identical in WIDTH — which is why the spacing is `margin-inline-end` on
   every card rather than `gap` on the track: a gap is drawn BETWEEN children,
   so a 2N-card track carries 2N-1 of them and half a gap goes missing at the
   fold. A trailing margin gives every card the same box and the halves match.

   The strip is also a real scroll container (`overflow-x:auto`), so a visitor
   who wants to browse it can drag or swipe past the animation instead of
   waiting for it. */
.hstrip{position:absolute;z-index:6;inset-block-end:0;inset-inline:0;height:var(--hstrip-h);
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);}
.hstrip::-webkit-scrollbar{display:none;}
/* A mouse cannot swipe a scroll container, so main.js lets it drag the track
   by hand; the cursor says so, and a drag in progress selects no text. */
.hstrip{cursor:grab;}
.hstrip.is-dragging{cursor:grabbing;user-select:none;}
.hstrip.is-dragging .hstrip__card{pointer-events:none;}
.hstrip__track{display:flex;width:max-content;height:100%;
  animation:hstrip 64s linear infinite;}
@keyframes hstrip{to{transform:translateX(-50%)}}
/* translateX is a physical axis, and an RTL flex row is laid out from the
   container's RIGHT edge leftwards — so the half of the track that is off
   screen is off to the LEFT, and revealing it means translating POSITIVE.
   A second keyframe rather than `animation-direction:reverse`: reversing
   starts the track at the -50% end state, which drops it half a track to the
   left before the first frame is even drawn. */
@keyframes hstrip-rtl{to{transform:translateX(50%)}}
html[dir="rtl"] .hstrip__track{animation-name:hstrip-rtl;}
/* Pause while the visitor is reading or tabbing through it — and while they
   are scrolling it by hand, which `:hover` on the container covers. */
.hstrip:hover .hstrip__track,.hstrip:focus-within .hstrip__track{animation-play-state:paused;}

.hstrip__card{position:relative;flex-shrink:0;display:flex;align-items:flex-end;
  width:clamp(148px,15vw,208px);margin-inline-end:12px;margin-block:14px;
  overflow:hidden;border:1px solid var(--hairline);
  transition:border-color .4s var(--ease),transform .4s var(--ease);}
.hstrip__card:hover{border-color:var(--glow);transform:translateY(-3px);}
.hstrip__img{position:absolute;inset:0;background-size:cover;background-position:center;
  filter:brightness(.44) contrast(1.04) saturate(.85);transition:filter .5s var(--ease),transform .8s var(--ease);}
.hstrip__card:hover .hstrip__img{filter:brightness(.62) contrast(1.04) saturate(1);transform:scale(1.06);}
/* A scrim under the name, so a light photograph cannot swallow it. */
.hstrip__card::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(7,18,58,.86) 6%,rgba(7,18,58,.28) 52%,transparent 88%);}
.hstrip__t{position:relative;z-index:1;padding:10px 12px;font-size:.82rem;font-weight:600;line-height:1.35;
  color:var(--offwhite);text-shadow:0 1px 10px rgba(7,18,58,.7);}

@media (prefers-reduced-motion:reduce){
  /* The strip stops travelling; it stays a scroll container, so every card is
     still reachable by drag, swipe or keyboard. */
  .hstrip__track{animation:none;}
}

/* =========================================================
   REVEAL
   ========================================================= */
/* base = gentle rise (body text, labels, lists) */
.rv{opacity:0;transform:translateY(24px);transition:opacity .7s var(--ease2),transform .7s var(--ease2);}
.rv.in{opacity:1;transform:none;}
/* headings = horizontal mask wipe in reading direction */
.rv[data-rv="mask"]{opacity:1;transform:none;clip-path:inset(0 0 0 100%);transition:clip-path .85s var(--ease2);}
html[dir="ltr"] .rv[data-rv="mask"]{clip-path:inset(0 100% 0 0);}
.rv[data-rv="mask"].in{clip-path:inset(0 0 0 0);}
/* Not a duplicate: the html[dir="ltr"] base rule above (0,3,1) outranks the plain
   .in rule (0,3,0), so LTR headings would stay clipped to zero width forever. */
html[dir="ltr"] .rv[data-rv="mask"].in{clip-path:inset(0 0 0 0);}
/* numbers = fade + slight scale up */
.rv[data-rv="num"]{opacity:0;transform:scale(.94);transition:opacity .7s var(--ease2),transform .7s var(--ease2);}
.rv[data-rv="num"].in{opacity:1;transform:none;}
/* logos = quiet opacity + blur lift */
.rv[data-rv="blur"]{opacity:0;filter:blur(7px);transform:translateY(8px);transition:opacity .8s var(--ease2),filter .8s var(--ease2),transform .8s var(--ease2);}
.rv[data-rv="blur"].in{opacity:1;filter:blur(0);transform:none;}
/* directional slide (project side cards, alternating via --rx) */
.rv[data-rv="slide"]{opacity:0;transform:translateX(var(--rx,30px));transition:opacity .7s var(--ease2),transform .75s var(--ease2);}
.rv[data-rv="slide"].in{opacity:1;transform:none;}

/* image PANEL WIPE — a brand royal→cyan panel retracts to reveal the image */
.clip{position:relative;}
.clip>img{transform:scale(1.08);transition:transform 1.2s var(--ease2);}
.clip.in>img{transform:none;}
.clip::after{content:"";position:absolute;inset:0;z-index:4;background:linear-gradient(120deg,var(--royal),var(--cyan));transform:scaleX(1);transform-origin:right;transition:transform .8s var(--ease2);}
html[dir="rtl"] .clip::after{transform-origin:left;}
.clip.in::after{transform:scaleX(0);}

/* grouped children reveal per-item via .rv (observed by IO) with a child-specific
   transition that delays ONLY the reveal props (via --rd) so hover stays snappy.
   Higher specificity (.x.rv) beats each element's own transition declaration. */
.sector.rv{opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease2) var(--rd,0s),transform .6s var(--ease2) var(--rd,0s),padding-inline-start .4s var(--ease);}
.sector.rv.in{opacity:1;transform:none;}
.cert.rv{opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease2) var(--rd,0s),transform .6s var(--ease2) var(--rd,0s);}
.cert.rv.in{opacity:1;transform:none;}
@media (prefers-reduced-motion:no-preference){
  .count-flash{animation:flash .6s var(--ease);}
  @keyframes flash{0%,100%{color:inherit}40%{color:var(--plant)}}
}

/* =========================================================
   INTRO (P-01 · Paper)
   ========================================================= */
.intro__grid{display:grid;grid-template-columns:1.85fr .85fr;gap:clamp(40px,7vw,110px);align-items:start;padding-top:clamp(30px,5vw,70px);}
.intro__statement{font-size:var(--fs-body);font-weight:400;line-height:var(--lh-body);letter-spacing:0;color:var(--mist-warm);margin-top:18px;}
.intro__statement b{font-weight:600;color:var(--ink);}
/* The client wants copy to run across its column rather than stack into a
   tall, narrow block (2026-09-15), so a body paragraph beside the statement
   fills the column instead of stopping at the global 80ch cap. */
.intro__head .body{max-width:none;}
.intro__statement .lit{color:var(--steel);font-weight:500;transition:color .8s var(--ease);}
.intro__statement.in .lit{color:var(--glow);text-shadow:0 0 22px rgba(14,153,225,.25);}
/* the statement's remainder: worn with .body, which brings the size, measure
   and the ar/en line-height. Only the gap to the lead is set here — 20px, the
   .intro__side stack gap — plus the lead's own <b> treatment, so a fact set in
   bold reads the same either side of the break. */
.intro__body{margin-top:20px;}
.intro__body b{font-weight:600;color:var(--ink);}
.intro__facts{display:flex;flex-wrap:wrap;gap:10px 22px;margin-top:30px;}
.intro__facts li{display:inline-flex;align-items:center;gap:9px;font-size:.86rem;color:var(--ink);font-weight:500;}
.intro__facts li::before{content:"";width:5px;height:5px;background:var(--brass);transform:rotate(45deg);flex-shrink:0;}
.intro__facts .num{font-weight:600;}
.intro__side{display:flex;flex-direction:column;gap:20px;}
.frame{position:relative;overflow:hidden;background:var(--paper-sink);}
.frame img{width:100%;height:clamp(300px,40vw,440px);object-fit:cover;}
/* The contact page's optional map embed, so it stands exactly where a figure's
   image would and wears the frame's own corner brackets. Same height ramp as
   the image above; `display:block` kills the inline-element baseline gap that
   would otherwise show as a hairline under the frame. */
.frame iframe{width:100%;height:clamp(300px,40vw,440px);border:0;display:block;}
.frame__b{position:absolute;width:22px;height:22px;z-index:2;}
.frame__b--tl{inset-block-start:12px;inset-inline-start:12px;border-block-start:1px solid var(--steel);border-inline-start:1px solid var(--steel);}
.frame__b--br{inset-block-end:12px;inset-inline-end:12px;border-block-end:1px solid var(--steel);border-inline-end:1px solid var(--steel);}
.frame figcaption{position:absolute;inset-block-end:0;inset-inline:0;display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:13px 15px;background:linear-gradient(transparent,rgba(7,18,58,.85));color:var(--offwhite);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;}
html[lang="ar"] .frame figcaption{text-transform:none;font-size:.82rem;}
.frame figcaption i{font-style:normal;color:var(--brass);font-variant-numeric:tabular-nums;letter-spacing:.04em;}
.intro__note{color:var(--mist-warm);font-size:var(--fs-body);}
.body{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--mist-warm);max-width:80ch;}
/* Content copy sets justified (2026-09-15). Centred cards keep their centring. */
:is(.body,.intro__statement,.lede,.stage__desc,.cert__scope,.phero__lead){text-align:justify;}
.journey__step .cert__scope{text-align:inherit;}
html[lang="en"]{--lh-body:1.7;}

/* The About page's editorial intro. This section's copy is long, so it is
   content-first rather than a column beside the image: a full-width lead over a
   full-width three-up body, with the image demoted to a slim full-width band
   that closes the section. The body's three columns hold the measure (~55ch)
   the copy would lose if it ran the full width in one column. Self-responsive
   via column-width — three up on desktop, two on tablet, one below. */
.intro__editorial{padding-top:clamp(30px,5vw,70px);}
.intro__editorial .intro__lead{max-width:64ch;margin-top:0;}
.intro__editorial .intro__prose{columns:36rem;column-gap:clamp(34px,3.4vw,60px);margin-top:clamp(30px,4vw,52px);}
.intro__editorial .intro__prose .body{max-width:none;break-inside:avoid;margin-bottom:1.15em;}
.intro__editorial .intro__prose .body:last-child{margin-bottom:0;}
/* The image, kept but restrained: a slim full-width band (the frame's own
   cover-crop + corner brackets + caption) closing the section, not a side
   column. Overrides the frame's default 300–440px height ramp. */
.intro__band{margin-top:clamp(42px,5vw,72px);}
.intro__band img{height:clamp(190px,24vw,300px);}

/* =========================================================
   METRICS (P-02 · Void)
   ========================================================= */
.metrics .label{margin-bottom:clamp(34px,5vw,56px);}
/* Fits the columns to the figures rather than assuming four. The home row
   dropped to three when the "380 kV max voltage" figure came off the site, and
   a fixed four-column track left the last cell empty — which on an RTL page
   parks the whole row against one edge with a quarter of the band blank. */
.metrics__row{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(180px,100%),1fr));position:relative;}
.metrics__row::before{content:"";position:absolute;inset-block-start:50%;inset-inline:0;height:1px;background:var(--hairline);z-index:0;}
.metric{position:relative;z-index:1;padding-inline:clamp(14px,2vw,34px);padding-block:8px;}
.metric:not(:first-child){border-inline-start:1px solid var(--hairline);}
.metric__node{width:7px;height:7px;background:var(--steel);transform:rotate(45deg);margin-bottom:18px;transition:background .5s,box-shadow .5s;}
.metric.lit .metric__node{background:var(--plant);box-shadow:0 0 8px rgba(84,191,240,.6);}
.metric__v{font-size:clamp(2rem,3.7vw,3.5rem);font-weight:600;line-height:1;letter-spacing:-.02em;color:var(--offwhite);display:flex;align-items:baseline;gap:4px;white-space:nowrap;}
.metric__v .num{font-variant-numeric:tabular-nums;}
.metric__v .u{font-size:.4em;font-weight:600;}
.metric__k{margin-top:14px;font-size:.84rem;color:var(--mist-cool);}
.metrics__tags{display:flex;flex-wrap:wrap;gap:10px 24px;margin-top:clamp(36px,5vw,54px);padding-top:28px;border-top:1px solid var(--hairline);}
.metrics__tags span{display:inline-flex;align-items:center;gap:9px;font-size:.8rem;letter-spacing:.06em;color:var(--mist-cool);font-variant-numeric:tabular-nums;}
.metrics__tags span::before{content:"";width:1px;height:11px;background:var(--brass);}
/* a chip carrying one of App\Support\Icons' marks stands its tick down — the
   icon is the marker, and two brass marks 9px apart read as a mistake rather
   than an index. Chips without one keep the tick, so the row degrades to what
   it has always been. */
.metrics__tags span:has(.ic)::before{display:none;}
/* six-up variant (the About page's row): four columns wrap six figures 4+2 and
   hang a stray hairline on the second row's first cell, since
   .metric:not(:first-child) only exempts the very first item. Re-cut at three
   and move that exemption to every row start. The row gap is what ::before's
   axis line then falls in, so the hairline that strikes through a single row
   reads as the rule between two. Scoped above 680px: below it .metrics__row's
   own 1fr 1fr and .metric:nth-child(even) rules take over, untouched. */
@media (min-width:681px){
  .metrics__row--3{grid-template-columns:repeat(3,1fr);row-gap:clamp(26px,4vw,44px);}
  .metrics__row--3 .metric:nth-child(3n+1){border-inline-start:none;}
}

/* =========================================================
   CAPABILITIES LEDGER (About · P-01·C · Void)
   ========================================================= */
/* Replaces the .metrics__tags chip row: the client asked for the capabilities
   to read as a set, not a .8rem footnote. Each takes its own ledger cell — icon
   + label. Hairlines sit on the cells' logical end edges (not on grid gaps), so
   an admin-set count that leaves a short last row still rules cleanly with no
   stray sliver. Reveal + hover share one transition; only the reveal props take
   the --rd stagger, so hover stays snappy (mirrors .cert.rv). */
.caps{display:grid;grid-template-columns:repeat(4,1fr);margin-top:clamp(36px,5vw,54px);
  border-block-start:1px solid var(--hairline);border-inline-start:1px solid var(--hairline);}
.caps .cap{display:flex;align-items:center;gap:14px;
  padding:clamp(18px,2.2vw,26px) clamp(16px,2vw,26px);
  border-block-end:1px solid var(--hairline);border-inline-end:1px solid var(--hairline);
  color:var(--offwhite);font-size:.94rem;line-height:1.35;}
.caps .cap .ic{width:1.55em;height:1.55em;}
.caps .cap__t{letter-spacing:.01em;}
.caps .cap.rv{opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease2) var(--rd,0s),transform .6s var(--ease2) var(--rd,0s),background .4s var(--ease);}
.caps .cap.rv.in{opacity:1;transform:none;}
.caps .cap:hover{background:var(--graphite);}

/* =========================================================
   SECTORS (P-03 · Paper)
   ========================================================= */
.sectors__head{margin-bottom:clamp(38px,5vw,64px);}
.h-section{font-size:1.5em;}
:is(.sectors__head,.projects__head,.clients__head,.sector-cta__inner) .h-section{font-size:var(--fs-title);font-weight:700;line-height:1.3;}
.label ~ .h-section,.label ~ .contact__title{font-size:var(--fs-sub);font-weight:500;line-height:1.6;color:var(--mist-warm);}
.label--dark ~ .h-section,.label--dark ~ .contact__title{color:var(--mist-cool);}
.sectors__head .h-section{margin-top:20px;}
.sectors__body{display:grid;grid-template-columns:.85fr 1.15fr;gap:clamp(34px,5vw,72px);align-items:stretch;}
.sectors__list{display:flex;flex-direction:column;}
.sector{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:16px;padding-block:clamp(15px,1.8vw,22px);
  border-top:1px solid var(--line-paper);cursor:pointer;transition:padding-inline .4s var(--ease);position:relative;}
/* The title links to the sector's page and stretches over the whole row. */
.sector__link{color:inherit;}
.sector__link::after{content:"";position:absolute;inset:0;z-index:1;}
/* The diamond is transformed, which paints it above the link's cover — let clicks pass through it. */
.sector__node{pointer-events:none;}
.sector__link:focus-visible{outline:none;}
.sector:has(.sector__link:focus-visible){outline:2px solid var(--glow);outline-offset:2px;}
.sector:last-child{border-bottom:1px solid var(--line-paper);}
.sector__t{font-size:clamp(1.1rem,1.7vw,1.55rem);font-weight:500;color:var(--mist-warm);transition:color .4s var(--ease);}
.sector__node{width:7px;height:7px;background:transparent;border:1px solid var(--mist-warm);transform:rotate(45deg);opacity:.5;transition:all .4s var(--ease);}
.sector .ic{stroke:var(--mist-warm);transition:stroke .4s var(--ease);}
.sector.active .ic{stroke:var(--brass);}
.sector.active{padding-inline-start:10px;}
.sector.active .sector__t{color:var(--royal);}
.sector.active .sector__node{background:var(--glow);border-color:var(--glow);opacity:1;box-shadow:0 0 8px rgba(14,153,225,.6);}
.sector:hover .sector__t{color:var(--ink);}

.sectors__stage{position:relative;background:var(--paper-sink);min-height:430px;display:flex;flex-direction:column;}
.stage__media{position:relative;flex:1;overflow:hidden;min-height:280px;}
.stage__img{position:absolute;inset:0;background-size:cover;background-position:center;opacity:0;transform:scale(1.05);
  clip-path:inset(0 0 0 14%);transition:opacity .55s var(--ease2),transform 1s var(--ease2),clip-path .7s var(--ease2);}
html[dir="ltr"] .stage__img{clip-path:inset(0 14% 0 0);}
.stage__img.is-active{opacity:1;transform:none;clip-path:inset(0 0 0 0);}
/* Not a duplicate: the html[dir="ltr"] base rule above (0,2,1) outranks the plain
   .is-active rule (0,2,0), so LTR stage images would stay cropped 14% forever. */
html[dir="ltr"] .stage__img.is-active{clip-path:inset(0 0 0 0);}
.stage__media::after{content:"";position:absolute;inset:0;background:linear-gradient(transparent 50%,rgba(7,18,58,.5));}
.stage__b{position:absolute;width:22px;height:22px;z-index:2;}
/* The stage image opens the sector it is showing. */
.stage__link{position:absolute;inset:0;z-index:3;}
.stage__b--tl{inset-block-start:14px;inset-inline-start:14px;border-block-start:1px solid var(--offwhite);border-inline-start:1px solid var(--offwhite);opacity:.6;}
.stage__b--br{inset-block-end:14px;inset-inline-end:14px;border-block-end:1px solid var(--offwhite);border-inline-end:1px solid var(--offwhite);opacity:.6;}
.stage__body{padding:24px;}
.stage__desc{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--mist-warm);min-height:3.4em;transition:opacity .35s;}
.stage__points{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:16px;}
.stage__points li{display:inline-flex;align-items:center;gap:8px;font-size:.86rem;color:var(--ink);}
.stage__points li::before{content:"";width:5px;height:5px;background:var(--steel);transform:rotate(45deg);}

/* =========================================================
   PROJECTS (P-04 · Void) — the register rail
   ========================================================= */
.projects__head{display:flex;justify-content:space-between;align-items:flex-end;gap:28px;flex-wrap:wrap;margin-bottom:clamp(32px,4vw,52px);}
.projects__head .h-section{margin-top:18px;}
.filters{display:flex;flex-wrap:wrap;gap:6px 20px;}
.filter{position:relative;padding:8px 2px;font-size:.86rem;font-weight:500;color:var(--mist-cool);transition:color .35s;}
.filter::after{content:"";position:absolute;inset-block-end:0;inset-inline-start:0;width:0;height:1px;background:var(--glow);box-shadow:0 0 6px var(--glow);transition:width .4s var(--ease);}
.filter:hover{color:var(--offwhite);}
.filter.active{color:var(--offwhite);}
.filter.active::after{width:100%;}

.pcard{position:relative;flex:1;min-height:96px;overflow:hidden;background:var(--slate);border:1px solid var(--hairline);display:flex;align-items:flex-end;
  color:var(--offwhite);cursor:pointer;transition:border-color .4s;}
.pcard__img{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center;filter:grayscale(.85) brightness(.55);transition:filter .5s var(--ease),transform 1s var(--ease);}
.pcard::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(to top,rgba(7,18,58,.9),rgba(7,18,58,.25));}
.pcard:hover{border-color:var(--steel);}
.pcard:hover .pcard__img{filter:grayscale(0) brightness(.72);transform:scale(1.05);}
.pcard__b{position:absolute;inset-block-start:12px;inset-inline-start:12px;z-index:2;width:16px;height:16px;border-block-start:1px solid transparent;border-inline-start:1px solid transparent;transition:border-color .4s;}
.pcard:hover .pcard__b{border-block-start-color:var(--glow);border-inline-start-color:var(--glow);}
.pcard__body{position:relative;z-index:2;padding:14px 16px;}
.pcard__cat{font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--brass);}
html[lang="ar"] .pcard__cat{letter-spacing:.02em;text-transform:none;}
.pcard__name{font-size:.95rem;font-weight:500;line-height:1.3;margin-top:4px;}
/* Covers the card, image included, above the scrim and the body. */
.pcard__link{position:absolute;inset:0;z-index:3;}
.pcard__meta{font-size:.82rem;color:rgba(234,241,251,.7);margin-top:6px;}
.pcard__meta b{color:var(--offwhite);font-weight:500;}
/* Year badge sits opposite the .pcard__b corner bracket (inline-start), so it
   never overlaps it. Logical properties (not left/right) keep it in the same
   visual corner in both dir="rtl" and dir="ltr" — see the LTR clip-path trap
   noted in project memory: a dir="ltr" override here would be one more place
   for that bug to recur, so it's avoided by construction. */
.pcard__year{position:absolute;z-index:2;inset-block-start:12px;inset-inline-end:12px;padding-inline:8px;padding-block:3px;font-size:.68rem;letter-spacing:.04em;color:var(--offwhite);background:rgba(7,18,58,.6);border:1px solid var(--hairline);}

/* Section lede: intro paragraph under an .h-section title. */
.lede{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--mist-warm);margin-top:14px;max-width:90ch;}
.lede--light{color:rgba(234,241,251,.75);}
/* .h-section inherits its color from the section's ground (paper vs void), so
   this modifier is the explicit light-on-dark value rather than relying on
   inheritance alone — kept in sync with .sec[data-ground="void"]'s color. */
.h-section--light{color:var(--offwhite);}

/* The completed-projects register (P-10) lays every project out as a card
   grid. It deliberately does NOT reuse .side: that is the four-card column
   beside the ongoing section's featured project — a single flex column whose
   .pcard children flex:1 to divide its height — so 28 cards in it become one
   very long ribbon of full-width banners. Declared after the .side media
   queries above so no breakpoint rule reaches back over it.
   auto-fill + minmax is what makes it responsive without its own breakpoints. */
.pgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,250px),1fr));gap:clamp(14px,1.4vw,18px);margin-top:clamp(22px,2.4vw,34px);}
/* .pcard sets flex:1 and min-height:96px for its life in .side; as a grid item
   the flex is inert, but the min-height still needs to become card-shaped. */
.pgrid .pcard{min-height:clamp(190px,18vw,225px);}
/* Mirrors .side .pcard.rv, but rises instead of sliding in from the side: in a
   grid there is no single edge for the cards to arrive from. */
.pgrid .pcard.rv{opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease2) var(--rd,0s),transform .6s var(--ease2) var(--rd,0s),border-color .4s var(--ease);}
.pgrid .pcard.rv.in{opacity:1;transform:none;}

/* Tabs on the merged /projects page: one clear strip above the register that
   switches between the ongoing and completed grids, defaulting to ongoing.
   Sits on the section's void ground, so colours read light-on-dark like the
   rest of the register. The active tab is the only offwhite one and carries the
   glowing underline; the strip's own hairline is the baseline they all share.
   The underline scales from centre (transform-origin, not width) so it animates
   identically in dir="rtl" and dir="ltr" — no logical-vs-physical trap. */
.ptabs{display:flex;flex-wrap:wrap;gap:clamp(22px,3vw,44px);border-block-end:1px solid var(--hairline);margin-bottom:clamp(26px,3vw,40px);}
.ptab{position:relative;padding:0 2px clamp(13px,1.3vw,17px);font-size:clamp(.98rem,1.5vw,1.12rem);font-weight:500;letter-spacing:.02em;color:var(--mist-cool);transition:color .35s var(--ease);}
.ptab::after{content:"";position:absolute;inset-block-end:-1px;inset-inline:0;height:2px;background:var(--glow);box-shadow:0 0 8px var(--glow);transform:scaleX(0);transform-origin:center;transition:transform .4s var(--ease);}
.ptab:hover{color:var(--offwhite);}
.ptab[aria-selected="true"]{color:var(--offwhite);}
.ptab[aria-selected="true"]::after{transform:scaleX(1);}
html[lang="ar"] .ptab{letter-spacing:0;}
/* The inactive panel is server-rendered but hidden; main.js swaps `hidden` on
   tab click. Explicit so no later rule can un-hide it. */
.ptab-panel[hidden]{display:none;}
/* The register grid's own margin-top is redundant once a tab strip sits above
   it — the strip already owns the gap — so it is zeroed inside a panel. */
.ptab-panel .pgrid{margin-top:0;}

/* The "more" button under the home page's projects grid, centred below the
   slice it teases and linking through to the full /projects register. */
/* Tabs and "more" share one ruled bar; with no tabs the link still sits at the end. */
.projects__bar{display:flex;align-items:flex-end;justify-content:space-between;gap:16px 24px;flex-wrap:wrap;
  border-block-end:1px solid var(--hairline);margin-bottom:clamp(26px,3vw,40px);}
.projects__bar .ptabs{border-block-end:0;margin-bottom:0;}
.projects__more{margin-inline-start:auto;margin-block-end:10px;padding:10px 22px;}
.sec[data-ground="paper"] .projects__bar{border-block-end-color:var(--line-paper);}
/* .btn--line is drawn for a dark ground; on white it needs ink, or it all but vanishes. */
.sec[data-ground="paper"] .btn--line{border-color:var(--line-paper);color:var(--ink);}
.sec[data-ground="paper"] .btn--line:hover{border-color:var(--royal);color:var(--royal);}

/* =========================================================
   CLIENTS + CERTS (P-05 · Paper)
   ========================================================= */
/* CLIENT WALL — a slow looping strip of logo cards (2026-09-15), replacing the
   bordered grid. Same seamless-loop idea as the hero's sector strip: the track
   holds the logos twice and travels exactly half its width, with the physical
   sign flipped for RTL. It pauses on hover and when the section is off screen. */
.clients__marquee{position:relative;overflow:hidden;padding-block:12px 18px;margin-block-end:clamp(40px,5vw,64px);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);}
.clients__track{display:flex;width:max-content;animation:hstrip 52s linear infinite;}
html[dir="rtl"] .clients__track{animation-name:hstrip-rtl;}
.clients__marquee:hover .clients__track,.offscreen .clients__track{animation-play-state:paused;}
/* Dragged by hand in main.js; pan-y keeps vertical page scrolling on touch. */
.clients__marquee{cursor:grab;touch-action:pan-y;}
.clients__marquee.is-dragging{cursor:grabbing;user-select:none;}
.clogo{flex-shrink:0;display:flex;align-items:center;justify-content:center;overflow:hidden;width:clamp(150px,13vw,210px);height:clamp(92px,7.6vw,118px);
  margin-inline-end:clamp(12px,1.3vw,20px);padding:16px 22px;background:#fff;border-radius:12px;
  box-shadow:0 1px 2px rgba(12,26,69,.06),0 10px 26px rgba(12,26,69,.07);
  transition:transform .45s var(--ease),box-shadow .45s var(--ease);}
/* The mark fills the card's padded box and is scaled to fit inside it, whatever its proportions —
   a percentage max-height alone did not hold, so tall marks spilled out of the card. */
.clogo img{display:block;width:100%;height:100%;min-width:0;min-height:0;object-fit:contain;opacity:.92;transition:opacity .4s;pointer-events:none;}
.clogo:hover{transform:translateY(-4px);box-shadow:0 2px 4px rgba(12,26,69,.08),0 16px 34px rgba(12,26,69,.12);}
.clogo:hover img{opacity:1;}
.sec[data-ground="void"] .clogo{box-shadow:0 10px 26px rgba(0,0,0,.25);}
@media (prefers-reduced-motion:reduce){
  /* No travel: the one real copy wraps into a centred set. */
  .clients__marquee{-webkit-mask-image:none;mask-image:none;cursor:auto;touch-action:auto;}
  .clients__track{animation:none;width:auto;flex-wrap:wrap;justify-content:center;gap:14px;}
  .clogo{margin-inline-end:0;}
  .clogo[aria-hidden="true"]{display:none;}
}

.clients__head{margin-bottom:clamp(38px,5vw,60px);}
.clients__head .h-section{margin-top:18px;}

/* certifications = instrument ledger (not a card grid): node + tabular code + scope on hairlines */
.certs .label{margin-bottom:26px;}
.certs__row{display:grid;grid-template-columns:repeat(3,1fr);border-block:1px solid var(--line-paper);}
/* A completed project's register renders exactly one tile (Year of
   Completion) in this fixed 3-column grid: without this, the lone .cert sits
   in column 1 of 3, one-third width, with two-thirds of the row a blank gap.
   Let it fill the row instead, same as the single-column mobile layout
   below.

   This applies to EVERY .certs__row, not just the project register — the
   About page chunks its cards three to a row (array_chunk in
   AboutPageController), so an admin-set count of 4 or 7 leaves a last row of
   one and gets the same treatment. That is the wanted behaviour in both
   places. It cannot reach a full row: :only-child never matches when three
   .certs render. */
.certs__row:has(.cert:only-child){grid-template-columns:1fr;}
.cert{position:relative;padding-block:clamp(22px,2.4vw,30px);padding-inline:clamp(16px,2vw,34px);display:flex;flex-direction:column;gap:7px;}
.cert:first-child{padding-inline-start:0;}
.cert:not(:first-child){border-inline-start:1px solid var(--line-paper);}
/* A row that does not fill its three columns (the last chunk of a five- or
   eight-card list) used to leave the cards at a third of the width with a
   blank cell beside them. Fitting the columns to the cards it actually has
   closes that gap, and the row still lines up with the full rows above it
   because every row starts at the same edge. */
.certs__row:has(.cert:nth-child(2):last-child){grid-template-columns:repeat(2,1fr);}
.cert__node{width:7px;height:7px;background:var(--steel);transform:rotate(45deg);margin-bottom:10px;}
/* When a card carries one of the client's icons (About's Why Choose, and the
   Careers/HSE/Quality/Contact cards), that icon IS the card's mark. The steel
   `.cert__node` diamond then stands as a second marker 16px above it, reading
   as a mistake — the same double-mark the capability chips avoid with
   `.metrics__tags span:has(.ic)::before`. Stand the node down there too, so the
   icon is the one mark. Cards with no icon (Vision/Purpose/Values) keep it. */
.cert:has(.ic) .cert__node{display:none;}
.cert__code{font-size:clamp(1.2rem,1.9vw,1.6rem);font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:.01em;direction:ltr;unicode-bidi:isolate;}
.cert__sub{font-size:.7rem;letter-spacing:.12em;color:var(--brass-dk);}
.cert__scope{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--mist-warm);}

/* =========================================================
   CONTACT (P-06 · Graphite)
   ========================================================= */
.contact{position:relative;}
.contact__bloom{position:absolute;inset:0;z-index:0;pointer-events:none;background:radial-gradient(40% 50% at 22% 60%,rgba(84,191,240,.12),transparent 70%);}
html[dir="ltr"] .contact__bloom{background:radial-gradient(40% 50% at 78% 60%,rgba(84,191,240,.12),transparent 70%);}
.contact__grid{display:grid;grid-template-columns:1.25fr .75fr;gap:clamp(40px,6vw,90px);align-items:end;}
/* The standalone /contact page, whose details list runs to six rows where the
   home page's section runs to three. Bottom-aligning the lead against a list
   that tall (the section's own `align-items:end`, which is right on home) would
   strand the title halfway down the band under an empty quarter-page. */
.contact--page .contact__grid{align-items:start;}
/* The licence block below the grid. Same gap the void-ground index row takes
   from the figures above it, so the two blocks read as separate rather than as
   one run-on list. */
.contact--page .certs{margin-top:clamp(36px,5vw,54px);}
.contact__title{font-size:clamp(1.9rem,3.6vw,3rem);font-weight:600;color:var(--offwhite);margin-block:24px 36px;max-width:32ch;line-height:1.2;}
html[lang="ar"] .contact__title{line-height:1.35;}
.contact__list{display:flex;flex-direction:column;position:relative;}
.contact__list li{display:flex;flex-direction:column;gap:5px;padding-block:18px;border-top:1px solid var(--hairline);}
.contact__list li:last-child{border-bottom:1px solid var(--hairline);position:relative;}
.contact__list li:last-child::after{content:"";position:absolute;inset-block-end:-4px;inset-inline-start:0;width:9px;height:9px;background:var(--glow);transform:rotate(45deg);box-shadow:0 0 8px rgba(14,153,225,.55);}
.contact__k{display:inline-flex;align-items:center;gap:9px;font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;color:var(--mist-cool);}
html[lang="ar"] .contact__k{letter-spacing:.02em;font-size:.82rem;text-transform:none;}
.contact__k::before{content:"";width:12px;height:1px;background:var(--brass);}
.contact__v{font-size:1.12rem;font-weight:500;color:var(--offwhite);font-variant-numeric:tabular-nums;transition:color .3s;}
a.contact__v:hover{color:var(--glow);}

/* =========================================================
   FOOTER (P-07)
   ========================================================= */
.ft{position:relative;background:var(--void);color:var(--mist-cool);padding-block:44px 26px;overflow:hidden;}
.ft__ground{position:absolute;inset-block-start:0;inset-inline:0;height:1px;background:var(--steel);opacity:.4;}
.ft__top{display:flex;justify-content:space-between;align-items:center;gap:28px;flex-wrap:wrap;padding-bottom:28px;border-bottom:1px solid var(--hairline);}
.ft__logo{height:38px;filter:brightness(0) invert(1);opacity:.92;}
.ft__nav{display:flex;gap:clamp(16px,2vw,30px);flex-wrap:wrap;}
.ft__nav a{font-size:.9rem;transition:color .3s;}
.ft__nav a:hover{color:var(--offwhite);}
.ft__bar{display:flex;justify-content:space-between;gap:14px 24px;flex-wrap:wrap;padding-top:22px;font-size:.8rem;}
.ft__left{display:flex;gap:8px 22px;flex-wrap:wrap;align-items:center;}
.ft__by{color:var(--cyan);font-weight:500;transition:color .3s;}
.ft__by:hover{color:var(--offwhite);}
.ft__meta{display:flex;gap:18px;flex-wrap:wrap;}
.ft__meta{align-items:center;}
/* The certification seals (see components/iso-badge). */
.ft__iso{display:flex;align-items:center;gap:10px;color:var(--mist-cool);}
.ft__iso .iso-badge{--iso-size:64px;transition:color .3s;}
.ft__iso .iso-badge:hover{color:var(--offwhite);}

/* =========================================================
   MODAL + TOAST
   ========================================================= */
.modal{position:fixed;inset:0;z-index:120;display:grid;place-items:center;padding:20px;opacity:0;visibility:hidden;transition:opacity .4s var(--ease),visibility .4s;}
.modal.open{opacity:1;visibility:visible;}
.modal__bg{position:absolute;inset:0;background:rgba(7,18,58,.72);backdrop-filter:blur(4px);}
.modal__box{position:relative;width:min(500px,100%);background:var(--paper);color:var(--ink);padding:clamp(30px,4vw,46px);transform:translateY(24px);transition:transform .45s var(--ease);}
.modal.open .modal__box{transform:none;}
.modal__box h3{font-size:1.7rem;margin-block:14px 26px;}
/* Same order as the sections: the modal's label is its title, the question under it a subtitle. */
.modal__box .label ~ h3{font-size:var(--fs-sub);font-weight:500;line-height:1.6;color:var(--mist-warm);}
.modal__x{position:absolute;inset-block-start:18px;inset-inline-end:20px;width:24px;height:24px;}
.modal__x::before,.modal__x::after{content:"";position:absolute;inset:0;margin:auto;width:18px;height:1.5px;background:var(--ink);}
.modal__x::before{transform:rotate(45deg);}.modal__x::after{transform:rotate(-45deg);}
.form{display:flex;flex-direction:column;gap:12px;}
.form__row{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
.form input,.form textarea,.form select{font-family:inherit;font-size:.96rem;color:var(--ink);background:var(--paper-sink);border:1px solid var(--line-paper);padding:14px 16px;width:100%;resize:vertical;transition:border-color .3s;}
.form input:focus,.form textarea:focus,.form select:focus{outline:none;border-color:var(--steel);}
/* select and file take the same field treatment as input/textarea above. Both
   arrived with the careers CV form and the client's contact form, which ask for
   a department chooser and a CV upload; a native control on those two slots
   would be the only thing on the site not wearing the design's tokens.
   appearance:none drops the UA's own chrome so the field reads as one of ours;
   the caret is drawn as a background mark, inset from whichever side the
   locale ends on. */
.form select{appearance:none;padding-inline-end:40px;
  background-image:linear-gradient(45deg,transparent 50%,var(--steel) 50%),linear-gradient(135deg,var(--steel) 50%,transparent 50%);
  background-size:6px 6px,6px 6px;background-repeat:no-repeat;}
/* The caret is two triangles: the 45deg gradient draws its left half and the
   135deg its right half, so the 45deg mark is always the further-left of the
   pair — on both sides of the mirror. Swapping them points the chevron up. */
html[dir="ltr"] .form select{background-position:right 24px center,right 18px center;}
html[dir="rtl"] .form select{background-position:left 18px center,left 24px center;}
/* The file input's own button is the one piece of UA chrome worth keeping —
   it is the affordance — so it is restyled rather than removed. */
.form input[type="file"]{padding:9px 10px;cursor:pointer;}
.form input[type="file"]::file-selector-button{font-family:inherit;font-size:.82rem;letter-spacing:.04em;color:var(--offwhite);background:var(--royal);border:0;padding:9px 14px;margin-inline-end:12px;cursor:pointer;transition:background .3s;}
.form input[type="file"]::file-selector-button:hover{background:var(--royal-600);}

.toast{position:fixed;inset-block-end:26px;inset-inline:50% auto;transform:translateX(50%) translateY(calc(100% + 60px));background:var(--void);color:var(--offwhite);border:1px solid var(--hairline);
  padding:15px 24px;font-size:.92rem;font-weight:500;z-index:130;display:flex;align-items:center;gap:12px;transition:transform .5s var(--ease);max-width:calc(100% - 40px);}
html[dir="ltr"] .toast{inset-inline:auto 50%;transform:translateX(-50%) translateY(calc(100% + 60px));}
.toast.show{transform:translateX(50%) translateY(0);}
html[dir="ltr"] .toast.show{transform:translateX(-50%) translateY(0);}
.toast i{width:7px;height:7px;background:var(--plant);transform:rotate(45deg);flex-shrink:0;box-shadow:0 0 6px var(--plant);}

:focus-visible{outline:2px solid var(--glow);outline-offset:3px;}
.sec[data-ground="paper"] :focus-visible,.modal__box :focus-visible,.mnav :focus-visible{outline-color:var(--ink);}
.sec[data-ground="paper"] .sector.active .ic{stroke:var(--brass-dk);}
/* pause perpetual animations when their section is off-screen */
.offscreen .thread .pulse,.hero.offscreen .hero__layer,.hero.offscreen .hstrip__track,.hero.offscreen .hero__bloom{animation-play-state:paused;}

/* =========================================================
   RESPONSIVE
   ========================================================= */
/* The header collapses to the burger on its OWN threshold, not the layout
   grids' 1024px one: with the Arabic labels plus the profile pill the nav needs
   room until ~1200px. The profile pill then rides in the mobile menu instead. */
@media (max-width:1200px){
  .hd__nav{display:none;}
  .burger{display:flex;}
  .hd__profile{display:none;}
}
@media (max-width:1024px){
  .intro__grid{grid-template-columns:1fr;gap:46px;}
  .caps{grid-template-columns:repeat(2,1fr);}
  .sectors__body{grid-template-columns:1fr;gap:28px;}
  .pcard{flex:none;min-height:168px;}
  .contact__grid{grid-template-columns:1fr;align-items:start;}
}
@media (max-width:680px){
  .hero{align-items:flex-end;--bloom-x:50%;--mask-lin:linear-gradient(to top,#000 0,#000 30%,transparent 92%);}
  html[dir="ltr"] .hero{--bloom-x:50%;--mask-lin:linear-gradient(to top,#000 0,#000 30%,transparent 92%);}
  .hero__nav{flex-direction:row;inset-block-start:auto;inset-block-end:92px;transform:none;inset-inline:var(--pad);}
  .hero__dot .bar{width:22px;}
  .hero{--hstrip-h:clamp(88px,20vw,104px);}
  .hero__bracket{display:none;}
  .metrics__row{grid-template-columns:1fr 1fr;gap:26px 0;}
  .metrics__row::before{display:none;}
  .metric:not(:first-child){border-inline-start:none;}
  .metric:nth-child(even){border-inline-start:1px solid var(--hairline);padding-inline-start:clamp(20px,6vw,40px);}
  .certs__row{grid-template-columns:1fr;}
  .caps{grid-template-columns:1fr;}
  .form__row{grid-template-columns:1fr;}
}
@media (max-width:420px){
  .hero__actions .btn{width:100%;justify-content:center;}
}

/* =========================================================
   REDUCED MOTION
   ========================================================= */
@media (prefers-reduced-motion:reduce){
  /* transition-delay too, not only duration: the staggered reveals set their
     delay from --rd, which a zeroed duration leaves untouched — so without
     this the .mnav links still cascaded in over 370ms with the motion the
     reader asked not to see. */
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;transition-delay:0s!important;scroll-behavior:auto!important;}
  .rv,.clip,.rvg>*{opacity:1!important;transform:none!important;clip-path:none!important;filter:none!important;}
  .clip::after{display:none!important;}
  .stage__img{clip-path:none!important;}
  .hero__layer{transform:none!important;}
  .hero__title .w.anim{opacity:1!important;transform:none!important;}
  .hero__lead,.hero__actions{opacity:1!important;transform:none!important;}
  .thread .rail{clip-path:none!important;}
  .thread .pulse{display:none!important;}
}

/* =========================================================
   PAGE HERO — the inner pages' opening block
   ========================================================= */
/* The home hero's quieter sibling. It replaces the dark title band that
   /about, /sectors, /projects, /clients, /contact, /quality and /hse used to
   open with, and keeps that band's one structural job: a `void` ground under
   the fixed, transparent header, so the white logo and near-white nav links
   stay legible on a page whose first section is `paper`.

   Deliberately NOT built on `.hero__*`: those are animation-gated (opacity:0
   until main.js adds `.go` from showHero(), which only runs on the home page),
   so reusing them off-home would ship invisible content. Every rule below is a
   resting state — the block is complete with CSS alone, needs no JS, and has
   no perpetual animation to pause off-screen. The mask geometry, the layer
   filter and the RTL/LTR flip are the home hero's, at a page header's volume.
   Everything here is an addition; no existing declaration is touched. */
.phero{position:relative;min-height:clamp(340px,50vh,560px);background:var(--void);color:var(--offwhite);overflow:hidden;display:flex;align-items:flex-end;
  --bloom-x:30%;--mask-lin:linear-gradient(to right,#000 0,#000 24%,transparent 84%);}
/* Same flip as .hero: the image reads on the far side, the type on the side
   the text starts from. The `html[dir]` prefix keeps it at the hero's own
   specificity rather than outranking a state class later. */
html[dir="ltr"] .phero{--bloom-x:70%;--mask-lin:linear-gradient(to left,#000 0,#000 24%,transparent 84%);}

/* The hero's own mask/bloom treatment: a directional wipe added to a radial
   bloom, so the photograph resolves out of the ground instead of ending at an
   edge. Shorter block than the home hero, so the linear stop runs further
   (24%/84% vs 16%/72%) — a steeper fade would read as a vignette at 450px. */
.phero__media{position:absolute;inset:0;z-index:0;
  -webkit-mask-image:var(--mask-lin),radial-gradient(58% 62% at var(--bloom-x) 54%,#000 26%,transparent 76%);
  -webkit-mask-composite:source-over; mask-image:var(--mask-lin),radial-gradient(58% 62% at var(--bloom-x) 54%,#000 26%,transparent 76%); mask-composite:add;}
/* .hero__layer's exact filter, for one tonal family across both heroes — but
   opacity:1 at rest and no ken-burns: this block is a page header, and it is
   not allowed to depend on the JS that drives the home carousel. */
.phero__layer{position:absolute;inset:0;background:var(--img) center/cover no-repeat;filter:brightness(.52) contrast(1.03) saturate(.9);}
/* Scrim: --void up from the base so the block hands off to the seam below it
   cleanly, plus the hero's royal→cyan rake. */
.phero__media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,var(--void) 3%,rgba(7,18,58,.5) 34%,transparent 78%),
             linear-gradient(125deg,rgba(22,46,189,.34),rgba(14,153,225,.1) 58%,transparent 84%);}
.phero__bloom{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(34% 40% at var(--bloom-x) 56%,rgba(84,191,240,.22),transparent 72%);}

/* Kept on the .wrap grid rather than .hero__content's centred 640px column,
   so the label and title line up with the section headings below them. The
   block-start padding is the fixed header's clearance; the type is bottom-set,
   like the home hero's. */
.phero__content{position:relative;z-index:5;width:100%;padding-block:clamp(118px,15vh,148px) clamp(38px,6vh,64px);}
.phero__title{font-weight:700;font-size:clamp(1.9rem,3.4vw,3rem);line-height:1.08;letter-spacing:-.02em;color:var(--offwhite);text-wrap:balance;max-width:40ch;margin-block-start:18px;}
html[lang="ar"] .phero__title{letter-spacing:0;line-height:1.2;}
/* A project's <h1> is a register entry, not a page name: a full contract
   description, 80 characters at the median and 202 at the longest. The scale
   above is set for "Quality" and "Careers"; at 22ch it turns a title like that
   into a nine-line wall taller than the block it sits in. Same hero, same
   everything else — the type steps down to a paragraph-length heading and
   widens so it stops stacking into a narrow column. The Arabic line-height
   needs restating at this specificity: `html[lang="ar"] .phero__title` (0,1,1)
   outranks a lone modifier class (0,1,0) and would otherwise hold 1.2 here. */
.phero__title--long{font-size:clamp(1.2rem,1.9vw,1.6rem);line-height:1.35;letter-spacing:0;max-width:90ch;}
html[lang="ar"] .phero__title--long{line-height:1.5;}
.phero__lead{font-size:var(--fs-body);line-height:var(--lh-body);font-weight:400;color:rgba(234,241,251,.8);max-width:80ch;margin-block-start:16px;}

@media (max-width:680px){
  /* Same move as .hero at this width: there is no room for a side-by-side
     image and column, so the wipe goes vertical and the bloom centres. */
  .phero{--bloom-x:50%;--mask-lin:linear-gradient(to top,#000 0,#000 34%,transparent 94%);}
  html[dir="ltr"] .phero{--bloom-x:50%;--mask-lin:linear-gradient(to top,#000 0,#000 34%,transparent 94%);}
  .phero__title,.phero__lead{max-width:none;}
}

/* =========================================================
   SECTOR PAGE — the service catalogue and its closing band
   ========================================================= */
/* Added for the per-sector pages (/sectors/{slug}). The rest of that page is
   built from vocabulary that already exists here — .phero, .intro__grid,
   .frame, .stage__points, .clients__head — so only the two blocks that had no
   equivalent are declared below.

   .svc is the full service catalogue: twenty-five to thirty-five plain lines.
   It is a column list rather than a card grid on purpose. At that count cards
   read as a wall of boxes and each one carries three words, so the box is
   almost all chrome; a ruled list is faster to scan and holds the site's
   hairline-and-node vocabulary without inventing a component. */
.svc{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:0 clamp(28px,4vw,64px);
  border-block-start:1px solid var(--line-paper);}
.svc__item{display:flex;align-items:flex-start;gap:12px;padding-block:14px;
  border-block-end:1px solid var(--line-paper);font-size:.94rem;line-height:1.6;color:var(--ink);}
/* The site's node mark, at list scale. `margin-block-start` centres it on the
   first line of a wrapping item instead of letting it ride the flex baseline. */
.svc__node{width:5px;height:5px;flex-shrink:0;background:var(--steel);transform:rotate(45deg);margin-block-start:.62em;
  transition:background .3s var(--ease),box-shadow .3s var(--ease);}
.svc__item:hover .svc__node{background:var(--glow);box-shadow:0 0 8px rgba(14,153,225,.55);}
.svc__t{flex:1;font-size:var(--fs-body);}

/* The closing band. `void` ground so the page hands off to the footer the way
   every other dark section does, and a two-column split so the actions sit
   beside the heading rather than under a full-width paragraph. */
.sector-cta__inner{display:grid;grid-template-columns:1.4fr auto;gap:clamp(28px,5vw,80px);align-items:center;}
.sector-cta .h-section{margin-block-start:18px;}
.sector-cta .body{color:var(--mist-cool);margin-block-start:14px;max-width:80ch;}
.sector-cta__actions{display:flex;flex-wrap:wrap;gap:14px;}
/* .btn--line takes --line-paper on a paper ground; on this one it needs the
   dark-ground hairline and near-white type, the same pair .hd__profile uses. */
.sector-cta .btn--line{border-color:var(--hairline);color:var(--offwhite);}
.sector-cta .btn--line:hover{border-color:var(--glow);color:var(--glow);}

@media (max-width:880px){
  .sector-cta__inner{grid-template-columns:1fr;align-items:start;}
}

/* =========================================================
   JOURNEY — the About/History timeline
   ========================================================= */
/* The site's THREAD · NODE motif at section scale: one rail across the row,
   a diamond node per step sitting on it, the step's card hanging below. The
   rail is drawn on the <ol> rather than per-step, so it is one continuous line
   however many steps an admin adds, and it is inset by half a column at each
   end so it starts and stops under the first and last node instead of running
   off into the gutter.

   Card type is `.cert`'s ladder — icon, `.h-section`, `.cert__scope` — reused
   deliberately: a step should read like every other card on the site. */
.journey{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:clamp(24px,3vw,48px);position:relative;}
.journey::before{content:"";position:absolute;inset-block-start:70px;inset-inline:12%;height:1px;
  background:linear-gradient(to right,transparent,var(--line-paper) 8%,var(--line-paper) 92%,transparent);}
.journey__step{position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;}
.journey__step .ic{width:2.4em;height:2.4em;}
/* The node rides the rail: 70px from the top of the row, which is where
   ::before is drawn. `background:var(--paper)` masks the rail behind it so the
   line reads as passing through the node rather than under it. */
.journey__node{display:grid;place-items:center;width:30px;height:30px;flex-shrink:0;
  background:var(--steel);color:var(--paper);transform:rotate(45deg);
  box-shadow:0 0 0 6px var(--paper);}
.journey__node b{font-size:.8rem;font-weight:600;transform:rotate(-45deg);font-variant-numeric:tabular-nums;}
.journey__step .h-section{margin-block-start:4px;}
.journey__step .cert__scope{max-width:none;}

@media (max-width:680px){
  /* One column: the rail would be a 1px stub between stacked cards, so it goes
     and the nodes carry the sequence on their own. */
  .journey::before{content:none;}
  .journey__step{align-items:flex-start;text-align:start;}
  .journey__step .cert__scope{max-width:none;}
}

/* =========================================================
   HEADER SUBMENUS — About · Sectors · Project Portfolio
   ========================================================= */
/* No JS. The panel rests at opacity:0 with pointer-events:none rather than
   display:none or visibility:hidden, so its links stay in the tab order and
   :focus-within opens it for a keyboard user exactly as :hover does for a
   pointer. Only shown at >=1024px — below that `.hd__nav` is display:none and
   the mobile menu lists the same destinations flat. */
.hd__item{position:relative;display:inline-flex;}
/* The trigger is `.hd__nav a`, so it already carries the nav's colour, size
   and underline-on-active. Only the caret is added. */
.hd__item > a{display:inline-flex;align-items:center;gap:6px;}
/* Physical `right`/`bottom`, not the logical pair: a chevron pointing down is
   the same shape in both directions, and border-inline-end resolves to the
   LEFT edge in RTL — which rotates the mark into a "<" on the Arabic site. */
.hd__caret{width:5px;height:5px;border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg);opacity:.55;transition:transform .3s var(--ease),opacity .3s var(--ease);
  margin-block-end:3px;}
.hd__item:hover .hd__caret,.hd__item:focus-within .hd__caret{opacity:1;transform:rotate(225deg);margin-block-end:-2px;}

/* The panel. `margin-block-start` opens a gap between the trigger and the
   list; ::before fills that gap with a transparent bridge so the pointer can
   cross it without the panel closing. The gap is NOT padding on the panel,
   because the panel carries a border and a radius — padding would put them
   14px above the list.

   Dividers are drawn by a 1px `gap` over a hairline-coloured container rather
   than by borders on the cells. Every internal rule is then exactly one pixel
   whatever the item count, nothing is painted twice where two cells meet, and
   the outer edge stays the panel's own single border. */
.hd__sub{position:absolute;inset-block-start:100%;inset-inline-start:50%;z-index:95;
  display:flex;flex-direction:column;gap:1px;margin-block-start:14px;
  background:var(--hairline);border:1px solid var(--hairline);border-radius:4px;
  transform:translateX(-50%) translateY(6px);
  opacity:0;pointer-events:none;transition:opacity .25s var(--ease),transform .25s var(--ease);}
/* The bridge sits above the panel, outside its box — which is why the panel
   must not be overflow:hidden: clipped, the bridge vanished, the pointer fell
   into the 14px gap, :hover dropped and the panel closed before it was reached.
   It is wider and taller than the gap so a diagonal path still lands on it. */
.hd__sub::before{content:"";position:absolute;inset-block-end:100%;inset-inline:-24px;height:22px;}
.hd__sub > a:first-child{border-start-start-radius:3px;border-start-end-radius:3px;}
.hd__sub > a:last-child{border-end-start-radius:3px;border-end-end-radius:3px;}
/* translateX is a physical axis, so RTL needs the sign flipped to stay
   centred under its trigger. */
html[dir="rtl"] .hd__sub{transform:translateX(50%) translateY(6px);}
.hd__item:hover > .hd__sub,.hd__item:focus-within > .hd__sub{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0);}
html[dir="rtl"] .hd__item:hover > .hd__sub,html[dir="rtl"] .hd__item:focus-within > .hd__sub{transform:translateX(50%) translateY(0);}

.hd__sub > a{display:flex;align-items:center;gap:10px;padding:11px 16px;white-space:nowrap;
  font-size:.88rem;font-weight:500;color:var(--offwhite);background:rgba(7,18,58,.97);
  transition:background .25s var(--ease),color .25s var(--ease);}
.hd__sub > a:hover{background:rgba(22,46,189,.62);color:#fff;}
.hd__sub .ic{width:1.15em;height:1.15em;}
/* "All sectors" heads the panel and is not one of the eleven, so it takes the
   accent rather than a heading row of its own. */
.hd__sub-all{font-weight:600;color:var(--glow);}

/* Eleven sectors in one column would run past the viewport, so the wide
   variant is a two-column grid. The 1px gap inherited above becomes the
   column rule as well as the row rules. */
.hd__sub--wide{display:grid;grid-template-columns:repeat(2,minmax(200px,1fr));}
.hd__sub--wide > .hd__sub-all{grid-column:1 / -1;}
/* An odd sector count leaves the last cell alone in the leading column; it
   spans instead of rendering a half-width row. `.hd__sub-all` is child 1, so
   sector k is child k+1 — an odd count ends on an EVEN child, which is what
   the guard tests. With an even count the last child lands in the trailing
   column and completes its row on its own. */
.hd__sub--wide > a:last-child:nth-child(even){grid-column:1 / -1;}

@media (max-width:1200px){
  /* The trigger is closer to the edge here, so a centred panel can overhang.
     Pin it to the trigger's own edge instead. */
  .hd__sub,html[dir="rtl"] .hd__sub{inset-inline-start:auto;inset-inline-end:0;transform:translateY(6px);}
  .hd__item:hover > .hd__sub,.hd__item:focus-within > .hd__sub,
  html[dir="rtl"] .hd__item:hover > .hd__sub,html[dir="rtl"] .hd__item:focus-within > .hd__sub{transform:translateY(0);}
  .hd__sub--wide{grid-template-columns:repeat(2,minmax(170px,1fr));}
}

/* Mobile menu: the eleven sector links, as chips under the Sectors row.
   `.mnav__chips a` is 0-2-0 and beats `.mnav a` (0-1-1), the same specificity
   move `.mnav .mnav__profile` documents above — it keeps the .mnav.open reveal
   and the stagger while dropping the 2.4rem type and the row border. */
.mnav__chips{display:flex;flex-wrap:wrap;gap:8px;padding-block:14px 4px;}
.mnav__chips a{display:inline-flex;font-size:.84rem;font-weight:500;padding:7px 13px;
  color:var(--mist-cool);border:1px solid var(--hairline);border-radius:999px;}
.mnav__chips a::before{content:none;}
.mnav__chips a:hover{color:var(--glow);border-color:var(--glow);}

/* =========================================================
   INTRO FIGURE — rotating frames + the SINCE mark
   ========================================================= */
/* The frames stack and cross-fade; `.frame img` already sets the box, so only
   the stacking and the fade are added. The FIRST frame keeps its place in
   normal flow — it is what gives `.frame` its height — and every later one is
   absolutely positioned over it. */
.frame--rot{position:relative;}
.frame--rot img{transition:opacity 1.1s var(--ease);}
.frame--rot img:not(:first-child){position:absolute;inset:0;}
.frame--rot img:not(.is-active){opacity:0;}

/* The client's standing mark: the word over the year, set on the brand navy
   and overlapping the figure's leading edge the way their mock draws it. */
.frame-wrap{position:relative;}
.frame__since{position:absolute;z-index:3;inset-block-end:44px;inset-inline-start:-22px;
  display:flex;flex-direction:column;gap:2px;padding:12px 20px;
  background:var(--royal);color:var(--offwhite);box-shadow:0 12px 30px rgba(7,18,58,.28);}
.frame__since b{font-size:.66rem;font-weight:600;letter-spacing:.22em;opacity:.85;}
html[lang="ar"] .frame__since b{letter-spacing:.06em;font-size:.74rem;}
.frame__since i{font-style:normal;font-size:clamp(1.5rem,2.4vw,2rem);font-weight:700;line-height:1;font-variant-numeric:tabular-nums;}

@media (max-width:680px){
  /* No gutter to hang into at this width — the mark tucks inside the frame. */
  .frame__since{inset-inline-start:0;inset-block-end:48px;}
}

/* =========================================================
   PROJECT RAIL — the home page's horizontal register
   ========================================================= */
/* Replaced the featured-plate-plus-side-column showcase: the client wanted to
   browse further into the register from the home page than five highlights.

   It is a real scroll container first — drag, swipe, trackpad and keyboard all
   work with no JS — and the two arrows are enhancement that main.js unhides
   only when there is something to scroll. `scroll-snap` keeps a card aligned
   to the leading edge after an arrow step or a flick.

   `.pcard` is the register's own card, so a project reads the same here as in
   the /projects grid; `--rail` only fixes its width and height, which the grid
   gets from its own columns. */
.pscroll{position:relative;}
.pscroll__track{display:flex;gap:clamp(14px,1.4vw,18px);overflow-x:auto;scroll-behavior:smooth;
  scroll-snap-type:x mandatory;scrollbar-width:none;padding-block-end:4px;}
.pscroll__track::-webkit-scrollbar{display:none;}
.pcard--rail{flex:0 0 clamp(240px,25vw,320px);min-height:clamp(250px,26vw,320px);scroll-snap-align:start;}

.pscroll__nav{display:flex;justify-content:flex-end;gap:10px;margin-block-start:20px;}
.pscroll__btn{width:42px;height:42px;display:grid;place-items:center;flex-shrink:0;
  border:1px solid var(--hairline);color:var(--offwhite);background:transparent;
  transition:border-color .3s var(--ease),background .3s var(--ease),opacity .3s var(--ease);}
.pscroll__btn:hover:not(:disabled){border-color:var(--glow);background:rgba(14,153,225,.1);}
.pscroll__btn:disabled{opacity:.32;cursor:default;}
/* A chevron drawn from two physical borders, like `.hd__caret`. Unlike that
   one it DOES flip with the writing direction: "previous" is a place, not a
   shape, and on an RTL page the earlier cards are to the right. */
.pscroll__btn::before{content:"";width:8px;height:8px;border-left:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg);margin-inline-start:3px;}
.pscroll__btn--next::before{transform:rotate(-135deg);margin-inline-start:-3px;}
html[dir="rtl"] .pscroll__btn::before{transform:rotate(-135deg);margin-inline-start:-3px;}
html[dir="rtl"] .pscroll__btn--next::before{transform:rotate(45deg);margin-inline-start:3px;}

@media (max-width:680px){
  .pcard--rail{flex-basis:78vw;}
}

/* The certification mark, when the client has supplied one. The card keeps its
   node, its standard number and its scope line — the logo is added above them,
   not instead of them, so a visitor still reads WHICH standard the mark is. */
.cert__logo{width:auto;max-width:min(180px,100%);height:clamp(44px,5vw,62px);object-fit:contain;object-position:left center;
  margin-block-end:14px;}
html[dir="rtl"] .cert__logo{object-position:right center;}
.cert--logo .cert__code{font-size:.82rem;color:var(--mist-warm);}


/* =========================================================
   CERTIFICATION SEAL — components/iso-badge.blade.php
   ========================================================= */
.iso-badge{display:inline-block;width:var(--iso-size,96px);height:var(--iso-size,96px);flex-shrink:0;direction:ltr;color:currentColor;}
.iso-badge__ring{fill:none;stroke:currentColor;stroke-width:3;}
.iso-badge__inner{fill:none;stroke:currentColor;stroke-width:1.2;opacity:.45;}
.iso-badge text{fill:currentColor;font-family:var(--font);font-weight:700;}
.iso-badge__arc{font-size:10px;letter-spacing:3px;}
.iso-badge__iso{font-size:17px;letter-spacing:1px;}
.iso-badge__num{font-size:23px;letter-spacing:.5px;}
.iso-badge__year{font-size:10.5px;letter-spacing:1px;opacity:.8;}
.iso-badge--compact .iso-badge__ring{stroke-width:4;}
.iso-badge--compact .iso-badge__iso{font-size:22px;letter-spacing:1.5px;}
.iso-badge--compact .iso-badge__num{font-size:30px;letter-spacing:0;}

/* =========================================================
   INNER PAGES — shared components (2026-09-16)
   Quality, HSE, a project and Contact are built from these so the inner pages
   read as one system. Every block works on either ground; sections alternate
   paper / void down a page, starting with paper under the navy page hero.
   A page's one-off adjustments live in public/assets/css/pages/<page>.css,
   pushed from its view with @push('styles').
   ========================================================= */
/* Section head: an <h2 class="label ip-title"><i></i><b>…</b></h2> — the label
   is the section title in this site's type scale — with an optional
   .ip-head__sub line under it. */
.ip-head{margin-bottom:clamp(26px,3.2vw,44px);}
.ip-title{margin:0;}
.ip-head__sub{margin-top:12px;font-size:var(--fs-sub);line-height:1.6;color:var(--mist-warm);max-width:70ch;}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-head__sub{color:var(--mist-cool);}
/* Body copy on a navy ground (the base .body colour is a paper one). */
.sec:is([data-ground="void"],[data-ground="graphite"]) .body{color:var(--mist-cool);}

/* Text beside a picture. The picture is landscape and fills its column. */
.ip-split{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(28px,5vw,80px);align-items:center;}
.ip-split--top{align-items:start;}
.ip-split__media{position:relative;overflow:hidden;border-radius:16px;aspect-ratio:4/3;background:var(--slate);box-shadow:0 18px 40px rgba(7,18,58,.18);}
.ip-split__media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
.ip-lead{font-size:var(--fs-sub);font-weight:600;line-height:1.6;color:var(--ink);}
.ip-lead .lit,.ip-lead b{color:var(--royal);font-weight:700;}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-lead{color:var(--offwhite);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-lead :is(.lit,b){color:var(--glow);}
.ip-lead + .body{margin-top:16px;}
.ip-actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:clamp(20px,2.4vw,30px);}

/* Cards: icon, title, text. The grid fits as many ~270px columns as there is
   room for, so three, five or six items all land as full rows or a clean
   remainder — no fixed column count to chunk around. */
.ip-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr));gap:clamp(14px,1.6vw,22px);}
.ip-card{position:relative;display:flex;flex-direction:column;gap:10px;padding:clamp(20px,2.2vw,30px);border-radius:16px;
  background:#fff;border:1px solid var(--line-paper);box-shadow:0 1px 2px rgba(12,26,69,.04);
  transition:transform .4s var(--ease),box-shadow .4s var(--ease),border-color .4s var(--ease);}
.ip-card:hover{transform:translateY(-3px);box-shadow:0 16px 34px rgba(12,26,69,.10);border-color:rgba(14,153,225,.35);}
.ip-card__ic{display:grid;place-items:center;width:48px;height:48px;border-radius:12px;background:rgba(14,153,225,.10);margin-bottom:6px;}
.ip-card__ic .ic{width:24px;height:24px;stroke:var(--brass);}
.ip-card__t{font-size:1.14rem;font-weight:700;line-height:1.45;color:var(--ink);}
.ip-card__x{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--mist-warm);}
.ip-card__k{font-size:.85rem;color:var(--mist-warm);}
.ip-card__v{font-size:1.06rem;font-weight:600;color:var(--ink);overflow-wrap:anywhere;}
a.ip-card__v:hover,a.ip-card:hover .ip-card__v{color:var(--royal);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card{background:var(--slate);border-color:var(--hairline);box-shadow:none;}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card:hover{border-color:var(--glow);box-shadow:0 16px 34px rgba(0,0,0,.28);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card__ic{background:rgba(84,191,240,.12);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card__t,.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card__v{color:var(--offwhite);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card__x,.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-card__k{color:var(--mist-cool);}
.sec:is([data-ground="void"],[data-ground="graphite"]) a.ip-card:hover .ip-card__v{color:var(--glow);}

/* A checklist: short statements, each with a tick, flowing into columns. */
.ip-checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:12px 28px;margin-top:clamp(18px,2.2vw,28px);}
.ip-checks li{position:relative;display:flex;align-items:flex-start;gap:12px;font-size:var(--fs-body);line-height:1.7;color:var(--ink);}
.ip-checks li::before{content:"";flex-shrink:0;width:22px;height:22px;margin-top:3px;border-radius:50%;
  background:rgba(14,153,225,.14) no-repeat center/12px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230E99E1' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-checks li{color:var(--offwhite);}

/* A highlighted note: a titled paragraph set apart by an accent edge. */
.ip-callout{padding:clamp(20px,2.4vw,32px);border-radius:16px;background:var(--paper-sink);border-inline-start:4px solid var(--brass);}
.ip-callout__t{font-size:var(--fs-sub);font-weight:700;color:var(--ink);margin-bottom:8px;}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-callout{background:var(--slate);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-callout__t{color:var(--offwhite);}

/* Certificates: a seal with its name and scope. */
.ip-certs{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:clamp(14px,1.6vw,22px);}
.ip-cert{display:flex;align-items:center;gap:18px;padding:clamp(18px,2vw,26px);border-radius:16px;background:#fff;border:1px solid var(--line-paper);}
.ip-cert .iso-badge{--iso-size:88px;color:var(--royal);}
.ip-cert__t{font-size:1.1rem;font-weight:700;color:var(--ink);direction:ltr;unicode-bidi:isolate;}
.ip-cert__x{font-size:var(--fs-body);color:var(--mist-warm);margin-top:4px;}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-cert{background:var(--slate);border-color:var(--hairline);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-cert .iso-badge{color:var(--glow);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-cert__t{color:var(--offwhite);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-cert__x{color:var(--mist-cool);}

/* Key facts: label over value, in cards. */
.ip-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:12px;}
.ip-fact{padding:18px 20px;border-radius:14px;background:#fff;border:1px solid var(--line-paper);}
.ip-fact__k{font-size:.85rem;color:var(--mist-warm);}
.ip-fact__v{margin-top:6px;font-size:1.06rem;font-weight:700;line-height:1.5;color:var(--ink);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-fact{background:var(--slate);border-color:var(--hairline);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-fact__k{color:var(--mist-cool);}
.sec:is([data-ground="void"],[data-ground="graphite"]) .ip-fact__v{color:var(--offwhite);}

/* Closing band: a short centred statement and its actions. */
.ip-cta{text-align:center;max-width:760px;margin-inline:auto;}
.ip-cta .ip-title{justify-content:center;}
.ip-cta .body{margin:14px auto 0;text-align:center;}
.ip-cta .ip-actions{justify-content:center;}

/* Space between blocks inside one section. */
.ip-stack > * + *{margin-top:clamp(28px,3.4vw,48px);}

@media (max-width:1024px){
  .ip-split{grid-template-columns:1fr;}
  .ip-split__media{order:-1;}
}
