/* ==========================================================================
   Sdeira Group homepage (English mirror) - page stylesheet
   ==========================================================================
   Lifted verbatim out of the <style> block that used to sit inline in
   en/index.html (the English mirror). Source order is preserved exactly, because it has to be: this
   file redefines the same selector many times across many @media blocks and
   the winning declaration is whichever one comes last. Do not regroup it by
   topic, and do not lift a rule out of it to reuse on another page - a
   partial copy carries the markup but not the behaviour. Author fresh from
   the winning computed values instead.

   Every colour, surface, radius, motion duration and font value comes from
   assets/css/sdeira-tokens.css, which must stay linked before this file.
   Nothing here may redeclare one of those custom properties: it would win on
   source order and detach the page from the design system with no visible
   error.

   One class of edit was made during the move. A url() inside a stylesheet
   resolves against the stylesheet's own location, not the document's, so the
   image paths lost their assets/ prefix and now start at ../ instead.
   ========================================================================== */
    /* Every design token lives in assets/css/sdeira-tokens.css. Nothing is
       redeclared here on purpose: an inline :root would beat the linked file on
       source order and this page would quietly stop following the system. */

    /* =========================================================================
       CASCADE STRUCTURE: why everything below sits inside @layer legacy

       Ported from sdeira-v2.html, where the same defect was measured directly:
       the same selector redefined dozens of times across roughly 100 @media
       blocks and 16 distinct max-width values, so a rule near the bottom of the
       file silently beats a correct rule near the top at any width where both
       match. This page grew by the same append pattern and was not assumed
       exempt - it was checked, see the verification note below.

       Everything historical is wrapped in @layer legacy. The SYSTEM LAYER at the
       very end of this block stays UNLAYERED, and unlayered styles beat layered
       ones in the cascade regardless of specificity or source order, giving the
       system one deterministic place to assert a canonical role without
       !important.

       VERIFIED, NOT ASSUMED: two stylesheets load before this block and are
       also unlayered (the Phosphor icon CSS and the token file). Computed-style
       hash comparison across all 919 elements plus their ::before/::after, 38
       properties each, at 360/560/720/980/1180/1181/1280/1600px: identical
       before and after wrapping at every width. Neither file contains a rule
       that outranks a page rule.

       RULE FOR FUTURE EDITS
       - A new canonical role, or a fix that must hold at every width, goes in
         the system layer at the end. No !important needed there.
       - A genuinely breakpoint-specific tweak to existing markup goes in
         @layer legacy where the rest of that component lives.
       - Never open a second layer. Two layers is the whole design: history, and
         the system that governs it.
       ====================================================================== */

    @layer legacy {

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box
    }

    /* Form controls do not inherit the document face by default. Without this,
       every <button> and <input> falls back to the UA default: the project
       filter tabs were rendering in Arial 700 next to Tajawal 700 headings,
       which is the single most visible typographic inconsistency on the page. */
    button,
    input,
    select,
    textarea {
      font-family: inherit;
      font-size: inherit;
      line-height: inherit;
      color: inherit;
    }

    /* Removing an author border from a <button> does not leave it borderless: the
       UA default takes over. Measured after the border purge: 28 border edges
       came back on .project-tab / .hero-arrow / .scroll-top from this alone. */
    button {
      background: none;
      border: 0;
    }

    html {
      scroll-behavior: smooth;
      overflow-x: hidden;
    }

    body {
      font-family: var(--font-brand);
      background: var(--offwhite);
      color: var(--ink);
      line-height: 1.75;
      overflow-x: hidden;
      -webkit-font-smoothing: antialiased;
    }

    h1,
    h2,
    h3,
    .display {
      font-family: var(--font-display);
      font-weight: 600;
      line-height: 1.2;
      letter-spacing: 0
    }

    h1,
    h2 {
      text-wrap: balance;
    }

    h1,
    h2,
    h3,
    p,
    a,
    span {
      overflow-wrap: break-word;
    }

    ::selection {
      background: var(--accent);
      color: #fff
    }

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

    a {
      color: inherit;
      text-decoration: none
    }

    .skip-link {
      position: fixed;
      top: 14px;
      right: 24px;
      z-index: 2000;
      padding: 10px 16px;
      background: var(--charcoal);
      color: #fff;
      border-radius: var(--r);
      transform: translateY(-140%);
      transition: transform var(--dur-base) var(--ease-out);
    }

    .skip-link:focus {
      transform: translateY(0);
    }


    /* ===== ICON SYSTEM: Phosphor Regular =====
       Phosphor glyphs are filled paths delivered as an icon font, so they are
       sized with font-size and coloured with `color`. stroke-width has no
       effect, which is exactly why the weight had to be chosen once. */
    i.ph {
      display: inline-block;
      line-height: 1;
      color: inherit;
      flex: 0 0 auto;
      /* Absolute, not em-relative. Sizing icons in em is how six different
         icon sizes appeared: each one inherited whatever its parent happened
         to set, so the same glyph was 12.48px in one card and 16px in another. */
      font-size: var(--ic-md);
    }

    /* ===== IMAGE TREATMENT =====
       One normalising pass over every card photograph so the grid reads as a
       single art-directed set rather than a pile of stock from four sources.
       Deliberately mild: enough to pull the exposures together, not enough to
       look filtered. Full opacity throughout: darkening for legibility is a
       separate veil layer on each card, never a fade on the photograph itself,
       because a faded photo blends toward whatever sits behind it and reads as
       a grey wash instead of a photo with a shadow on it. */
    .project-card-img img,
    .why-media img,
    .news-card img,
    .story-image img {
      filter: saturate(.94) contrast(1.04);
    }

    /* ===== SECTOR CARDS =====
       Inside the hero, the way the original site had them, not spun off into
       their own section. Five identical cards: same shape, same behaviour, no
       special case for Investment. Portrait, not landscape: three fit one row
       at the widths this grid is built for, the other two wrap to a second row
       and the hero is sized to show it. On very wide screens all five fit one
       row and the second row never forms.
       The pointer still darkens the card and brings its own link forward, and
       on top of that a panel opens above the card, the way the original site's
       hero-sector-panel did: a larger preview and the same approved copy, nothing
       invented, just given room. */
    .sector-grid {
      display: grid;
      grid-template-columns: repeat(3, clamp(170px, 19vw, 232px));
      justify-content: center;
      gap: 18px;
    }

    @media (min-width: 1600px) {
      .sector-grid {
        grid-template-columns: repeat(5, clamp(170px, 13vw, 210px));
      }
    }

    .sector-card {
      position: relative;
      isolation: isolate;
      aspect-ratio: 1 / 1;
      display: flex;
      align-items: flex-end;
      border-radius: var(--r);
      background: var(--surface-inverse);
    }

    /* The clipping boundary. Split out from .sector-card itself because the
       panel below has to escape this card's box to open above it, and an
       overflow:hidden ancestor would clip an absolutely positioned child
       regardless of its own position, panel included. */
    .sector-card-media {
      position: absolute;
      inset: 0;
      z-index: -2;
      overflow: hidden;
      border-radius: var(--r);
    }

    /* Softened: a texture behind the card, not the subject of it. The card's
       own colour and the text on it carry the weight, closer to how the
       original site's dark, blurred strip read than a showcased photograph. */
    .sector-card-img {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      object-fit: cover;
      filter: saturate(.85) brightness(.92);
      transition: transform var(--dur-slow) var(--ease-out);
    }


    /* Much stronger than a readability floor: the photo is not the point here,
       the label is, the same balance the original site struck with a near-solid
       rgba(65,64,66,.78) bar. Dark from well above the text now, not just
       behind it, so the card reads as a dark tile with a photo texture behind
       it rather than a photo with text stamped on top. Worst case, a fully
       white photo region: at .55 the composite is #A19FA0 and white measures
       3.1, at .78 it is #767576 and white measures 5.3, at .92 it is
       #5C5B5C and white measures 7.3. */
    .sector-card-veil {
      position: absolute;
      inset: 0;
      background: linear-gradient(180deg,
        rgba(var(--image-overlay-rgb), .40) 0%,
        rgba(var(--image-overlay-rgb), .58) 40%,
        rgba(var(--image-overlay-rgb), .92) 100%);
      transition: opacity var(--dur-base) var(--ease-out);
    }

    .sector-card-media::after {
      content: "";
      position: absolute;
      inset: 0;
      background: rgba(var(--image-overlay-rgb), .82);
      opacity: 0;
      transition: opacity var(--dur-base) var(--ease-out);
    }


    .sector-card-body {
      position: relative;
      inline-size: 100%;
      padding: 22px 20px 20px;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 8px;
      color: #fff;
    }

    .sector-card-mark {
      display: grid;
      place-items: center;
      inline-size: 40px;
      block-size: 40px;
      margin-bottom: 4px;
      border-radius: var(--r);
      background: rgba(255, 255, 255, .14);
      color: #fff;
    }

    .sector-card-mark i.ph {
      font-size: var(--ic-md);
    }

    .sector-card-title {
      font-family: var(--font-display);
      font-size: clamp(1.22rem, 1.5vw, 1.5rem);
      line-height: 1.25;
      margin: 0;
      color: #fff;
    }

    .sector-card-sub {
      color: rgba(255, 255, 255, .88);
      font-size: .92rem;
      line-height: 1.6;
    }

    /* The subsidiaries under this sector. This is the only place on the page
       where Zoad and Your Laundry appear at all. */
    .sector-card-subs {
      color: var(--gold-on-dark);
      font-size: .82rem;
      line-height: 1.5;
    }

    /* Hidden until the pointer arrives, so the resting card stays quiet. It is
       revealed by focus too, so keyboard users are never shown a card whose
       action they cannot see. */
    .sector-card-action {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      margin-top: 8px;
      color: #fff;
      font-size: .88rem;
      font-weight: 800;
      opacity: 0;
      transform: translateY(6px);
      transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }


    .sector-card-action i.ph {
      font-size: var(--ic-sm);
    }

    /* A sector whose page does not exist yet. The dash marker carries the
         status; no sentence is spelled out. */
    .sector-card-action.is-pending {
      color: rgba(255, 255, 255, .82);
      font-weight: 600;
      cursor: default;
    }

    .sector-card-action.is-pending .pending-val {
      color: currentColor;
    }

    /* Touch and keyboard have no hover, so the action is simply always visible
       below the pointer breakpoint. */
    @media (hover: none) {

      .sector-card-action {
        opacity: 1;
        transform: none;
      }
    }

    /* The panel from the original site's hero-sector-panel, opening above the
       card instead of covering the hero. Width is pinned to the page's own
       content column regardless of which card triggers it (mid-row cards need
       this as much as edge cards do), which is why it is positioned off the
       viewport edge rather than off the card's own, much narrower, box. */
    .sector-card-panel {
      position: absolute;
      right: max(20px, calc((100vw - var(--max)) / 2 + 20px));
      left: max(20px, calc((100vw - var(--max)) / 2 + 20px));
      bottom: 100%;
      margin-bottom: 14px;
      z-index: 6;
      display: grid;
      grid-template-columns: minmax(180px, .8fr) minmax(240px, 1.2fr);
      background: rgba(255, 255, 255, .98);
      color: var(--charcoal);
      border-radius: var(--r);
      box-shadow: 0 26px 70px rgba(0, 0, 0, .32);
      opacity: 0;
      visibility: hidden;
      transform: translateY(16px);
      pointer-events: none;
      transition: opacity var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out),
        visibility var(--dur-base) var(--ease-out);
    }

    .sector-card:hover .sector-card-panel,
    .sector-card:focus-within .sector-card-panel {
      opacity: 1;
      visibility: visible;
      transform: none;
      pointer-events: auto;
    }

    .sector-card-panel-visual {
      min-height: 220px;
      background-size: cover;
      background-position: center;
      border-radius: var(--r);
    }

    .sector-card-panel-copy {
      padding: 30px 34px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      gap: 12px;
      text-align: left;
    }

    .sector-card-panel-copy h3 {
      font-family: var(--font-display);
      font-size: clamp(1.3rem, 2vw, 1.7rem);
      color: var(--charcoal);
    }

    .sector-card-panel-copy p {
      color: var(--muted);
      line-height: 1.85;
    }

    .sector-card-panel-subs {
      color: var(--label);
      font-size: .86rem;
    }

    .sector-card-panel-link {
      width: fit-content;
      display: inline-flex;
      align-items: center;
      gap: 10px;
      color: var(--accent);
      font-weight: 700;
      margin-top: 4px;
    }

    .sector-card-panel-link i.ph {
      font-size: var(--ic-sm);
    }

    .sector-card-panel-link.is-pending {
      color: var(--pending);
      font-weight: 600;
      cursor: default;
    }

    /* No hover on touch, so no panel either: the action link on the card
       itself already carries the destination. */
    @media (hover: none) {

      .sector-card-panel {
        display: none;
      }
    }

    @media (max-width: 980px) {

      .sector-card-panel {
        display: none;
      }
    }

    .project-card:hover .project-card-img img,
    .why-card:hover .why-media img,
    .news-card:hover img,
    .story-item:hover .story-image img {
      filter: saturate(1) contrast(1.03) brightness(1);
    }

    /* The supplied composites are branded in the green of the services company.
       Pulled most of the way to neutral so they sit inside the group's warm
       palette instead of introducing a second, competing brand colour. */
    .project-card-img img[src$=".png"],
    .why-media img[src$=".png"],

    .project-card:hover .project-card-img img[src$=".png"],
    .why-card:hover .why-media img[src$=".png"] {
      filter: saturate(.55) contrast(1.06) brightness(.98) sepia(.1);
    }

    /* Directional glyphs mirror in RTL by explicit opt-in only. A blanket rule
       would also flip the clock, the map pin and every brand logo. */
    [dir="rtl"] i.ph.icon--dir {
      transform: scaleX(-1);
    }


    /* A value awaiting delivery from Sdeira.
       It used to spell out "قيد التحديث" in every slot, which put the same
       sentence on screen ten times and made the page read as a list of excuses.
       It is a single dash now: a mark, not a message. The dash occupies the slot
       so the layout does not shift when the real figure lands, and the meaning
       lives in aria-label for anyone who cannot see it.
       The tone is deliberately neutral rather than red. A value that has not
       arrived yet is not an error, and colouring it like one told the visitor
       something had gone wrong. */
    /* The element IS the dash. It was an inline-flex box with a ::before rule
       drawing the bar, and the box collapsed to zero height wherever it sat
       inside a block-level <strong>, so the marker rendered as nothing at all in
       the partner stats. One element, explicit size, nothing to collapse. */
    .pending-val {
      display: inline-block;
      inline-size: .62em;
      min-inline-size: 22px;
      block-size: .1em;
      min-block-size: 3px;
      background: currentColor;
      color: var(--pending);
      border-radius: var(--r);
      vertical-align: middle;
    }

    /* On a dark or brand surface the neutral grey disappears, so the marker
       switches to the on-dark tone. */
    .surface-inverse .pending-val,
    .cta .pending-val,
    .about-badge .pending-val,
    footer .pending-val {
      color: var(--pending-on-dark);
    }

    /* ===== NAV =====
       Two distinct states. The resting bar is tall and airy over the hero; on
       scroll it compresses. Previously only the padding moved (100px -> 72px)
       while the logo stayed 48px in both, so the bar changed colour without ever
       reading as compressing. The logo and the CTA now shrink with it, which is
       what makes the motion legible. */
    /* --hd-pad/--logo-h/--cta-h, this rule's own padding and its
       background/padding transition used to be declared here. They are now
       set unconditionally in the SYSTEM LAYER at the end of this file (the
       English homepage uses the same one-size floating pill as the Arabic
       homepage and every generated sub-page - see that block's own comment),
       which as an unlayered rule always wins over anything declared in
       @layer legacy regardless of specificity. Redeclaring them here changed
       nothing and was a landmine for anyone who edited the "obvious" rule
       expecting it to have effect - removed, matching the Arabic file, which
       never carried this second copy. Only position/z-index survive here
       because the system layer does not redeclare them. */
    header {
      position: fixed;
      top: 0;
      right: 0;
      left: 0;
      z-index: 1000;
    }

    /* The bar carries its own readability floor instead of borrowing one from
       the hero. It used to rely on the hero scrim being near-opaque at the top,
       which meant lightening the hero (to cut the page's dark area) silently
       took the nav labels with it: white on the worst-case composite dropped to
       2.7. This gradient is local, fades to nothing within the bar's own height,
       and holds white at 5.4 over a fully white photo region. It disappears the
       moment the bar goes solid on scroll. */
    header::before {
      content: "";
      position: absolute;
      inset: 0 0 auto;
      block-size: 230px;
      z-index: -1;
      pointer-events: none;
      /* Holds its floor across the whole bar before it fades, because the nav
         row sits between 40px and 60px: a gradient that starts fading at the top
         is already down to .60 by the time it reaches the labels, which measures
         3.3 and fails. Flat .82 through 45% gives white 5.71 over a fully white
         photo region. */
      background: linear-gradient(180deg,
        rgba(var(--image-overlay-rgb), .82) 0%,
        rgba(var(--image-overlay-rgb), .78) 45%,
        rgba(var(--image-overlay-rgb), .30) 78%,
        transparent 100%);
      transition: opacity var(--dur-base) var(--ease-out);
    }

    header.scrolled::before {
      opacity: 0;
    }

    /* header.scrolled's own --hd-pad/--logo-h/--cta-h/background/backdrop-filter
       used to be set here too. Same landmine as header{} above: the SYSTEM
       LAYER's header.scrolled rule is unlayered and always wins, so this
       block changed nothing. Removed - the Arabic file's header.scrolled
       never carried more than the one property that still matters
       (--logo-h), set directly where it takes effect. */

    .nav {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 18px;
    }

    .logo {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 1.6rem;
      letter-spacing: 0;
      color: #fff;
      transition: color var(--dur-base);
      /* Never shrinks. The nav absorbs the width instead, so a wide menu can no
         longer squeeze the mark and slide a link underneath it. */
      flex: 0 0 auto;
    }

    .logo img {
      display: block;
      width: auto;
      max-width: 220px;
      height: var(--logo-h);
      object-fit: contain;
      transition: height var(--dur-base) var(--ease-out);
    }

    header.scrolled .logo {
      color: var(--charcoal)
    }

    .menu {
      display: flex;
      /* Fluid gap: at 1280 the fixed 34px gap plus 8 links overflowed the row
         the moment the fallback font measured wider than Tajawal, which is what
         wrapped the menu onto two lines and pushed "الأثر" under the logo. */
      gap: clamp(12px, 1.55vw, 30px);
      align-items: center;
      flex: 1 1 auto;
      min-width: 0;
      justify-content: center;
    }

    .menu a {
      font-size: clamp(.86rem, .95vw, .95rem);
      font-weight: 500;
      /* Solid, not .9. Over a photograph every tenth of alpha comes straight off
         the contrast ratio, and these are 14px labels. */
      color: #fff;
      position: relative;
      /* A nav label must never wrap: a two-line link changes the bar height and
         reflows every sibling. */
      white-space: nowrap;
      transition: color var(--dur-base)
    }

    .menu a::after {
      content: "";
      position: absolute;
      bottom: -6px;
      right: 0;
      width: 0;
      height: 1.5px;
      background: var(--accent);
      transition: width var(--dur-base)
    }

    .menu a:hover::after,
    .menu a.active::after {
      width: 100%
    }

    .menu-mobile-actions a::after {
      display: none;
    }

    header.scrolled .menu a {
      color: var(--ink)
    }

    .menu a.active {
      color: #fff;
    }

    header.scrolled .menu a.active {
      color: var(--accent-text);
    }

    .menu-mobile-actions {
      display: none;
    }

    .menu-lang,
    .menu-contact {
      display: none;
    }

    .nav-actions {
      display: flex;
      align-items: center;
      gap: 12px;
      flex: 0 0 auto;
    }

    .nav-icon {
      width: 44px;
      height: 44px;
      display: inline-grid;
      place-items: center;
      border-radius: var(--r);
      color: #fff;
      transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .nav-icon i.ph {
      font-size: var(--ic-md);
      line-height: 1;
    }

    .nav-icon:hover {
      background: rgba(255, 255, 255, .14);
    }

    header.scrolled .nav-icon {
      color: var(--charcoal);
    }

    header.scrolled .nav-icon:hover {
      background: rgba(145, 8, 17, .1);
      color: var(--accent-text);
    }

    .nav-cta {
      /* Height is driven by the header state so the CTA compresses with the bar
         instead of pinning it open. */
      min-height: var(--cta-h);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      padding: 0 clamp(18px, 1.8vw, 28px);
      background: var(--charcoal);
      border-radius: var(--r);
      font-size: .82rem;
      font-weight: 700;
      letter-spacing: 0;
      white-space: nowrap;
      color: #fff;
      transition: min-height var(--dur-base) var(--ease-out),
        padding var(--dur-base) var(--ease-out),
        background var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

    .nav-cta:hover {
      background: var(--accent);
      color: #fff;
      border-color: var(--accent);
    }

    header.scrolled .nav-cta {
      border-color: var(--charcoal);
      background: var(--charcoal);
      color: #fff
    }

    header.scrolled .nav-cta:hover {
      background: var(--accent);
      border-color: var(--accent);
      color: #fff
    }

    .lang {
      font-size: .85rem;
      font-weight: 500;
      color: rgba(255, 255, 255, .8);
      cursor: pointer
    }

    header.scrolled .lang {
      color: var(--muted)
    }

    .burger {
      display: none;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 5px;
      cursor: pointer;
      /* The bars stay 26px wide, but the hit area is a full 44px square.
         Measured before this: 26x16, which fails WCAG 2.5.8 (24x24 minimum) on
         height and is far under the 44px usability standard, on the one control
         that opens navigation on touch devices. */
      min-inline-size: 44px;
      min-block-size: 44px;
      margin-inline-end: -9px;
    }

    .burger span {
      width: 26px;
      height: 2px;
      background: #fff;
      transition: var(--dur-base)
    }

    header.scrolled .burger span {
      background: var(--charcoal)
    }

    .menu-backdrop {
      position: fixed;
      inset: 0;
      z-index: 999;
      display: none;
      border: 0;
      background: rgba(var(--image-overlay-rgb), .38);
      backdrop-filter: blur(8px);
      cursor: pointer;
    }

    body.menu-open .menu-backdrop {
      display: block;
    }

    /* Low-priority utility, not a primary action: smaller footprint, no
       border/blur, and it rests at partial opacity even while "visible" -
       full opacity only kicks in on hover/focus. */
    .scroll-top {
      position: fixed;
      left: 24px;
      bottom: 24px;
      z-index: 999;
      width: 38px;
      height: 38px;
      border-radius: var(--r);
      background: rgba(65, 64, 66, .55);
      border: none;
      color: #fff;
      font-size: .95rem;
      line-height: 1;
      display: grid;
      place-items: center;
      cursor: pointer;
      opacity: 0;
      pointer-events: none;
      transform: translateY(12px);
      transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
    }

    .scroll-top.visible {
      opacity: .55;
      pointer-events: auto;
      transform: none;
    }

    .scroll-top:hover,
    .scroll-top:focus-visible {
      background: var(--accent);
      opacity: 1;
    }

    /* ===== HERO ===== */
    /* No longer a fixed 100dvh box. The sector grid is back inside the hero in
       normal flow after .hero-content, so the hero's real height is 100dvh plus
       whatever that grid needs, and the photo/veil (both inset:0 on .hero
       itself) stretch to cover the whole of it automatically. */
    .hero {
      position: relative;
      min-height: max(680px, 100dvh);
    }

    .hero-bg {
      position: absolute;
      inset: 0;
      z-index: -2
    }

    .hero-slide {
      position: absolute;
      inset: 0;
      opacity: 0;
      transition: opacity var(--dur-slow) var(--ease-out);
    }

    .hero-slide.active {
      opacity: 1;
    }

    .hero-slide img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transform: scale(1.08);
    }

    .hero-slide.active img {
      animation: slowZoom 7s ease-out forwards;
    }

    @keyframes slowZoom {
      to {
        transform: scale(1)
      }
    }

    /* Mobile: each slide scales from its top edge so the headline sits on the
       sky rather than over the buildings (25 Sept change request). Applied to
       the slide itself, not the image; no overlay; desktop unchanged. */
    @media (max-width: 980px) {
      .hero-bg {
        height: 100dvh;
        bottom: auto;
        overflow: hidden;
      }

      .hero-slide {
        transform-origin: 50% 0;
      }

      .hero-slide:nth-child(1) { transform: scale(1.6); }
      .hero-slide:nth-child(2) { transform: scale(2.3); }
      .hero-slide:nth-child(3) { transform: scale(2.2); }
    }

    /* A flat, gentle wash over the whole hero (photo plus the sector grid
       below it), just enough to pull the exposure together. Not the text's
       readability floor: that gradient used to live here, sized against
       .hero's own height, and broke the moment the sector grid started adding
       a variable, viewport-width-dependent amount to that height (the grid's
       columns are vw-based, .hero's own height is not, so "46% of .hero" moved
       every time the window resized even though the text itself had not
       moved). The text's floor now lives on .hero-content, which is reliably
       100dvh regardless of what the grid below it is doing. */
    .hero::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: rgba(var(--image-overlay-rgb), .16);
    }

    /* Skewed ribbons, extracted from the Eskan microsite's about-deco
       pattern (idarat-aqarat.css:1120-1155). Spans the hero's full height
       (inset:0 plus each span's own -10%/120% overshoot) so the effect reads
       clearly at any scroll position, not just near one corner. Sat in the
       empty photo space past the centred copy column so it never crosses the
       text. Drawn in Sweihan rather than the source's translucent white: on
       this dark photograph the white reading was too faint to register as a
       deliberate mark, and the brand tone carries at the same hairline
       weight. */
    /* z-index 1, not 0: `.hero::after` (the darkening scrim, further down this
       file) is also z-index 0, and as generated content it paints as the LAST
       child of `.hero` regardless of DOM order - so at equal z-index the scrim
       painted over this mark and hid it completely. Site owner flagged the
       hero corner mark invisible, 28 Aug 2026. */
    .hero-glass {
      position: absolute;
      z-index: 1;
      inset: 0;
      overflow: hidden;
      pointer-events: none;
    }

    .hero-glass span {
      position: absolute;
      top: -10%;
      height: 120%;
      width: 60px;
      border: 1px solid var(--brand-sweihan);
      border-radius: var(--r);
      background: color-mix(in srgb, var(--brand-sweihan) 8%, transparent);
      transform: skewX(-24deg);
    }

    .hero-glass .r1 { inset-inline-start: 68%; }
    .hero-glass .r2 { inset-inline-start: 78%; }
    /* Third ribbon steps back so the group reads as depth, not three equals -
       the same relationship the source had between its own three ribbons. */
    .hero-glass .r3 {
      inset-inline-start: 88%;
      border-color: color-mix(in srgb, var(--brand-sweihan) 55%, transparent);
    }

    @media (max-width: 920px) {
      .hero-glass { display: none; }
    }

    /* ===== IMAGE RIBBON =====
       One decoration for photography, from the Eskan microsite. It replaced
       an earlier three-drifting-bars variant: three thin outlines competed
       with the photograph instead of marking it, and at hairline weight they
       read as a rendering artefact rather than as identity.

       Geometry comes from the same identity-band tokens used by the section
       ribbons. Image-specific strength tokens keep the 2px shape legible but
       secondary on photography. The frame clips that overfill at the image
       edges, so the visible mark occupies the full photograph instead of
       floating short inside it.

       The element is still a FRAME with the band as its ::before, because the
       band is SKEWED: a -24deg skew over a 500px band throws its corners about
       122px sideways, well past the photograph, and the frame's overflow is
       what contains that. Two shapes of this rule do not work and should not
       be reinstated:

         - clip-path on the band itself. It is applied BEFORE the transform, so
           it cannot contain the skew at all.
         - overflow: hidden on the host. .about-visual deliberately lets
           another child, the year badge, hang outside its box, so clipping
           the host would cut the badge off.

       Every band uses the system radius, so the image mark reads as a cut
       identity band rather than a second visual language. Needs a positioned
       parent. */
    .ribbon-frame {
      --ribbon-line: color-mix(in srgb, var(--brand-sweihan) var(--image-ribbon-line-strength), transparent);
      --ribbon-fill: color-mix(in srgb, var(--brand-sweihan) var(--image-ribbon-fill-strength), transparent);
      position: absolute;
      inset: 0;
      z-index: 2;
      overflow: hidden;
      border-radius: var(--r);
      pointer-events: none;
    }

    .ribbon-frame::before {
      content: "";
      position: absolute;
      right: 14%;
      top: var(--identity-band-top);
      width: var(--identity-band-width);
      height: var(--identity-band-height);
      border: var(--identity-band-border) solid var(--ribbon-line);
      border-radius: var(--r);
      background: var(--ribbon-fill);
      transform: skewX(-24deg);
    }

    /* A ribbon host MUST be positioned. The frame is inset: 0, so on a static
       host it resolves against whatever ancestor happens to be positioned and
       stretches to that instead - and because the frame is what clips the
       skewed band, the band then runs clean across the card, over the white
       body and out the other side. Written at the base class, not scoped to
       the secondary cards, so the trap cannot reopen from another direction:
       the feature card's own absolute (0,2,0, later in the file) still wins
       where it applies, and the filtered view - which deliberately returns
       the feature card to normal flow - asks for relative for this reason. */
    .project-card-img {
      position: relative;
    }

    /* The About photograph carries the band on its outer (left) edge, away
       from the copy column and the year badge that sits at the image's inner
       bottom corner. Physical left, not inline-start: this is decorative
       geometry, and the RTL/LTR mirror is a per-page decision (see the
       sub-page rules in CLAUDE.md), not something the property should do on
       its own.

       MIRRORED FROM THE ARABIC. Measured at 1280: the Arabic page puts the
       photograph in the left column with the year badge hanging off its right
       edge; this page is the exact mirror, photograph right and badge left. So
       "the outer edge, away from the copy" is physical LEFT there and physical
       RIGHT here - which is already the base rule's value, restated rather
       than left implicit so the next reader does not re-derive it. */
    .about-visual .ribbon-frame::before {
      left: auto;
      right: 14%;
    }

    /* Large images push the shared band past the edge so the frame crops it
       sideways and it reads as passing behind the photograph rather than
       sitting inside it. This variant changes position only; its geometry
       remains on the same system tokens as every other photographic band. */
    .ribbon-frame--tall::before {
      right: auto;
      left: -4%;
    }

    /* The route cards alternate their layout, so a band pinned to one physical
       side is behind the white panel on half of them, which is where it cannot
       be seen at all. Each card takes the edge AWAY from its own panel.

       MIRRORED FROM THE ARABIC. .needs-route is direction: rtl on this page
       and direction: ltr on the Arabic one, so `justify-self: end` resolves to
       the opposite physical side and the odd/even pairing swaps with it: the
       Arabic puts its band right on odd cards, this page puts it right on
       EVEN cards. Measured, not assumed - see the port log. */
    .needs-route:nth-child(even) .ribbon-frame--tall::before {
      left: auto;
      right: -4%;
    }

    /* Its own full-viewport box, flexed to the bottom edge, exactly the role
       .hero itself used to play alone. The sector grid is a sibling after this
       one in normal flow, so whatever height it needs extends the hero past
       100dvh without this box's own sizing having to know about it. */
    .hero-content {
      position: relative;
      width: min(100%, 860px);
      min-height: 100dvh;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      padding-block: clamp(112px, 15vh, 180px) 48px;
      max-width: 860px;
    }

    /* The copy and the slide rail as a row, so the rail can stretch (align-
       items: stretch) to match whatever height the copy needs, and never has
       to be told that height. Copy comes first in markup, rail second, so in
       RTL the copy still sits flush against the reading edge exactly as
       before and the rail is what's new beside it, not the other way round. */
    .hero-content-row {
      display: flex;
      align-items: stretch;
      gap: 22px;
    }

    .hero-content-copy {
      flex: 1 1 auto;
      min-width: 0;
      text-align: left;
      transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    /* The text's actual readability floor, scoped to this box instead of to
       .hero. This box is reliably 100dvh (a height quantity), so a stop
       measured against it stays correct at every window width, unlike a stop
       measured against .hero's total height once the sector grid below made
       that total depend on viewport width too.
       Eyebrow (smallest text, 4.5:1 needed) sits at ~46% of this box, the
       paragraph at ~65%: spread wide, one continuous rise, no flat plateau. */
    .hero-content::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: linear-gradient(180deg,
        rgba(var(--image-overlay-rgb), .04) 0%,
        rgba(var(--image-overlay-rgb), .10) 16%,
        rgba(var(--image-overlay-rgb), .68) 46%,
        rgba(var(--image-overlay-rgb), .76) 65%,
        rgba(var(--image-overlay-rgb), .80) 100%);
    }

    /* Scoped to the copy alone, not the whole row: the slide rail keeps
       animating its own fill through a rotation, and the buttons/rail no
       longer flicker out and back in on every change, only the text does. */
    .hero-content-copy.is-changing {
      opacity: 0;
      transform: translateY(14px);
    }

    .eyebrow {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      font-size: .85rem;
      font-weight: 500;
      letter-spacing: 0;
      /* 14px over a photograph, so it takes the 4.5 floor and cannot afford
         alpha. .85 measured 3.83 at this height. */
      color: #fff;
      margin-bottom: 22px
    }

    /* removed decorative rule: eyebrow rule (hero) */
    .__removed-eyebrow-rule-hero { display: none }

    .hero h1 {
      font-size: clamp(2.25rem, min(4.75vw, 8svh), 4.18rem);
      color: #fff;
      font-weight: 700;
      margin-bottom: 22px;
      line-height: 1.16;
      text-wrap: balance;
    }

    .hero h1 .em {
      display: inline-block;
      color: #fff;
      background: var(--accent);
      padding: .02em .11em .09em;
      margin-inline: .075em;
      white-space: nowrap;
      vertical-align: baseline;
      line-height: inherit;
      -webkit-text-stroke: 0;
      box-decoration-break: clone;
      -webkit-box-decoration-break: clone;
    }

    @media (max-width: 360px) {
      .hero h1 .em {
        margin-inline: .06em;
      }
    }

    .hero p {
      font-size: clamp(1.05rem, 2vw, 1.3rem);
      color: rgba(255, 255, 255, .88);
      max-width: 560px;
      font-weight: 400;
      line-height: 1.8;
    }

    .hero-actions {
      display: flex;
      gap: 16px;
      margin-top: 38px;
      flex-wrap: wrap
    }

    .btn {
      display: inline-flex;
      align-items: center;
      gap: 12px;
      padding: 15px 30px;
      font-weight: 500;
      font-size: 1rem;
      border-radius: var(--r);
      transition: background var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out),
        border-color var(--dur-fast) var(--ease-out);
      cursor: pointer;
}

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

    .btn-primary:hover {
      background: var(--accent-deep);
      color: #fff;
      box-shadow: 0 14px 30px rgba(145, 8, 17, .35);
    }

    /* The secondary hero button. This is the sanctioned border exception: it has
       no fill, so the outline is the only thing that makes its hit area visible.
       Border alpha raised to .6 so the outline itself clears 3:1 against the
       hero photo, measured across all three slides. */
    .btn-ghost {
      /* Full shorthand, not just border-color. The base .btn no longer carries
         a transparent border, so a colour-only declaration would resolve to
         border-style:none and draw nothing at all. */
      border: 1px solid rgba(255, 255, 255, .6);
      color: #fff;
    }

    .btn-ghost:hover {
      border-color: #fff
    }

    /* .arr is gone from the markup. Links signal themselves with an underline
       that grows from the reading edge instead of a sliding arrow glyph. */
    .more {
      position: relative;
      display: inline-block;
    }

    .more::after {
      content: "";
      position: absolute;
      inset-block-end: -3px;
      inset-inline-start: 50%;
      inline-size: 100%;
      block-size: 1px;
      background: currentColor;
      opacity: .32;
      transform: scaleX(0);
      transform-origin: right;
      transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
    }

    a:hover .more::after,
    .more:hover::after {
      transform: scaleX(1);
      opacity: 1;
    }

    .btn:hover .__arr-removed {
      transform: none
    }

    /* A child of .hero now, not .hero-content, and deliberately so: it sits at
       the viewport's actual left edge regardless of where the content column
       (the 860px reading width, itself inset by the page's own side margin)
       happens to fall, rather than at a fixed offset from that column's own
       left edge the way it did while nested inside it. Vertical position is
       pinned to 100dvh rather than to .hero's own height, since .hero is
       taller than one screen once the sector grid is in normal flow below
       .hero-content, and this hint is only meaningful within the first one. */
    .scroll-hint {
      position: absolute;
      top: calc(100dvh - 76px);
      left: 24px;
      z-index: 2;
      display: flex;
      align-items: center;
      gap: 10px;
      /* .7 measured 3.57 over the worst-case photo composite at this height. */
      color: rgba(255, 255, 255, .95);
      font-size: .8rem;
      letter-spacing: 0
    }

    /* Was a 22x36 bordered rectangle standing in for a mouse. With borders gone
       it rendered as an empty outline box next to the label, so it is rebuilt as
       a filled track with a travelling highlight: readable with no border. */
    .scroll-hint .dot {
      width: 2px;
      height: 34px;
      background: rgba(255, 255, 255, .28);
      position: relative;
      overflow: hidden;
    }

    /* A smoother fall than a linear one: eased in as it leaves the top, held
       at full opacity through the travel, eased out only at the very end
       instead of fading across the whole distance. */
    .scroll-hint .dot::after {
      content: "";
      position: absolute;
      top: 4px;
      left: 50%;
      transform: translateX(-50%);
      width: 3px;
      height: 8px;
      background: #fff;
      border-radius: var(--r);
      animation: scrollDot 2s cubic-bezier(.4, 0, .2, 1) infinite;
    }

    @keyframes scrollDot {
      0% {
        opacity: 0;
        top: 4px
      }

      20% {
        opacity: 1
      }

      72% {
        opacity: 1;
        top: 24px
      }

      100% {
        opacity: 0;
        top: 24px
      }
    }

    /* A vertical rail beside the copy block, stretched to its full height by
       the row's align-items: stretch, replacing both the old arrow-button
       pair and the flat horizontal line row. Each segment fills top-to-bottom
       on its own timer instead of just swapping colour, so the rail reads as
       a countdown to the next slide, not a static position marker. */
    .hero-slides-ind {
      display: flex;
      flex-direction: column;
      gap: 10px;
      width: 3px;
      flex: 0 0 auto;
    }

    .hero-slide-line {
      flex: 1 1 0;
      width: 3px;
      padding: 0;
      border: 0;
      border-radius: var(--r);
      background: rgba(255, 255, 255, .28);
      cursor: pointer;
      position: relative;
      overflow: hidden;
    }

    .hero-slide-line::before {
      content: "";
      position: absolute;
      inset-inline: 0;
      top: 0;
      height: 0;
      background: var(--accent);
    }

    /* A slide already passed keeps a solid fill instead of resetting to
       empty, so the rail also reads as "how far through the set", not just
       "which one is playing now". */


    .hero-slide-line:focus-visible {
      outline: 2px solid #fff;
      outline-offset: 4px;
    }

    @media (prefers-reduced-motion: reduce) {

      .hero-slide-line.active::before {
        transition: none;
      }
    }

    /* Normal flow, not pinned: it sits right after .hero-content, which is its
       own 100dvh box, so this grid is what makes the hero taller than one
       screen. Three cards land in the first row, which is why "a little
       taller than the page" is true rather than "twice as tall": only the
       first row has to fit inside that extra reach, the second row is what a
       small scroll reveals. */


    @media (prefers-reduced-motion: reduce) {

      *,
      *::before,
      *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
        transition-duration: .01ms !important;
      }

      /* Reduced motion must never mean reduced content. */
      .reveal.armed {
        opacity: 1 !important;
        transform: none !important;
      }
    }

    /* ===== GROUP IMPACT ===== */
    /* The section that used to be the page's largest dark plate, 1126px of it.
       Measured against four reference sites, dark neutral surface runs from 0%
       (AD Ports Group, this group's own parent, and Modon) through 2.4% (u.ae,
       the federal government portal) to 6.8% (Aldar). This page was at 38.8%.
       Keeping one dark band this tall would still have left it at roughly 15%,
       so the impact band moved onto the light ladder and the weight it used to
       carry is now carried by Liwa, which is a brand colour rather than an
       absence of one. Dark neutral survives only where it earns its place: the
       footer and the sector strip over the hero photograph. */
    .impact {
      background: var(--surface-sunken-strong);
      padding: var(--sec-pad) 0;
      color: var(--ink);
    }

    /* The middle layer is gone.
       This section was three stacked surfaces: a grey section, a white panel
       inside it, and grey cards inside that. Each layer added its own padding,
       so the content sat inside 48px of panel padding inside 96px of section
       padding, and the reader crossed three tone changes to reach a number. A
       panel that only exists to hold a background is not structure, it is an
       extra box.
       The cards now sit directly on the section surface, which is what the tone
       ladder was for in the first place: the section is the sunken surface and
       the cards step up from it. */
    .impact-panel {
      position: relative;
      isolation: isolate;
    }

    .impact-main {
      display: grid;
      grid-template-columns: minmax(310px, .72fr) minmax(0, 1.18fr);
      gap: clamp(26px, 3.2vw, 46px);
      align-items: stretch;
    }

    .impact-visual {
      min-height: 520px;
      position: relative;
      overflow: hidden;
      border-radius: var(--r);
      background: var(--surface-sunken-strong);
    }

    .impact-visual img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      filter: saturate(.92) contrast(1.04);
      opacity: 1;
    }

    .impact-visual::after {
      content: "";
      position: absolute;
      inset: 0;
      /* Both ends carry white text over a photograph, so both ends need a floor,
         with the middle left for the photo. A single gradient that darkens,
         lightens, then darkens again reverses direction twice and draws a visible
         edge at each reversal. Two independently monotonic layers, one fading
         from the top and one from the bottom, give the same dark-light-dark
         shape without either one ever reversing.
         Worst case is a fully white photo region: at .76 the composite clears
         5.1, at .85 it clears 6.6. */
      background:
        linear-gradient(to bottom, rgba(var(--image-overlay-rgb), .76) 0%, rgba(var(--image-overlay-rgb), .76) 15%, transparent 46%),
        linear-gradient(to top, rgba(var(--image-overlay-rgb), .85) 0%, rgba(var(--image-overlay-rgb), .85) 20%, transparent 50%);
    }

    .impact-identity-strips {
      position: absolute;
      z-index: 1;
      top: 34%;
      left: clamp(24px, 8%, 42px);
      width: 92px;
      height: 32%;
      pointer-events: none;
    }

    .impact-identity-strips span {
      position: absolute;
      bottom: 0;
      width: 9px;
      transform: rotate(var(--brand-stripe-angle));
      transform-origin: center;
    }

    .impact-identity-strips span:nth-child(1) {
      left: 4px;
      height: 72%;
      background: var(--brand-white);
    }

    .impact-identity-strips span:nth-child(2) {
      left: 26px;
      height: 100%;
      background: var(--brand-razeen);
    }

    .impact-identity-strips span:nth-child(3) {
      left: 50px;
      height: 84%;
      background: var(--brand-al-khatim);
    }

    .impact-identity-strips span:nth-child(4) {
      left: 74px;
      height: 58%;
      background: var(--brand-liwa);
    }

    .impact-visual-brand,
    .impact-visual-copy {
      position: absolute;
      z-index: 2;
    }

    .impact-visual-brand {
      top: 34px;
      right: 34px;
      display: flex;
      align-items: center;
      gap: 14px;
      color: #fff;
      font-size: .98rem;
      line-height: 1.7;
    }

    /* Was logo.png, the same improvised gold stripe used in the footer bars.
       A plain icon, on-dark colour, matches every other marker on the page. */
    .impact-visual-brand i.ph {
      color: var(--icon-on-dark);
      font-size: var(--ic-lg);
      line-height: 1;
    }

    .impact-visual-copy {
      right: 34px;
      bottom: 32px;
      left: 34px;
      color: rgba(255, 255, 255, .82);
      font-size: 1rem;
      line-height: 1.85;
    }

    .impact-content {
      min-width: 0;
    }

    .impact-head {
      text-align: left;
      max-width: 780px;
      margin: 0 0 34px;
    }

    .impact-kicker {
      display: inline-flex;
      align-items: center;
      gap: 12px;
      color: var(--label);
      font-size: .84rem;
      font-weight: 800;
      letter-spacing: 0;
      margin-bottom: 18px;
    }

    /* removed decorative rule: impact kicker rules */
    .__removed-impact-kicker-rules { display: none }

    .impact h2 {
      color: var(--ink);
      font-size: clamp(2.25rem, 4.6vw, 4.2rem);
      margin-bottom: 18px;
    }

    .impact-head p {
      color: var(--muted);
      font-size: clamp(1rem, 1.7vw, 1.16rem);
      line-height: 1.9;
    }

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

    /* Single column, content stacked from the top. The old grid was `1fr auto`
       with the icon pinned to column 2 spanning three rows, so the icon floated
       beside the label with nothing aligning them, and a 168px min-height left
       roughly half of every card empty. */
    .impact-card {
      padding: 24px 22px;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 14px;
      text-align: left;
      border-radius: var(--r);
      /* The section is Silver now that the white panel is gone, so the card
         steps UP to white to read as raised. Before, both card and panel were on
         the light half of the ladder and the card had nothing to step away
         from. */
      background: var(--surface-raised);
      transition: background var(--dur-base) var(--ease-out);
    }

    .impact-card:hover {
      background: var(--surface-sunken);
    }

    .impact-number {
      font-family: var(--font-display);
      font-size: clamp(2.1rem, 3.4vw, 3rem);
      font-weight: 800;
      line-height: 1;
      color: var(--figure);
      letter-spacing: 0;
    }

    .impact-number .accent {
      color: var(--figure);
    }

    /* Removed: a 1px divider that occupied the same grid cell as the icon. */
    .impact-rule {
      display: none;
    }

    /* Leads the card. `order` puts it first visually without reordering the DOM,
       so the label still precedes the decorative icon for a screen reader. */
    .impact-icon {
      order: -1;
      width: 52px;
      height: 52px;
      display: grid;
      place-items: center;
      border-radius: var(--r);
      background: var(--icon-wash);
      color: var(--icon);
      transition: background var(--dur-base) var(--ease-out);
    }

    /* Al Khatim, not Liwa: this tile is a decorative marker, not the action
       itself, so it follows the "icons are not red" rule instead of the
       accent colour. Was a raw rgba(145, 8, 17, .14) literal. */
    .impact-card:hover .impact-icon {
      background: var(--icon-warm-wash);
    }

    .impact-icon i.ph {
      font-size: var(--ic-lg);
      line-height: 1;
    }

    .impact-card-body {
      min-width: 0;
    }

    .impact-label {
      color: var(--ink);
      font-size: clamp(1.05rem, 1.5vw, 1.28rem);
      font-weight: 800;
      line-height: 1.25;
    }

    .impact-note {
      color: var(--muted);
      font-size: .84rem;
      margin-top: 8px;
      line-height: 1.55;
    }

    .impact-dots {
      display: none;
    }

    .impact-dots span {
      width: 4px;
      height: 4px;
      border-radius: var(--r);
      background: var(--gold);
    }

    /* Four separate tonal cards on the section background, not one strip carved
       up by dividers. The dividers were the only thing separating the items, so
       with borders gone the four ran together as a single paragraph block. */
    .impact-footer {
      margin-top: 22px;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
      gap: 14px;
      padding: 0;
      background: none;
      color: var(--ink);
    }

    .impact-value {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 12px;
      padding: 22px 20px;
      border-radius: var(--r);
      background: var(--surface-raised);
      transition: background var(--dur-base) var(--ease-out);
    }

    .impact-value:hover {
      background: var(--surface-sunken);
    }

    .impact-value-icon {
      width: 44px;
      height: 44px;
      display: grid;
      place-items: center;
      border-radius: var(--r);
      background: var(--icon-wash);
      color: var(--icon);
    }

    .impact-value-icon i.ph {
      font-size: var(--ic-md);
      line-height: 1;
    }

    .impact-value h3 {
      color: var(--ink);
      font-size: 1.05rem;
      margin-bottom: 6px;
    }

    .impact-value p {
      color: var(--muted);
      font-size: .86rem;
      line-height: 1.6;
    }

    /* ===== GROUP PROCESS ===== */
    /* Was a photograph under a 0.86-0.94 dark scrim, which put a third dark
       band between two others and made the page read as mostly dark. It is one
       tone step below the page now: the separation is still there, the weight is
       not. This single change removes 854px of dark surface and one stock photo. */
    .process {
      position: relative;
      overflow: hidden;
      padding: var(--sec-pad) 0;
      background: var(--surface-sunken);
      color: var(--ink);
      isolation: isolate;
    }

    .process-head {
      /*max-width: 820px;*/
      margin-inline-start: auto;
      margin-bottom: 48px;
      text-align: left;
    }

    .process-kicker {
      display: inline-flex;
      align-items: center;
      gap: 12px;
      color: var(--label);
      font-size: .86rem;
      font-weight: 800;
      letter-spacing: 0;
      margin-bottom: 18px;
    }

    /* removed decorative rule: process kicker rules */
    .__removed-process-kicker-rules { display: none }

    .process h2 {
      color: var(--ink);
      font-size: clamp(2.45rem, 5vw, 4.4rem);
      margin-bottom: 18px;
    }

    .process-head p {
      color: var(--muted);
      font-size: clamp(1rem, 1.7vw, 1.16rem);
      line-height: 1.9;
    }

    .process-flow {
      display: grid;
      /* Five steps, so the row must hold five. A flat 210px floor could not:
         5x210 + 4x22 = 1138 against a 1115px container, which dropped step 05
         onto a second row by itself. Flooring each track just above 100%/6
         guarantees a 6th track is impossible while letting the row fit 5, and
         still collapse to 4, 3, 2 and 1 as the viewport narrows. */
      grid-template-columns: repeat(auto-fit, minmax(max(180px, calc(100% / 6 + 1px)), 1fr));
      gap: 22px;
      align-items: stretch;
    }

    .process-step {
      position: relative;
      /* Was 340px. The grid already equalises the row, so a hard floor only
         added empty space under the shortest card. */
      padding: 30px 24px 26px;
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      gap: 14px;
      border-radius: var(--r);
      /* White on Cloud. The card is the raised surface now, which is the same
         elevation-by-tone rule read in the opposite direction. */
      background: var(--surface-raised);
      transition: background var(--dur-base) var(--ease-out);
    }


    /* Removed. This drew a 48px box at left:-34px, straddling the gap between
       two cards and clipping into both. The numbered steps already carry the
       order, so the connector was redundant as well as broken. */

    /* order puts the icon and the step number at the head of the card without
       reordering the DOM: the heading still precedes the decorative icon for
       assistive tech. */
    .process-num {
      order: -1;
      font-family: var(--font-display);
      color: var(--icon);
      font-size: 1.05rem;
      font-weight: 700;
      line-height: 1;
      letter-spacing: 0;
    }

    .process-step h3 {
      color: var(--ink);
      font-size: clamp(1.25rem, 1.7vw, 1.6rem);
      margin: 0;
    }

    .process-line {
      display: none;
    }

    .process-icon {
      order: -2;
      width: 58px;
      height: 58px;
      display: grid;
      place-items: center;
      border-radius: var(--r);
      background: var(--icon-wash);
      color: var(--icon);
      margin: 0;
      transition: background var(--dur-base) var(--ease-out);
    }

    /* Al Khatim, not Liwa: same reasoning as impact-icon above. Was a raw
       rgba(145, 8, 17, .14) literal. */

    .process-icon i.ph {
      font-size: var(--ic-lg);
      line-height: 1;
    }


    .process-summary {
      margin-top: 28px;
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 28px;
      align-items: center;
      padding: 26px 34px;
      border-radius: var(--r);
      background: var(--surface-raised);
    }

    .process-summary strong {
      color: var(--ink);
      font-size: 1.25rem;
      padding-inline-start: 24px;
      white-space: nowrap;
    }


    /* ===== SECTION SHELL ===== */
    section {
      position: relative
    }

    /* Default surface for any section that does not declare its own. White,
       so a new section joins the ladder at the page level instead of inheriting
       a tint that used to blanket six sections at once. */
    .pad {
      padding: var(--sec-pad) 0;
      background: var(--surface-base);
    }

    /* One rule for every raised surface on a light band. This used to rely on
       --card (pure white) alone to separate the surface from the page, which
       works on Cloud or Silver but is invisible where the section itself is
       also white: .why, .featured-projects and .news-section all are, so
       .why-footer, .projects-footer, .news-tabs, .news-subscribe and
       .about-values were white cards on a white page, with nothing marking
       their edge. A hairline border holds the edge regardless of what surface
       the card happens to sit on. */
    .news-card,
    .why-card,
    .partner-card,
    .news-tabs,
    .news-subscribe,
    .about-values,
    .story-footer,
    .why-footer,
    .projects-footer,
    .project-tab {
      background: var(--card);
      border: 1px solid var(--line);
    }

    /* The header is fixed, so an in-page anchor would otherwise land with the
       section heading hidden underneath it. 56px is the compressed bar height. */
    section[id] {
      scroll-margin-top: 72px;
    }

    .sec-head {
      margin-bottom: var(--sec-head-gap);
      max-width: 680px
    }

    .kicker {
      font-size: .82rem;
      font-weight: 700;
      letter-spacing: 0;
      color: var(--label);
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 20px
    }

    /* removed decorative rule: kicker rule (about/projects/why/news/cta) */
    .__removed-kicker-rule-about-projects-why-news-cta { display: none }

    .sec-head h2 {
      font-size: clamp(2rem, 4vw, 3.1rem);
      color: var(--charcoal);
      margin-bottom: 18px
    }

    .sec-head p {
      font-size: 1.12rem;
      color: var(--muted);
      font-weight: 400;
    }

    /* ===== ABOUT ===== */
    .sectors {
      background: var(--surface-sunken);
    }

    /* Grey 70 measures 4.01 on Silver and fails body text there. The token file
       states the limit; these are the three sections that hit it. Rather than
       chase every kicker and caption inside them, each Silver surface declares
       what "label" means within itself. Jais measures 5.51 on Silver. */
    .impact,
    .story,
    .partners {
      --label: var(--brand-jais);
      --pending: var(--brand-jais);
      /* Sweihan is the warm figure tone and it is white-only: 3.35 on White,
         2.99 on Cloud, 2.63 on Silver. It fails even the large-text floor here,
         so these surfaces fall back to Black at 8.11. Figures on Silver are
         distinguished by size, not by hue. */
      --figure: var(--ink);
    }

    .about {
      background: var(--surface-base);
    }

    .about-layout {
      direction: ltr;
      display: grid;
      /* Was .78fr/1.22fr (text-majority), before --media-wide moved to 4:3.
         At that split the photo column measured 435px, and .split-badge's
         width follows it (min(72%, 340px) = 313px) while its own height
         stays fixed - driven by its own vw-based padding and its three lines
         of real copy, not by the photo. Shortening the photo from the old
         ~0.87:1 to 4:3 at the same 435px width shrank its area much faster
         than the badge's, so the badge went from covering ~37% of the photo
         to 57% - site owner flagged the badge reading as if it had eaten the
         picture, 16 Aug 2026. An even split gives the photo column back the
         width it needs to carry that fixed-size badge at the new, shorter
         ratio - measured down to ~45% coverage - without touching the badge
         itself or the crop already approved for this photo. */
      grid-template-columns: minmax(360px, 1fr) minmax(0, 1fr);
      gap: clamp(64px, 7vw, 132px);
      align-items: center;
    }

    /* Height is not set here. The About visual is one number shared by the
       photograph and the diagonal band overlay, so it lives in a single
       component variable at the end of this block. */
    /* direction: rtl removed (site owner flagged, 12 Aug 2026). It was written
       for .about-badge (dead CSS below - the markup uses the shared
       .split-badge from sdeira-sections.css now, positioned with physical
       left/right and its own [dir="rtl"] override, needing no local direction
       flip). Forcing rtl here did nothing harmless on this page the way it
       does on the Arabic file it was copied from: it also flips text-align:
       start inside .split-badge, so "Where It Began" and the sentence under
       it rendered right-aligned on an English page. */
    .about-visual {
      position: relative;
    }

    .about-visual img {
      width: 100%;
      object-fit: cover;
      border-radius: var(--r);
      filter: saturate(.94) contrast(1.04);
    }

    .about-badge {
      position: absolute;
      right: -36px;
      bottom: -28px;
      width: min(420px, 72%);
      padding: 34px 42px;
      border-radius: var(--r);
      /* Was black at .92 over the photograph. On a white section that is a dark
         tile, so it becomes the brand band instead: white on Liwa is 9.35 and
         the badge now carries brand colour where it used to carry weight. */
      background: var(--surface-brand);
      color: #fff;
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 20px;
      align-items: center;
    }

    .about-badge i.ph {
      font-size: var(--ic-sm);
      line-height: 1;
      color: inherit;
    }

    .about-badge .big {
      font-family: var(--font-display);
      font-size: clamp(2.8rem, 4vw, 4.6rem);
      /* The badge is a Liwa band now, and --gold-text also resolves to Liwa, so
         this was Liwa on Liwa at 1.0. White on Liwa measures 9.35. */
      color: #fff;
      line-height: .9;
      letter-spacing: 0;
    }

    .about-badge .label {
      margin-top: 8px;
      color: #fff;
      font-size: 1.05rem;
      font-weight: 700;
    }

    .about-badge .t {
      grid-column: 2;
      color: rgba(255, 255, 255, .72);
      font-size: .98rem;
      line-height: 1.7;
    }

    .about-content {
      direction: rtl;
      text-align: left;
      /* Sized off the column, not the viewport - see the h2 note below. */
      container-type: inline-size;
    }

    .about-content .kicker {
      justify-content: flex-start;
      font-size: 1rem;
      letter-spacing: 0;
      text-transform: none;
      color: var(--charcoal);
      margin-top: 10px;
    }

    /* aboutTitle is two fixed phrases (a manual <br> between them), meant to
       read as exactly two lines. The old clamp scaled off 5.5vw - the full
       viewport - while this title lives in one half of a two-column grid, so
       past ~1500px (above every existing breakpoint below) the viewport grew
       faster than the column did and the type outgrew its own box: each
       phrase wrapped a second time and the title rendered as four lines
       instead of two. Sizing off cqi (the container's own inline size, see
       container-type above) ties the type to the box it actually has to fit,
       at any width, above or between the breakpoints already handled lower
       in this file. .about-title-line's nowrap is the hard guarantee: if a
       phrase ever would wrap, this makes it overflow visibly instead of
       silently breaking the two-line rule. Mirrors the same fix in
       sdeira-v2.css; the two homepages do not share this sheet.

       WHAT THE ABOVE GETS WRONG, found 21 Aug 2026 by photographing the
       section rather than reading the file. NONE of the four
       `.about-content h2` font-size rules in this sheet applies to anything:
       they are all inside @layer legacy, and `h2 { font-size:
       var(--type-section) }` in the SYSTEM LAYER at the end of this file is
       unlayered, so it wins over every one of them at every width. The title
       renders at --type-section, full stop - which is 4.3vw, the viewport-
       sized clamp this comment says was replaced.

       So the guarantee is doing its job and the fix behind it never ran. At
       1440 the column is 558px and --type-section is 62px, which holds about
       17 characters: "From KEZAD Communities" needs 713px and ran out from
       under the photograph next to it. The phrases are therefore broken to
       fit the column at the role's own size - three of them, not two - and
       that is the constraint to respect when this heading is next reworded:
       one phrase, one line, about 17 characters at 1440. Sizing the heading
       below --type-section to buy a longer phrase would be a type-scale
       decision, not a layout one, and belongs with the identity owner. */
    .about-title-line {
      white-space: nowrap;
    }

    .about-content h2 {
      max-width: 850px;
      color: var(--charcoal);
      font-size: clamp(2.6rem, 7cqi, 4.6rem);
      line-height: 1.12;
      margin: 0 0 34px;
      letter-spacing: 0;
    }

    .about-copy {
      max-width: 820px;
      margin-inline-start: auto;
      padding-inline-start: 28px;
    }

    .about-copy p {
      color: var(--ink);
      font-size: clamp(1.08rem, 1.25vw, 1.32rem);
      line-height: 2;
      margin: 0 0 14px;
    }

    .about-copy p:last-child {
      margin-bottom: 0;
    }

    .about-pillars {
      margin-top: 46px;
      display: grid;
      /* Same reason as .cta-actions: indefinite container, so keep a shrinkable
         fixed count. */
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 0;
    }


    .about-icon,
    .about-value-icon {
      display: grid;
      place-items: center;
    }

    .about-icon {
      width: 74px;
      height: 74px;
      margin: 0 auto 20px;
      border-radius: var(--r);
      color: var(--icon);
      background: var(--icon-razeen-wash);
    }

    /* Al Khatim tile, same treatment as why-ic and story-icon. The pillars
       above already carry the Razeen wash, so the two rows in this section
       read as two distinct groups rather than one repeated colour. */
    .about-value-icon {
      color: var(--icon-warm-text);
      background: var(--icon-warm-fill);
      border-radius: var(--r);
    }

    .about-value-icon i.ph {
      font-size: var(--ic-lg);
      line-height: 1;
    }

    .about-pillar h3 {
      margin: 0 0 12px;
      color: var(--charcoal);
      font-size: 1.22rem;
    }

    .about-pillar p {
      margin: 0;
      color: var(--muted);
      font-size: .98rem;
      line-height: 1.8;
    }

    .about-values {
      margin-top: 72px;
      padding: 32px 36px;
      border-radius: var(--r);
      background: var(--card);
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
      gap: 0;
    }

    .about-value {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 20px;
      align-items: start;
      padding: 0 28px;
    }

    .about-value:first-child {
      border-inline-start: 0;
    }


    .about-value h3 {
      margin: 0 0 8px;
      color: var(--charcoal);
      font-size: 1.1rem;
    }

    .about-value p {
      margin: 0;
      color: var(--muted);
      line-height: 1.65;
      font-size: .94rem;
    }

    /* ===== FEATURED PROJECTS ===== */
    .featured-projects {
      background: var(--surface-base);
    }

    .projects-head {
      display: grid;
      /*grid-template-columns: minmax(0, 1fr) minmax(320px, .82fr);*/
      gap: 44px;
      align-items: end;
      margin-bottom: 54px;
      justify-content: space-between;
      align-items: end;
    }

    .projects-copy {
      text-align: left;
      max-width: 620px;
      margin-inline-start: auto;
    }

    .projects-copy h2 {
      color: var(--charcoal);
      font-size: clamp(2.3rem, 4.8vw, 4.2rem);
      margin-bottom: 18px;
    }

    .projects-copy p {
      color: var(--muted);
      font-size: 1.08rem;
      line-height: 1.9;
    }

    .project-tabs {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(max(130px, calc(20% + 1px)), 1fr));
      gap: 18px;
      direction: rtl;
    }

    .project-tab {
      min-height: 62px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 12px;
      border-radius: var(--r);
      background: rgba(242, 242, 242, .72);
      color: var(--muted);
      font-size: .88rem;
      font-weight: 700;
      transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
    }

    .project-tab i.ph {
      font-size: var(--ic-sm);
      line-height: 1;
    }

    .project-tab {
      transition: background var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }


    .project-cards {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(max(250px, calc(20% + 1px)), 1fr));
      gap: 22px;
    }

    .project-card {
      overflow: hidden;
      border-radius: var(--r);
      background: var(--charcoal);
      transition: transform var(--dur-base) var(--ease-out);
    }

    .project-card:hover {
      background: var(--surface-sunken);
    }

    .project-card-img {
      height: 310px;
      overflow: hidden;
      background: var(--charcoal-soft);
    }

    /* The client's own composites (call-us.png / eskan-*.png) each
       carry roughly 40% empty canvas on one side, which is why this card rendered
       as a white wedge with the photograph shoved against the frame edge.
       Cropping off-centre fills the frame with the photographed content. */
    .project-card-img img[src$=".png"],
    .why-media img[src$=".png"] {
      object-position: 78% center;
    }

    .project-card-img img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform var(--dur-slow) var(--ease-out), filter var(--dur-base) var(--ease-out);
    }

    .project-card:hover .project-card-img img {
      transform: scale(var(--zoom));
    }

    /* Was a dark slab under every photograph. Four of those on a light section
       is a large part of why the page read as dark overall: the sampler found
       dark surface in the card bodies even where the section behind them was
       white. The body is a light card now and the photograph above it is what
       separates the card from the page. */
    .project-card-body {
      padding: 27px 28px 25px;
      color: var(--ink);
      background: var(--surface-sunken);
    }

    .project-type {
      display: block;
      color: var(--label);
      font-size: .82rem;
      font-weight: 800;
      margin-bottom: 8px;
    }

    .project-card h3 {
      color: var(--ink);
      font-size: 1.45rem;
      margin-bottom: 12px;
    }

    .project-card p {
      color: var(--muted);
      font-size: .94rem;
      line-height: 1.8;
      min-height: 76px;
    }

    .projects-footer {
      margin-top: 38px;
      display: grid;
      grid-template-columns: auto 1fr auto;
      gap: 26px;
      align-items: center;
      padding: 26px 30px;
      border-radius: var(--r);
      background: var(--card);
    }

    .projects-footer-cta {
      white-space: nowrap;
      background: var(--accent);
      color: #fff;
      font-weight: 700;
    }

    .projects-footer-cta:hover {
      background: var(--accent-deep);
      color: #fff;
    }

    .projects-footer-mark i.ph,
    .footer-mark i.ph {
      font-size: var(--ic-lg);
      line-height: 1;
    }

    .projects-footer h3 {
      color: var(--charcoal);
      font-size: 1.25rem;
      margin-bottom: 6px;
    }

    .projects-footer p {
      color: var(--muted);
      line-height: 1.7;
    }

    /* Shared with .story-footer and .why-footer: a plain icon mark, not a
       decorative image. Those two used to carry logo.png (a diagonal Razeen
       stripe) at 48x48 as a stand-in brand mark, on a card whose fill and the
       page's own background were the same white, so it read as invisible
       rather than as a logo. */
    .projects-footer-mark,
    .footer-mark {
      color: var(--icon);
      width: 50px;
      height: 50px;
      display: grid;
      place-items: center;
      padding-inline-end: 28px;
    }

    /* ===== SDEIRA STORY ===== */
    .story {
      background: var(--surface-sunken-strong);
      color: var(--ink);
      overflow: hidden;
    }

    .story-head {
      /*max-width: 780px;*/
      margin: 0 auto 58px;
      text-align: left;
    }

    .story-kicker {
      display: inline-flex;
      align-items: center;
      gap: 14px;
      color: var(--label);
      font-size: .86rem;
      font-weight: 800;
      margin-bottom: 18px;
    }

    /* removed decorative rule: story kicker rules */
    .__removed-story-kicker-rules { display: none }

    .story h2 {
      color: var(--charcoal);
      font-size: clamp(2.4rem, 5vw, 4.35rem);
      margin-bottom: 18px;
    }

    .story-head p {
      color: var(--muted);
      font-size: 1.08rem;
      line-height: 1.9;
    }


    .story-item {
      position: relative;
      direction: rtl;
      text-align: center;
      padding: 0 22px;
      /* A column, so the paragraph can absorb the slack and everything below it
         lines up across all five items. Without this, a station whose text runs
         one line shorter lifts its image 9px above the others and the row of
         photographs stops being a row. */
      display: flex;
      flex-direction: column;
    }

    /* The paragraph takes the leftover height; the image and the achievement row
       below it therefore start at the same y in every column. */
    .story-item>p {
      flex: 1 0 auto;
    }


    .story-dot {
      position: absolute;
      top: -43px;
      left: 50%;
      width: 24px;
      height: 24px;
      border-radius: var(--r);
      background: var(--icon);
      transform: translateX(-50%);
    }

    .story-year {
      font-family: var(--font-display);
      color: var(--figure);
      font-size: clamp(1.85rem, 3vw, 2.55rem);
      font-weight: 800;
      line-height: 1;
      margin-bottom: 24px;
    }

    .story-item h3 {
      color: var(--charcoal);
      font-size: 1.2rem;
      margin-bottom: 12px;
    }

    .story-item p {
      color: var(--muted);
      font-size: .94rem;
      line-height: 1.75;
      min-height: 96px;
    }

    .story-image {
      margin-top: 28px;
      border-radius: var(--r);
      overflow: hidden;
      aspect-ratio: 4 / 3;
      background: var(--warm-grey);
    }

    .story-image img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform var(--dur-slow) var(--ease-out);
    }

    .story-item:hover .story-image img {
      transform: scale(var(--zoom));
    }

    .story-achievement {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 14px;
      align-items: center;
      /* Pushed to the bottom of the item so the achievement rows line up across
         columns regardless of how long each paragraph runs. */
      margin-top: auto;
      padding-top: 22px;
      text-align: left;
    }

    .story-icon {
      width: 44px;
      height: 44px;
      display: grid;
      place-items: center;
      border-radius: var(--r);
      color: var(--icon-warm-text);
      background: var(--icon-warm-fill);
    }

    .story-icon i.ph {
      font-size: var(--ic-md);
      line-height: 1;
    }

    .story-achievement strong {
      display: block;
      color: var(--charcoal);
      font-size: .98rem;
      margin-bottom: 4px;
    }

    .story-achievement span {
      color: var(--muted);
      font-size: .86rem;
      line-height: 1.55;
    }

    .story-footer {
      margin-top: 62px;
      display: grid;
      grid-template-columns: auto 1fr auto;
      gap: 28px;
      align-items: center;
      padding: 26px 30px;
      border-radius: var(--r);
      background: var(--card);
    }

    .story-footer p {
      color: var(--muted);
      line-height: 1.85;
      font-size: 1.02rem;
      padding-inline-start: 24px;
    }

    /* ===== WHY ===== */
    .why {
      background: var(--surface-base);
      color: var(--ink)
    }

    .why .sec-head {
      max-width: 760px;
      /*margin-inline-start: auto;*/
      text-align: left;
    }

    .why .sec-head h2 {
      color: var(--charcoal)
    }

    .why .sec-head p {
      color: var(--muted)
    }

    .why .kicker {
      color: var(--label);
    }

    /* removed decorative rule: why kicker rule recolour */
    .__removed-why-kicker-rule-recolour { display: none }

    /* Two per row, not four: at four across, a one-line difference in copy
       length between cards made every row a different height, because the
       photo sat above the text and could not absorb that difference. Media
       beside text instead of above it removes the problem at the root: within
       a row both cards stretch to whichever is taller, photo included, so the
       row is never lopsided regardless of how long any one card's copy runs. */
    .why-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 22px;
    }

    .why-card {
      display: grid;
      grid-template-columns: minmax(160px, 34%) 1fr;
      overflow: hidden;
      border-radius: var(--r);
      background: var(--card);
      transition: transform var(--dur-base) var(--ease-out);
    }

    .why-card:hover {
      background: var(--surface-sunken);
    }

    .why-media {
      position: relative;
      overflow: hidden;
      /* The well behind the photograph. Black here reads as a dark plate
         wherever the image does not fully cover, on a section that is white. */
      background: var(--surface-sunken-strong);
    }

    /* Full opacity, full colour: the same rule as .sector-card-img. It used to
       carry opacity:.56 plus its own saturate(.85), fading the photo toward the
       sunken well behind it, which is what actually read as "grey" rather than
       "black" underneath the veil below. Darkening is .why-media::after alone. */
    .why-media img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
      transition: transform var(--dur-slow) var(--ease-out);
    }

    .why-card:hover .why-media img {
      transform: scale(var(--zoom));
    }

    .why-media::after {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(180deg, rgba(var(--image-overlay-rgb), .12) 0%, rgba(var(--image-overlay-rgb), .34) 45%, rgba(var(--image-overlay-rgb), .88) 100%);
    }

    /* Was centred in the photo frame with a 2px accent outline, so it read as an
       empty bracket floating on the image and clipped the frame edge. It is now a
       solid tile anchored to the bottom reading corner of the photo. */
    /* Al Khatim, not Liwa. Four identical red tiles on one card grid is the same
       "everything is red" problem as the sector icons; this is the marker role,
       not the action role. */
    .why-ic {
      position: absolute;
      inset-block-end: 0;
      inset-inline-start: 0;
      z-index: 1;
      width: 62px;
      height: 62px;
      display: grid;
      place-items: center;
      color: var(--icon-warm-text);
      background: var(--icon-warm-fill);
    }

    .why-ic i.ph {
      font-size: var(--ic-lg);
      line-height: 1;
    }

    .why-card-body {
      padding: 30px 30px 32px;
      text-align: left;
    }

    .why-card h3 {
      font-size: clamp(1.35rem, 2.3vw, 1.8rem);
      color: var(--charcoal);
      margin-bottom: 12px;
    }


    .why-card h3::after {
      content: none;
      display: block;
      width: 34px;
      height: 2px;
      background: var(--accent);
      margin-top: 12px;
    }

    .why-card p {
      color: var(--muted);
      font-weight: 400;
      font-size: .98rem;
      line-height: 1.85;
      margin-bottom: 22px;
    }

    .why-card ul {
      list-style: none;
      display: grid;
      gap: 10px;
      color: var(--muted);
      font-size: .92rem;
      line-height: 1.65;
    }

    .why-card li {
      position: relative;
      padding-inline-start: 18px;
    }

    .why-card li::before {
      content: "";
      position: absolute;
      top: .75em;
      inset-inline-start: 0;
      width: 6px;
      height: 6px;
      border-radius: var(--r);
      background: var(--accent);
    }

    .why-footer {
      margin-top: 40px;
      display: grid;
      grid-template-columns: auto 1fr auto;
      gap: 28px;
      align-items: center;
      padding: 26px 30px;
      border-radius: var(--r);
      background: var(--card);
    }

    .why-footer p {
      color: var(--muted);
      line-height: 1.85;
      font-size: 1.04rem;
      text-align: left;
      padding-inline-start: 24px;
    }


    /* ===== PARTNERS ===== */
    .partners {
      background: var(--surface-sunken-strong);
    }

    .partners-head {
      max-width: 820px;
      margin: 0 auto 58px;
      text-align: center;
    }

    .partners-kicker {
      display: inline-flex;
      align-items: center;
      gap: 14px;
      color: var(--label);
      font-size: .86rem;
      font-weight: 800;
      margin-bottom: 18px;
    }

    /* removed decorative rule: partners kicker rules */
    .__removed-partners-kicker-rules { display: none }

    .partners h2 {
      color: var(--charcoal);
      font-size: clamp(2.35rem, 5vw, 4.25rem);
      margin-bottom: 18px;
    }

    .partners-head p {
      color: var(--muted);
      font-size: 1.08rem;
      line-height: 1.9;
    }

    /* There are five partner slots, so the row must hold five and never six.
       A flat 190px floor let auto-fit create a sixth track on a wide container,
       which pushed the row past the container edge and clipped the last card.
       Flooring each track just above 100%/6 makes a sixth track arithmetically
       impossible while still collapsing to 4, 3, 2 and 1 as the viewport
       narrows. */
    .partners-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(max(190px, calc(100% / 6 + 1px)), 1fr));
      gap: 20px;
    }

    .partner-card {
      min-height: 300px;
      padding: 34px 26px 30px;
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      border-radius: var(--r);
      background: var(--card);
      transition: transform var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
    }

    .partner-card:hover {
      border-color: rgba(221, 177, 118, .32);
      background: var(--surface-sunken-strong);
    }

    .partner-logo i.ph {
      font-size: var(--ic-xl);
      color: var(--muted);
    }

    .partner-logo {
      min-height: 74px;
      display: grid;
      place-items: center;
      margin-bottom: 24px;
      font-family: var(--font-display);
      font-weight: 800;
      line-height: 1;
    }

    .partner-card h3 {
      color: var(--charcoal);
      font-size: 1.18rem;
      margin-bottom: 14px;
    }

    .partner-card h3::after {
      content: none;
      display: block;
      width: 34px;
      height: 2px;
      margin: 14px auto 0;
      background: var(--accent);
    }

    .partner-card p {
      color: var(--muted);
      font-size: .94rem;
      line-height: 1.8;
      flex: 1;
    }

    .partner-domain {
      color: var(--pending);
      font-size: .85rem;
      font-weight: 800;
      margin-top: 22px;
    }

    .partners-trust {
      margin-top: 42px;
      position: relative;
      overflow: hidden;
      display: grid;
      /* Was 1fr + three 130px columns + a 260px column. At 130px an Arabic
         caption like "من كبرى الشركات الرائدة في مجالات متعددة" broke to one
         word per line, five lines deep. The stats share one auto-fit row with a
         floor wide enough to set a line of text, and the copy keeps its own
         column above them. */
      grid-template-columns: minmax(280px, 1fr) minmax(0, 1.6fr);
      gap: 0;
      align-items: center;
      border-radius: var(--r);
      /* A white card on the Silver band. As a dark slab it was the single
         largest patch of dark surface outside the intended dark sections. */
      background: var(--surface-raised);
      color: var(--ink);
    }

    .partners-trust-copy {
      padding: 34px;
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 22px;
      align-items: center;
    }

    .partners-trust-icon {
      width: 54px;
      height: 54px;
      /* Sits on a white card on the Silver band, not on a dark surface. */
      color: var(--icon);
    }

    .partner-stat i.ph {
      font-size: var(--ic-md);
      line-height: 1;
    }

    .partners-trust h3 {
      color: var(--ink);
      font-size: 1.32rem;
      margin-bottom: 8px;
    }

    .partners-trust p {
      color: var(--muted);
      line-height: 1.75;
      font-size: .95rem;
    }

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

    .partner-stat {
      padding: 14px 16px;
      text-align: center;
    }

    .partner-stat strong {
      display: block;
      color: var(--figure);
      font-family: var(--font-display);
      font-size: 2rem;
      line-height: 1;
      margin-bottom: 10px;
    }

    .partner-stat span {
      display: block;
      color: var(--ink);
      font-weight: 800;
      margin-bottom: 6px;
    }

    .partner-stat small {
      color: var(--muted);
      line-height: 1.6;
    }

    /* ===== NEWS ===== */
    .news-section {
      background: var(--surface-base);
    }

    .news-head {
      display: flex;
      justify-content: space-between;
      align-items: flex-end;
      gap: 34px;
      max-width: none;
      margin-bottom: 30px;
    }

    .news-head h2 {
      margin: 0;
    }

    .news-head p {
      max-width: 620px;
      margin: 16px 0 0;
      color: var(--muted);
      font-size: 1.05rem;
      line-height: 1.8;
    }

    .news-all {
      min-height: 44px;
      padding: 0 26px;
      border-radius: var(--r);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      color: var(--accent-text);
      font-weight: 700;
      white-space: nowrap;
      transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .news-all:hover {
      background: var(--accent);
      color: #fff;
    }

    /* Newsroom awaiting content.
       Documented fact (content checklist, section 10): not one item has been
       published under the Sdeira Group name since the November 2024 rebrand.
       The four cards that used to sit here carried invented headlines and
       invented dates, so they are replaced by a state that declares itself.
       The category filter bar was removed with them: it was never wired to any
       handler, so it was a control that could not control anything. Both come
       back together the day real press material is delivered. */
    .news-pending {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: clamp(20px, 2.4vw, 34px);
      align-items: center;
      padding: clamp(34px, 4vw, 56px);
      border-radius: var(--r);
      background: var(--card);
      border: 1px dashed var(--line);
    }

    .news-pending-icon {
      display: grid;
      place-items: center;
      inline-size: 64px;
      block-size: 64px;
      border-radius: var(--r);
      background: var(--surface-sunken);
      color: var(--muted);
    }

    .news-pending-icon i.ph {
      font-size: var(--ic-lg);
    }

    .news-pending h3 {
      margin: 0 0 8px;
      font-size: clamp(1.1rem, 1.6vw, 1.4rem);
      color: var(--ink);
    }

    .news-pending p {
      margin: 0;
      max-width: 62ch;
      color: var(--muted);
      line-height: 1.85;
    }

    .news-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(max(250px, calc(20% + 1px)), 1fr));
      gap: 24px;
      align-items: stretch;
    }

    .news-card {
      display: grid;
      grid-template-rows: auto 1fr;
      overflow: hidden;
      background: var(--card);
      border-radius: var(--r);
      cursor: pointer;
      transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
    }

    .news-card .img {
      overflow: hidden;
      aspect-ratio: 16 / 9.7;
      height: auto;
      margin-bottom: 0;
      background: #ddd;
    }

    .news-card img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform var(--dur-slow)
    }

    .news-card:hover,
    .news-card:focus-within {
      background: #fff;
      border-color: rgba(145, 8, 17, .34);
    }

    /* .news-card:hover img,
    .news-card:focus-within img {
      transform: scale(var(--zoom))
    } */

    .news-body {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      min-height: 270px;
      padding: 24px 26px;
    }

    .news-card .date {
      margin-top: 14px;
      font-size: .86rem;
      color: var(--muted);
      display: inline-flex;
      align-items: center;
      gap: 8px;
      letter-spacing: 0;
    }

    /* Removed: a purely decorative 14px bordered square sat after every news
       date and rendered as an empty box, reading as a failed icon. */

    .news-category {
      color: var(--label);
      font-size: .84rem;
      font-weight: 800;
    }

    .news-card h3 {
      font-size: clamp(1.05rem, 1.35vw, 1.28rem);
      color: var(--charcoal);
      margin: 18px 0 0;
      line-height: 1.5;
      transition: color var(--dur-base)
    }

    .news-card p {
      margin: 14px 0 0;
      color: var(--muted);
      font-size: .92rem;
      line-height: 1.8;
    }

    .news-card:hover h3 {
      color: var(--accent-text);
    }

    .news-card .more {
      min-height: 44px;
      margin-top: auto;
      font-size: .92rem;
      color: var(--muted);
      display: inline-flex;
      align-items: center;
      gap: 8px
    }

    .news-subscribe {
      margin-top: 48px;
      min-height: 116px;
      padding: 24px 32px;
      border-radius: var(--r);
      background: var(--card);
      display: grid;
      grid-template-columns: 1fr minmax(320px, .8fr) auto;
      gap: 28px;
      align-items: center;
    }

    .news-subscribe-copy {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 18px;
      align-items: center;
    }

    .news-subscribe-icon {
      width: 52px;
      aspect-ratio: 1;
      border-radius: var(--r);
      color: var(--icon);
      display: grid;
      place-items: center;
    }

    .news-subscribe-icon i.ph,
    .news-social a i.ph {
      font-size: var(--ic-sm);
      line-height: 1;
    }

    .news-subscribe h3 {
      margin: 0;
      color: var(--charcoal);
      font-size: 1.12rem;
    }

    .news-subscribe p {
      margin: 6px 0 0;
      color: var(--muted);
      line-height: 1.7;
    }

    /* One composite control: the field is the container and the submit sits
       inside it, so there is no floating second box beside the input. The only
       moving parts are a focus bar that grows from the reading edge and a fill
       that wipes across the button. No gradient, no lift, no sliding glyph. */
    .news-form {
      position: relative;
      min-width: 0;
      display: flex;
      align-items: stretch;
      gap: 0;
      padding: 5px;
      border-radius: var(--r);
      background: var(--surface-sunken);
      transition: background var(--dur-base) var(--ease-out);
    }


    /* The focus bar. Sits under the whole composite and grows from the reading
       edge, which in RTL is the right. */
    .news-form::after {
      content: "";
      position: absolute;
      inset-block-end: 0;
      inset-inline-start: 0;
      inline-size: 100%;
      block-size: 2px;
      background: var(--accent);
      transform: scaleX(0);
      transform-origin: right;
      transition: transform var(--dur-base) var(--ease-out);
    }

    .news-form:focus-within::after {
      transform: scaleX(1);
    }

    .news-form input {
      flex: 1 1 auto;
      min-width: 0;
      min-height: 46px;
      padding: 0 16px;
      border: 0;
      border-radius: var(--r);
      background: none;
      color: var(--charcoal);
      font: inherit;
      outline: 0;
    }

    .news-form input::placeholder {
      color: var(--muted);
    }

    .news-form button {
      position: relative;
      overflow: hidden;
      flex: 0 0 auto;
      min-height: 46px;
      padding: 0 26px;
      border-radius: var(--r);
      background: var(--accent-deep);
      color: #fff;
      font: inherit;
      font-weight: 700;
      cursor: pointer;
      z-index: 0;
    }

    /* Fill wipe. A solid block sweeps across from the reading edge on hover
       instead of the button changing colour all at once. */
    .news-form button::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: var(--charcoal);
      transform: scaleX(0);
      transform-origin: right;
      transition: transform var(--dur-base) var(--ease-out);
    }

    .news-form button:hover::before,
    .news-form button:focus-visible::before {
      transform: scaleX(1);
    }

    .news-social {
      padding-inline-start: 28px;
      display: flex;
      align-items: center;
      gap: 12px;
      color: var(--charcoal);
      font-weight: 800;
      white-space: nowrap;
    }

    .news-social a {
      width: 42px;
      aspect-ratio: 1;
      border-radius: var(--r);
      color: var(--icon);
      display: grid;
      place-items: center;
      transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .news-social a:hover {
      background: var(--accent);
      color: #fff;
    }

    /* ===== CTA ===== */
    /* The one place on the page that is the brand colour. This is the highest
       conversion point, which is what earns the primary colour, and it replaces
       a fourth dark photo band. White on Liwa measures 9.35 and Razeen on Liwa
       measures 4.73, the exact pairing the brand guide uses on pages 30 and 32. */
    /* Jais, not Liwa: a full-band red felt like exactly the kind of surface-
       scale use of the accent colour the brand guide's own 50/25/25
       proportion warns against, and this band sits directly above a black
       footer, so it also can't just become --surface-inverse (identical to
       the footer, an adjacent-duplicate surface). Jais is the system's other
       dark neutral, distinct from both. */
    .cta {
      position: relative;
      color: #fff;
      overflow: hidden;
      margin: 0;
      display: grid;
      align-items: center;
      background: var(--surface-inverse-soft);
    }

    /* The three stacked scrims are gone with the photograph they were covering. */

    .cta-inner {
      width: min(980px, 100%);
      margin: 0 auto;
      padding: calc(var(--sec-pad) * 1.35) 0;
      text-align: center;
    }

    .cta .kicker {
      color: var(--gold-on-dark);
      justify-content: center;
      margin-bottom: 30px;
    }

    .cta h2 {
      font-size: clamp(3rem, 6vw, 5.4rem);
      color: #fff;
      margin: 0 auto 26px;
      line-height: 1.16;
    }

    .cta p {
      max-width: 720px;
      margin: 0 auto 54px;
      font-size: clamp(1.1rem, 1.55vw, 1.42rem);
      color: rgba(255, 255, 255, .8);
      font-weight: 400;
      line-height: 1.9;
    }

    .cta-actions {
      display: grid;
      /* Fixed count on purpose: the container width is indefinite, so an auto-fit
         floor resolves against max-content and overflows. minmax(0,...) can
         always shrink. */
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 18px;
      max-width: 1120px;
      margin: 0 auto;
    }

    /* Cards, not buttons in a row. As buttons their content sat flush to the
       reading edge with the icon detached from the label, and two of the three
       had no visible surface at all on the near-black section. As cards they
       carry a real surface, centre their own content, and equalise. */
    /* Three routes, three identical cards.
       They used to be near-invisible: two were rgba(255,255,255,.12) over Liwa,
       which composites to #9C262E and gives the card edge a 1.2 step against the
       band behind it, and the third was filled with --accent-deep, which
       resolves to Liwa itself, so the "primary" card was the same colour as the
       section it sat on. One of the three could not be seen at all and the other
       two were guesses.
       They are white cards now. Same surface, same weight, same contrast: the
       card against the band measures 9.35, the label on the card 10.31, and the
       note 7.01. Nothing here ranks the three routes against each other, because
       nothing about them is ranked. */
    .cta-action {
      padding: 30px 22px 26px;
      border-radius: var(--r);
      background: var(--surface-raised);
      color: var(--ink);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-start;
      gap: 14px;
      font-weight: 700;
      font-size: 1.02rem;
      text-align: center;
      transition: background var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .cta-action i.ph {
      display: grid;
      place-items: center;
      inline-size: 56px;
      block-size: 56px;
      border-radius: var(--r);
      /* Red belongs here: this is the action itself, not decoration. */
      background: var(--accent-wash);
      color: var(--accent-text);
      font-size: var(--ic-md);
      line-height: 1;
      flex: 0 0 auto;
      transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
    }


    .cta-action .cta-action-note {
      font-weight: 400;
      font-size: .92rem;
      line-height: 1.7;
      color: var(--muted);
    }

    .cta-action .arr {
      color: rgba(255, 255, 255, .82);
      font-size: 1.35rem;
    }

    /* ===== FOOTER ===== */
    footer {
      /* True black at .90, the owner's exception for the closing band. See the
         --scrim-footer comment in the token file and section 6-b of
         docs/brand/black-usage-research.md for why this one place is allowed
         outside the eight colours. */
      background: var(--scrim-footer);
      backdrop-filter: blur(16px) saturate(125%);
      -webkit-backdrop-filter: blur(16px) saturate(125%);
      /* .6 composites to 4.85 on Black, which passes but leaves no headroom for
         anything nested that dims further. The floor lives here so descendants
         can step down without falling through it. --muted-on-dark (213,213,213)
         WAS that floor and is not any more: the Arabic footer was raised to
         near-white so the contact rows read at the same weight as the links
         beside them. Matched here rather than left a step behind. */
      color: rgba(255, 255, 255, .96);
      font-weight: 600;
      padding: 80px 0 36px;
      /* Extra bottom clearance keeps the socials row from sitting under the
         fixed .scroll-top button once the page is scrolled all the way down. */
      padding-bottom: max(36px, calc(96px + env(safe-area-inset-bottom)));
    }

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

    .foot-brand .logo {
      color: #fff;
      font-size: 1.9rem;
      margin-bottom: 20px;
      display: inline-block
    }

    .foot-brand p {
      font-weight: 400;
      max-width: 300px;
      font-size: .98rem;
    }

    .foot-col h4 {
      font-family: var(--font-display);
      color: #fff;
      font-size: 1.05rem;
      margin-bottom: 22px;
      font-weight: 500
    }

    .foot-col a,
    .foot-col .foot-pending {
      display: block;
      margin-bottom: 13px;
      font-size: .95rem;
      font-weight: 400;
      transition: color var(--dur-base)
    }

    .foot-col a {
      color: #fff;
    }

    /* An entry with no destination yet. It reads as a label, so the footer never
       offers a link that goes nowhere. Distinguished by tone, not by opacity: at
       .62 on top of an already-dimmed inherited colour the effective alpha fell
       to .37 and the text measured 2.88 on Black. A declared colour is 7.02 and
       still sits a clear step below the white links above it. */
    .foot-col .foot-pending {
      color: var(--muted-on-dark);
      cursor: default;
    }

    .foot-bottom {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding-top: 30px;
      flex-wrap: wrap;
      gap: 16px
    }

    .foot-bottom .socials {
      display: flex;
      gap: 14px
    }

    .foot-bottom .socials a {
      width: 40px;
      height: 40px;
      border-radius: var(--r);
      display: grid;
      place-items: center;
      background: rgba(255, 255, 255, .12);
      transition: background var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }


    .foot-bottom .socials a:hover {
      background: var(--accent);
      border-color: var(--accent);
      color: #fff;
    }

    .foot-bottom .socials i.ph {
      font-size: var(--ic-sm);
      line-height: 1;
    }

    .copy {
      font-size: .85rem;
    }

    /* ===== REVEAL ===== */
    /* Content is visible by default. JS adds .armed to opt an element in to
       animating. If the script never runs, nothing is hidden. The original
       started at opacity:0 and depended on JS to reveal it. */


    /* The hero reveal used to be JS-gated: a .armed class set the hidden
       start state, then a class added a frame later (via rAF, with a
       window-load fallback) triggered the transition to visible. That
       needs a real paint of the "armed, not yet revealed" frame to exist
       before the second class lands, or the browser never sees a value
       change and the content just appears with no fade - and whether that
       paint happens in time is not guaranteed: on a warm cache the load
       event can fire fast enough to win the race even past a double
       requestAnimationFrame defer, which is exactly what was happening
       here. A CSS animation does not have this problem: it does not need a
       prior painted frame to animate from, only a starting keyframe, so it
       plays reliably regardless of how fast the page loads (port log item 25). */
    @keyframes hero-reveal {
      from {
        opacity: 0;
        visibility: hidden;
        transform: translateY(30px);
      }
      .1% {
        visibility: visible;
      }
      to {
        opacity: 1;
        visibility: visible;
        transform: none;
      }
    }

    /* Longhand, not the `animation` shorthand: the shorthand also resets
       animation-delay to 0s, and .hero .reveal (2 classes) is more specific
       than the per-element .hero h1 / .hero p stagger rules below (1 class +
       1 type), so the shorthand's implicit 0s would win over their delay
       regardless of source order and the stagger would collapse to nothing. */
    /* --dur-base per element with a --dur-fast stagger step, not --dur-slow
       with a --dur-base step: the first pass read as sluggish because the
       last element (the slide rail) did not finish until 960ms of stagger
       plus its own 480ms, 1.44s before the hero read as fully in. Same two
       system tokens, tightened to the steps meant for on-load motion rather
       than the ones meant for image zoom and full-panel reveals (port log
       item 27). */
    .hero .reveal {
      animation-name: hero-reveal;
      animation-duration: var(--dur-base);
      animation-timing-function: var(--ease-out);
      animation-fill-mode: both;
    }

    .hero h1 {
      animation-delay: calc(var(--dur-fast) * 1);
    }

    .hero p {
      animation-delay: calc(var(--dur-fast) * 2);
    }

    .hero .hero-actions {
      animation-delay: calc(var(--dur-fast) * 3);
    }

    .hero .hero-slides-ind {
      animation-delay: calc(var(--dur-fast) * 4);
    }

    /* ===== RESPONSIVE ===== */
    @media(max-height:900px) and (min-width:981px) {
      .hero {
        min-height: 760px;
      }

      .hero-content {
        width: min(100%, 780px);
        max-width: 780px;
        padding-block: 96px 48px;
      }

      .hero h1 {
        font-size: clamp(2.25rem, min(4.05vw, 6.9svh), 3.55rem);
        line-height: 1.18;
        margin-bottom: 16px;
      }

      .hero p {
        max-width: 540px;
        font-size: clamp(.98rem, 1.35vw, 1.14rem);
        line-height: 1.72;
      }

      .hero-actions {
        margin-top: 26px;
      }

      .scroll-hint {
        top: calc(100dvh - 68px);
      }

    }

    @media(max-width:1500px) and (min-width:981px) {
      .wrap {
        width: min(calc(100% - 84px), var(--max));
      }

      /* header/header.scrolled --hd-pad/--logo-h/--cta-h overrides used to be
         declared here. Dead: the SYSTEM LAYER's unlayered header rules win at
         every width, media query or not. See header{}'s own comment above. */

      .nav-cta {
        letter-spacing: 0;
      }

      .logo img {
        max-width: 220px;
      }

      .menu {
        gap: 22px;
      }

      .nav-actions {
        gap: 8px;
      }

      .nav-cta {
        padding-inline: 20px;
      }

      .hero-content {
        width: min(100%, 800px);
        max-width: 800px;
      }

      .hero h1 {
        font-size: clamp(2.35rem, min(4.25vw, 7.4svh), 3.85rem);
        line-height: 1.17;
      }

      .hero p {
        max-width: 540px;
      }

      /* DEAD FONT-SIZE, kept only because deleting it is a separate change:
         `h2 { font-size: var(--type-section) }` in this file's SYSTEM LAYER is
         unlayered, so it beats every `.about-content h2` size in @layer legacy
         regardless of specificity or source order, this one included. The
         title renders at --type-section at every width. See the base rule's
         comment for what that means for the two phrases. */
      .about-content h2 {
        font-size: clamp(3rem, 4.85vw, 5.15rem);
        line-height: 1.14;
      }

      .impact-head h2,
      .process-head h2,
      .projects-copy h2,
      .story-head h2,
      .why .sec-head h2,
      .partners-head h2,
      .news-head h2 {
        font-size: clamp(2.2rem, 4vw, 3.65rem);
        line-height: 1.18;
      }

      .cta h2 {
        font-size: clamp(2.65rem, 5vw, 4.6rem);
      }
    }

    @media(max-width:1180px) {
      .menu {
        gap: 22px;
      }

      .nav-actions {
        gap: 8px;
      }

      .nav-cta {
        padding: 0 20px;
        letter-spacing: 0;
      }

      .impact-main {
        grid-template-columns: minmax(280px, .62fr) minmax(0, 1fr);
      }

    }

    @media(max-width:980px) {

      .cta-actions,
      .about-pillars {
        grid-template-columns: 1fr;
      }

      /* The icon column leaves 182px for the copy at 375px, which is too narrow
         for Arabic body text to set. It stacks instead. */
      .news-pending {
        grid-template-columns: 1fr;
        gap: 20px;
      }

      /* Hover-to-reveal is not a pattern a phone can use. @media (hover: none)
         already covers real touch hardware, but it does not fire under desktop
         viewport emulation and it misses hybrid devices, so the action is simply
         always visible at this width. */
      .sector-card-action {
        opacity: 1;
        transform: none;
      }

      /* The sector strip is absolutely pinned to the bottom of the hero on
         desktop, over the darkest part of the veil. At this width the hero
         itself stops being a fixed viewport-tall box, so an absolute strip
         would land on top of the headline instead of under it. Below this
         breakpoint it leaves the overlay and flows in normal document flow
         underneath the first screen instead. */

      .hero {
        height: auto;
        min-height: 0;
        display: block;
      }

      /* The copy block now carries the viewport height the hero used to hold, so
         the first screen is still a full-height image with the headline on it. */
      .hero-content {
        min-height: 100dvh;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
      }

      /* Positioned against the hero box, which is no longer viewport-tall, so
         it would land on top of the sector strip once the strip flows below. */
      .scroll-hint {
        display: none;
      }

      .hero-sectors {
        position: static;
        padding-block: 22px clamp(28px, 6vw, 40px);
        background: var(--surface-inverse);
      }

      /* The desktop track floors each column at 170px, which is wider than a
         phone viewport has to give three of. Two columns fit five cards as
         2/2/1 instead of overflowing the page horizontally. */
      .sector-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 14px;
      }

      .hero-sectors-label {
        color: rgba(255, 255, 255, .7);
      }


      .menu,
      .nav-cta {
        display: none
      }

      .menu.open {
        display: flex;
        position: fixed;
        top: 74px;
        right: 20px;
        left: 20px;
        z-index: 1001;
        flex-direction: column;
        align-items: center;
        background: var(--offwhite);
        padding: 28px 32px;
        gap: 22px;
      }

      .menu.open a {
        min-height: 44px;
        display: flex;
        align-items: center;
        color: var(--ink);
      }

      .menu.open .menu-mobile-actions {
        width: 100%;
        display: flex;
        flex-direction: column;
        gap: 22px;
        padding-top: 12px;
      }

      .menu.open .menu-lang {
        display: flex;
        width: 100%;
        min-height: 52px;
        align-items: center;
        justify-content: space-between;
        color: var(--charcoal);
        font-size: 1.05rem;
        font-weight: 700;
        letter-spacing: 0;
      }

      .menu.open .menu-lang::after {
        content: "›";
        color: var(--charcoal);
        font-size: 2.2rem;
        line-height: 1;
      }

      .menu.open .menu-contact {
        width: 100%;
        min-height: 58px;
        display: flex;
        justify-content: center;
        background: var(--charcoal);
        color: #fff;
        border-radius: var(--r);
        font-size: .88rem;
        font-weight: 800;
        letter-spacing: 0;
      }

      .menu.open .menu-contact:hover {
        background: var(--accent);
        border-color: var(--accent);
        color: #fff;
      }

      .nav-actions>.lang {
        display: none;
      }

      .nav {
        gap: 18px;
      }

      .logo img {
        max-width: 180px;
        height: 42px;
      }

      .hero {
        min-height: 640px;
      }

      .hero-content {
        padding-block: 90px 40px;
      }

      .hero h1 {
        font-size: clamp(2.05rem, 6.1vw, 3.35rem);
        line-height: 1.2;
        max-width: 760px;
      }

      .hero p {
        max-width: 620px;
      }

      .hero-actions {
        width: min(100%, 620px);
      }

      .hero-actions .btn {
        flex: 1 1 230px;
        justify-content: center;
        min-height: 54px;
      }

      .burger {
        display: flex
      }

      .impact-main {
        grid-template-columns: 1fr;
      }

      .impact-visual {
        min-height: 360px;
      }


      .process-head {
        margin-inline-start: 0;
      }

      .about-layout {
        grid-template-columns: 1fr;
        gap: 56px;
      }

      .about-content h2 {
        font-size: clamp(3rem, 8vw, 5.2rem);
      }


      .about-pillar {
        border-inline-start: 0;
        padding: 28px 18px;
      }

      .about-pillar:first-child {
        border-top: 0;
      }

      .about-values {
        gap: 28px 0;
      }

      .about-badge {
        right: 24px;
        bottom: -22px;
      }

      .projects-head {
        grid-template-columns: 1fr;
        align-items: start;
      }

      .projects-copy {
        margin-inline-start: 0;
      }

      .project-tabs {
        order: 2;
      }


      .project-card-img {
        height: 260px;
      }

      .projects-footer {
        grid-template-columns: auto 1fr;
      }

      .projects-footer-mark {
        display: none;
      }

      .story-timeline {
        gap: 42px 0;
      }

      .story-timeline::before {
        display: none;
      }

      .story-item {
        border-inline-start: 0;
      }

      .story-dot {
        display: none;
      }

      .story-item p {
        min-height: 0;
      }

      .story-footer {
        grid-template-columns: auto 1fr;
      }

      .story-footer .btn {
        grid-column: 1 / -1;
        justify-content: center;
      }


      .why-footer {
        grid-template-columns: auto 1fr;
      }

      .why-footer .footer-mark {
        display: none;
      }


      .partners-trust {
        grid-template-columns: 1fr;
      }

      .partner-stat {
        border-inline-start: 0;
      }

      .news-head {
        flex-direction: column;
        align-items: stretch;
        margin-bottom: 36px;
      }

      .news-head p {
        max-width: none;
      }

      .news-all {
        align-self: flex-start;
      }

      .news-tabs {
        width: 100%;
        margin-bottom: 34px;
      }

      .news-grid {
        gap: 18px;
      }

      .news-card .img {
        aspect-ratio: 16 / 10;
      }

      .news-body {
        padding: 22px;
      }

      .news-subscribe {
        grid-template-columns: 1fr;
        padding: 26px 24px;
      }

      .news-form {
        max-width: 560px;
      }

      .news-social {
        padding-inline-start: 0;
        padding-top: 22px;
        border-inline-start: 0;
      }

      .cta-inner {
        padding: var(--sec-pad) 0;
      }

      .cta-actions {
        max-width: 620px;
      }

      .foot-grid {
        grid-template-columns: 1fr 1fr
      }
    }

    @media(max-width:560px) {
      .wrap {
        padding: 0 20px
      }

      .pad {
        padding: var(--sec-pad) 0
      }

      /* Same dead header/header.scrolled overrides as the 1500px block
         above - the SYSTEM LAYER always wins, media query or not. */

      .nav-actions {
        gap: 6px;
      }

      .logo img {
        max-width: min(42vw, 146px);
        height: var(--logo-h);
      }

      .nav-icon {
        width: 40px;
        height: 40px;
      }

      .nav-icon i.ph {
        font-size: var(--ic-sm);
        line-height: 1;
      }

      .burger {
        width: 40px;
        height: 40px;
        align-items: center;
        justify-content: center;
      }

      .burger span {
        width: 24px;
      }

      .hero {
        min-height: 820px;
      }

      .hero-content {
        padding-block: 70px 32px;
      }

      .hero h1 {
        font-size: clamp(1.72rem, 7.6vw, 2.28rem);
        line-height: 1.22;
        margin-bottom: 18px;
      }

      .hero p {
        font-size: .98rem;
        line-height: 1.8;
      }

      .hero-actions {
        gap: 12px;
        margin-top: 28px;
      }

      .hero-actions .btn {
        width: 100%;
        flex-basis: 100%;
        justify-content: center;
        min-height: 52px;
      }

      .scroll-top {
        left: 16px;
        bottom: max(16px, env(safe-area-inset-bottom));
        width: 34px;
        height: 34px;
        font-size: .9rem;
      }

      .impact {
        padding: var(--sec-pad) 0;
      }

      .about {
        padding: var(--sec-pad) 0;
      }

      .about-layout {
        gap: 46px;
      }

      .about-visual img {
        border-radius: var(--r);
      }

      .about-badge {
        width: calc(100% - 28px);
        right: 14px;
        bottom: -26px;
        padding: 24px 24px;
      }

      .about-badge .big {
        font-size: 2.7rem;
      }

      .about-badge .t {
        grid-column: 1 / -1;
      }

      .about-content h2 {
        font-size: clamp(2.35rem, 12vw, 3.6rem);
        margin-bottom: 24px;
      }

      .about-copy {
        padding-inline-start: 18px;
      }

      .about-copy p {
        font-size: 1rem;
      }

      .about-pillars {
        margin-top: 34px;
      }

      .about-values {
        margin-top: 42px;
        padding: 24px 20px;
      }

      .about-value {
        border-inline-start: 0;
        padding: 22px 0 0;
      }

      .about-value:first-child {
        border-top: 0;
        padding-top: 0;
      }

      .impact-panel {
        padding: 34px 18px 28px;
      }

      .impact-grid {
        gap: 10px;
      }

      .impact-card {
        padding: 20px 18px;
        gap: 12px;
      }

      .impact-icon {
        width: 44px;
        height: 44px;
      }

      .impact-note {
        font-size: .74rem;
      }

      .impact-value {
        padding: 18px 16px;
      }

      .impact-value:first-child {
        border-top: 0;
        padding-top: 0;
      }

      .process {
        padding: var(--sec-pad) 0;
      }

      .process-head {
        margin-bottom: 34px;
      }

      .process-flow {
        gap: 38px;
      }

      .process-step {
        min-height: 0;
        padding: 28px 22px 26px;
      }

      .process-step:not(:last-child)::after {
        content: "⌄";
        top: auto;
        right: 50%;
        left: auto;
        bottom: -32px;
        width: 42px;
        height: 42px;
        font-size: 1.55rem;
        transform: translateX(50%);
      }

      .process-summary {
        grid-template-columns: 1fr;
        gap: 14px;
        padding: 24px 20px;
      }

      .process-summary strong {
        width: fit-content;
      }

      .projects-head {
        gap: 26px;
        margin-bottom: 34px;
      }

      .project-tabs {
        gap: 10px;
      }

      .project-tab {
        min-height: 56px;
      }


      .project-card-img {
        height: 245px;
      }

      .project-card-body {
        padding: 24px 22px 22px;
      }

      .projects-footer {
        grid-template-columns: 1fr;
        padding: 24px 22px;
      }

      .projects-footer-cta {
        justify-self: start;
      }

      .story-head {
        margin-bottom: 36px;
      }

      .story-timeline {
        gap: 0;
        padding-top: 0;
        direction: rtl;
      }

      .story-item {
        display: grid;
        grid-template-columns: 84px 1fr;
        gap: 0 20px;
        padding: 0 0 34px;
        text-align: left;
        border-inline-start: 0;
        padding-inline-end: 24px;
      }

      .story-item:last-child {
        padding-bottom: 0;
      }

      .story-year {
        grid-row: 1 / span 4;
        font-size: 1.8rem;
        margin: 0;
      }

      .story-image {
        margin-top: 18px;
      }

      .story-achievement {
        margin-top: 18px;
      }

      .story-footer {
        grid-template-columns: 1fr;
        padding: 24px 22px;
      }

      .story-footer p {
        border-inline-start: 0;
        padding-inline-start: 0;
      }

      .why .sec-head {
        margin-bottom: 34px;
      }


      /* Media-beside-text needs width to spare for the narrower column; below
         this breakpoint the card goes back to stacking media above text. */
      .why-grid {
        grid-template-columns: 1fr;
      }

      .why-card {
        grid-template-columns: 1fr;
      }

      .why-media {
        height: 220px;
      }

      .why-card-body {
        padding: 26px 22px 28px;
      }

      .why-footer {
        grid-template-columns: 1fr;
        padding: 24px 22px;
      }

      .why-footer p {
        text-align: left;
      }

      .partners-head {
        margin-bottom: 34px;
      }


      .partner-card {
        min-height: 0;
        padding: 30px 22px 26px;
      }

      .partners-trust-copy {
        grid-template-columns: 1fr;
        padding: 28px 24px;
      }

      .partner-stat {
        padding: 26px 22px;
      }

      .news-tabs {
        border-radius: var(--r);
        padding: 6px;
      }

      .news-tab {
        min-height: 40px;
        padding: 0 16px;
      }


      .news-body {
        min-height: 0;
      }

      .news-subscribe {
        gap: 22px;
        padding: 24px 20px;
      }

      .news-subscribe-copy {
        grid-template-columns: 1fr;
      }

      .news-form {
        flex-wrap: wrap;
      }

      .news-form input {
        flex-basis: 100%;
      }

      .news-form button {
        flex: 1 1 100%;
      }

      .news-social {
        flex-wrap: wrap;
        white-space: normal;
      }

      .cta-inner {
        padding: 88px 0;
      }

      .cta h2 {
        font-size: clamp(2.35rem, 13vw, 3.6rem);
      }

      .cta h2 br {
        display: none;
      }

      .cta p {
        margin-bottom: 34px;
      }

      .cta-action {
        min-height: 74px;
        padding: 0 20px;
        font-size: .98rem;
      }

      .foot-grid {
        grid-template-columns: 1fr
      }

    }

    @media(max-width:420px) {
      .nav {
        gap: 10px;
      }

      .logo img {
        max-width: min(39vw, 146px);
      }

      .lang {
        display: none;
      }

      .nav-actions {
        gap: 4px;
      }
    }

    .h-\[3rem\] {
      height: 3rem
    }

    /* ===== REVIEW PASS: PROJECTS / STORY / WHY / PARTNERS / NEWS / CONTACT =====
       These rules keep sdeira.html's content structure while replacing the
       compressed card rows with clearer, responsive compositions. */

    /* Projects: one connected portfolio rail. Every card owns the same rows, so
       a longer paragraph cannot expose the old dark backing below its siblings. */
    .project-cards {
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 1px;
      background: var(--line);
      overflow: hidden;
      border-radius: var(--r);
    }

    .project-card {
      min-width: 0;
      height: 100%;
      display: grid;
      grid-template-rows: clamp(220px, 22vw, 310px) 1fr;
      background: var(--surface-sunken);
      border-radius: var(--r);
    }

    .project-card-img {
      height: auto;
    }

    .project-card-body {
      min-height: 100%;
      display: flex;
      flex-direction: column;
      padding: clamp(24px, 2.4vw, 34px);
    }

    .project-card p {
      min-height: 0;
      flex: 1 1 auto;
    }

    .projects-footer {
      margin-top: 1px;
      border: 0;
      background: var(--surface-warm);
      padding: clamp(26px, 3vw, 38px);
    }

    .projects-footer h3,
    .projects-footer p {
      color: var(--ink);
    }

    /* Timeline: a real central rail with alternating editorial panels. Each
       milestone gets its own row, so copy length never compresses its neighbour. */
    .story-timeline {
      display: grid;
      grid-template-columns: minmax(0, 1fr) 80px minmax(0, 1fr);
      grid-template-rows: repeat(5, auto);
      gap: 0;
      padding-top: 0;
      margin-top: clamp(48px, 6vw, 82px);
      direction: rtl;
    }

    .story-timeline::before {
      top: 0;
      bottom: 0;
      right: 50%;
      left: auto;
      width: 2px;
      height: auto;
      transform: translateX(50%);
      background: var(--icon-warm-fill);
    }

    .story-item {
      width: 100%;
      min-width: 0;
      display: grid;
      grid-template-columns: minmax(0, 1.05fr) minmax(180px, .95fr);
      grid-template-rows: auto auto 1fr;
      gap: 0 clamp(24px, 3vw, 42px);
      align-items: start;
      padding: clamp(26px, 3.2vw, 42px);
      margin: 0 0 clamp(30px, 4vw, 54px);
      background: var(--surface-raised);
      text-align: left;
      border-radius: var(--r);
    }

    .story-item:nth-child(odd) {
      grid-column: 1;
      margin-inline-end: 0;
    }

    .story-item:nth-child(even) {
      grid-column: 3;
      margin-inline-start: -17px;
    }

    .story-item:nth-child(1) { grid-row: 1; }
    .story-item:nth-child(2) { grid-row: 2; }
    .story-item:nth-child(3) { grid-row: 3; }
    .story-item:nth-child(4) { grid-row: 4; }
    .story-item:nth-child(5) { grid-row: 5; }

    .story-dot {
      top: clamp(30px, 3.2vw, 42px);
      left: auto;
      right: auto;
      width: 18px;
      height: 18px;
      transform: none;
      background: var(--accent);
      outline: 8px solid var(--surface-sunken-strong);
    }

    .story-item:nth-child(odd) .story-dot {
      left: calc(-40px - 9px);
      right: auto;
    }

    .story-item:nth-child(even) .story-dot {
      right: calc(-40px - 9px);
      left: auto;
    }


    .story-item h3 {
      grid-column: 1;
      margin-bottom: 12px;
      font-size: clamp(1.25rem, 1.8vw, 1.65rem);
    }


    .story-image {
      grid-column: 2;
      grid-row: 1 / span 3;
      align-self: stretch;
      min-height: 230px;
      margin: 0;
      aspect-ratio: auto;
    }


    .story-footer .btn {
      min-height: 54px;
      justify-content: center;
      text-align: center;
      line-height: 1.45;
    }

    /* Why: image-led editorial cards. Photos remain large at the review width
       instead of being squeezed into a narrow third of each card. */
    .why-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 1px;
      background: var(--line);
      overflow: hidden;
      border-radius: var(--r);
    }

    .why-card {
      min-width: 0;
      display: grid;
      grid-template-columns: 1fr;
      grid-template-rows: clamp(280px, 30vw, 390px) 1fr;
      border-radius: var(--r);
      background: var(--surface-raised);
    }

    .why-media img {
      position: relative;
    }


    .why-card-body {
      padding: clamp(28px, 3.4vw, 46px);
    }

    .why-card h3 {
      min-height: 0;
    }

    /* Partner names restored from the agreed sdeira.html baseline. */
    .partners-grid {
      grid-template-columns: repeat(5, minmax(0, 1fr));
      gap: 1px;
      background: var(--line);
      overflow: hidden;
      border-radius: var(--r);
    }

    .partner-card {
      min-width: 0;
      min-height: 360px;
      border-radius: var(--r);
      background: var(--surface-raised);
    }

    .partner-logo {
      width: 100%;
      min-height: 88px;
      color: var(--ink);
      font-family: Arial, sans-serif;
      font-size: clamp(1.45rem, 2.2vw, 2rem);
      letter-spacing: 0;
    }

    .partner-logo span {
      font-size: .62em;
      letter-spacing: 0;
    }

    .partner-logo.schneider { color: var(--brand-liwa); }
    .partner-logo.abb { color: var(--brand-liwa); font-weight: 900; }
    .partner-logo.carrier { color: var(--brand-jais); font-weight: 500; }
    .partner-logo.honeywell { color: var(--brand-liwa); font-weight: 700; }
    .partner-logo.johnson { color: var(--brand-jais); }

    .partners-trust {
      grid-template-columns: minmax(300px, .9fr) minmax(0, 1.5fr);
      background: var(--surface-raised);
    }

    .partner-stats {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 1px;
      padding: 0;
      background: var(--line);
    }

    .partner-stat {
      min-width: 0;
      min-height: 180px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 24px 18px;
      background: var(--surface-sunken);
    }

    .partner-stat i.ph {
      margin-bottom: 12px;
      color: var(--icon);
    }

    .partner-stat strong {
      font-size: clamp(1.35rem, 2.2vw, 2rem);
      color: var(--ink);
    }

    .partner-stat span,
    .partner-stat small {
      color: var(--muted);
    }

    /* News: source-backed cards with a locally stored image for stable previews. */
    .news-grid {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 1px;
      background: var(--line);
      overflow: hidden;
      border-radius: var(--r);
    }

    .news-card {
      min-width: 0;
      border-radius: var(--r);
      cursor: default;
    }

    .news-image-link {
      display: block;
      overflow: hidden;
    }

    .news-card h3 a {
      color: inherit;
    }


    .news-subscribe {
      background: var(--surface-warm);
      color: var(--ink);
    }

    .news-subscribe h3,
    .news-subscribe p {
      color: var(--ink);
    }

    .news-form {
      background: var(--surface-raised);
    }

    .news-form:focus-within {
      background: var(--surface-base);
    }

    .news-social {
      border-color: rgba(65, 64, 66, .22);
    }

    .news-social,
    .news-social a {
      color: var(--ink);
    }

    /* Contact routes: dark cards belong to the Liwa field; white slabs did not. */
    .cta-action {
      min-height: 230px;
      justify-content: center;
      background: var(--surface-inverse);
      color: #fff;
    }


    .foot-contact bdi {
      direction: ltr;
      unicode-bidi: isolate;
    }

    @media(max-width:1180px) {
      .project-cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }

      .partners-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
      }

      .partners-trust {
        grid-template-columns: 1fr;
      }
    }

    @media(max-width:900px) {
      .story-timeline {
        grid-template-columns: 30px minmax(0, 1fr);
        grid-template-rows: none;
        direction: ltr;
      }

      .story-timeline::before {
        left: 15px;
        right: auto;
        transform: none;
      }

      .story-item,
      .story-item:nth-child(odd),
      .story-item:nth-child(even) {
        grid-column: 2;
        grid-row: auto;
        margin-inline: 0;
        direction: rtl;
      }

      .story-item .story-dot,
      .story-item:nth-child(odd) .story-dot,
      .story-item:nth-child(even) .story-dot {
        display: block;
        left: -24px;
        right: auto;
      }

      /* .news-grid's own auto-fit already handles column collapse now (see
         the active .news-grid rule further down). The old side-by-side
         .news-card override below this used to fire here too, splitting
         each secondary card into image-right/text-left columns while the
         card's height was driven by the (taller) text column - the image
         column then had nowhere to grow into, leaving a large empty grey
         gap under the photo. Removed: the default vertical .news-card
         layout (image full-width on top, body below, no side-by-side
         split) already matches the feature card's own single-column
         behaviour at this width, so nothing needs overriding here. */
    }

    @media(max-width:720px) {
      .project-cards,
      .why-grid,
      .partners-grid,
      .partner-stats {
        grid-template-columns: 1fr;
      }

      .project-card {
        grid-template-rows: clamp(240px, 72vw, 340px) 1fr;
      }

      .projects-footer {
        grid-template-columns: auto 1fr;
      }

      .projects-footer-cta {
        grid-column: 1 / -1;
        width: 100%;
        justify-content: center;
      }

      .story-item {
        grid-template-columns: 1fr;
      }

      .story-image {
        grid-column: 1;
        grid-row: auto;
        min-height: 260px;
        margin-top: 24px;
      }

      .story-achievement {
        grid-column: 1;
      }

      .why-card {
        grid-template-rows: clamp(240px, 76vw, 360px) 1fr;
      }

      .partner-card {
        min-height: 300px;
      }

      .news-card {
        grid-template-columns: 1fr;
        grid-template-rows: auto 1fr;
      }

      .news-card .img {
        height: auto;
      }

      .news-subscribe {
        background: var(--surface-warm);
      }

      .cta-action {
        min-height: 190px;
        padding: 30px 22px;
      }
    }

    /* ===== REVIEW PASS: NAV / SECTION SIGNATURE / ABOUT / PROCESS ===== */
    .lang,
    .menu-lang {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 7px;
      min-height: 44px;
      padding-inline: 8px;
      color: rgba(255, 255, 255, .84);
      font-size: .82rem;
      font-weight: 600;
      line-height: 1;
      text-decoration: none;
      white-space: nowrap;
      transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
    }

    .lang i.ph,
    .menu-lang i.ph {
      font-size: var(--ic-sm);
    }

    .lang:hover,
    .lang:focus-visible {
      color: var(--brand-white);
      background: rgba(255, 255, 255, .12);
    }

    header.scrolled .lang:hover,
    header.scrolled .lang:focus-visible {
      /* --accent-strong, not --accent-text: matches the shared fix in
         sdeira-subpage.css's .lang hover (solid-fill ink fails on this wash). */
      color: var(--accent-strong);
      background: var(--accent-wash);
    }

    main section:not(.hero) :is(.kicker, .impact-kicker, .process-kicker, .story-kicker, .partners-kicker) {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      width: auto;
    }

    main section:not(.hero) :is(.kicker, .impact-kicker, .process-kicker, .story-kicker, .partners-kicker)::before {
      content: "";
      width: 20px;
      height: 20px;
      flex: 0 0 20px;
      background: url("../images/brand/sdeira-mark.png?v=c1949ae876afaeca") center / contain no-repeat;
    }

    .about-badge {
      grid-template-columns: auto 1fr;
      align-items: start;
    }

    .about-badge .big {
      font-size: clamp(4rem, 7vw, 7.4rem);
      line-height: .72;
      font-variant-numeric: tabular-nums;
    }

    .about-badge .label {
      margin-top: 18px;
    }

    .about-values {
      margin-top: clamp(64px, 8vw, 112px);
      padding: 0;
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 1px;
      overflow: hidden;
      background: var(--surface-sunken-strong);
      border: 0;
    }

    /* display/background here are dead against the live markup - a later
       .about-values-head (this file, "no background and no one-sided
       border" comment) sets display:block and wins on source order, so
       this grid/background never rendered. background removed anyway: it
       is exactly the property this rule would otherwise reintroduce if the
       later one is ever edited without checking here first - see that
       rule's comment for why it has none. */
    .about-values-head {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: minmax(190px, .6fr) minmax(0, 1.4fr);
      align-items: end;
      gap: 32px;
      padding: clamp(28px, 4vw, 48px);
      color: var(--brand-white);
    }

    /* The homepage About figures continue the layout above; keep the same
       established values spacing after the figure/badge composition. */
    #about .about-layout + .stat-strip {
      margin-block-start: var(--sec-head-gap);
    }

    .about-values-head .kicker {
      color: var(--accent-on-dark);
      margin: 0;
    }

    .about-values-head h3 {
      margin: 0;
      color: var(--brand-white);
      font-size: clamp(2rem, 4vw, 3.8rem);
      line-height: 1.1;
    }

    .about-value {
      min-height: 220px;
      padding: clamp(26px, 3vw, 38px);
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 24px;
      background: var(--surface-sunken);
    }

    .about-value:nth-child(even) {
      background: var(--surface-base);
    }

    .about-value-icon {
      width: 54px;
      height: 54px;
    }

    .about-value h3 {
      font-size: clamp(1.1rem, 1.55vw, 1.35rem);
      margin-bottom: 10px;
    }

    .about-value p {
      max-width: 26ch;
      font-size: 1rem;
      line-height: 1.8;
    }

    .process-head {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(280px, .54fr);
      gap: clamp(30px, 5vw, 76px);
      align-items: end;
      max-width: none;
      margin: 0 0 clamp(42px, 6vw, 76px);
    }

    .process-head .process-kicker,
    .process-head h2 {
      grid-column: 1;
    }


    .process-head p {
      grid-column: 2;
      grid-row: 1 / span 2;
      max-width: 42ch;
      margin: 0;
      padding-inline-start: clamp(22px, 3vw, 42px);
      border-inline-start: 1px solid var(--brand-grey-70);
    }


    .process-step {
      min-width: 0;
      height: 100%;
      padding: clamp(28px, 3vw, 46px);
      align-items: flex-start;
      justify-content: flex-end;
      text-align: left;
      overflow: hidden;
      isolation: isolate;
      background: var(--surface-raised);
      transition: background var(--dur-base) var(--ease-out);
    }

    .process-step:nth-child(1) { grid-column: span 5; }
    .process-step:nth-child(2) { grid-column: span 4; background: var(--surface-sunken-strong); }
    .process-step:nth-child(3) { grid-column: span 3; }
    .process-step:nth-child(4) {
      grid-column: span 7;
      background: var(--surface-inverse);
      color: var(--brand-white);
    }
    .process-step:nth-child(5) { grid-column: span 5; background: var(--surface-warm); }


    .process-step::after,
    .process-step:not(:last-child)::after {
      content: none;
      display: none;
    }

    .process-step:nth-child(4):hover {
      background: var(--surface-inverse-soft);
    }

    .process-step:nth-child(5):hover {
      background: var(--brand-al-khatim);
    }

    .process-num {
      position: absolute;
      z-index: -1;
      inset-block-start: clamp(10px, 2vw, 24px);
      inset-inline-end: clamp(18px, 3vw, 42px);
      color: var(--surface-sunken-strong);
      font-size: clamp(5.6rem, 10vw, 9.6rem);
      font-weight: 700;
      line-height: .8;
      opacity: .62;
      pointer-events: none;
      transition: transform 480ms var(--ease-out);
    }

    .process-step:nth-child(2) .process-num { color: var(--brand-white); }
    .process-step:nth-child(4) .process-num { color: var(--brand-grey-70); opacity: .48; }
    .process-step:nth-child(5) .process-num { color: var(--brand-white); opacity: .42; }

    .process-step:hover .process-num {
      transform: translate3d(-10px, 0, 0);
    }

    .process-step h3,
    .process-step p,
    .process-icon {
      position: relative;
      z-index: 1;
    }


    .process-step:nth-child(4) h3,
    .process-step:nth-child(4) p {
      color: var(--brand-white);
    }

    .process-step:nth-child(4) p {
      color: var(--muted-on-dark);
    }

    .process-icon {
      order: -2;
      width: 60px;
      height: 60px;
      margin-bottom: auto;
      background: var(--surface-sunken);
      color: var(--brand-jais);
    }

    .process-step:nth-child(2) .process-icon {
      background: var(--brand-razeen);
      color: var(--brand-black);
    }

    .process-step:nth-child(3) .process-icon {
      background: var(--brand-al-khatim);
      color: var(--brand-black);
    }

    .process-step:nth-child(4) .process-icon {
      background: var(--brand-grey-70);
      color: var(--brand-white);
    }

    .process-step:nth-child(5) .process-icon {
      background: var(--brand-black);
      color: var(--brand-white);
    }

    .process-step:hover .process-icon {
      background: inherit;
    }

    .process-summary {
      position: relative;
      margin-top: clamp(28px, 4vw, 48px);
      grid-template-columns: minmax(230px, .6fr) minmax(0, 1.4fr);
      gap: clamp(28px, 6vw, 88px);
      padding: clamp(34px, 5vw, 64px);
      overflow: hidden;
      background: var(--surface-brand);
      color: var(--brand-white);
    }

    .process-summary::before {
      content: "";
      position: absolute;
      inset-block-start: 0;
      inset-inline-start: 0;
      width: 100%;
      height: 5px;
      transform: scaleX(0);
      transform-origin: right center;
      background: var(--brand-razeen);
      transition: transform 800ms var(--ease-out);
    }

    .process-summary.reveal.in::before {
      transform: scaleX(1);
    }

    .process-summary-title {
      display: grid;
      gap: 12px;
      align-self: start;
    }

    .process-summary-title span {
      color: var(--accent-on-dark);
      font-family: var(--font-display);
      font-size: .82rem;
      letter-spacing: .08em;
    }

    .process-summary strong {
      padding: 0;
      color: var(--brand-white);
      font-size: clamp(1.7rem, 3vw, 2.8rem);
      line-height: 1.2;
      white-space: normal;
    }

    .process-summary p {
      max-width: 52ch;
      margin: 0;
      color: var(--brand-white);
      font-size: clamp(1.05rem, 1.4vw, 1.25rem);
      line-height: 2;
    }

    @media(max-width:980px) {
      .process-flow {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-auto-rows: minmax(300px, auto);
      }

      .process-step:nth-child(n) {
        grid-column: span 1;
      }

      .process-step:nth-child(5) {
        grid-column: 1 / -1;
      }

    }

    @media(max-width:720px) {
      .nav-actions > .lang {
        display: none;
      }

      .menu-lang {
        gap: 9px;
      }


      .about-values-head {
        grid-template-columns: 1fr;
        gap: 14px;
      }

      .about-value {
        min-height: 0;
      }

      .process-head {
        grid-template-columns: 1fr;
        gap: 22px;
      }

      .process-head .process-kicker,
      .process-head h2,
      .process-head p {
        grid-column: 1;
        grid-row: auto;
      }

      .process-head p {
        max-width: none;
        padding-inline-start: 0;
        padding-block-start: 20px;
        border-inline-start: 0;
        border-block-start: 1px solid var(--brand-grey-70);
      }

      .process-flow {
        grid-template-columns: 1fr;
        grid-auto-rows: minmax(280px, auto);
      }

      .process-step:nth-child(n) {
        grid-column: 1;
      }

      .process-summary {
        grid-template-columns: 1fr;
        gap: 26px;
      }
    }

    @media(prefers-reduced-motion: reduce) {
      .process-summary::before {
        transform: scaleX(1);
        transition: none;
      }

      .process-step:hover .process-num {
        transform: none;
      }
    }

    /* ===== REVIEW PASS: HERO RECONSTRUCTION / ABOUT RHYTHM ===== */
    .hero {
      min-height: max(700px, 100svh);
      display: flex;
      flex-direction: column;
      isolation: isolate;
      background: var(--image-overlay);
    }


    .hero-content {
      width: min(calc(100% - 40px), var(--max));
      max-width: var(--max);
      min-height: clamp(430px, 55svh, 560px);
      margin-inline: auto;
      padding-block: clamp(112px, 15vh, 180px) 48px;
      justify-content: flex-start;
    }

    .hero-content::after {
      content: none;
      display: none;
    }

    .hero-content-row {
      width: min(100%, 860px);
      gap: clamp(18px, 3vw, 34px);
      align-items: stretch;
    }

    .hero-content-copy {
      max-width: 760px;
    }


    .hero h1 {
      max-width: 15ch;
      font-size: clamp(2.35rem, min(5vw, 7.5svh), 4.4rem);
      margin-bottom: 18px;
    }

    .hero p {
      max-width: 52ch;
      font-size: clamp(1rem, 1.6vw, 1.2rem);
    }

    .hero-actions {
      gap: 10px;
      margin-top: 28px;
      align-items: center;
    }

    .hero-actions .btn {
      width: auto;
      min-width: 0;
      min-height: 48px;
      padding: 0 22px;
      justify-content: center;
      font-size: .95rem;
    }

    .hero-sectors {
      flex: 1 0 auto;
      padding-block: 0 clamp(24px, 4svh, 38px);
    }

    .hero-sectors-label {
      margin-bottom: 10px;
    }

    .sector-grid {
      grid-template-columns: repeat(5, minmax(0, 1fr));
      justify-content: stretch;
      gap: 1px;
      overflow: hidden;
      background: rgba(var(--image-overlay-rgb), .7);
    }

    @media(min-width:1600px) {
      .sector-grid {
        grid-template-columns: repeat(5, minmax(0, 1fr));
      }
    }

    .sector-card {
      min-width: 0;
      min-height: clamp(210px, 24svh, 260px);
      aspect-ratio: auto;
      border-radius: var(--r);
    }

    .sector-card-media {
      border-radius: var(--r);
    }


    .sector-card-media::after {
      background: rgba(var(--image-overlay-rgb), .82);
    }

    .sector-card-body {
      min-height: 100%;
      padding: clamp(18px, 2.2vw, 26px);
      justify-content: flex-end;
      gap: 7px;
    }

    .sector-card-mark {
      width: 42px;
      height: 42px;
      margin-bottom: auto;
      background: rgba(255, 255, 255, .15);
    }

    .sector-card-title {
      font-size: clamp(1.08rem, 1.45vw, 1.35rem);
    }

    .sector-card-sub {
      min-height: 3.1em;
      font-size: .86rem;
    }

    .sector-card-action {
      min-height: 24px;
      margin-top: 2px;
      opacity: .82;
      transform: none;
      font-size: .8rem;
    }

    .sector-card-panel {
      display: none;
    }

    .about-copy {
      max-width: 820px;
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 22px clamp(28px, 4vw, 52px);
      padding: 0;
    }

    .about-copy p {
      margin: 0;
      font-size: clamp(1rem, 1.18vw, 1.18rem);
      line-height: 1.95;
    }

    .about-copy p:first-child {
      grid-column: 1 / -1;
      color: var(--accent-text);
      font-family: var(--font-display);
      font-size: clamp(1.35rem, 2vw, 1.8rem);
      line-height: 1.45;
    }

    .about-copy p:nth-child(3) {
      padding-inline-start: clamp(22px, 3vw, 38px);
      border-inline-start: 1px solid var(--surface-sunken-strong);
    }

    .about-pillars {
      margin-top: clamp(42px, 6vw, 68px);
      gap: 0;
      border-block: 1px solid var(--surface-sunken-strong);
    }

    .about-pillar {
      min-width: 0;
      padding: clamp(26px, 3vw, 38px);
      text-align: left;
      border-inline-start: 1px solid var(--surface-sunken-strong);
    }

    .about-pillar:first-child {
      border-inline-start: 0;
    }

    .about-icon {
      width: 50px;
      height: 50px;
      margin: 0 0 20px;
    }

    .about-pillar p {
      max-width: 22ch;
    }

    .impact-visual::after {
      background:
        linear-gradient(to bottom,
          rgba(var(--image-overlay-rgb), .78) 0%,
          rgba(var(--image-overlay-rgb), .78) 15%,
          transparent 48%),
        linear-gradient(to top,
          rgba(var(--image-overlay-rgb), .88) 0%,
          rgba(var(--image-overlay-rgb), .88) 20%,
          transparent 52%);
    }


    @media(max-width:980px) {
      .hero-content {
        min-height: clamp(470px, 64svh, 610px);
      }

      .sector-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
      }

      .sector-card {
        min-height: 230px;
      }
    }

    @media(max-width:720px) {

      .hero-content {
        width: calc(100% - 36px);
        min-height: clamp(470px, 66svh, 590px);
        padding-block: 94px 30px;
      }

      .hero-content-row {
        width: 100%;
        gap: 16px;
      }

      .hero-slides-ind {
        flex-basis: 14px;
      }

      .hero h1 {
        max-width: none;
        font-size: clamp(2.15rem, 11vw, 3.2rem);
        line-height: 1.14;
      }

      .hero p {
        font-size: 1rem;
        line-height: 1.75;
      }

      .hero-actions {
        flex-wrap: nowrap;
      }

      .hero-actions .btn {
        min-height: 46px;
        padding-inline: 16px;
        font-size: .88rem;
      }


      .hero-sectors {
        padding-block: 4px 26px;
      }

      .hero-sectors .wrap {
        width: 100%;
        max-width: none;
        padding-inline: 18px;
      }

      .sector-grid {
        grid-auto-flow: column;
        grid-template-columns: none;
        grid-auto-columns: calc((100vw - 48px) / 2);
        justify-content: start;
        gap: 1px;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: inline mandatory;
        scrollbar-width: thin;
        overscroll-behavior-inline: contain;
      }

      .sector-grid::-webkit-scrollbar {
        height: 4px;
      }

      .sector-grid::-webkit-scrollbar-track {
        background: rgba(var(--image-overlay-rgb), .65);
      }

      .sector-grid::-webkit-scrollbar-thumb {
        background: var(--brand-razeen);
      }

      .sector-card {
        min-height: 224px;
        scroll-snap-align: start;
      }

      .sector-card-body {
        padding: 16px;
      }

      .sector-card-mark {
        width: 38px;
        height: 38px;
      }

      .sector-card-title {
        font-size: 1rem;
      }

      .sector-card-sub {
        min-height: 3.2em;
        font-size: .78rem;
      }

      .sector-card-subs,
      .sector-card-action {
        font-size: .72rem;
      }

      .about-copy {
        grid-template-columns: 1fr;
        gap: 18px;
      }

      .about-copy p:first-child {
        grid-column: 1;
      }

      .about-copy p:nth-child(3) {
        padding-inline-start: 0;
        padding-block-start: 18px;
        border-inline-start: 0;
        border-block-start: 1px solid var(--surface-sunken-strong);
      }

      .about-pillars {
        grid-template-columns: 1fr;
      }

      .about-pillar {
        display: grid;
        grid-template-columns: auto 1fr;
        gap: 6px 18px;
        align-items: start;
        border-inline-start: 0;
        border-block-start: 1px solid var(--surface-sunken-strong);
      }

      .about-pillar:first-child {
        border-block-start: 0;
      }

      .about-icon {
        grid-row: 1 / span 2;
        margin: 0;
      }

      .about-pillar h3,
      .about-pillar p {
        grid-column: 2;
      }
    }

    /* ===== REVIEW PASS: ABOUT BADGE / INSTITUTIONAL VALUES ===== */
    .about-badge {
      grid-template-columns: 1fr;
      overflow: hidden;
      isolation: isolate;
    }

    .about-badge > i.ph {
      position: absolute;
      z-index: -1;
      inset-block-start: 18px;
      inset-inline-end: 18px;
      font-size: clamp(6.5rem, 10vw, 10rem);
      line-height: 1;
      color: var(--brand-white);
      opacity: .12;
      transform: rotate(-8deg);
      pointer-events: none;
    }

    .about-badge .t {
      grid-column: 1;
      max-width: 25ch;
    }

    .about-values {
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 1px;
      background: var(--surface-base);
      border: 0;
    }

    /* No background and no one-sided border: this block sits directly on the
       section's own --surface-base, and neither the same-colour fill nor
       the border-block-end (Arabic never had it - drift, not intent; see
       AGENTS.md's ban on one-sided borders as a treatment) were doing
       anything a visitor should keep. Both were kept only because an older
       sibling component (.about-values/.about-value, no longer in any
       page's markup) shared this class name.

       THE TITLE LABELS .stat-strip, IT DOES NOT INTRODUCE A SEPARATE BLOCK.
       First pass after the byline paragraph was removed used
       --sec-head-gap - the token for a heading standing apart from an
       unrelated row (.section-heading-row's kicker+heading vs. its "view
       all" link) - and it read as too much air between a caption and the
       thing it captions (site owner instruction, 2026-08-12). No extra
       margin now: the existing symmetric 18px block padding is the whole
       gap, on both sides of the title, same as it always was above it. */
    .about-values-head {
      grid-column: 1 / -1;
      display: block;
      padding: 18px clamp(24px, 3vw, 34px);
      color: var(--ink);
    }

    .about-values-head h3 {
      color: var(--ink);
      font-size: clamp(1.1rem, 1.5vw, 1.3rem);
      font-weight: 600;
      line-height: 1.3;
    }

    .about-value,
    .about-value:nth-child(even) {
      min-height: 210px;
      background: var(--surface-sunken);
    }

    .about-value-icon {
      background: var(--icon-value-fill);
      color: var(--icon-value-text);
    }

    @media(max-width:980px) {
      .about-values {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }
    }

    @media(max-width:720px) {
      .about-badge > i.ph {
        inset-block-start: 14px;
        inset-inline-end: 14px;
        font-size: 5.25rem;
        opacity: .08;
      }

      .about-values {
        grid-template-columns: 1fr;
      }

      .about-values-head {
        padding: 16px 20px;
      }

      .about-value,
      .about-value:nth-child(even) {
        min-height: 220px;
      }
    }

    /* ===== REVIEW PASS: HERO STAGE / FULL-BLEED SECTOR OVERLAP ===== */
    .hero {
      display: block;
      height: max(700px, 100svh);
      min-height: max(700px, 100svh);
      overflow: hidden;
      background: transparent;
    }


    header:not(.scrolled)::before {
      opacity: 0;
    }

    .hero-content {
      height: 100%;
      min-height: 0;
      padding-block: clamp(104px, 14svh, 140px) clamp(132px, 15.75svh, 160px);
    }

    .scroll-hint {
      top: auto;
      bottom: calc(200px + 32px);
      z-index: 5;
    }

    .hero-sectors {
      position: relative;
      z-index: 4;
      width: 100%;
      margin-top: clamp(-112px, -10svh, -84px);
      padding: 0 0 clamp(28px, 4svh, 40px);
      background: var(--surface-inverse);
    }

    .hero-sectors .wrap {
      width: 100%;
      max-width: none;
      padding-inline: clamp(24px, 6vw, 84px);
    }

    .hero-sectors-label {
      min-height: 38px;
      margin: 0;
      display: flex;
      align-items: center;
      color: var(--muted-on-dark);
    }

    .sector-grid {
      width: 100%;
    }

    @media(max-width:720px) {
      .hero {
        height: 100svh;
        min-height: 680px;
      }

      .hero-content {
        min-height: 0;
        height: 100%;
        padding-block: 94px 128px;
      }

      .scroll-hint {
        display: flex;
        left: 18px;
        bottom: 112px;
        font-size: .74rem;
      }

      .scroll-hint span:last-child {
        display: none;
      }

      .hero::after {
        background:
          radial-gradient(ellipse 112% 62% at 64% 62%,
            rgba(var(--image-overlay-rgb), .44) 0%,
            rgba(var(--image-overlay-rgb), .20) 46%,
            rgba(var(--image-overlay-rgb), .04) 72%,
            transparent 100%),
          linear-gradient(180deg,
            transparent 0%,
            rgba(var(--image-overlay-rgb), .05) 55%,
            transparent 100%);
      }

      .hero-sectors {
        margin-top: -92px;
        padding-bottom: 26px;
      }

      .hero-sectors .wrap {
        padding-inline: 18px;
      }

      .hero-sectors-label {
        min-height: 34px;
      }
    }

    /* Sector cards, photographic depth without the previous heavy black hover. */
    .sector-card-img {
      filter: saturate(.96) contrast(1.02);
      transition: transform 450ms var(--ease-out), filter 300ms ease;
    }

    .sector-card:nth-child(3) .sector-card-img {
      object-position: 65% center;
    }

    .sector-card:nth-child(4) .sector-card-img {
      object-position: 48% center;
    }

    .sector-card-veil {
      background: linear-gradient(180deg,
          rgba(var(--image-overlay-rgb), .08) 0%,
          rgba(var(--image-overlay-rgb), .26) 46%,
          rgba(var(--image-overlay-rgb), .78) 100%);
      transition: background 300ms ease;
    }

    .sector-card-media::after {
      display: none;
    }

    .sector-card:hover .sector-card-img,
    .sector-card:focus-within .sector-card-img {
      transform: scale(1.025);
      filter: saturate(1) contrast(1.03);
    }

    .sector-card:hover .sector-card-veil,
    .sector-card:focus-within .sector-card-veil {
      background: linear-gradient(180deg,
          rgba(var(--image-overlay-rgb), .1) 0%,
          rgba(var(--image-overlay-rgb), .3) 46%,
          rgba(var(--image-overlay-rgb), .84) 100%);
    }

    .sector-card-body {
      position: relative;
      padding-bottom: 52px;
    }

    .sector-card-mark {
      color: var(--color-white);
      background: rgba(var(--image-overlay-rgb), .62);
      transition: background-color 200ms ease, transform 200ms var(--ease-out);
    }


    .sector-card-action {
      position: absolute;
      inset-inline-start: clamp(18px, 2.2vw, 26px);
      bottom: 20px;
      min-height: 24px;
      margin: 0;
      opacity: 0;
      visibility: visible;
      pointer-events: none;
      transform: translateY(6px);
      transition: opacity 200ms ease, transform 200ms var(--ease-out);
    }

    .sector-card:hover .sector-card-action,
    .sector-card:focus-within .sector-card-action {
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transform: translateY(0);
    }

    .sector-card-action.is-pending {
      display: none;
    }

    .sector-card-action:focus,
    .sector-card-action:focus-visible {
      outline: 2px solid var(--color-white);
      outline-offset: 5px;
    }

    .sector-card:focus-within {
      outline: 2px solid rgba(255, 255, 255, .9);
      outline-offset: -4px;
    }

    @media (hover: none), (pointer: coarse) {
      .sector-card-action:not(.is-pending) {
        display: flex;
        min-height: 44px;
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transform: none;
      }
    }

    @media (max-width: 720px) {
      .sector-card-action:not(.is-pending) {
        display: flex;
        min-height: 44px;
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transform: none;
      }


      .sector-card-action {
        bottom: 10px;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .sector-card-img,
      .sector-card-action,
      .sector-card-veil,
      .sector-card-mark {
        transition: none;
      }

      .sector-card:hover .sector-card-img,
      .sector-card:focus-within .sector-card-img {
        transform: none;
      }

      .sector-card:hover .sector-card-mark,
      .sector-card:focus-within .sector-card-mark {
        transform: none;
      }
    }

    /* ===== REVIEW PASS: FULL-BLEED SECTORS / BRAND BEAM / STORY RAIL / WHY ===== */

    .hero-sectors-label {
      min-height: 58px;
      padding-inline: max(20px, calc((100vw - var(--max)) / 2 + 20px));
      font-family: var(--font-display);
      font-size: clamp(1rem, 1.35vw, 1.2rem);
      font-weight: 700;
      letter-spacing: 0;
      color: var(--color-white);
    }

    .sector-grid {
      gap: 1px;
    }

    .projects-footer {
      position: relative;
      isolation: isolate;
      overflow: hidden;
      grid-template-columns: 1fr auto;
      min-height: 170px;
      padding: clamp(30px, 4vw, 48px);
      padding-inline-start: clamp(150px, 17vw, 210px);
    }

    .projects-footer-mark {
      display: none;
    }

    .projects-footer::after {
      content: "";
      position: absolute;
      z-index: -1;
      inset-inline-start: clamp(-48px, -3vw, -24px);
      inset-block-end: clamp(-72px, -5vw, -46px);
      width: clamp(170px, 18vw, 230px);
      aspect-ratio: 1;
      background: url("../images/brand/sdeira-mark.png?v=c1949ae876afaeca") center / contain no-repeat;
    }

    .projects-footer h3 {
      font-family: var(--font-display);
      font-size: clamp(1.35rem, 2vw, 1.8rem);
      line-height: 1.45;
    }

    /* A contemporary chapter rail: chronological, horizontally explorable,
       and equal-height. It replaces the old alternating central spine. */
    .story-timeline {
      display: grid;
      grid-auto-flow: column;
      grid-auto-columns: minmax(320px, min(38vw, 450px));
      grid-template-columns: none;
      grid-template-rows: 1fr;
      gap: 1px;
      margin-top: clamp(42px, 6vw, 72px);
      padding: 0 0 18px;
      overflow-x: auto;
      overflow-y: hidden;
      overscroll-behavior-inline: contain;
      scroll-snap-type: inline mandatory;
      scrollbar-width: thin;
      scrollbar-color: var(--accent) rgba(var(--image-overlay-rgb), .12);
      background: transparent;
    }


    .story-timeline::-webkit-scrollbar {
      height: 6px;
    }

    .story-timeline::-webkit-scrollbar-track {
      background: rgba(var(--image-overlay-rgb), .1);
    }

    .story-timeline::-webkit-scrollbar-thumb {
      background: var(--accent);
    }

    .story-timeline:focus-visible {
      outline: 3px solid var(--accent);
      outline-offset: 8px;
    }

    .story-item,
    .story-item:nth-child(odd),
    .story-item:nth-child(even) {
      grid-column: auto;
      grid-row: 1;
      width: auto;
      min-width: 0;
      min-height: 620px;
      display: grid;
      grid-template-columns: 1fr;
      grid-template-rows: 250px auto auto 1fr auto;
      gap: 0;
      align-items: start;
      margin: 0;
      padding: 0;
      overflow: hidden;
      scroll-snap-align: start;
      text-align: left;
      background: var(--surface-raised);
      border-radius: var(--r);
    }

    .story-item::before {
      content: "";
      position: absolute;
      inset-block-start: 0;
      inset-inline-start: 0;
      z-index: 3;
      width: 42%;
      height: 5px;
      background: var(--accent);
    }

    .story-dot {
      display: none;
    }

    .story-image {
      grid-column: 1;
      grid-row: 1;
      width: 100%;
      min-height: 0;
      height: 250px;
      margin: 0;
      aspect-ratio: auto;
    }

    .story-year {
      grid-column: 1;
      grid-row: 2;
      margin: 0;
      padding: 26px 28px 4px;
      font-family: var(--font-brand);
      font-size: clamp(2.6rem, 4vw, 4rem);
      line-height: 1;
      color: var(--accent-text);
    }

    .story-item h3 {
      grid-column: 1;
      grid-row: 3;
      margin: 0;
      padding: 8px 28px 10px;
      font-family: var(--font-display);
      font-size: clamp(1.2rem, 1.7vw, 1.5rem);
    }

    .story-item>p {
      grid-column: 1;
      grid-row: 4;
      min-height: 0;
      margin: 0;
      padding: 0 28px 24px;
      font-size: .96rem;
      line-height: 1.85;
    }

    .story-achievement {
      grid-column: 1;
      grid-row: 5;
      min-height: 92px;
      margin: 0;
      padding: 20px 28px;
      border-top: 1px solid var(--line);
      background: var(--surface-sunken);
    }

    .story-icon {
      background: var(--surface-inverse);
      color: var(--color-white);
    }

    .why-card {
      position: relative;
    }

    .why-media::after {
      background: linear-gradient(180deg,
        rgba(var(--image-overlay-rgb), .02) 0%,
        rgba(var(--image-overlay-rgb), .12) 58%,
        rgba(var(--image-overlay-rgb), .46) 100%);
    }

    .why-ic {
      inset-block-end: 20px;
      inset-inline-start: 22px;
      width: 92px;
      height: 92px;
      color: #fff;
      background: transparent;
    }

    .why-card:nth-child(2) .why-media img {
      object-position: 50% 24%;
    }

    .why-ic::before {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      inset-block: 10px;
      width: 3px;
      background: var(--accent);
    }

    .why-ic i.ph {
      font-size: 3.25rem;
      filter: drop-shadow(0 2px 8px rgba(var(--image-overlay-rgb), .34));
    }

    .why-card:hover .why-ic i.ph {
      transform: translateY(-2px);
    }

    @media (max-width: 720px) {
      .hero-sectors-label {
        min-height: 50px;
        padding-inline: 18px;
        font-size: .98rem;
      }

      .projects-footer {
        grid-template-columns: 1fr;
        gap: 22px;
        min-height: 0;
        padding: 30px 28px 118px;
      }

      .projects-footer::after {
        width: 140px;
        inset-inline-start: -24px;
        inset-block-end: -44px;
      }

      .projects-footer-cta {
        width: fit-content;
      }

      .story-timeline {
        grid-auto-columns: min(84vw, 340px);
        margin-inline: -18px;
        padding-inline: 18px;
        scroll-padding-inline: 18px;
      }

      .story-item,
      .story-item:nth-child(odd),
      .story-item:nth-child(even) {
        min-height: 590px;
        grid-template-rows: 220px auto auto 1fr auto;
      }

      .story-image {
        height: 220px;
      }

      .story-year {
        padding: 24px 24px 4px;
      }

      .story-item h3 {
        padding-inline: 24px;
      }

      .story-item>p {
        padding-inline: 24px;
      }

      .story-achievement {
        padding-inline: 24px;
      }

      .why-ic {
        width: 72px;
        height: 72px;
        inset-block-end: 16px;
        inset-inline-start: 16px;
      }

      .why-ic i.ph {
        font-size: 2.6rem;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .why-card:hover .why-ic i.ph {
        transform: none;
      }
    }
    /* ===== Closing sections refinement, 2026-07-26 ===== */

    .news-card {
      grid-template-rows: auto 1fr;
      border: 0;
      border-radius: var(--r);
    }

    .news-card .img {
      block-size: clamp(220px, 22vw, 260px);
      aspect-ratio: auto;
      margin: 0;
    }

    .news-card:nth-child(1) img { object-position: 55% center; }
    .news-card:nth-child(2) img { object-position: center 38%; }
    .news-card:nth-child(3) img { object-position: center 42%; }


    .news-card h3 {
      min-height: 4.5em;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 3;
      overflow: hidden;
    }

    .news-card p {
      min-height: 3.6em;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow: hidden;
    }

    .news-card .more {
      gap: 9px;
      color: var(--accent-text);
      font-weight: 700;
    }

    .news-card .more i.ph {
      font-size: 1.15rem;
      line-height: 1;
      transition: transform var(--dur-base) var(--ease-out);
    }

    .news-card .more:hover i.ph,
    .news-card .more:focus-visible i.ph {
      transform: translate(-2px, -2px);
    }

    .news-category::before {
      content: "◈";
      margin-inline-end: 7px;
      color: var(--accent);
      font-size: .78rem;
    }

    .news-card .date::before {
      content: "◷";
      color: var(--icon);
      font-size: 1rem;
    }

    .news-subscribe {
      min-height: 0;
      padding: 20px 24px;
      grid-template-columns: minmax(240px, .85fr) minmax(340px, 1.15fr) 132px;
      gap: 22px;
    }

    .news-subscribe-copy {
      gap: 12px;
    }

    .news-subscribe-icon {
      inline-size: 40px;
    }

    .news-subscribe p {
      font-size: .9rem;
      line-height: 1.55;
    }

    .news-social {
      padding: 0;
      display: grid;
      grid-template-columns: repeat(3, 44px);
      gap: 6px 8px;
      justify-content: start;
      white-space: normal;
    }

    .news-social > span {
      grid-column: 1 / -1;
      font-size: .8rem;
      line-height: 1.2;
    }

    .news-social a {
      inline-size: 44px;
      min-block-size: 44px;
    }

    .cta {
      position: relative;
      isolation: isolate;
      overflow: hidden;
    }

    /* The old .cta::before here was a small faint logo watermark (opacity
       fading in to .085 on reveal), from before the section carried a real
       photo. ::before is now the full-cover photo layer declared further
       down (background: url(real-estate-v2.webp)) - that rule and this one
       shared the same selector and fought over `opacity`, and because
       ".cta:has(.reveal.in)::before" is more specific than plain
       ".cta::before" it was winning regardless of source order, so the
       photo was rendering at ~8.5% opacity (effectively invisible) no
       matter what opacity was set on the actual photo rule. Removed along
       with its matching @media (max-width:800px) and
       @media (prefers-reduced-motion) fragments below. */

    .cta .wrap,
    .cta-inner {
      position: relative;
      z-index: 1;
    }


    .cta-action {
      min-height: 202px;
      padding: 26px 22px;
      gap: 11px;
      border: 0;
    }

    .cta-action > span:not(.cta-action-note) {
      font-family: var(--font-display);
      font-size: clamp(1.12rem, 1.35vw, 1.28rem);
      line-height: 1.35;
      font-weight: 700;
    }

    .cta-action i.ph {
      inline-size: 64px;
      block-size: 58px;
      font-size: 2.5rem;
    }

    .foot-brand {
      min-width: 0;
    }

    .foot-brand .logo {
      display: block;
      inline-size: min(220px, 100%);
      max-inline-size: 100%;
      aspect-ratio: 360 / 92;
      margin-bottom: 20px;
    }

    .foot-brand .logo img {
      display: block;
      inline-size: 100%;
      block-size: 100%;
      max-inline-size: 100%;
      object-fit: contain;
      object-position: left center;
    }

    @media (max-width: 800px) {
      .news-subscribe {
        grid-template-columns: minmax(0, 1fr) minmax(280px, 1fr);
      }

      .news-social {
        grid-column: 1 / -1;
      }

    }

    @media (max-width: 560px) {

      .news-body {
        padding: 20px;
      }

      .news-card h3 {
        min-height: 4.5em;
      }

      .news-card p {
        min-height: 3.6em;
      }

      .news-subscribe {
        grid-template-columns: minmax(0, 1fr);
        padding: 20px;
        gap: 16px;
      }

      .news-social {
        grid-column: auto;
      }

      .news-subscribe-copy {
        grid-template-columns: 40px minmax(0, 1fr);
      }

      .news-form {
        flex-wrap: nowrap;
      }

      .news-form input {
        flex: 1 1 auto;
        flex-basis: auto;
      }

      .news-form button {
        flex: 0 0 auto;
        padding-inline: 18px;
      }

      .cta-action {
        min-height: 168px;
      }

      .cta-action i.ph {
        inline-size: 56px;
        block-size: 52px;
        font-size: 2.15rem;
      }

      .foot-brand .logo {
        inline-size: min(190px, 100%);
      }
    }

    /* ===== Hero responsive reconstruction, 2026-07-26 ===== */
    /* The progress rail uses the x-axis at every viewport. Its 44px controls
       keep touch and keyboard access while the visible track stays 3px thin. */
    .hero-content-row {
      flex-direction: column;
      gap: clamp(12px, 2vw, 18px);
    }

    .hero-slides-ind {
      order: -1;
      flex: 0 0 44px;
      inline-size: clamp(220px, 28vw, 320px);
      block-size: 44px;
      flex-direction: row;
      align-items: center;
      align-self: flex-start;
      gap: 8px;
    }

    .hero-slide-line {
      flex: 1 1 0;
      inline-size: auto;
      block-size: 44px;
      overflow: visible;
      background:
        linear-gradient(to bottom,
          transparent calc(50% - 1.5px),
          rgba(255, 255, 255, .28) calc(50% - 1.5px),
          rgba(255, 255, 255, .28) calc(50% + 1.5px),
          transparent calc(50% + 1.5px));
    }

    .hero-slide-line::before {
      inset-inline-start: 0;
      inset-inline-end: auto;
      inset-block-start: 50%;
      inline-size: 0;
      block-size: 3px;
      height: 3px;
      transform: translateY(-50%);
    }

    .hero-slide-line.done::before {
      inline-size: 100%;
      height: 3px;
    }

    .hero-slide-line.active::before {
      inline-size: 100%;
      height: 3px;
      transition: inline-size var(--hero-slide-duration, 5.2s) linear;
    }

    @media (max-width: 720px) {
      .hero {
        min-height: 660px;
      }

      .hero-content {
        inline-size: calc(100% - 24px);
        min-height: 100svh;
        padding-block: 88px 86px;
        padding-inline: 4px;
      }

      .hero-content-row {
        gap: 8px;
      }

      .hero-content-copy {
        text-align: left;
      }

      .hero-slides-ind {
        flex-basis: 44px;
        inline-size: 100%;
        gap: 6px;
      }

      .hero .eyebrow {
        margin-bottom: 10px;
        font-size: .78rem;
      }

      .hero h1 {
        max-inline-size: 100%;
        margin: 0 0 16px;
        font-size: clamp(1.9rem, 9.6vw, 2.6rem);
        line-height: 1.17;
      }

      .hero p {
        max-inline-size: 31ch;
        margin: 0;
        font-size: clamp(.92rem, 4.1vw, .98rem);
        line-height: 1.68;
      }

      .hero-actions {
        inline-size: 100%;
        margin-top: 22px;
        gap: 8px;
      }

      .hero-actions .btn {
        flex: 1 1 0;
        min-inline-size: 0;
        padding-inline: 10px;
      }

      .hero-sectors {
        margin-top: -56px;
        padding-block: 0 24px;
      }

      .scroll-hint {
        display: none;
      }

      .hero-sectors .wrap {
        inline-size: 100%;
        max-inline-size: none;
        padding-inline: 0;
      }

      .hero-sectors-label {
        min-height: 48px;
        padding-inline: 12px;
      }

      .sector-grid {
        display: grid;
        grid-auto-flow: row;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-auto-columns: auto;
        gap: 1px;
        overflow: visible;
        scroll-snap-type: none;
        scrollbar-width: none;
      }

      .sector-card {
        min-inline-size: 0;
        min-height: clamp(190px, 58vw, 224px);
        scroll-snap-align: none;
      }

      .sector-card:last-child:nth-child(odd) {
        grid-column: 1 / -1;
        min-height: 168px;
      }

      .sector-card-body {
        padding: 14px;
        padding-bottom: 56px;
      }

      .sector-card-title {
        font-size: clamp(.98rem, 5vw, 1.14rem);
      }

      .sector-card-sub {
        min-height: 3em;
        font-size: clamp(.74rem, 3.6vw, .84rem);
        line-height: 1.55;
      }

      .sector-card-mark {
        inline-size: 40px;
        block-size: 40px;
      }
    }

    @media (max-width: 360px) {
      .hero-content {
        inline-size: calc(100% - 20px);
        padding-inline: 4px;
      }

      .hero h1 {
        font-size: 2rem;
      }

      .hero p {
        font-size: .94rem;
      }

      .sector-card {
        min-height: 190px;
      }
    }
    /* ===== Mobile page guide + navigation drawer, 2026-07-26 ===== */
    :root {
      --page-gutter: 32px;
    }

    .menu-head {
      display: none;
    }

    @media (max-width: 720px) {
      :root {
        --page-gutter: clamp(14px, 4.6vw, 18px);
      }

      main > section > .wrap,
      footer > .wrap {
        padding-inline: var(--page-gutter);
      }

      /* Full-bleed media/grid exceptions keep their own internal guide. */
      .hero > .wrap {
        padding-inline: 4px;
      }

      .hero-sectors > .wrap {
        padding-inline: 0;
      }

      .hero-sectors-label {
        padding-inline: var(--page-gutter);
      }

      .impact-panel {
        padding-inline: 0;
      }

      .story-timeline {
        margin-inline: calc(-1 * var(--page-gutter));
        padding-inline: var(--page-gutter);
        scroll-padding-inline: var(--page-gutter);
      }
    }

    @media (max-width: 980px) {
      .sector-card.is-marquee-clone {
        display: none;
      }

      .sector-motion-toggle {
        display: none;
      }
       
    }

    /* English labels reach the header's content limit before the page layout
       reaches its tablet breakpoint. Reuse the same drawer through 1180px:
       this prevents the logo, language switcher, CTA, and long labels from
       competing for a single compressed row. */
    @media (max-width: 1280px) {
      .nav-cta,
      .nav-actions > .lang {
        display: none;
      }

      .burger {
        display: flex;
      }

      body.menu-open {
        overflow: hidden;
        overscroll-behavior: none;
      }

      .menu {
        display: flex;
        position: fixed;
        z-index: 1101;
        top: 0;
        right: 0;
        bottom: 0;
        left: auto;
        inline-size: min(88vw, 380px);
        block-size: 100dvh;
        padding: 16px var(--page-gutter) max(24px, env(safe-area-inset-bottom));
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
        background: var(--surface-raised);
        color: var(--ink);
        visibility: hidden;
        pointer-events: none;
        opacity: .98;
        transform: translateX(100%);
        transition:
          transform var(--dur-base) var(--ease-out),
          opacity var(--dur-base) var(--ease-out),
          visibility 0s linear var(--dur-base);
      }

      .menu::after {
        content: "";
        position: absolute;
        z-index: -1;
        inset-inline-end: 0;
        inset-block-end: 0;
        inline-size: 160px;
        aspect-ratio: var(--photo-mark-p43-ratio);
        background: var(--drawer-corner-art, url("../images/patterns/lines.svg?v=d874099296964b63")) right bottom / contain no-repeat;
        opacity: .055;
        pointer-events: none;
      }

      .menu.open {
        display: flex;
        top: 0;
        right: 0;
        bottom: 0;
        left: auto;
        padding: 16px var(--page-gutter) max(24px, env(safe-area-inset-bottom));
        align-items: stretch;
        gap: 0;
        visibility: visible;
        pointer-events: auto;
        opacity: 1;
        transform: translateX(0);
        transition-delay: 0s;
      }

      .menu-head {
        min-block-size: 64px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 14px;
        border-block-end: 1px solid var(--line);
      }

      .menu-logo {
        min-block-size: 44px;
        display: flex;
        align-items: center;
      }

      .menu-logo img {
        display: block;
        inline-size: min(152px, 52vw);
        block-size: auto;
      }

      .menu-logo::after,
      .menu > a:not(.menu-logo)::after {
        display: none;
      }

      .menu-close {
        position: relative;
        inline-size: 44px;
        block-size: 44px;
        flex: 0 0 44px;
        border: 1px solid var(--line);
        background: transparent;
        color: var(--ink);
        cursor: pointer;
      }

      .menu-close span {
        position: absolute;
        left: 50%;
        right: auto;
        top: 50%;
        inline-size: 22px;
        block-size: 2px;
        background: currentColor;
        transform-origin: center;
      }

      .menu-close span:first-child {
        transform: translate(-50%, -50%) rotate(45deg);
      }

      .menu-close span:last-child {
        transform: translate(-50%, -50%) rotate(-45deg);
      }

      .menu > a:not(.menu-logo) {
        position: relative;
        min-block-size: 54px;
        padding-inline: 4px 12px;
        display: flex;
        align-items: center;
        justify-content: flex-start;
        border-block-end: 1px solid var(--line);
        color: var(--ink);
        font-family: var(--font-display);
        font-size: 1.05rem;
        font-weight: 600;
        opacity: 0;
        transform: translateX(10px);
        transition:
          color 180ms var(--ease-out),
          background 180ms var(--ease-out),
          opacity 220ms var(--ease-out),
          transform 260ms var(--ease-out);
      }

      .menu.open > a:not(.menu-logo) {
        opacity: 1;
        transform: translateX(0);
      }

      .menu.open > a:nth-of-type(2) { transition-delay: 45ms; }
      .menu.open > a:nth-of-type(3) { transition-delay: 70ms; }
      .menu.open > a:nth-of-type(4) { transition-delay: 95ms; }
      .menu.open > a:nth-of-type(5) { transition-delay: 120ms; }
      .menu.open > a:nth-of-type(6) { transition-delay: 145ms; }
      .menu.open > a:nth-of-type(7) { transition-delay: 170ms; }
      .menu.open > a:nth-of-type(8) { transition-delay: 195ms; }
      .menu.open > a:nth-of-type(9) { transition-delay: 220ms; }

      .menu > a:not(.menu-logo):hover,
      .menu > a:not(.menu-logo):focus-visible,
      .menu > a:not(.menu-logo).active {
        background: var(--surface-sunken);
        color: var(--accent-text);
      }

      .menu > a:not(.menu-logo).active::before {
        content: "";
        position: absolute;
        inset-inline-start: 0;
        inline-size: 3px;
        block-size: 24px;
        background: var(--accent);
      }

      .menu.open .menu-mobile-actions {
        width: 100%;
        display: flex;
        flex-direction: column;
        margin-block-start: auto;
        padding-block-start: 14px;
        gap: 10px;
        border-block-start: 1px solid var(--line);
      }

      .menu.open .menu-lang {
        width: 100%;
        display: flex;
        align-items: center;
        min-height: 48px;
        padding-inline: 4px;
        justify-content: flex-start;
        gap: 10px;
        color: var(--ink);
        font-size: .95rem;
      }

      .menu.open .menu-lang::after {
        content: none;
      }

      .menu.open .menu-contact {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 52px;
        background: var(--accent-deep);
      }

      .menu-backdrop {
        display: block;
        z-index: 999;
        visibility: hidden;
        pointer-events: none;
        opacity: 0;
        background: rgba(var(--image-overlay-rgb), .44);
        backdrop-filter: blur(4px);
        transition:
          opacity 250ms var(--ease-out),
          visibility 0s linear 250ms;
      }

      body.menu-open .menu-backdrop {
        display: block;
        visibility: visible;
        pointer-events: auto;
        opacity: 1;
        transition-delay: 0s;
      }

      body.menu-open .scroll-top {
        z-index: 997;
      }

      .burger {
        position: relative;
        margin-inline-end: 0;
        border: 0;
        background: transparent;
      }

      .burger span {
        position: absolute;
        left: 50%;
        right: auto;
        inline-size: 24px;
        transition:
          transform var(--dur-base) var(--ease-out),
          opacity var(--dur-fast) var(--ease-out);
      }

      .burger span:nth-child(1) {
        transform: translate(-50%, -7px);
      }

      .burger span:nth-child(2) {
        transform: translate(-50%, 0);
      }

      .burger span:nth-child(3) {
        transform: translate(-50%, 7px);
      }

      .burger[aria-expanded="true"] span:nth-child(1) {
        transform: translate(-50%, 0) rotate(45deg);
      }

      .burger[aria-expanded="true"] span:nth-child(2) {
        opacity: 0;
        transform: translate(-50%, 0) scaleX(.2);
      }

      .burger[aria-expanded="true"] span:nth-child(3) {
        transform: translate(-50%, 0) rotate(-45deg);
      }

      body.menu-open .burger {
        opacity: 0;
        pointer-events: none;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .menu,
      .menu-backdrop,
      .menu > a:not(.menu-logo),
      .burger span {
        transition: none !important;
      }
    }
    /* 2026-07-26 content and identity revision */
    .btn-primary,
    .news-form button {
      background: var(--brand-sweihan);
      color: var(--brand-black);
    }

    .btn-primary:hover,
    .btn-primary:focus-visible,
    .news-form button:hover,
    .news-form button:focus-visible {
      background: var(--brand-al-khatim);
      color: var(--brand-black);
      box-shadow: none;
    }

    .method-en {
      display: block;
      color: var(--brand-jais);
      font-size: .78rem;
      font-weight: 700;
      text-transform: uppercase;
      margin-block: 14px 2px;
    }

    .about-figures .about-values-head p {
      max-width: 34ch;
      margin: 8px 0 0;
      color: var(--muted-on-dark);
      line-height: 1.6;
    }

    .verified-figure {
      display: block;
      direction: ltr;
      font-size: clamp(2rem, 3.8vw, 3.7rem);
      line-height: 1;
      color: var(--brand-black);
      font-weight: 500;
      margin-bottom: 12px;
      border-inline-start: 5px solid var(--brand-sweihan);
      padding-inline-start: 14px;
    }

    .value-sections {
      background: var(--surface-sunken);
      padding-block: var(--sec-pad);
    }

    .value-block + .value-block {
      margin-top: clamp(54px, 7vw, 96px);
    }

    .value-head {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(280px, .72fr);
      gap: clamp(24px, 5vw, 72px);
      align-items: end;
      margin-bottom: clamp(28px, 4vw, 48px);
    }

    .value-head .kicker {
      color: var(--brand-jais);
    }

    .value-head h2 {
      margin: 8px 0 0;
      font-size: clamp(2rem, 4vw, 4.4rem);
      line-height: 1.08;
    }

    .value-head p {
      margin: 0;
      color: var(--muted);
      font-size: 1.03rem;
      line-height: 1.8;
    }

    .companies-grid,
    .services-grid {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      background: var(--line);
      gap: 1px;
    }

    .company-card,
    .service-card {
      background: var(--surface-base);
      padding: clamp(24px, 3vw, 40px);
      min-height: 250px;
      position: relative;
      overflow: hidden;
    }

    .company-card::before {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      top: 0;
      width: 7px;
      height: 100%;
      background: var(--company-accent, var(--brand-sweihan));
    }

    .company-card .company-num,
    .service-card .service-num {
      color: var(--label);
      font-size: .8rem;
      direction: ltr;
      display: block;
      margin-bottom: 44px;
    }

    .company-card h3,
    .service-card h3 {
      font-size: clamp(1.45rem, 2vw, 2rem);
      margin: 0 0 12px;
    }

    .company-card p,
    .service-card p {
      color: var(--muted);
      margin: 0;
      line-height: 1.7;
    }

    .company-card a,
    .service-card a {
      color: var(--ink);
      display: inline-flex;
      gap: 8px;
      align-items: center;
      margin-top: 24px;
      font-weight: 700;
      min-height: 44px;
      padding-block: 10px;
    }


    .service-card .service-meta {
      color: var(--brand-jais);
      font-size: .8rem;
      font-weight: 700;
      margin-bottom: 10px;
    }

    .service-card a {
      margin-top: auto;
      padding-top: 24px;
    }

    .service-pending {
      margin-top: auto;
      padding-top: 24px;
      min-height: 44px;
      display: inline-flex;
      align-items: center;
      color: var(--label);
      font-size: .88rem;
    }

    .openings-panel {
      display: grid;
      grid-template-columns: minmax(220px, .65fr) minmax(0, 1.35fr);
      background: var(--brand-black);
      color: white;
    }

    .openings-intro {
      padding: clamp(28px, 4vw, 52px);
      background: var(--brand-sweihan);
      color: var(--brand-black);
    }

    .openings-intro i {
      font-size: 2rem;
    }

    .openings-intro h3 {
      font-size: clamp(1.7rem, 3vw, 2.8rem);
      margin: 28px 0 10px;
    }

    .openings-intro p {
      margin: 0;
      line-height: 1.7;
    }

    .opening-row {
      display: grid;
      grid-template-columns: 1.4fr .8fr .8fr;
      gap: 24px;
      align-items: center;
      padding: clamp(24px, 3vw, 36px);
    }

    .opening-row + .opening-row {
      border-top: 1px solid var(--line-on-dark);
    }

    .opening-row strong {
      font-size: 1.25rem;
    }

    .opening-row span,
    .opening-row time {
      color: var(--muted-on-dark);
    }

    .opening-status {
      color: var(--brand-razeen) !important;
      font-weight: 700;
    }

    .opening-announcement {
      display: grid;
      grid-template-columns: auto minmax(220px, 1fr) auto minmax(220px, .8fr);
      align-items: center;
      gap: 22px;
      padding: 22px 26px;
      margin-top: 28px;
      background: var(--brand-black);
      color: white;
    }

    .opening-announcement-icon {
      width: 52px;
      height: 52px;
      display: grid;
      place-items: center;
      background: var(--brand-sweihan);
      color: var(--brand-black);
      font-size: 1.45rem;
    }

    .opening-announcement .kicker,
    .opening-announcement time,
    .opening-announcement > span:last-child {
      color: var(--muted-on-dark);
    }

    .opening-announcement h3 {
      margin: 3px 0 0;
      font-size: 1.25rem;
    }

    @media (min-width: 981px) {
      .hero-sectors {
        overflow: hidden;
      }

      .hero-sectors .wrap {
        max-width: none;
        padding-inline: 0;
      }

      .hero-sectors-head {
        max-width: var(--max);
        margin-inline: auto;
        padding-inline: clamp(28px, 5vw, 72px);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 18px;
      }

      .sector-motion-toggle {
        min-width: 44px;
        min-height: 44px;
        display: inline-grid;
        place-items: center;
        background: transparent;
        color: var(--muted-on-dark);
        border: 0;
        cursor: pointer;
      }

      .sector-grid {
        display: flex;
        width: max-content;
        grid-template-columns: none;
        animation: sectors-marquee 38s linear infinite;
      }

      .sector-grid:hover,
      .sector-grid:focus-within,
      .sector-grid.is-paused {
        animation-play-state: paused;
      }

      .sector-card {
        flex: 0 0 clamp(240px, 20vw, 340px);
      }

      .sector-card-panel {
        display: grid;
        inset: 0;
        margin: 0;
        grid-template-columns: 1fr;
        background: rgba(var(--image-overlay-rgb), .88);
        color: white;
        transform: translateY(12px);
        z-index: 8;
      }

      .sector-card-panel-visual {
        position: absolute;
        inset: 0;
        min-height: 0;
        opacity: .18;
      }

      .sector-card-panel-copy {
        position: relative;
        z-index: 1;
        text-align: start;
        padding: 28px;
      }

      .sector-card-panel-copy h3,
      .sector-card-panel-copy p {
        color: white;
      }

      .sector-card-panel-link {
        color: var(--brand-razeen);
      }

      @keyframes sectors-marquee {
        from { transform: translateX(0); }
        to { transform: translateX(50%); }
      }

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

    @media (max-width: 980px) {
      .value-head {
        grid-template-columns: 1fr;
        align-items: start;
      }

      .companies-grid,
      .services-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }

      .openings-panel {
        grid-template-columns: 1fr;
      }

      .opening-announcement {
        grid-template-columns: auto 1fr;
      }

      .opening-announcement time,
      .opening-announcement > span:last-child {
        grid-column: 2;
      }
    }

    @media (max-width: 560px) {
      .companies-grid,
      .services-grid {
        grid-template-columns: 1fr;
      }

      .company-card,
      .service-card {
        min-height: 0;
        padding: 24px;
      }

      .companies-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }

      .company-card {
        padding: 18px;
      }

      /* NO CLAMP on the description (reserve, do not clamp - the token file
         rule, site owner 28 Aug 2026). The two-line webkit clamp that sat
         here never truncated in current browsers: the box grew with
         flex: 1 1 auto and a third line peeked past it. The four card
         descriptions were re-measured on 8 Sep 2026 to genuinely fit two
         lines at 360px, so there is nothing left to mask. */

      .company-card h3 {
        font-size: 1.25rem;
      }

      .service-card {
        display: grid;
        grid-template-columns: 46px minmax(0, 1fr) auto;
        grid-template-areas:
          "num meta action"
          "num title action"
          "num copy action";
        align-items: center;
        gap: 4px 12px;
        min-height: 132px;
      }

      .service-card .service-num {
        grid-area: num;
        margin: 0;
      }

      .service-card .service-meta {
        grid-area: meta;
        margin: 0;
      }

      .service-card h3 {
        grid-area: title;
        font-size: 1.18rem;
        margin: 0;
      }

      .service-card p {
        grid-area: copy;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        font-size: .9rem;
      }

      .service-card a {
        grid-area: action;
        margin: 0;
        padding: 10px;
        font-size: 0;
      }

      .service-card .service-pending {
        grid-area: action;
        margin: 0;
        padding: 8px;
        max-width: 78px;
        font-size: .72rem;
      }

      .service-card a i {
        font-size: 1.25rem;
      }

      .company-card .company-num,
      .service-card .service-num {
        margin-bottom: 24px;
      }

      .opening-row {
        grid-template-columns: 1fr;
        gap: 8px;
      }
    }

    .partner-logo.schneider,
    .partner-logo.abb,
    .partner-logo.honeywell {
      color: var(--brand-black);
    }

    .investment-rail {
      max-width: var(--max);
      margin: 0 auto;
      padding: 0 clamp(28px, 5vw, 72px) 28px;
    }

    .investment-rail .sector-card {
      min-height: 150px;
      display: grid;
      grid-template-columns: auto minmax(0, 1fr) auto;
      align-items: center;
      gap: 24px;
      background: var(--brand-black);
      color: white;
      padding: 28px;
    }

    .investment-rail .sector-card-media,
    .investment-rail .sector-card-panel {
      display: none;
    }

    .investment-rail .sector-card-body {
      display: contents;
    }

    .investment-rail .sector-card-title,
    .investment-rail .sector-card-sub {
      color: white;
    }

    .investment-rail .sector-card-action {
      color: var(--brand-razeen);
    }

    @media (max-width: 980px) {
      .investment-rail {
        padding-inline: var(--page-gutter, 16px);
      }

      .investment-rail .sector-card {
        grid-template-columns: 1fr;
        gap: 8px;
      }
    }
    /* ===== Hero / sector integration, visual QA pass =====
       The sectors are intentionally part of the hero on wide screens. The
       former marquee was visually busy, made the sector order unstable and
       hid the interaction. A fixed high-contrast grid now uses the original
       card-overlay pattern: the detail panel is revealed on hover and focus. */
    .hero {
      isolation: isolate;
      min-height: max(760px, 100svh);
      padding-bottom: clamp(236px, 23vw, 320px);
    }

    .hero::after {
      z-index: 0;
      background: linear-gradient(180deg,
        rgba(0, 0, 0, .48) 0%,
        rgba(0, 0, 0, .17) 24%,
        rgba(0, 0, 0, .30) 55%,
        rgba(0, 0, 0, .80) 100%);
    }

    .hero-content,
    .scroll-hint,
    .hero-sectors { z-index: 2; }

    .hero-content {
      min-height: max(560px, 100svh - clamp(236px, 23vw, 320px));
      padding-block: 120px 38px;
    }

    .hero-content::after { display: none; }

    .hero-content-row { gap: 18px; }


    .hero h1 .em {
      display: inline-flex;
      align-items: center;
      vertical-align: middle;
      line-height: 1;
      padding: .13em .18em .17em;
      margin-inline: .07em;
      transform: translateY(-.015em);
    }

    .hero-slides-ind .hero-slide-line {
      isolation: isolate;
    }

    .hero-slides-ind .hero-slide-line.active::before {
      animation: heroProgress var(--hero-slide-duration, 5.2s) linear both;
      transition: none;
    }

    @keyframes heroProgress {
      from { inline-size: 0; }
      to { inline-size: 100%; }
    }

    .hero-sectors {
      position: absolute;
      inset-inline: 0;
      inset-block-end: 0;
      width: 100%;
      padding: 0;
      background: linear-gradient(180deg, rgba(0,0,0,0), rgba(0,0,0,.78) 30%, rgba(0,0,0,.93));
    }

    .hero-sectors .wrap { max-width: none; padding-inline: 0; }

    .hero-sectors-head {
      width: min(100%, var(--max));
      min-height: 42px;
      margin-inline: auto;
      padding-inline: clamp(24px, 5vw, 80px);
      display: flex;
      align-items: end;
    }

    .hero-sectors-label {
      margin: 0 0 9px;
      color: #fff;
      font-size: .9rem;
      letter-spacing: 0;
    }

    .sector-grid {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      width: 100%;
      gap: 1px;
      overflow: visible;
      background: rgba(255,255,255,.22);
      animation: none !important;
      transform: none !important;
    }

    .sector-card,
    .sector-card.is-marquee-clone {
      display: block;
      min-width: 0;
      min-height: clamp(184px, 17vw, 238px);
      margin: 0;
      outline: none;
    }

    .sector-card.is-marquee-clone { display: none; }

    .sector-card-body {
      z-index: 3;
      padding: clamp(18px, 2.1vw, 30px);
      background: linear-gradient(180deg, rgba(0,0,0,.12), rgba(0,0,0,.78));
    }

    .sector-card-title,
    .sector-card-sub { color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.66); }
    .sector-card-sub { min-height: 0; opacity: .94; }
    .sector-card-mark { background: rgba(0,0,0,.64); color: #fff; }
    .sector-card-action { min-height: 44px; color: #fff; }

    .sector-card-panel {
      display: grid;
      grid-template-columns: 1fr;
      inset: 0;
      margin: 0;
      z-index: 6;
      opacity: 0;
      pointer-events: none;
      transform: translateY(8px);
      background: rgba(0, 0, 0, .92);
      transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .sector-card:hover .sector-card-panel,
    .sector-card:focus .sector-card-panel,
    .sector-card:focus-within .sector-card-panel {
      opacity: 1;
      transform: none;
      pointer-events: auto;
    }

    .sector-card-panel-visual { opacity: .16; }
    .sector-card-panel-copy { padding: clamp(18px, 2.1vw, 30px); }
    .sector-card-panel-copy h3,
    .sector-card-panel-copy p { color: #fff; }
    .sector-card-panel-link { min-height: 44px; color: var(--brand-razeen); }

    .investment-rail {
      display: none;
    }

    .sector-card:focus-visible { outline: 3px solid var(--brand-razeen); outline-offset: -3px; }

    @media (max-width: 980px) {
      .hero {
        height: auto;
        min-height: auto;
        overflow: visible;
        padding-bottom: 0;
      }
      .hero-content { min-height: 100svh; }
      .hero-sectors { position: relative; background: var(--surface-inverse); }
      .hero-sectors-head { padding-inline: var(--page-gutter); align-items: center; }
      .sector-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .sector-card { min-height: clamp(190px, 46vw, 242px); }
    }

    @media (max-width: 560px) {
      .hero-content { padding-block: 96px 54px; }
      .hero h1 .em { padding: .14em .16em .18em; margin-inline: .04em; }
      .hero-sectors-head { min-height: 44px; }
      .sector-grid { gap: 1px; }
      .sector-card { min-height: 196px; }
      .sector-card-body,
      .sector-card-panel-copy { padding: 15px; }
      .sector-card-title { font-size: 1rem; }
      .sector-card-sub { font-size: .78rem; line-height: 1.45; }
      .sector-card-mark { inline-size: 38px; block-size: 38px; }
      .sector-card:last-child:nth-child(odd) { grid-column: auto; }
    }

    @media (prefers-reduced-motion: reduce) {
      .hero-slides-ind .hero-slide-line.active::before { animation: none; inline-size: 100%; }
    }

    /* ===== About / evidence / methodology refinement ===== */
    .about-copy {
      display: block;
      max-width: 62ch;
      padding: 0;
    }

    .about-copy p,
    .about-copy p:first-child,
    .about-copy p:nth-child(3) {
      display: block;
      margin: 0;
      padding: 0;
      border: 0;
      color: var(--ink);
      font-family: inherit;
      font-size: clamp(1.08rem, 1.3vw, 1.3rem);
      font-weight: 400;
      line-height: 1.9;
    }

    .about-pillars {
      border-block: 0;
    }

    .about-badge > i.ph {
      display: none;
    }

    .about-badge::before {
      content: "";
      position: absolute;
      inset-block-start: 18px;
      inset-inline-end: 18px;
      inline-size: clamp(96px, 10vw, 148px);
      aspect-ratio: 1;
      background: url("../images/brand/sdeira-mark.png?v=c1949ae876afaeca") center / contain no-repeat;
      opacity: .16;
      transform: rotate(-10deg);
      pointer-events: none;
    }


    .process-head .process-kicker,
    .process-head h2,
    .process-head p {
      display: block;
      margin-inline: 0;
      padding: 0;
      border: 0;
    }

    .process-head h2 { margin-bottom: 18px; }

    .impact-card-unverified { display: none; }

    .impact-footer { display: none; }

    .impact-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    @media (max-width: 640px) {
      .impact-grid { grid-template-columns: 1fr; }
    }

    /* Governmental process register: a single, readable sequence instead of a
       bento composition. Every stage uses the same restrained surface. */
    .process-flow {
      display: flex;
      flex-direction: column;
      gap: 0;
      background: var(--surface-base);
      overflow: visible;
    }

    .process-step {
      display: flex;
      gap: clamp(16px, 3vw, 42px);
      align-items: center;
      min-height: 128px;
      padding: 24px clamp(22px, 4vw, 52px);
      background: var(--surface-raised);
      color: var(--ink);
      text-align: left;
      border: 0;
      border-block-end: 1px solid var(--surface-sunken-strong);
    }

    .process-step:last-child { border-block-end: 0; }
    .process-step:hover { background: var(--surface-raised); }
    .process-step .process-num { flex: 0 0 84px; font-size: clamp(2.1rem, 4vw, 3.5rem); color: var(--brand-razeen); opacity: .78; }
    .process-step .process-icon { flex: 0 0 48px; width: 48px; height: 48px; margin: 0; background: var(--icon-wash); color: var(--brand-black); }
    .process-step h3 { flex: 0 1 240px; margin: 0; font-size: clamp(1.25rem, 1.8vw, 1.55rem); }
    .process-step p { flex: 1 1 360px; max-width: 48ch; margin: 0; color: var(--muted); font-size: 1rem; line-height: 1.75; }

    .projects-footer {
      background: var(--brand-black);
    }

    .projects-footer h3 { color: var(--brand-white); }
    .projects-footer p { color: var(--muted-on-dark); }
    .projects-footer-mark { color: var(--brand-razeen); }

    /* .projects-head's own margin-bottom (54px / 34px on tablet, set where
       .projects-head is defined) was tuned for a plain paragraph ending in
       flowing text. With the filter pills now the last element in that
       head, the same margin plus the pill row's own line-height read as an
       oversized empty band before the cards - a pill row carries far less
       visual weight per pixel than text, so it needs less breathing room
       after it, not the same amount. Tightened only for this section. */
    .projects-head:has(.project-filters) {
      margin-bottom: 28px;
    }

    /* Projects and news use one filter-tab component. The container is the
       white surface; individual tabs have no visible borders, and the orange
       fill is the only selected-state signal.

       ONE LINE, ALWAYS (site owner, 8 Sep 2026): the strip never wraps to a
       second row; when the labels outgrow it, it scrolls sideways instead.
       This is the same answer the sub-page tab strip (.news-tabs in
       sdeira-subpage.css) already gives, and that file's parity note runs
       both ways - one component, one behaviour. The tabs' focus ring goes
       inset for the reason theirs did: an outward ring on the first or last
       tab is clipped by the scroller. */
    :is(.project-filters, .news-filters) {
      display: inline-flex;
      flex-wrap: nowrap;
      gap: 4px;
      width: fit-content;
      min-inline-size: 0;
      max-inline-size: 100%;
      padding: 4px;
      border: 0;
      border-radius: var(--r);
      background: var(--surface-raised);
      overflow-x: auto;
      overscroll-behavior-inline: contain;
      scrollbar-width: none;
    }

    :is(.project-filters, .news-filters)::-webkit-scrollbar {
      display: none;
    }

    :is(.project-filter, .news-filter) {
      flex: none;
      white-space: nowrap;
      border: 0;
      background: var(--surface-raised);
      color: var(--brand-jais);
      padding: 10px 22px;
      border-radius: var(--r);
      font-size: .92rem;
      font-weight: 700;
      cursor: pointer;
      transition: background-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

    :is(.project-filter, .news-filter):hover {
      background: var(--surface-raised);
      color: var(--brand-black);
    }

    :is(.project-filter, .news-filter).is-active {
      background: var(--accent);
      color: var(--brand-white);
    }

    :is(.project-filter, .news-filter):focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: -2px;
    }

    .project-card.is-filtered-out {
      display: none;
    }

    /* Projects read as an editorial sequence, not a repeated card grid: one
       lead community, a photographic interlude, then two equal records. */
    .featured-projects .project-cards {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: clamp(16px, 2vw, 28px);
      background: transparent;
      overflow: visible;
      border-radius: var(--r);
    }

    /* height:auto overrides the generic .project-card { height: 100% } from
       the "REVIEW PASS" rules earlier in the cascade. That 100% was resolving
       against the outer grid's default row stretch, which fed all the way
       down through this card's own auto body row and into the flex-grow:1
       paragraph -- padding a two-line description out to four line-heights
       of empty space. Auto lets each card size to its own real content. */
    .featured-projects .project-card {
      height: auto;
      min-height: 0;
      grid-template-rows: clamp(230px, 25vw, 350px) auto;
      background: var(--surface-base);
    }

    /* The system already answers "how much space between a card's title,
       description, meta row and action link": .news-item-body in
       sdeira-subpage.css (the same stack, on the canonical .project-card-base
       component) uses flex gap: 10px, not per-child margins. This card never
       picked that up - .project-type/h3 carry their own margin-bottom and
       .project-card-action its own margin-top, and nothing at all sits
       between the description and the meta row, which is why the meta row
       read as glued to the paragraph above it. Adopting the same 10px gap
       here and dropping the now-redundant margins so they cannot compound
       with it. Site owner flagged, 12 Aug 2026 (ported from the Arabic
       fix). */
    .featured-projects .project-card-body {
      gap: 10px;
    }
    .featured-projects :is(.project-type, .project-card h3) {
      margin-bottom: 0;
    }
    .featured-projects .project-card-action {
      margin-top: 0;
    }

    .project-card--feature {
      grid-column: 1 / -1;
      position: relative;
      min-height: clamp(460px, 52vw, 650px) !important;
      overflow: hidden;
      background: var(--brand-black) !important;
    }

    .project-card--feature .project-card-img {
      position: absolute;
      inset: 0;
      height: auto;
    }

    .project-card--feature .project-card-img::after {
      content: "";
      position: absolute;
      inset: 0;
      /* This page is LTR, so the copy sits at the left reading edge - the
         strongest contrast begins there and releases toward the image on
         the right (mirrored from the RTL version's 270deg). */
      background: linear-gradient(90deg, rgba(var(--image-overlay-rgb), .74), rgba(var(--image-overlay-rgb), .20) 68%, rgba(var(--image-overlay-rgb), .48));
      pointer-events: none;
    }

    .project-card--feature .project-card-img img {
      object-position: center 54%;
      transform: scale(1);
      transform-origin: center;
    }

    .project-card--feature:is(:hover, :focus-within) .project-card-img img {
      transform: scale(var(--zoom));
    }

    .project-card--feature .project-card-body {
      position: absolute;
      z-index: 2;
      inset: auto clamp(24px, 5vw, 72px) clamp(28px, 5vw, 70px);
      max-width: min(620px, 62%);
      min-height: 0;
      padding: 0;
      background: transparent;
      color: var(--brand-white);
    }

    .project-card--feature :is(.project-type, h3, p, .project-meta) { color: var(--brand-white); }
    .project-card--feature h3 { font-size: clamp(2.1rem, 4.3vw, 4.4rem); line-height: 1.04; }
    .project-card--feature p { max-width: 52ch; }
    .project-card--feature .project-meta { margin-top: 24px; padding-top: 16px; border-top: 1px solid rgba(255, 255, 255, .46); }

    /* Per-project action, reusing the .action-link underline-grow motion. The
       destination (map vs. an internal project page) isn't decided yet, so
       this ships as a visible but inert placeholder rather than a link to
       nowhere.
       .project-card-body picks up display:flex/flex-direction:column further
       down the cascade (the "REVIEW PASS" rule), which stretches every direct
       child full width by default -- including this one, which is why the
       underline was running the full card width instead of hugging the text.
       align-self + width:fit-content opt this element back out of the stretch. */
    .project-card-action {
      margin-top: 18px;
      font-size: .88rem;
      align-self: flex-start;
      width: fit-content;
      transition: color var(--dur-fast) var(--ease-out);
    }

    .project-card-action i.ph {
      color: currentColor;
      font-size: .95rem;
    }

    .project-card-action.is-pending {
      color: var(--label);
      cursor: pointer;
    }

    .project-card-action.is-pending::after { opacity: .35; }
    .project-card--feature .project-card-action.is-pending { color: rgba(255, 255, 255, .82); }

    /* Every card has a real action link and the whole-card click handler, so
       every card exposes the same pointer affordance before and after the
       script adds its enhancement class. */
    .featured-projects .project-card,
    .project-card.is-clickable {
      cursor: pointer;
    }

    /* The grid owns all spacing. Supporting cards do not add a second margin
       or a divider on top of the shared gap. */
    .project-card--secondary {
      border: 0;
      margin-top: 0;
    }
    .project-card--secondary .project-card-img { min-height: clamp(240px, 27vw, 370px); }
    /* Same family of runaway-height bug the comment above .featured-projects
       .project-card already fixed once, recurring one level deeper. That fix
       only reset the CARD's own height:100%; .project-card-body still
       inherits min-height:100% from the generic rule, and .project-card p
       still inherits flex:1 1 auto from it too. Measured effect (Arabic
       page): with min-height:100% in place the body/paragraph pair renders a
       two-line description at ~450px tall regardless of text-wrap:balance.
       min-height: 0 removes the inherited percentage and the inflation
       stops. Site owner flagged, 12 Aug 2026 (ported from the Arabic fix). */
    .project-card--secondary .project-card-body {
      min-height: 0;
      background: var(--surface-sunken);
    }

    .project-card--secondary .project-card-action {
      color: var(--brand-black);
      font-weight: 700;
    }

    /* Tone-step feedback for the now whole-card-clickable secondary cards,
       same vocabulary as every other hover state in the system: one step
       darker, no new colour. */
    /* Two ragged lines (one long, one short trailing word) read as an
       accident. Balancing keeps every description's line lengths even. */
    .featured-projects .project-card p {
      text-wrap: balance;
    }

    @media (max-width: 760px) {
      .featured-projects .project-cards { grid-template-columns: 1fr; gap: 28px; }
      .project-card--feature { min-height: 560px !important; }
      .project-card--feature .project-card-body { max-width: none; inset-inline: 22px; bottom: 28px; }
      .project-card--feature h3 { font-size: clamp(2rem, 10vw, 3rem); }
      .project-card--secondary { border-inline-start: 0; border-block-start: 1px solid var(--surface-sunken-strong); margin-top: 0; }
    }

    @media (max-width: 720px) {
      .process-step {
        flex-wrap: wrap;
        align-items: start;
        gap: 8px 14px;
        min-height: 0;
        padding: 24px 18px;
      }
      .process-step .process-num { flex-basis: 52px; font-size: 2rem; }
      .process-step h3 { flex-basis: calc(100% - 66px); }
      .process-step p { flex-basis: calc(100% - 66px); margin-inline-start: 66px; }
    }

    /* Story: restore the original concise five-column chronology. */
    .story {
      background: linear-gradient(180deg, var(--surface-sunken) 0%, var(--surface-base) 100%);
    }

    .story-timeline {
      position: relative;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      grid-template-rows: none;
      grid-auto-flow: row;
      grid-auto-columns: auto;
      gap: 0;
      margin: 0;
      padding: 50px 0 0;
      overflow: visible;
      direction: rtl;
      background: transparent;
      scrollbar-width: auto;
    }

    .story-timeline::before {
      content: "";
      position: absolute;
      inset-block-start: 16px;
      inset-inline: 5%;
      inline-size: auto;
      block-size: 2px;
      transform: none;
      background: linear-gradient(90deg, transparent, var(--brand-razeen), transparent);
    }

    .story-item,
    .story-item:nth-child(odd),
    .story-item:nth-child(even) {
      grid-column: auto;
      grid-row: auto;
      display: flex;
      flex-direction: column;
      align-items: stretch;
      width: auto;
      min-width: 0;
      margin: 0;
      padding: 0 18px;
      text-align: center;
      direction: rtl;
      background: transparent;
      border: 0;
      border-inline-start: 1px solid color-mix(in srgb, var(--brand-black) 12%, transparent);
      box-shadow: none;
      transform: none;
    }

    .story-item:first-child { border-inline-start: 0; }

    .story-dot {
      position: absolute;
      inset-block-start: -43px;
      inset-inline-start: 0;
      inset-inline-end: auto;
      transform: translateX(-50%);
    }

    .story-year {
      min-height: 3.5em;
      margin: 0 0 24px;
      color: var(--brand-sweihan);
    }

    .story-item > p { min-height: 96px; }

    .story-image {
      margin-top: 28px;
      aspect-ratio: 4 / 3;
    }

    .story-achievement {
      margin-top: 22px;
      padding-top: 18px;
    }


    .why-footer a.btn.btn-primary:hover {
      background: var(--brand-sweihan);
      color: var(--brand-black);
    }

    @media (max-width: 900px) {
      .story-timeline {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 34px 0;
        padding-top: 0;
      }

      .story-timeline::before,
      .story-dot { display: none; }

      .story-item,
      .story-item:nth-child(odd),
      .story-item:nth-child(even) {
        padding: 0 14px;
        border-inline-start: 0;
      }

      .story-item > p { min-height: 0; }
    }

    @media (max-width: 560px) {
      .story-timeline { grid-template-columns: 1fr; gap: 30px; }
      .story-item, .story-item:nth-child(odd), .story-item:nth-child(even) { padding: 0; }
    }

    /* Subsidiaries and services: distinct editorial lists, not joined card grids. */
    .value-head {
      display: block;
      max-width: 760px;
      margin-bottom: clamp(28px, 4vw, 44px);
    }

    .value-head h2 { max-width: 14ch; }
    .value-head p {
      max-width: 58ch;
      margin: 16px 0 0;
      font-size: 1.04rem;
    }

    .companies-grid {
      display: flex;
      flex-wrap: wrap;
      gap: 16px;
      background: transparent;
    }

    .company-card {
      flex: 1 1 230px;
      min-height: 270px;
      padding: clamp(26px, 3vw, 38px);
      background: var(--surface-base);
      border-block: 1px solid var(--surface-sunken-strong);
      border-inline-start: 0;
      box-shadow: none;
    }

    .company-card::before {
      inset-inline-start: auto;
      inset-inline-end: 0;
      width: 4px;
    }

    .company-card .company-num {
      margin-bottom: 34px;
      color: var(--brand-jais);
      font-weight: 700;
    }

    .company-card a {
      color: var(--brand-black);
      margin-top: 18px;
    }

    .services-grid {
      display: flex;
      flex-direction: column;
      gap: 14px;
      background: transparent;
    }

    .service-card {
      display: flex;
      flex-direction: row;
      align-items: center;
      gap: clamp(18px, 3vw, 42px);
      min-height: 0;
      padding: 24px clamp(24px, 4vw, 48px);
      background: var(--surface-base);
      border-inline: 0;
      border-block: 1px solid var(--surface-sunken-strong);
    }

    .service-card .service-num {
      flex: 0 0 42px;
      margin: 0;
      color: var(--brand-jais);
      font-weight: 700;
    }

    .service-card .service-meta {
      flex: 0 1 190px;
      margin: 0;
      color: var(--brand-jais);
    }

    .service-card h3 {
      flex: 0 1 280px;
      margin: 0;
      font-size: clamp(1.2rem, 2vw, 1.55rem);
    }

    .service-card p {
      flex: 1 1 340px;
      margin: 0;
      max-width: 42ch;
    }

    .service-card a,
    .service-pending {
      flex: 0 0 auto;
      margin: 0;
      padding: 0;
      color: var(--brand-black);
      white-space: nowrap;
    }

    .openings-block { margin-top: clamp(54px, 7vw, 96px); }
    .openings-block .value-head h2 { max-width: none; }
    .openings-panel { border-block: 1px solid var(--surface-sunken-strong); }
    .openings-intro { background: var(--surface-raised); }
    .opening-row { grid-template-columns: 1.2fr 1fr auto; }
    .opening-row .opening-status { grid-column: 2 / -1; color: var(--brand-razeen) !important; }

    /* Partner introduction: a restrained reading measure instead of one long line. */
    .partners-head p {
      max-width: 62ch;
      margin: 16px auto 0;
      text-wrap: balance;
    }

    /* News: the latest item runs full-width as a horizontal feature, the two
       older ones share a row underneath - same "one lead, two secondary"
       rhythm as the projects section. auto-fit with a real minimum (not a
       fixed max-width:680px breakpoint) so the two secondary cards drop to
       one per row as soon as a column would get too narrow to hold a title
       without breaking mid-word - that happened at tablet widths the old
       single breakpoint never covered, only phone widths below 680px. */
    .news-grid {
      --news-media-height: clamp(260px, 26vw, 380px);
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
      gap: 18px;
      background: transparent;
    }

    /* News reuses the project filter-tab component defined above. Its
       section row owns the spacing, so no component-specific margin is
       needed here. */
    .news-filters {
      margin: 0;
    }

    /* .news-grid.is-filtered-view .news-card--feature (three classes) sets
       display: block to strip the feature card's grid layout for a narrowed
       result, and that is more specific than this two-class rule, so when the
       lead news card itself is the one filtered out, its own
       demotion-to-block-layout rule outranked its own hidden state and it
       kept rendering. The demotion block already reaches for !important for
       the same "this state must win" reason; matching that local convention.
       Site owner flagged, 12 Aug 2026 (ported from the Arabic fix). */
    .news-card.is-filtered-out {
      display: none !important;
    }

    /* News copy always sits on a clean white surface, independent of the
       photo above or beside it. */
    .news-card {
      background: var(--surface-raised);
      border: 0;
      border-radius: var(--r);
      cursor: pointer;
      transition: background-color var(--dur-base) var(--ease-out);
    }

    .news-card:hover,
    .news-card:focus-within {
      background: var(--surface-raised);
    }

    .news-card--feature {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
      align-items: stretch;
      order: -1;
    }

    .news-card--feature .news-image-link {
      height: 100%;
    }

    .news-card--feature .img {
      block-size: 100%;
      min-height: clamp(260px, 26vw, 380px);
    }

    .news-card--feature .news-body {
      justify-content: center;
    }

    .news-card--feature h3 {
      font-size: clamp(1.35rem, 2vw, 1.85rem);
      -webkit-line-clamp: 3;
    }

    /* Fixed container height and object-fit:cover keep every photo the same
       visible size regardless of its own source dimensions - the mismatch
       was in framing, not in the box, so this is the ceiling on that. */
    .news-card .img,
    .news-card--feature .img {
      block-size: var(--news-media-height);
      min-height: 0;
      aspect-ratio: auto;
      background: var(--brand-black);
    }

    .news-card img { object-fit: cover; }
    .news-body { min-height: 0; padding: 22px 24px 20px; }

    /* font-weight above 400 has no visual effect here: only the Regular
       DIN Next LT Arabic file is licensed, and every other weight slot
       (500-800) intentionally points at that same file to block browser-
       synthesized bold, which distorts Arabic letter joins - see the
       @font-face comment in sdeira-tokens.css. The title has to read as a
       title through size and colour instead, not weight, until a licensed
       Bold file exists. */
    /* Reserve the space for the max line count every card is allowed, so a
       one-line title/description doesn't leave the "read more" link
       floating at a different height card to card - that gap was the bug.
       The clamp is also cut down (title 2 lines, description 1) so the
       reserved block stays compact instead of ballooning the card. */
    .news-card h3 {
      min-height: 2.8em;
      margin-top: 14px;
      color: var(--brand-black);
      font-size: clamp(1.2rem, 1.7vw, 1.5rem);
      line-height: 1.4;
      text-wrap: balance;
      -webkit-line-clamp: 2;
    }
    .news-card p {
      min-height: 1.7em;
      margin-top: 10px;
      font-size: .96rem;
      line-height: 1.7;
      -webkit-line-clamp: 1;
    }

    /* Reuse the site's underline-grow action link instead of a plain text
       link, matching the projects and subsidiary-company cards. */
    .news-card .more {
      margin-top: 16px;
      color: var(--brand-black);
      font-weight: 700;
    }

    .news-card .more i.ph {
      color: currentColor;
    }

    @media (max-width: 860px) {
      .news-card--feature {
        grid-template-columns: minmax(0, 1fr);
      }

      .news-card--feature .img {
        min-height: 220px;
      }
    }

    @media (max-width: 680px) {
      /* .news-grid's own auto-fit already collapses to one column here -
         only the feature card's explicit full-span needs resetting since
         there's nothing to span across anymore. */
      .news-card--feature {
        grid-column: auto;
      }
    }

    @media (max-width: 860px) {
      .company-card { flex-basis: calc(50% - 8px); }
      .service-card { flex-wrap: wrap; gap: 10px 18px; }
      .service-card .service-meta { flex-basis: calc(100% - 60px); }
      .service-card h3 { flex-basis: calc(100% - 60px); margin-inline-start: 60px; }
      .service-card p { flex-basis: calc(100% - 60px); margin-inline-start: 60px; }
      .service-card a, .service-pending { margin-inline-start: 60px; }
    }

    @media (max-width: 560px) {
      .company-card { flex-basis: 100%; min-height: 0; }
      .service-card { padding: 22px; }
      .service-card h3, .service-card p, .service-card a, .service-pending { margin-inline-start: 0; flex-basis: 100%; }
      .opening-row { grid-template-columns: 1fr; }
      .opening-row .opening-status { grid-column: auto; }
      .news-grid { --news-media-height: 210px; }
    }

    /* Contact states and newsletter: one clear action in each place. Colour
       stays fixed - the only hover feedback is the diagonal wipe defined
       further down, tinted with the card's own icon colour. */

    .news-subscribe {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: clamp(20px, 5vw, 76px);
      grid-template-columns: none;
      padding: clamp(24px, 3vw, 36px);
    }

    .news-subscribe-copy { display: block; }
    .news-subscribe-copy h3 { margin: 0; }
    .news-subscribe-copy p { max-width: 46ch; margin: 8px 0 0; }
    .news-form { flex: 1 1 380px; max-width: 520px; }
    .news-social { display: none; }

    @media (max-width: 680px) {
      .news-subscribe { align-items: stretch; flex-direction: column; gap: 18px; }
      .news-form { max-width: none; width: 100%; }
    }

    /* The full five-part group model: four operating sectors plus investment. */
    @media (min-width: 981px) {
      .sector-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    }

    .sector-card,
    .sector-card:hover,
    .sector-card:focus-within {
      transform: none;
      box-shadow: none;
    }

    .sector-card .sector-card-img,
    .sector-card:hover .sector-card-img,
    .sector-card:focus-within .sector-card-img {
      transform: none;
      filter: saturate(.9) brightness(.9);
    }

    .sector-card .sector-card-media::after {
      opacity: 0;
      background: rgba(0, 0, 0, .16);
    }

    .sector-card:hover .sector-card-media::after,
    .sector-card:focus-within .sector-card-media::after { opacity: 1; }

    .sector-card:hover .sector-card-veil,
    .sector-card:focus-within .sector-card-veil { opacity: .86; }

    .sector-card:hover .sector-card-title,
    .sector-card:focus-within .sector-card-title,
    .sector-card:hover .sector-card-sub,
    .sector-card:focus-within .sector-card-sub { color: var(--brand-white); }

    /* ===== GROUP SITE FEATURE =====
       Restores the useful part of the original hero-sector panel: a real
       group-company destination and its website preview. It is now a stable
       feature above the five-sector strip, rather than a transient layer that
       covered a card and disappeared before it could be read. */
    .sector-feature {
      width: min(calc(100% - clamp(32px, 7vw, 112px)), var(--max));
      margin: 0 auto clamp(14px, 2vw, 24px);
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      min-height: clamp(214px, 18vw, 280px);
      background: var(--surface-base);
      color: var(--brand-black);
      overflow: hidden;
    }

    .sector-feature-copy {
      position: relative;
      padding: clamp(28px, 4vw, 54px);
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      gap: 12px;
    }

    .sector-feature-copy::after {
      content: "";
      position: absolute;
      inset-inline-end: clamp(24px, 4vw, 58px);
      inset-block-end: -34px;
      width: 118px;
      height: 118px;
      background: url("../images/brand/sdeira-mark.png?v=c1949ae876afaeca") center / contain no-repeat;
      opacity: .07;
      pointer-events: none;
    }

    .sector-feature-kicker {
      color: var(--brand-liwa);
      font-size: .82rem;
      font-weight: 700;
    }

    .sector-feature h2 {
      margin: 0;
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: clamp(1.65rem, 2.6vw, 2.45rem);
      line-height: 1.15;
    }

    .sector-feature p {
      max-width: 53ch;
      margin: 0;
      color: var(--brand-jais);
      font-size: clamp(.98rem, 1.2vw, 1.1rem);
      line-height: 1.8;
    }

    .sector-feature-link {
      position: relative;
      z-index: 1;
      min-height: 44px;
      margin-top: 5px;
      padding-inline: 17px;
      display: inline-flex;
      align-items: center;
      gap: 9px;
      background: var(--brand-black);
      color: var(--brand-white);
      font-weight: 700;
      transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
    }

    .sector-feature-link:hover,
    .sector-feature-link:focus-visible {
      background: var(--brand-sweihan);
      color: var(--brand-black);
    }

    .sector-feature-link i.ph { font-size: var(--ic-sm); }

    .sector-feature-visual {
      padding: clamp(20px, 3vw, 42px);
      display: grid;
      place-items: center;
      background: var(--surface-sunken);
    }

    .sector-feature-visual img {
      width: min(100%, 520px);
      height: auto;
      display: block;
      object-fit: contain;
    }

    @media (min-width: 981px) {


      /* The feature is the single, readable destination preview. Individual
         card overlays would duplicate it and conflict with the five-card row. */
      .sector-card-panel { display: none; }
    }

    @media (max-width: 980px) {
      .sector-feature {
        width: calc(100% - (var(--page-gutter) * 2));
        grid-template-columns: 1fr;
        margin-block: 14px 18px;
      }

      .sector-feature-copy { order: 2; }
      .sector-feature-visual { order: 1; padding: 18px; }
      .sector-feature-visual img { width: min(100%, 440px); }
    }

    /* Hero copy is a headline, not a narrow poster column. The wider measure
       keeps the message to two composed lines on wide screens. */
    @media (min-width: 981px) {
      .hero-content-row {
        width: min(100%, 1080px);
      }

      .hero-content-copy {
        flex-basis: auto;
        max-width: 960px;
      }

      .hero h1 {
        max-width: 23ch;
        font-size: clamp(2.35rem, min(4.1vw, 6.8svh), 3.95rem);
        line-height: 1.12;
        text-wrap: balance;
      }

      .hero p { max-width: 64ch; }
    }
    /* Final process reset. Earlier exploratory bento rules leave absolute
       numbers and column spans behind; reset every layout property here so the
       five stages always render as one calm institutional sequence. */
    .process-head {
      display: block;
      max-width: 760px;
      margin: 0 0 clamp(30px, 4vw, 46px);
      text-align: left;
    }

    .process-head .process-kicker,
    .process-head h2,
    .process-head p {
      grid-column: auto;
      grid-row: auto;
    }

    .process-head h2 { margin: 0; }
    .process-head p {
      max-width: 58ch;
      margin: 14px 0 0;
      padding: 0;
      border: 0;
    }

    .process-flow {
      display: grid;
      grid-template-columns: 1fr;
      grid-auto-rows: auto;
      gap: 0;
      overflow: visible;
      background: var(--surface-sunken-strong);
    }

    .process-step,
    .process-step:nth-child(n) {
      position: relative;
      display: grid;
      grid-template-columns: 74px 52px minmax(150px, .55fr) minmax(0, 1.45fr);
      grid-column: auto;
      align-items: center;
      min-width: 0;
      min-height: 136px;
      height: auto;
      padding: 24px clamp(22px, 4vw, 52px);
      gap: clamp(14px, 2.5vw, 34px);
      overflow: visible;
      isolation: auto;
      background: var(--surface-raised);
      color: var(--ink);
      text-align: left;
      transition: background var(--dur-base) var(--ease-out);
    }

    .process-step:not(:last-child) { border-block-end: 1px solid var(--surface-sunken-strong); }
    .process-step:hover,
    .process-step:nth-child(n):hover { background: var(--surface-sunken); }

    .process-step .process-num,
    .process-step:nth-child(n) .process-num {
      position: static;
      z-index: auto;
      inset: auto;
      order: initial;
      margin: 0;
      color: var(--brand-sweihan);
      font-size: clamp(1.85rem, 3vw, 2.65rem);
      font-weight: 700;
      line-height: 1;
      opacity: 1;
      transform: none;
    }

    .process-step .process-icon,
    .process-step:nth-child(n) .process-icon {
      position: static;
      z-index: auto;
      order: initial;
      width: 48px;
      height: 48px;
      margin: 0;
      background: var(--icon-wash);
      color: var(--brand-black);
    }

    .process-step h3,
    .process-step p,
    .process-step:nth-child(n) h3,
    .process-step:nth-child(n) p {
      position: static;
      z-index: auto;
      margin: 0;
      color: var(--ink);
    }

    .process-step h3 { font-size: clamp(1.15rem, 1.5vw, 1.4rem); }
    .process-step p { max-width: 54ch; font-size: 1rem; line-height: 1.75; }

    @media (max-width: 720px) {
      .process-step,
      .process-step:nth-child(n) {
        grid-template-columns: 48px 1fr;
        grid-template-areas: "number icon" "number title" "number copy";
        align-items: start;
        min-height: 0;
        padding: 22px 18px;
        gap: 8px 14px;
      }

      .process-step .process-num { grid-area: number; }
      .process-step .process-icon { grid-area: icon; }
      .process-step h3 { grid-area: title; }
      .process-step p { grid-area: copy; }
    }

    /* Keep intentionally retired sections out of the visual and accessibility
       trees even when their component rules declare a display value. */
    [hidden] {
      display: none !important;
    }
    /* ===== Sector interaction repair, 2026-07-26 =====
       The large preview is an overlay above the strip, never another row in
       the document flow. Opening it cannot move the title, cards, or scroll. */
    .sector-feature { display: none !important; }
    .hero-sectors,
    .hero-sectors .wrap { overflow: visible; }
    .hero-sectors-head { position: relative; z-index: 2; background: none; }
    .sector-card-panel { display: none !important; }

    .sector-hover-region {
      position: absolute;
      inset-inline: 0;
      bottom: 100%;
      z-index: 12;
      display: block;
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transform: translateY(12px);
      transition:
        opacity var(--dur-slow) var(--ease-out),
        transform var(--dur-slow) var(--ease-out),
        visibility 0s linear var(--dur-slow);
    }

    .sector-hover-panels {
      width: min(calc(100% - clamp(32px, 7vw, 112px)), var(--max));
      margin-inline: auto;
      display: grid;
      overflow: visible;
    }

    .sector-hover-panel {
      grid-area: 1 / 1;
      display: grid;
      grid-template-columns: minmax(300px, .82fr) minmax(480px, 1.38fr);
      align-items: stretch;
      width: 100%;
      min-height: 0;
      margin-block-end: 18px;
      background: var(--surface-base);
      color: var(--brand-black);
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transform: translate3d(0, 18px, 0);
      transition:
        opacity var(--dur-slow) var(--ease-out),
        transform var(--dur-slow) var(--ease-out),
        visibility 0s linear var(--dur-slow);
    }

    .sector-hover-copy {
      padding: clamp(28px, 4vw, 54px);
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      gap: 12px;
    }

    .sector-hover-copy > span { color: var(--brand-liwa); font-size: .82rem; font-weight: 700; }
    /* --type-feature: the panel's spotlight headline, bigger than the small
       card's own --type-card title. Added 2026-08-12 - see sdeira-tokens.css
       for why --type-section was wrong here. */
    .sector-hover-copy h3 { margin: 0; color: var(--brand-black); font-family: var(--font-display); font-size: var(--type-feature); line-height: var(--leading-feature); }
    .sector-hover-copy p { max-width: 52ch; margin: 0; color: var(--brand-jais); line-height: 1.8; }

    .sector-hover-visual {
      position: relative;
      isolation: isolate;
      aspect-ratio: 16 / 9;
      min-height: 0;
      overflow: hidden;
      background: var(--surface-sunken);
    }

    /* Keyed to data-sector, not :nth-child(): orderSectorElements() reorders
       these panels at runtime, so a position-keyed backdrop can end up on the
       wrong panel. It already had - panels 1 and 2 were serving each other's
       photograph, and the services panel had no entry at all. */
    [data-sector="development"] .sector-hover-visual { --sector-preview-image: url("../images/group-living/development-community.webp?v=434e826d203216fd"); }
    [data-sector="properties"] .sector-hover-visual { --sector-preview-image: url("../images/group-living/living-community.webp?v=ce893ec401aaeaa3"); }
    [data-sector="management"] .sector-hover-visual { --sector-preview-image: url("../images/group-living/community-operations.webp?v=cebf4f57f0e06c57"); }
    [data-sector="services"] .sector-hover-visual { --sector-preview-image: url("../images/group-living/community-services.webp?v=6ffae8431d38f82f"); }
    [data-sector="investment"] .sector-hover-visual { --sector-preview-image: url("../images/group-living/community-portfolio.webp?v=7d83f8cc334bda25"); }

    .sector-hover-visual::before {
      content: "";
      position: absolute;
      z-index: 0;
      inset: -18px;
      background-image: var(--sector-preview-image);
      background-size: cover;
      background-position: center;
      filter: blur(18px) saturate(.78) brightness(.92);
      opacity: .82;
      transform: scale(1.04);
    }

    .sector-hover-visual img {
      position: relative;
      z-index: 1;
      width: 100%;
      height: 100%;
      display: block;
      object-fit: cover;
      object-position: center;
    }

    @media (hover: hover) and (pointer: fine) {
      .hero-sectors:has(.sector-card:nth-child(-n + 5):hover) .sector-hover-region,
      .hero-sectors:has(.sector-card:nth-child(-n + 5):focus-within) .sector-hover-region {
        opacity: 1;
        visibility: visible;
        transform: none;
        transition-delay: 0s;
      }

      .hero-sectors:has(.sector-card:nth-child(1):hover) .sector-hover-panel:nth-child(1),
      .hero-sectors:has(.sector-card:nth-child(1):focus-within) .sector-hover-panel:nth-child(1),
      .hero-sectors:has(.sector-card:nth-child(2):hover) .sector-hover-panel:nth-child(2),
      .hero-sectors:has(.sector-card:nth-child(2):focus-within) .sector-hover-panel:nth-child(2),
      .hero-sectors:has(.sector-card:nth-child(3):hover) .sector-hover-panel:nth-child(3),
      .hero-sectors:has(.sector-card:nth-child(3):focus-within) .sector-hover-panel:nth-child(3),
      .hero-sectors:has(.sector-card:nth-child(4):hover) .sector-hover-panel:nth-child(4),
      .hero-sectors:has(.sector-card:nth-child(4):focus-within) .sector-hover-panel:nth-child(4),
      .hero-sectors:has(.sector-card:nth-child(5):hover) .sector-hover-panel:nth-child(5),
      .hero-sectors:has(.sector-card:nth-child(5):focus-within) .sector-hover-panel:nth-child(5) {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transform: none;
        transition-delay: 90ms, 90ms, 0s;
      }

      .sector-card .sector-card-media::after {
        display: block;
        /* One state for the entire sector family: the photo still reads
           through the warm wash, while the black base keeps white copy clear.

           THE FILL IS THE TOKEN, NOT RAW SWEIHAN. It used to be a literal
           rgba(216, 112, 44) - Sweihan itself - and white copy over the
           finished composite measured 4.04 to 4.44 against the description and
           the action link, under AA for text that size. --surface-brand-deep is
           the value the token file already designates for the diagonal wipe,
           and the same composite measures 6.58 to 7.23 with it. Same one
           sanctioned orange step, no ninth colour. */
        background:
          linear-gradient(180deg,
            color-mix(in srgb, var(--surface-brand-deep) 76%, transparent) 0%,
            color-mix(in srgb, var(--surface-brand-deep) 90%, transparent) 100%),
          linear-gradient(180deg,
            rgba(var(--image-overlay-rgb), .46) 0%,
            rgba(var(--image-overlay-rgb), .62) 100%);
        /* Oversized diagonal layer: its slanted ends sit outside the card, so
           the completed state is a full fill rather than a clipped rectangle. */
        inset: -1px -40%;
        opacity: 1;
        clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
        transform: translate3d(-78%, 0, 0);
        transition: transform var(--dur-slow) var(--ease-out);
      }

      .sector-card:hover .sector-card-media::after,
      .sector-card:focus-within .sector-card-media::after {
        transform: none;
      }

      .sector-card:hover .sector-card-veil,
      .sector-card:focus-within .sector-card-veil {
        /* The stable base never drops out; the brand diagonal travels above it. */
        opacity: 1;
      }

      .sector-card:hover .sector-card-img,
      .sector-card:focus-within .sector-card-img {
        transform: none;
        filter: saturate(.9) brightness(.9);
      }

      .sector-card:hover .sector-card-sub,
      .sector-card:focus-within .sector-card-sub {
        opacity: 0;
        visibility: hidden;
      }

      .sector-card:hover .sector-card-title,
      .sector-card:focus-within .sector-card-title,
      .sector-card:hover .sector-card-mark,
      .sector-card:focus-within .sector-card-mark {
        color: var(--brand-white);
      }

      .sector-card:hover .sector-card-body,
      .sector-card:focus-within .sector-card-body {
        background: none;
      }

      .sector-card:hover .sector-card-action,
      .sector-card:focus-within .sector-card-action {
        width: fit-content;
        min-height: 0;
        padding: 0 0 8px;
        background: transparent;
        color: var(--brand-white);
      }
    }

    /* All five sectors now share the same card interaction and the same
       preview-panel choreography; none is treated as a special case. */

    .sector-card-title,
    .sector-card-sub,
    .sector-card-action {
      text-shadow: none !important;
    }

    .sector-card-body {
      height: 100%;
      padding: 20px clamp(16px, 1.7vw, 24px);
      display: grid;
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: 42px auto minmax(0, 1fr) auto;
      align-items: end;
      gap: 8px;
    }

    .sector-card-mark {
      grid-row: 1;
      align-self: start;
      margin: 0;
      background: transparent;
      transform: none;
    }

    .sector-card:hover .sector-card-mark,
    .sector-card:focus-within .sector-card-mark {
      background: transparent;
      transform: none;
    }

    .sector-card-title {
      grid-row: 2;
      grid-column: 1;
      align-self: end;
    }

    .sector-card-sub,
    .sector-card-action {
      grid-column: 1;
      align-self: start;
      margin: 0;
      transition:
        opacity var(--dur-base) var(--ease-out),
        visibility var(--dur-base) var(--ease-out);
    }

    .sector-card-sub {
      grid-row: 3;
    }

    .sector-card-action {
      grid-row: 4;
      position: static;
      inset: auto;
      inline-size: fit-content;
      min-height: 0;
      pointer-events: none;
      transform: none;
    }

    .sector-card:hover .sector-card-action,
    .sector-card:focus-within .sector-card-action {
      pointer-events: auto;
      transform: none;
    }

    /* Button hierarchy: .btn is the filled CTA, .btn-ghost is secondary,
       and .action-link is the contextual action placed over imagery. */
    .action-link,
    .sector-card-action {
      position: relative;
      z-index: 0;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      min-height: 0;
      padding: 0 0 8px;
      overflow: visible;
      isolation: auto;
      background: transparent;
      color: var(--brand-white);
      font-weight: 800;
      line-height: 1.3;
      transition:
        opacity var(--dur-base) var(--ease-out),
        visibility var(--dur-base) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

    .action-link::before,
    .sector-card-action::before {
      content: none;
    }

    .action-link::after,
    .sector-card-action::after {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      inset-block-end: 0;
      inline-size: 100%;
      block-size: 3px;
      background: currentColor;
      transform: scaleX(.42);
      transform-origin: right center;
      transition: transform 300ms var(--ease-out);
    }

    .action-link:is(:hover, :focus-visible)::after,
    .sector-card:hover .sector-card-action::after,
    .sector-card:focus-within .sector-card-action::after {
      transform: scaleX(1);
    }

    .sector-card-action i.ph { color: currentColor; }

    /* The visible action label explains the destination, while the whole
       coloured sector surface remains the same generous pointer target. */
    .sector-card { cursor: pointer; }

    @media (max-width: 980px) {
      .sector-grid > .sector-card:last-child:nth-child(odd) { grid-column: 1 / -1; }
    }

    @media (max-width: 680px) {
      .sector-hover-region { display: none; }
      .hero-sectors-head { background: none; }
    }

    @media (prefers-reduced-motion: reduce) {
      .sector-card-media::after,
      .sector-card-sub,
      .sector-card-action,
      .sector-hover-region,
      .sector-hover-panel {
        transition: none;
      }
    }

    /* The About photograph stays intact. These parallel surface-colour bands
       sit above it and create the same rising direction as the logomark without
       cropping or editing the source image. */
    .about-visual > img {
      position: relative;
      z-index: 0;
      display: block;
    }

    /* A calendar is a clearer cue for a dated beginning than the previous
       certification seal. The strokes stay tonal so they read as part of the
       badge surface rather than a second multi-colour logo. */
    .about-badge {
      z-index: 2;
    }

    .about-badge::before { content: none; }
    .about-badge > i.ph {
      position: absolute;
      z-index: 1;
      inset-block-start: 24px;
      inset-inline-end: 24px;
      color: var(--brand-white);
      font-size: 1.7rem;
      opacity: .9;
    }

    .about-badge > div { position: relative; z-index: 1; }

    /* Alternate impact composition kept beside the original for comparison.
       It follows the supplied editorial reference: copy on the RTL reading
       edge, an angled multi-image composition, then one continuous metric rail. */
    .impact-alt {
      padding: clamp(72px, 7vw, 108px) 0;
      background: var(--surface-base);
    }

    .impact-alt-intro {
      display: grid;
      grid-template-columns: minmax(300px, .72fr) minmax(520px, 1.28fr);
      gap: clamp(44px, 6vw, 92px);
      align-items: center;
    }

    .impact-alt-copy {
      text-align: left;
    }

    .impact-alt-copy .impact-kicker {
      margin-bottom: 18px;
    }

    .impact-alt-copy h2 {
      max-width: 13ch;
      margin: 0 0 22px;
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: clamp(2.5rem, 4.7vw, 5rem);
      line-height: 1.05;
    }

    .impact-alt-copy p {
      max-width: 52ch;
      margin: 0;
      color: var(--brand-jais);
      font-size: clamp(1rem, 1.2vw, 1.16rem);
      line-height: 1.9;
    }

    /* Same .section-view-all action the projects and news sections use, so the
       three read as one kind of section-level link rather than three buttons.
       Only two things differ here, both because it sits in a text column
       instead of a filter bar: it needs its own space under the paragraph, and
       the 4px of inline padding that keeps it clear of a filter tab has to be
       pulled back so its text starts on the same line as the h2 above it. The
       pull is on the START side, which is what makes one rule correct in both
       directions. (Port log item 38.) */
    .impact-alt-action {
      margin-top: 26px;
      margin-inline-start: -4px;
    }

    .impact-alt-collage {
      direction: ltr;
      display: grid;
      grid-template-columns: 1.08fr 1fr;
      grid-template-rows: repeat(3, minmax(128px, 1fr));
      gap: 8px;
      height: clamp(470px, 43vw, 620px);
      /* The top and bottom breathing room holds the deliberate image offsets
         inside the composition, instead of letting the collage spill outside
         the section. */
      padding-block: 22px;
      overflow: hidden;
      background: var(--surface-base);
    }

    .impact-alt-collage figure {
      position: relative;
      margin: 0;
      overflow: hidden;
      background: var(--surface-sunken-strong);
    }

    .impact-alt-collage figure:first-child {
      grid-row: 1 / -1;
      clip-path: polygon(0 0, 100% 0, 86% 100%, 0 100%);
    }

    .impact-alt-collage figure:not(:first-child) {
      margin-left: -12%;
      clip-path: polygon(4.881% 0, 100% 0, 95.119% 100%, 0 100%);
    }

    .impact-alt-collage img {
      width: 100%;
      height: 100%;
      display: block;
      object-fit: cover;
      filter: saturate(.9) contrast(1.03);
    }

    .impact-alt-collage figure:nth-child(2) img { object-position: center 58%; }
    .impact-alt-collage figure:nth-child(3) img { object-position: center 45%; }
    .impact-alt-collage figure:nth-child(4) img { object-position: center 55%; }

    /* Below 981px the grid stays 2 columns x 3 rows (no min-width override
       fires), so the supporting trio is a STACKED column, not a horizontal
       row. The desktop clip-path + margin-left:-12% on those figures exists
       to overlap them into one diagonal-seamed strip when they sit side by
       side - stacked vertically instead, that same offset shoves each one
       sideways with no neighbour to seam against, so the right edge reads as
       a broken staircase instead of one straight line. Cancelling both here
       restores plain rectangles for the stacked case; the lead image's own
       corner taper (figure:first-child) is unaffected and still reads fine
       against a straight-edged column. */
    @media (max-width: 980px) {
      .impact-alt-collage figure:not(:first-child) {
        margin-left: 0;
        clip-path: none;
      }
    }

    /* The photographs keep their original editorial cuts. The supporting trio
       is shifted as whole images, rather than receiving a different angle for
       every row; this makes one calm, stepped image field beside the lead. */
    @media (min-width: 981px) {
      .impact-alt-collage {
        overflow: hidden;
      }

      .impact-alt-collage figure:not(:first-child) {
        margin-left: 0;
        z-index: 1;
      }

      /* Percentages, not fixed px: both columns are fr-based and scale together
         with viewport width, so a percentage offset (relative to the figure's
         own width) keeps the diagonal seam exact at every width. Fixed px
         offsets only matched the one viewport they were measured at. */
      .impact-alt-collage figure:nth-child(2) {
        transform: translate3d(-5.513%, 0, 0);
      }

      .impact-alt-collage figure:nth-child(3) {
        transform: translate3d(-10.632%, 0, 0);
      }

      .impact-alt-collage figure:nth-child(4) {
        transform: translate3d(-15.751%, 0, 0);
      }
    }

    .impact-alt-stats {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      margin-top: clamp(36px, 4vw, 58px);
      background: var(--surface-raised);
    }

    .impact-alt-stat {
      position: relative;
      min-width: 0;
      min-height: 212px;
      padding: 30px clamp(18px, 1.9vw, 30px);
      display: grid;
      grid-template-columns: 42px minmax(0, 1fr);
      grid-template-rows: 54px 26px minmax(66px, auto);
      align-content: start;
      align-items: start;
      gap: 6px 14px;
    }

    .impact-alt-stat + .impact-alt-stat::before {
      content: "";
      position: absolute;
      top: 50%;
      left: 0;
      width: 2px;
      height: 72px;
      background: var(--brand-sweihan);
      transform: translateY(-50%) rotate(var(--brand-stripe-angle));
    }

    .impact-alt-stat i.ph {
      grid-column: 1;
      grid-row: 1;
      align-self: center;
      color: var(--brand-sweihan);
      font-size: var(--ic-lg);
    }

    .impact-alt-stat strong {
      grid-column: 2;
      grid-row: 1;
      align-self: center;
      min-width: 0;
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: clamp(1.65rem, 2.2vw, 2.55rem);
      line-height: 1;
      font-weight: 500;
      white-space: nowrap;
    }

    .impact-alt-stat span {
      grid-column: 2;
      grid-row: 2;
      color: var(--brand-black);
      font-size: .96rem;
      line-height: 1.35;
      white-space: nowrap;
    }

    .impact-alt-stat p {
      grid-row: 3;
      grid-column: 2;
      margin: 0;
      color: var(--brand-jais);
      font-size: .86rem;
      line-height: 1.6;
      /* RESERVE, DO NOT CLAMP. This reserved 4.8em AND clamped at 3 lines, so
         a fourth line was hidden from the visitor - the one thing the token
         file's card rule rules out, and the same defect recorded against
         .news-card. The reservation stays and is expressed in lh, so it
         follows the line-height instead of restating it; all four figures are
         one grid row, so a longer sentence grows the row evenly rather than
         leaving one column short. */
      min-block-size: calc(3 * 1lh);
    }

    @media (max-width: 1180px) {
      .impact-alt-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .impact-alt-stat { min-height: 196px; }
      /* In the two-column layout, only the second card in each LTR row gets
         the diagonal divider. */
      .impact-alt-stat + .impact-alt-stat::before { content: none; }
      .impact-alt-stat:nth-child(even)::before { content: ""; }
    }

    @media (max-width: 980px) {
      .impact-alt-intro { grid-template-columns: 1fr; }
      .impact-alt-collage { grid-row: 2; }
    }

    @media (max-width: 640px) {
      .impact-alt { padding-block: 64px; }
      .impact-alt-intro { gap: 38px; }
      .impact-alt-copy h2 { font-size: clamp(2.25rem, 12vw, 3rem); }
      .impact-alt-collage { height: min(126vw, 490px); }
      .impact-alt-stats {
        grid-template-columns: 1fr;
        margin-top: 28px;
      }
      .impact-alt-stat {
        min-height: 168px;
        padding: 24px 22px;
        grid-template-rows: 46px 24px minmax(52px, auto);
      }
      .impact-alt-stat:nth-child(even)::before { content: none; }
      .impact-alt-stat strong {
        font-size: clamp(1.45rem, 7vw, 1.8rem);
      }
      .impact-alt-stat p { min-block-size: calc(2 * 1lh); }
    }

    /* The slider was initialized in JavaScript but absent from the document.
       inline-size used to be capped at 360px max - fine on narrow phones
       (where 100% is under 360px anyway) and on desktop (where
       .hero-content-row's own max-width keeps the column narrow), but
       .hero-content-row is column-direction at every width (see the
       "Hero responsive reconstruction" rule above), so at tablet widths the
       column itself is much wider than 360px and the rail shrank to a thin
       stub in the corner instead of spanning the row like the buttons above
       it. Full width at every size instead of a fixed cap. */
    .hero-slides-ind { display: flex; visibility: visible; opacity: 1; order: 2; inline-size: 100%; margin-top: 4px; }

    /* The page-wide wash was visually too light on the brightest mobile slide:
       white hero copy became dependent on the photograph behind it. This is a
       measured black scrim, intentionally lighter at the header and then
       stronger through the reading zone; it protects text without flattening
       the entire image. */
    .hero::after {
      background: linear-gradient(180deg,
        rgba(0, 0, 0, .58) 0%,
        rgba(0, 0, 0, .44) 24%,
        rgba(0, 0, 0, .72) 58%,
        rgba(0, 0, 0, .88) 100%);
    }

    header::before {
      background: linear-gradient(180deg,
        rgba(0, 0, 0, .72) 0%,
        rgba(0, 0, 0, .48) 52%,
        transparent 100%);
    }

    /* Restore the hero's reading zone after an older feature-preview rule
       reserved twice the required strip height. The copy now clears the header
       and stays bottom-aligned above the five-sector strip. */
    @media (min-width: 981px) {
      .hero { padding-bottom: clamp(236px, 23vw, 320px); }
      .hero-content {
        min-height: calc(100svh - clamp(236px, 23vw, 320px));
        padding-block: 120px 38px;
      }
    }

    /* ===== Unified action colour =====
       Primary actions use the same Sweihan surface as the active sector card.
       White, heavier labels give the CTA the required visual authority. */
    :is(.btn-primary, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a) {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
      font-weight: 800;
      box-shadow: none;
    }

    :is(.btn-primary, .btn-ghost, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a, .project-tab) {
      position: relative;
      isolation: isolate;
      overflow: hidden;
      transition:
        background-color var(--dur-fast) var(--ease-out),
        border-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

    :is(.btn-primary, .btn-ghost, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a, .project-tab)::before {
      content: "";
      position: absolute;
      z-index: -1;
      inset: -1px -40%;
      background: rgba(65, 64, 66, .30);
      clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
      transform: translate3d(-78%, 0, 0);
      transition: transform var(--dur-slow) var(--ease-out) 55ms;
      pointer-events: none;
    }

    :is(.btn-primary, .btn-ghost, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a, .project-tab):is(:hover, :focus-visible) {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
      box-shadow: none;
    }

    :is(.btn-primary, .btn-ghost, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a, .project-tab):is(:hover, :focus-visible)::before {
      transform: none;
    }

    /* Keep the higher-specificity project footer in the same primary-action
       family instead of allowing it to drift back to a black variant. */
    .projects-footer .projects-footer-cta {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
      font-weight: 800;
    }

    .projects-footer .projects-footer-cta:is(:hover, :focus-visible) {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
    }

    .sector-hover-copy a:is(:hover, :focus-visible),
    .why-footer a.btn.btn-primary:is(:hover, :focus-visible) {
      background: var(--brand-sweihan);
      color: var(--brand-white);
    }

    .why-footer a.btn.btn-primary {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
      font-weight: 800;
    }

    /* Ghost actions share the same diagonal wipe entrance as the primary CTA,
       using the same dark overlay fill (no white). Text stays white in both
       states since the wipe never becomes light enough to need a dark label. */
    .btn-ghost {
      background: transparent;
      color: var(--brand-white);
      border-color: var(--brand-white);
      font-weight: 800;
    }

    .btn.btn-ghost:is(:hover, :focus-visible) {
      color: var(--brand-white);
      border-color: var(--brand-white);
    }

    header.scrolled .nav-cta,
    header.scrolled .nav-cta:is(:hover, :focus-visible) {
      background: var(--brand-sweihan);
      color: var(--brand-white);
      border-color: var(--brand-sweihan);
      font-weight: 800;
    }

    .project-tab.active,
    .project-tab:hover {
      background: var(--brand-black);
      border-color: var(--brand-black);
      color: var(--brand-white);
    }

    .project-tab.active:hover,
    .project-tab:focus-visible {
      background: var(--brand-black);
      border-color: var(--brand-black);
      color: var(--brand-white);
    }

    /* .scroll-top used to be in this list too, and being later in source than
       its own :hover rule above (background: var(--accent)) silently won -
       a hardcoded Razeen instead of the direction's own accent (Liwa/Al
       Khatim) on the one shared control meant to carry it. Kept out here;
       the direction accent is the only hover colour that control gets now. */
    .foot-bottom .socials a:hover,
    .menu.open .menu-contact:hover {
      background: var(--brand-razeen);
      border-color: var(--brand-razeen);
      color: var(--brand-black);
    }

    /* Subsidiary cards: logo-led surfaces with no framing edges. Four fit on a
       wide desktop; the same cards become two-by-two before they get narrow. */
    /* Paired layout: two cards per row with straight outer edges and one
       diagonal seam between each pair, matching the contact action motif.
       The shallow taper and generous inline padding keep copy clear. */
    .companies-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 0;
      background: transparent;
    }

    .company-card {
      position: relative;
      min-width: 0;
      min-height: 310px;
      padding: clamp(24px, 2.5vw, 36px) clamp(32px, 3.4vw, 46px);
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      border: 0;
      background: var(--surface-base);
    }

    /* Cards keep straight rectangular edges - no clip-path on the card
       itself. The diagonal motif lives only in the watermark bars below,
       styled after the Sdeira mark's own parallel bars (see the SVG in the
       "إسكان" card icon: three parallel parallelogram bars, same slant,
       stepped widths). A responsive transparent gutter separates the four
       cards, matching the spacing used by the Arabic homepage. */
    .companies-grid {
      gap: clamp(16px, 2vw, 24px);
      background: transparent;
    }

    @media (max-width: 760px) {
      .companies-grid {
        grid-template-columns: 1fr;
        gap: clamp(14px, 4vw, 24px);
        background: transparent;
      }
    }

    /* Corner mark, oversized and positioned past the card's own top-right
       edge (mirrored from sdeira-v2.html's top-left, since this page is
       LTR: the corner pin sits on the side away from the left-aligned
       English copy). The card clips it via overflow: hidden (see the
       "Company card: one radius" rule below) rather than letting it bleed
       into the neighbouring card in the tight 2-column grid. */
    .company-card::before {
      inset: auto;
      top: -40px;
      right: -78px;
      width: clamp(230px, 46%, 360px);
      height: clamp(230px, 46%, 360px);
      z-index: -1;
      opacity: .1;
      pointer-events: none;
      transform: translate3d(0, 0, 0);
      transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    /* The mark itself, matching sdeira-v2.html: the actual three-bar
       identity cut from the logo, not a hand-built gradient standing in for
       it. One consistent placement for all four cards. */
    .company-card::before {
      background: url("../images/brand/sdeira-mark.png?v=c1949ae876afaeca") center / contain no-repeat;
    }

    /* The card itself never changes colour on hover (see the .action-link
       note below) - the watermark stepping up in strength and drifting a
       couple of pixels is the hover cue instead, on both real and pending
       cards so the whole surface still feels reactive. Drift is mirrored
       from sdeira-v2.html's -6px: the mark drifts further away from the
       card's copy, which sits on the opposite physical side here. */
    .company-card:hover::before,
    .company-card:focus-within::before {
      opacity: .16;
      transform: translate3d(6px, 0, 0);
    }

    /* Kept in the DOM for screen readers, without adding a visual ordering
       system that competes with the company identity (matches
       sdeira-v2.html). */
    .company-card .company-num {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip: rect(0 0 0 0);
      white-space: nowrap;
    }

    .company-logo {
      position: relative;
      z-index: 1;
      width: 100%;
      min-height: 78px;
      margin-bottom: 24px;
      display: flex;
      align-items: flex-start;
      gap: 14px;
      color: var(--company-accent);
      /* Push the logo to the inline-end (visual right in LTR) and sit it
         flush with the top padding, so the identity mark reads as a corner
         pin rather than a centred plate. Matches sdeira-v2.html's treatment
         (inline-end resolves to the opposite physical side there, since
         that page is RTL). Applies to every card in the group because the
         corner-pin treatment is the group pattern. */
      align-self: flex-end;
    }

    .company-logo svg {
      width: 54px;
      height: 48px;
      flex: 0 0 auto;
    }

    .company-logo--eskan {
      align-items: center;
      justify-content: flex-start;
      color: var(--brand-black);
    }

    .company-logo--eskan-wordmark {
      display: grid;
      gap: 0;
      color: var(--brand-black);
      font-family: var(--font-display);
      font-weight: 600;
      line-height: .85;
    }

    .company-logo--eskan-wordmark b {
      font-size: clamp(2rem, 2.8vw, 2.85rem);
      font-weight: 600;
    }

    .company-logo--eskan-wordmark small {
      margin: 0;
      color: var(--brand-black);
      font-size: .78rem;
      font-weight: 600;
      line-height: 1;
    }

    .company-logo strong,
    .company-logo h3 {
      margin: 0;
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: clamp(1.6rem, 2vw, 2.1rem);
      font-weight: 500;
      line-height: 1;
    }

    .company-logo small {
      display: block;
      margin-top: 7px;
      color: var(--brand-jais);
      font-size: .72rem;
    }

    .company-logo--image img {
      width: min(190px, 88%);
      height: 76px;
      object-fit: contain;
      object-position: left center;
    }

    .company-logo--zoad img {
      width: min(154px, 82%);
      height: 82px;
    }

    .company-card-title--sr {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
    }

    .company-card > h3 {
      margin-top: 0;
    }

    .company-card > h3 small {
      display: block;
      margin-top: 7px;
      color: var(--brand-jais);
      font-size: .72rem;
      font-weight: 400;
    }

    .company-card p {
      flex: 1 1 auto;
    }

    /* The card itself never changes colour on hover/click - only the link's
       underline activates, reusing the same .action-link motion used across
       the site. A real destination makes the whole card a click target (via
       JS delegation below); a pending one stays a muted, inert label. */
    .company-card .action-link {
      margin-top: 18px;
      color: var(--brand-black);
      font-weight: 700;
    }

    .company-card .action-link i.ph {
      color: currentColor;
      font-size: .95rem;
    }

    .company-card .action-link.is-pending {
      color: var(--brand-jais);
      cursor: default;
    }

    .company-card.is-clickable {
      cursor: pointer;
    }

    .company-card:hover .action-link:not(.is-pending)::after,
    .company-card:focus-within .action-link:not(.is-pending)::after {
      transform: scaleX(1);
    }

    /* Contact choices remain four distinct routing subjects, but the visible
       box grid and the large background mark are removed. Angled card ends and
       short identity strokes carry the Sdeira geometry instead. */

    /* Real photography, kept genuinely visible - a flat 90%-opacity wash
       made the section read as a solid colour band with the photo barely
       showing through as texture, which defeats the point of having a
       photo at all. A gradient wash was tried next (strong behind the
       text, fading out toward the edges) but that produced a visible
       banding seam partway down the section, which read as a bug rather
       than a deliberate effect - so this is one flat, uniform identity
       tint (white+Razeen, not grey) at a light opacity instead: no seam,
       and the photo shows through evenly across the whole section. The
       three cards use their own solid identity-colour fill regardless, so
       they never depend on this wash for contrast. ::before carries the
       photo, ::after the flat tint, both behind .cta-inner's own z-index:1
       stacking context. */
    .cta::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -2;
      background: var(--cta-image, url("../images/sectors/real-estate-v2.webp?v=dd60f68eedf6c379")) center / cover no-repeat;
      opacity: 1;
      transform: none;
      pointer-events: none;
    }

    .cta::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: var(--brand-black);
      opacity: .55;
      pointer-events: none;
    }

    /* The black tint over the photo darkens the section again, so heading/
       body copy flips back to white for contrast (AAA on the solid-black
       reading, comfortably clear over the darkened photo). The three
       routing cards keep their own solid Razeen fill with brand-black
       text/icon regardless - measured 5.19:1, clears AA body text same as
       the news-card category badge decision, and reads well against dark
       or light surroundings alike. */
    .cta .kicker,
    .cta h2 {
      color: var(--brand-white);
    }

    .cta p {
      color: rgba(255, 255, 255, .82);
    }

    .cta-action {
      border: 1px solid color-mix(in srgb, var(--brand-black) 14%, transparent);
    }

    .cta-inner {
      width: min(1120px, 100%);
      text-align: left;
    }

    .cta .kicker { justify-content: flex-start; }
    .cta h2,
    .cta p { margin-inline: 0; }

    .cta-actions {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 8px;
      max-width: none;
      background: transparent;
    }

    .cta-action {
      position: relative;
      isolation: isolate;
      overflow: hidden;
      min-height: 190px;
      padding: 30px 28px;
      align-items: flex-start;
      text-align: left;
      background: var(--brand-razeen);
      color: var(--brand-black);
      clip-path: polygon(5% 0, 100% 0, 95% 100%, 0 100%);
    }

    /* Straight outer edges and diagonal seams between cards only. In LTR,
       grid auto-placement renders the first DOM child leftmost, so these
       polygons mirror the Arabic version. */
    .cta-action:first-child {
      clip-path: polygon(0 0, 100% 0, 95% 100%, 0 100%);
    }

    .cta-action:last-child {
      clip-path: polygon(5% 0, 100% 0, 100% 100%, 0 100%);
    }

    .cta-action i.ph {
      width: auto;
      height: auto;
      background: transparent;
      color: var(--brand-black);
      position: relative;
      z-index: 1;
    }

    .cta-action > span {
      position: relative;
      z-index: 1;
    }

    .cta-action .cta-action-note {
      color: var(--brand-black);
      text-align: left;
    }

    /* Hover is motion only - the diagonal wipe. The card fill is now Razeen
       itself, so a razeen-tinted wipe would be invisible on it; Sweihan
       gives a visible pop of colour instead. */
    .cta-action::before {
      content: "";
      position: absolute;
      z-index: -1;
      inset: -1px -40%;
      background: color-mix(in srgb, var(--brand-sweihan) 30%, transparent);
      clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
      transform: translate3d(-78%, 0, 0);
      transition: transform var(--dur-slow) var(--ease-out) 55ms;
      pointer-events: none;
    }

    .cta-action:is(:hover, :focus-visible)::before {
      transform: none;
    }

    /* Three routing choices read as one deliberate set - breaking them into
       2+1 at ordinary laptop widths (the old max-width:1180px breakpoint
       fired on almost any non-ultra-wide screen) made the third card wrap
       onto its own row with a big empty gap beside it. Cards shrink instead
       of wrapping all the way down to real mobile, where the "no lone
       diagonal card" rule below takes over instead. */
    @media (max-width: 620px) {
      .cta-actions { grid-template-columns: 1fr; }

      /* Same rule as .company-card at mobile: a lone diagonal card with
         nothing to seam against reads as visually broken, so the cut is
         removed entirely rather than kept on an isolated stacked card. */
      .cta-action,
      .cta-action:first-child,
      .cta-action:last-child {
        clip-path: none;
      }
    }

    /* Reuse the diagonal button wipe for the three contact routes. It sits
       above the card surface but below its content, so the movement is clear
       without reducing the white label/icon contrast. */
    .cta-action::before {
      display: block;
      z-index: 0;
      inset: -1px -40%;
      background: var(--brand-sweihan);
      opacity: .34;
      clip-path: polygon(22% 0, 100% 0, 78% 100%, 0 100%);
      transform: translate3d(78%, 0, 0);
      transition: transform var(--dur-slow) var(--ease-out) 55ms;
    }

    .cta-action:first-child::before {
      background: color-mix(in srgb, var(--brand-liwa) 58%, var(--brand-sweihan));
    }

    .cta-action:is(:hover, :focus-visible) {
      border-color: var(--accent);
    }

    /* Contact routes read as three large, self-contained actions. Stacking
       the icon and title removes the competing icon-text-icon rhythm while
       keeping the entire surface as the accessible link target. */
    .cta-action,
    .cta-action:first-child,
    .cta-action:last-child {
      display: flex;
      position: relative;
      flex-direction: column;
      align-items: flex-start;
      justify-content: space-between;
      gap: 20px;
      min-height: 168px;
      padding: 26px 30px;
    }

    .cta-action > i.ph:not(.cta-arrow) {
      font-size: 2.15rem;
      line-height: 1;
    }

    .cta-action > span:not(.cta-action-note) {
      max-width: 18ch;
      font-size: clamp(1.1rem, 1.5vw, 1.4rem);
      line-height: 1.35;
    }

    .cta-action .cta-arrow {
      display: none !important;
    }

    @media (max-width: 620px) {
      .cta-actions { grid-template-columns: 1fr; gap: 12px; }
    }

    /* Calm institutional scroll choreography: a short vertical travel and
       natural deceleration make sections appear without the old abrupt jump.
       Ported from sdeira-v2.html (port log item 18): --dur-slow is the token
       file's entrance stagger by name, and --ease-out is the only easing the
       system has. This rule used to run at 620ms on a second, undocumented
       curve - 140ms longer than the system allows, on every revealed element
       on the page, which is most of it. */
    .reveal.armed {
      opacity: 0;
      visibility: hidden;
      transform: translate3d(0, 24px, 0);
      transition:
        opacity var(--dur-slow) var(--ease-out),
        transform var(--dur-slow) var(--ease-out),
        visibility 0s linear var(--dur-slow);
      will-change: opacity, transform;
    }

    .reveal.armed.in {
      opacity: 1;
      visibility: visible;
      transform: translate3d(0, 0, 0);
      transition-delay: 0s;
      will-change: auto;
    }

    .reveal.armed[data-d="1"] { transition-delay: 80ms; }
    .reveal.armed[data-d="2"] { transition-delay: 160ms; }
    .reveal.armed[data-d="3"] { transition-delay: 240ms; }

    .reveal.armed.in[data-d="1"] { transition-delay: 80ms; }
    .reveal.armed.in[data-d="2"] { transition-delay: 160ms; }
    .reveal.armed.in[data-d="3"] { transition-delay: 240ms; }

    :is(.btn, .nav-cta, .project-tab, .sector-card-action, .sector-hover-copy a, .cta-action):focus-visible {
      outline: 3px solid var(--brand-razeen);
      outline-offset: 3px;
    }

    /* Sector-section title: centred above the grid, on its own blurred bar
       coloured like the card veils, per brand request. Declared last on
       purpose - .hero-sectors-head/-label already carry close to a dozen
       partial redefinitions across breakpoints above, so overriding each one
       is fragile; being last in source order for an unconditional
       (non-media-gated) rule wins the cascade at every width instead. */
    /* Ported from sdeira-v2.html (port log item 16): the bar sits on the hero
       photograph, and two scrims already darken that photograph before the
       bar is painted (measured on the rendered page across the band the bar
       occupies: hero::after .78-.80, the .hero-sectors gradient 0-.54,
       combined .78-.90), so after a flat fill only 1.3% of the photograph
       survived - the bar read as a solid slab, and lowering the fill only
       made it darker (still 2.8% at .70). Brand Black at .90, deliberately
       NOT --scrim-footer: that token is the owner's true-black exception for
       the footer alone, and pointing here at it once already turned this bar
       black by accident. */
    .hero-sectors-head {
      position: relative;
      isolation: isolate;
      justify-content: center;
      text-align: center;
      min-height: 42px;
      padding-block: 0;
      background: var(--scrim-bar);
      backdrop-filter: blur(18px) saturate(112%);
      -webkit-backdrop-filter: blur(18px) saturate(112%);
    }

    .hero-sectors-head::after {
      content: "";
      position: absolute;
      z-index: 1;
      inset-inline: 0;
      inset-block-end: 0;
      height: 1px;
      background: rgb(255 255 255 / .16);
    }

    .hero-sectors-label {
      width: 100%;
      min-height: 0;
      margin: 0;
      display: grid;
      place-items: center;
      font-family: var(--font-display);
      gap: 10px;
      font-size: .86rem;
      font-weight: 700;
      /* Body-size text on these dark layers is white only; white at .82
         opacity is not white, and cost more contrast than the fill decision
         above. At solid white the shadow it was leaning on holds nothing up,
         so it goes too. */
      color: var(--brand-white);
    }

    /* Every sector card shares this single preview anchor. Keeping the hover
       region at zero height in normal flow makes each preview finish 6px above
       the card row, rather than leaving a separate empty band below it. */
    @media (min-width: 981px) and (hover: hover) and (pointer: fine) {
      .sector-hover-region {
        position: relative;
        inset: auto;
        bottom: auto;
        height: 0;
      }

      .sector-hover-panels {
        position: absolute;
        inset-inline: 0;
        bottom: 6px;
      }

      .sector-hover-panel {
        margin-block-end: 0;
      }
    }

    /* Sector cards: the 5-column desktop/tablet layout collapses them to a
       1px seam (see the "seamless grid" background fill above), which reads
       as one solid slab instead of 5 distinct cards. A real gap, transparent
       grid background so the hero photo shows through the gap instead of the
       old translucent fill tinting it. */
    @media (min-width: 981px) {
      .hero-sectors .wrap {
        width: 100%;
        max-width: none;
        padding-inline: 0;
      }

      .hero-sectors-head {
        width: 100vw;
        max-width: none;
        margin-inline: calc(50% - 50vw);
        padding-inline: 0;
        display: grid;
        place-items: center;
      }

      .hero-sectors-label {
        position: absolute;
        z-index: 2;
        inset: 0;
        display: grid;
        place-items: center;
        text-align: center;
      }

      /* The gap between the five cards is deliberate and stays. An opaque
         fill here reads as five drawn black divider lines over the hero
         photograph (port log item 24/36); taking the same --scrim-bar glass
         as the "Group Sectors" bar directly above makes the bar and the
         gaps read as one glass frame around the row instead. Same
         backdrop-filter as the bar for the same reason: a different blur
         either side of a 10px seam is visible. */
      .sector-grid {
        gap: clamp(6px, .55vw, 12px);
        background: var(--scrim-bar);
        border-top: 0;
        backdrop-filter: blur(18px) saturate(112%);
        -webkit-backdrop-filter: blur(18px) saturate(112%);
      }

      .sector-card {
        border-inline-start: 0;
      }

      .sector-card:first-child {
        border-inline-start: 0;
      }
    }

    /* Slide-progress rail: an earlier fix stretched it to the full width of
       the content column (see the "Full width at every size" comment above)
       to fix a tablet-only bug, but on desktop that means it spans the whole
       hero instead of tracking just the two buttons above it. Capped back
       down and kept end-aligned with the buttons on desktop only; the
       mobile/tablet full-width behaviour that earlier fix targeted is
       untouched below 981px. */
    @media (min-width: 981px) {
      .hero-slides-ind {
        inline-size: clamp(160px, 18vw, 240px);
      }
    }

    /* The cue has a real grid row in the hero instead of an absolute offset.
       It therefore sits below the hero copy and before the sector strip,
       regardless of the cards' responsive height. */
    /* It now holds the slide rail as well, matching the Arabic page. The two
       used to sit on separate lines - the rail as the last item of
       .hero-content-row, the cue in its own row underneath - which spent two
       nearly empty lines of hero height on them.

       The rail is first in the markup and this is a plain flex row with no
       direction override, so the rail takes the main start, which is the side
       the hero buttons are anchored to. That also survives the hint being
       hidden between 721px and 980px: a lone rail stays on the buttons' side
       instead of sliding to the empty corner.

       These four rules are deliberately last for this component. .hero-slides-ind
       is declared many times above, including unconditionally, so the child
       selector here is what makes the new placement win without !important. */
    .hero-scroll-cue {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
    }

    /* The rail carried a top margin as the last item of the content column,
       and a `flex: 0 0 44px` basis that was sized for that column: the parent
       was column-direction, so 44px was its HEIGHT. In a row that same basis
       becomes its WIDTH and collapsed the rail to a 44px stub. The order reset
       undoes two `order` declarations further up that were also written for
       the old parent and would re-sort this row. */
    .hero-scroll-cue > .hero-slides-ind {
      margin-top: 0;
      flex: 0 0 auto;
      inline-size: clamp(160px, 18vw, 240px);
      order: 0;
    }

    /* Below 720px the hint is hidden, so the rail is alone on the row and
       keeps the full width it had inside the content column. */
    @media (max-width: 720px) {
      .hero-scroll-cue > .hero-slides-ind {
        inline-size: 100%;
      }
    }

    @media (min-width: 981px) {
      .hero {
        display: grid;
        /* Two rows, not three. The middle 58px row existed only to hold the
           scroll cue; the cue is now the last line of the content column, so
           that row would be empty height. */
        grid-template-rows: minmax(0, 1fr) auto;
        height: max(760px, 100svh);
        min-height: max(760px, 100svh);
        padding-bottom: 0;
      }

      .hero-content {
        grid-row: 1;
        align-self: stretch;
        min-height: 0;
        height: auto;
      }

      .hero-scroll-cue {
        position: relative;
        z-index: 3;
      }

      .hero-sectors {
        grid-row: 2;
        position: relative;
        inset: auto;
        margin-top: 0;
      }
    }

    /* The scroll cue adds no value on the compact mobile hero. */
    @media (max-width: 720px) {
      .scroll-hint {
        display: none;
      }
    }

    /* Filtering changes the information set, not the editorial hierarchy. The
       curated "all" state keeps its lead-card composition; a narrowed result
       is always a conventional, equal-card grid so one surviving item never
       inherits a full-width feature layout. */
    .news-grid.is-filtered-view,
    .featured-projects .project-cards.is-filtered-view {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: clamp(16px, 2vw, 28px);
      background: transparent;
      overflow: visible;
      border-radius: var(--r);
    }

    /* A narrowed result stays a 2-up grid at every width, even the very
       widest desktop screens - the wider column this gives each surviving
       card reads as generous rather than sparse. A 3rd column used to cut in
       here at >=1680px; removed rather than kept, since two spacious cards
       is the reading this whole "conventional, equal-card grid" treatment
       was built for. Site owner flagged, 12 Aug 2026 (ported from the
       Arabic fix). */

    .news-grid.is-filtered-view .news-card--feature {
      grid-column: auto;
      display: grid;
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: auto 1fr;
    }

    .news-grid.is-filtered-view .news-card--feature.is-filtered-out {
      display: none;
    }

    .news-grid.is-filtered-view .news-card--feature .news-image-link {
      height: auto;
    }

    /* .news-card:not(.news-card--feature) .img (SYSTEM LAYER) is the
       var(--media-wide) (4:3 since 15 Aug 2026, was 16:9), card-width-
       independent rule every other card's photo uses; it deliberately
       excludes .news-card--feature because that card's normal editorial
       state stretches its image to match a two-column split, not a fixed
       ratio. Once .is-filtered-view puts this card in the same equal-width
       grid as its siblings, that exclusion stops being correct:
       var(--news-media-height) is a fixed clamp independent of aspect ratio,
       so the demoted lead card's photo no longer matched its sibling's crop
       at the same card width - the two "equal" cards in a "conventional,
       equal-card grid" were visibly uneven. Site owner flagged, 12 Aug 2026
       ("الكرت الأول مختلف... التنسيق مثل الكرت الثانية"). Kept reading
       var(--media-wide) rather than a literal so the two can never drift
       apart like this again. */
    .news-grid.is-filtered-view .news-card--feature .img {
      min-height: 0;
      aspect-ratio: var(--media-wide);
      block-size: auto;
    }

    .news-grid.is-filtered-view .news-card--feature .news-body {
      justify-content: initial;
    }

    .news-grid.is-filtered-view .news-card--feature h3 {
      font-size: clamp(1.2rem, 1.7vw, 1.5rem);
      -webkit-line-clamp: 2;
    }

    .featured-projects .project-cards.is-filtered-view .project-card--feature {
      grid-column: auto;
      position: static;
      min-height: 0 !important;
      overflow: hidden;
      background: var(--surface-raised) !important;
    }

    .project-cards.is-filtered-view .project-card--feature .project-card-img {
      /* relative, not static: the card returns to normal flow here, but it
         still hosts a .ribbon-frame that is inset: 0 and must resolve against
         the photo box. See the base .project-card-img rule. */
      position: relative;
      inset: auto;
      height: auto;
    }

    /* A filtered portfolio is a comparison view, not the editorial feature
       composition. Give every surviving project the exact same media track
       and body rules so an original lead card cannot crop or stretch unlike
       its peers. */
    .featured-projects .project-cards.is-filtered-view .project-card {
      grid-template-rows: clamp(240px, 25vw, 340px) auto;
      min-height: 0;
      height: auto;
      background: var(--surface-raised);
    }

    .project-cards.is-filtered-view .project-card .project-card-img,
    .project-cards.is-filtered-view .project-card--secondary .project-card-img {
      min-height: 0;
      height: clamp(240px, 25vw, 340px);
    }

    .project-cards.is-filtered-view .project-card .project-card-body {
      min-height: 0;
      padding: clamp(24px, 2.4vw, 34px);
      background: var(--surface-raised);
    }

    .project-cards.is-filtered-view .project-card--feature .project-card-img::after {
      display: none;
    }

    /* The filtered feature card is a peer of the secondary cards, not an
       editorial leader any more, so it takes the secondary card's exact
       treatment: no inflated min-height, the same sunken surface with the
       same hover tone-step, and the same containing block for its chevron.
       Only the chevron's own rule differs (it is scoped below). */
    .project-cards.is-filtered-view .project-card--feature .project-card-body {
      position: relative;
      overflow: hidden;
      inset: auto;
      max-width: none;
      min-height: 0;
      padding: clamp(24px, 2.4vw, 34px);
      background: var(--surface-sunken);
      color: var(--brand-black);
    }

    .project-cards.is-filtered-view .project-card--feature:hover .project-card-body {
      background: var(--surface-sunken-strong);
    }

    /* The LTR surface override that pins .project-card--secondary and its body
       to --surface-raised applies to the demoted feature card too: one grid,
       one surface. Without this the filtered feature body stayed on the warm
       --surface-sunken beside its white sibling. */
    html[dir="ltr"] .project-cards.is-filtered-view .project-card--feature,
    html[dir="ltr"] .project-cards.is-filtered-view .project-card--feature .project-card-body {
      background: var(--surface-raised);
    }

    html[dir="ltr"] .project-cards.is-filtered-view .project-card--feature:hover .project-card-body {
      background: var(--surface-sunken);
    }

    /* One flat var(--brand-black) here used to cover all four - correct for
       h3, but .project-type/p/.project-meta each have their own on-light-surface
       token already (--badge-text, --muted, --icon/--label), and the
       secondary card right next to this one in the same grid uses exactly
       those, not black. Split so each element matches its sibling's actual
       token instead of one flattened color. Found by diffing every computed
       property against .project-card--secondary, not by another one-off
       screenshot report. Site owner flagged, 12 Aug 2026. */
    .project-cards.is-filtered-view .project-card--feature h3 {
      color: var(--brand-black);
    }

    .project-cards.is-filtered-view .project-card--feature p {
      color: var(--muted);
    }

    .project-cards.is-filtered-view .project-card--feature h3 {
      font-size: clamp(1.35rem, 2vw, 1.85rem);
      line-height: 1.25;
    }

    .project-cards.is-filtered-view .project-card--feature p {
      max-width: none;
    }

    .project-cards.is-filtered-view .project-card--feature .project-meta {
      /* No forced margin-top: the secondary card's meta owns no extra gap
         either, and the flex column already spaces its children evenly. */
      margin-top: 0;
      padding-top: 0;
      border-top: 0;
    }

    .project-cards.is-filtered-view .project-card--feature .project-card-action {
      /* Matches the secondary card's action exactly: same dark label and the
         same 700 weight, not the 800 the dark feature panel carries. */
      color: var(--brand-black);
      font-weight: 700;
    }

    /* The feature card's own corner mark, on loan from the same shared
       .card-chevron secondary/company cards already carry (same tokens, same
       drawing, same white-line-on-white-surface treatment - nothing invented).
       Hidden by default: the editorial "all" state has no chevron on this
       card and no z-index escape hatch for its text, so an always-on chevron
       would paint over the copy there (position:0 stacks above in-flow text).
       Only turned on once .is-filtered-view has already demoted this card to
       the same plain white surface as its siblings. Mirrored for LTR exactly
       like the secondary/company card chevron (sdeira-sections.css). Site
       owner flagged, 12 Aug 2026 (ported from the Arabic fix). */
    .project-card--feature .card-chevron {
      display: none;
    }

    .project-cards.is-filtered-view .project-card--feature .card-chevron {
      display: block;
      position: absolute;
      z-index: 0;
      /* `inset: auto` FIRST - clears the blanket `.card-chevron.card-chevron
         { inset: 0 }` reset in sdeira-sections.css (higher specificity,
         always wins) before this rule's own edges apply, or `top` stays
         pinned at 0 underneath them. */
      inset: auto;
      left: auto;
      right: -7%;
      bottom: -8%;
      width: min(40%, 180px);
      aspect-ratio: 434 / 281;
      opacity: 1;
      --chev-line: var(--brand-white);
      --chev-tint: rgba(255, 255, 255, .30);
      pointer-events: none;
      transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
    }

    .project-cards.is-filtered-view .project-card--feature .card-chevron svg {
      width: 100%;
      height: 100%;
      overflow: visible;
      transform: scaleX(-1);
    }

    .project-cards.is-filtered-view .project-card--feature .project-card-body > :not(.card-chevron) {
      position: relative;
      z-index: 1;
    }

    .project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within) .card-chevron {
      transform: translate3d(-14px, -10px, 0);
    }

    @media (prefers-reduced-motion: reduce) {
      .project-cards.is-filtered-view .project-card--feature .card-chevron { transition: none; }
    }

    @media (max-width: 720px) {
      .news-grid.is-filtered-view,
      .featured-projects .project-cards.is-filtered-view {
        grid-template-columns: 1fr;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .project-card--feature .project-card-img img {
        transition: none;
      }

      .project-card--feature:is(:hover, :focus-within) .project-card-img img {
        transform: none;
      }
    }

    /* One oversized identity mark enters from the quiet side of the footer.
       Varying the strip widths makes it read as a deliberate brand gesture,
       rather than a repeated pattern behind every column. */
    footer {
      position: relative;
      isolation: isolate;
      overflow: hidden;
    }

    /* The oversized identity strips that used to enter from the quiet side of
       the footer were removed, matching the Arabic page. The positioning
       context stays because .wrap below still relies on it. */
    footer > .wrap {
      position: relative;
      z-index: 1;
    }

    /* Descriptive copy benefits from balanced line endings in Arabic. This
       keeps section summaries deliberate without changing their content. */
    main p,
    footer .foot-brand p {
      text-wrap: balance;
    }

    .cta-inner > p {
      max-inline-size: 53ch;
    }

    /* A section-level action shares the filter row, but stays visually
       secondary to the active tab. The same pattern works as an archive link
       once a dedicated archive page is available. */
    .section-filter-bar {
      display: flex;
      align-items: stretch;
      justify-content: space-between;
      gap: 20px;
      width: 100%;
    }

    .section-filter-bar :is(.project-filters, .news-filters) {
      margin: 0;
    }

    .section-view-all {
          position: relative;
    z-index: 0;
    display: inline-flex;
    align-items: center;
    gap: .48rem;
    min-height: 0;
    padding: 0 0 4px;
    overflow: visible;
    isolation: auto;
    cursor: pointer;
    background: transparent;
    color: var(--brand-white);
    font-size: var(--type-action);
    font-weight: 800;
    line-height: 1.3;
    transition: opacity var(--dur-base) var(--ease-out), visibility var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-out);
    }

    /* The same underline-grow motion the Arabic homepage's .section-view-all
       carries (shared .action-link treatment): 3px line resting at scaleX(.42),
       growing to full width on hover/focus, originating from the same side. */
    .section-view-all::after {
          content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-end: 0;
    inline-size: 100%;
    block-size: 2px;
    background: currentColor;
    transform: scaleX(.42);
    transform-origin: left center;
    transition: transform var(--dur-base) var(--ease-out);
    }

    [dir="ltr"] .section-view-all > i.ph {
    transform: rotate(-35deg);
}


    .section-view-all:is(:hover, :focus-visible)::after {
      transform: scaleX(1);
    }

    :is(.action-link, .sector-card-action, .section-view-all) > i.ph {
      flex: 0 0 auto;
      transform: rotate(45deg);
      transition: transform var(--dur-base) var(--ease-out);
    }

    .section-view-all > i.ph {
      display: inline-block;
    line-height: 1;
    color: inherit;
    flex: 0 0 auto;
    font-size: var(--ic-md);
    }

    .section-view-all:is(:hover, :focus-visible) > i.ph {
      transform: rotate(0deg);
    }

    .section-view-all:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 4px;
    }

    @media (max-width: 620px) {
      .section-filter-bar {
        align-items: flex-start;
        flex-direction: column;
      }

      /* On phones, project and news filters replace their section actions. */
      :is(.featured-projects, .news-section) .section-view-all {
        display: none;
      }
    }

    /* Match the approved Arabic contact composition. Language direction only
       changes the reading order; photography, contrast, spacing, surfaces,
       and action hierarchy remain one bilingual component. */
    .cta::before {
      background-image: var(--cta-image, url("../images/group-living/contact-community.webp?v=c00aaa588af31a4f"));
      background-position: center;
    }

    .cta::after {
      background: rgb(0 0 0);
      opacity: .76;
    }

    .cta-inner {
      width: min(1420px, 100%);
      text-align: center;
    }

    .cta .kicker {
      justify-content: center;
    }

    .cta h2,
    .cta p {
      margin-inline: auto;
    }

    .cta-actions {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 26px;
      max-width: none;
    }

    .cta-action,
    .cta-action:first-child,
    .cta-action:last-child {
      background: rgba(43, 41, 41, .92);
      border: 1px solid rgba(255, 255, 255, .22);
      border-radius: var(--r);
      color: var(--brand-white);
      clip-path: none;
    }

    .cta-action:first-child {
      background: var(--accent);
      border-color: var(--accent);
    }

    .cta-action i.ph {
      color: currentColor;
    }

    .cta-action .cta-action-note {
      display: none;
    }

    /* Contact routes keep every action element on one horizontal line: route
       mark, label, then the English-direction arrow. */
    .cta-action,
    .cta-action:first-child,
    .cta-action:last-child {
      display: flex;
      position: relative;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      gap: 14px;
      min-height: 84px;
      padding: 14px 20px;
      text-align: start;
    }

    .cta-action > i.ph:not(.cta-arrow) {
      display: none !important;
    }

    /* The route mark stays in the normal horizontal flow for every action. */
    .cta-action > i.ph.cta-action-mark:not(.cta-arrow) {
      display: block !important;
      position: relative;
      z-index: 2;
      width: auto;
      height: auto;
      margin: 0;
      background: transparent;
      color: currentColor;
      font-size: 1.7rem;
      line-height: 1;
      opacity: 1;
      pointer-events: none;
      transform: none;
    }

    .cta-action > span:not(.cta-action-note),
    .cta-action .cta-arrow {
      position: relative;
      z-index: 2;
    }

    .cta-action > span:not(.cta-action-note) {
      flex: 0 1 auto;
      max-width: none;
      font-size: clamp(1rem, 1.25vw, 1.18rem);
      line-height: 1.35;
      text-align: start;
    }

    .cta-action .cta-arrow {
      display: grid !important;
      place-items: center;
      position: relative !important;
      inset: auto;
      margin-inline-start: auto;
      font-size: .9rem !important;
      transform: none;
    }

    /* Contact routes use the same concise colour response as the primary
       button: no lift, wipe, or layout movement. */
    .cta-action {
      overflow: hidden;
      transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }

    .cta-action::before {
      display: none;
    }

    .cta-action:is(:hover, :focus-visible),
    .cta-action:first-child:is(:hover, :focus-visible) {
      transform: none;
      background-color: var(--accent-deep);
      border-color: var(--accent-deep);
    }

    /* Desktop contact routes remain a single three-action row. Mobile keeps
       its intentional one-column layout below 620px. */
    @media (min-width: 621px) {
      .cta-actions { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
    }

    @media (max-width: 620px) {
      .cta-actions {
        grid-template-columns: 1fr;
        gap: 12px;
      }
    }

    /* Filter strips get their own breathing room: they are controls between
       the editorial introduction and the card collection, never a divider
       glued to either. */
    .section-filter-bar {
      margin-block: clamp(28px, 3vw, 42px) clamp(24px, 2.5vw, 36px);
    }

    .projects-head:has(.section-filter-bar) {
      gap: clamp(28px, 3vw, 42px);
      margin-bottom: 0;
      grid-template-columns: minmax(0, 1fr);
      justify-content: stretch;
    }

    .projects-head .section-filter-bar {
      margin-block: 0 clamp(24px, 2.5vw, 36px);
    }

    /* Contextual action is the one shared card-link component.  Colours may
       vary for contrast against each card surface, but its spacing, underline
       and directional movement never vary by section. */
    :is(.action-link, .sector-card-action) {
      gap: .48rem;
      padding-block-end: 4px;
      overflow: visible;
    }

    :is(.action-link, .sector-card-action) > i.ph {
      flex: 0 0 auto;
      transform: rotate(45deg);
      transition: transform var(--dur-base) var(--ease-out);
    }

    :is(.action-link, .sector-card-action):is(:hover, :focus-visible) > i.ph,
    :is(.news-card, .project-card, .sector-card, .company-card, .needs-route):is(:hover, :focus-within) :is(.action-link, .sector-card-action) > i.ph {
      transform: rotate(0deg);
    }

    :is(.news-card, .project-card, .sector-card, .company-card, .needs-route):is(:hover, :focus-within)
      :is(.action-link, .sector-card-action):not(.is-pending)::after {
      transform: scaleX(1);
    }

    :is(.action-link, .sector-card-action)::after {
      block-size: 2px;
    }

    /* On touch-size sector cards the Arabic action keeps its literal leftward
       arrow. The desktop turn-on-hover rotation is not useful without hover
       and made the direction visually ambiguous. The 8px gutter separates
       every card without changing the two-column structure. */
    @media (max-width: 720px) {
      .hero-sectors .sector-grid {
        gap: 8px;
      }

      .hero-sectors .sector-card-action > i.ph,
      .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-action > i.ph {
        transform: none;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      :is(.action-link, .sector-card-action) > i.ph {
        transition: none;
      }
    }

    /* The five sector cards share one square geometry. Interaction moves only
       their content, so hover and keyboard focus never resize the hero rail. */
    .hero-sectors .sector-grid {
      grid-auto-rows: 1fr;
      align-items: stretch;
    }

    /* Ported from sdeira-v2.html (port log item 13a): the card no longer forces
       a square, so its resting height follows its content instead of a ratio
       that left a gap under the shorter description. Only possible now that
       the two-line description reservation (item 10) makes all five cards
       agree on a height without a fixed number. The hover action link is
       absolutely positioned and hidden at rest, and only needs to clear its
       own small reveal, so the card can shrink without the hover state
       colliding with it. */
    .hero-sectors .sector-card {
      aspect-ratio: auto;
      inline-size: 100%;
      block-size: auto;
      min-block-size: 0;
      min-height: 0;
      overflow: hidden;
    }

    /* The ramp climbs gradually across nearly the whole card, not in a short
       jump partway down.

       Two earlier attempts inside this same edit were measured against
       unloaded <img> elements (loading="lazy" images that were never
       force-decoded before sampling): getImageData on an incomplete image
       returns transparent black for every pixel, so those contrast numbers
       were computed against rgba(0,0,0,0), not the photograph. They happened
       to still report AA passes, which is meaningless - they were not
       measuring the real composite at all. This is the first version verified
       against fully decoded images (img.decode() awaited before sampling).

       Against the real, loaded photos, the previous stops (a jump from .42 at
       50% to .82 at 65%, slope .027 per 1%) failed Services at 4.36, below
       the 4.5 AA floor. This curve widens the climb further and lifts the
       55%-70% band specifically, where Services' brightest region sits: peak
       slope is .02 per 1%, 44% gentler than the original .036 jump, and every
       card now clears AA with the real images loaded - worst case 6.42 on
       Services, up to 9.16 on Development. */
    .hero-sectors .sector-card-veil {
      background: linear-gradient(180deg,
        rgba(var(--image-overlay-rgb), .04) 0%,
        rgba(var(--image-overlay-rgb), .06) 10%,
        rgba(var(--image-overlay-rgb), .09) 20%,
        rgba(var(--image-overlay-rgb), .14) 30%,
        rgba(var(--image-overlay-rgb), .22) 40%,
        rgba(var(--image-overlay-rgb), .34) 50%,
        rgba(var(--image-overlay-rgb), .42) 55%,
        rgba(var(--image-overlay-rgb), .52) 60%,
        rgba(var(--image-overlay-rgb), .62) 65%,
        rgba(var(--image-overlay-rgb), .70) 70%,
        rgba(var(--image-overlay-rgb), .80) 80%,
        rgba(var(--image-overlay-rgb), .87) 90%,
        rgba(var(--image-overlay-rgb), .92) 100%);
    }

    .hero-sectors .sector-card-body {
      position: relative;
      min-block-size: 0;
      padding: clamp(14px, 1.35vw, 18px);
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-end;
      gap: 6px;
    }

    .hero-sectors .sector-card-mark,
    .hero-sectors .sector-card-title,
    .hero-sectors .sector-card-sub {
      margin: 0;
      transition: transform var(--dur-base) var(--ease-out),
        opacity var(--dur-fast) var(--ease-out);
    }

    .hero-sectors .sector-card-mark {
      flex: 0 0 auto;
      margin-block-end: 2px;
    }

    .hero-sectors .sector-card-sub {
      min-height: 0;
    }

    .hero-sectors .sector-card-action {
      position: absolute;
      inset-inline-start: clamp(14px, 1.35vw, 18px);
      inset-block-end: clamp(14px, 1.35vw, 18px);
      margin: 0;
      padding: 0 0 4px;
      min-height: 0;
      opacity: 0;
      pointer-events: none;
      transform: translateY(6px);
      transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .hero-sectors .sector-card:is(:hover, :focus-within) :is(.sector-card-title, .sector-card-sub) {
      transform: translateY(-32px);
    }

    .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-sub {
      opacity: 1;
      visibility: visible;
    }

    .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-action {
      opacity: 1;
      pointer-events: auto;
      transform: none;
    }

    @media (prefers-reduced-motion: reduce) {
      .hero-sectors .sector-card-mark,
      .hero-sectors .sector-card-title,
      .hero-sectors .sector-card-sub,
      .hero-sectors .sector-card-action {
        transition: none;
      }
    }

    @media (max-width: 980px) {
      .hero-sectors .sector-grid {
        grid-auto-rows: auto;
      }

      /* RETUNED, site owner 29 Aug 2026: the forced 1/1 square this comment
         used to defend read as oversized on the narrower end of this range
         (a 2-column card at ~450px wide squared to ~450px tall). Left
         auto, matching every other breakpoint's own height-driven card, so
         min-height (below, first max-width:980px block) sets the card's
         height instead of its own width - shorter and calmer on
         tablet-width screens. The 2/1 rule on the trailing odd card also
         drops: with no square pair to match, a plain span is enough. */
      .hero-sectors .sector-card {
        aspect-ratio: auto;
      }
    }

    /* Direct routes use the same calm white-card language as the subsidiary
       companies. The audience appears first so visitors can recognise their
       route before having to decode the service name. */
    .needs {
      position: relative;
      overflow: hidden;
      padding-block: clamp(76px, 8vw, 124px);
      background: var(--surface-sunken);
      color: var(--ink);
    }

    .needs-layout {
      display: grid;
      grid-template-columns: minmax(250px, .72fr) minmax(0, 1.28fr);
      gap: clamp(40px, 6vw, 92px);
      align-items: start;
    }

    .needs-intro {
      padding-top: clamp(8px, 1.2vw, 20px);
    }

    .needs-intro .kicker {
      color: var(--label);
    }

    .needs-intro h2 {
      max-width: 10ch;
      margin: 16px 0 24px;
      color: var(--ink);
      font-size: clamp(2.6rem, 5vw, 5rem);
      line-height: 1.03;
    }

    .needs-intro p {
      max-width: 37ch;
      margin: 0;
      color: var(--muted);
      font-size: clamp(1rem, 1.25vw, 1.16rem);
      line-height: 1.85;
    }

    .needs-routes {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: clamp(16px, 2vw, 24px);
    }

    .needs-route {
      position: relative;
      display: grid;
      grid-template-rows: clamp(132px, 12vw, 176px) 1fr;
      overflow: hidden;
      min-width: 0;
      min-height: 360px;
      background: var(--surface-base);
      color: var(--ink);
      text-decoration: none;
    }

    .needs-route-media {
      position: relative;
      display: block;
      overflow: hidden;
      border-radius: var(--r);
    }

    .needs-route-media img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform var(--dur-slow);
    }

    .needs-route:hover .needs-route-media img,
    .needs-route:focus-within .needs-route-media img {
      transform: scale(var(--zoom));
    }

    /* ===== CARD CHEVRON =====
       The Khadamat service-card sticker (khadamat.css:975-1029), carried over
       whole: same paths, same per-path opacities, same corner overhang, same
       hover step. One shared class for both white-card families (direct
       routes and subsidiary companies) so the two cannot drift apart.

       Two adaptations the source did not need, both forced by the surface:
       the source sits on a dark photograph, this sits on a white card. Its
       four hairlines are stroked #fff, which is invisible here, so they take
       Sweihan; and the small highlight wedge is likewise a tint rather than
       near-white. Everything else is untouched.

       Layering is z-index 0 with the copy raised to 1, NOT z-index -1. A
       negative index was tried first and is invisible on both hosts, for two
       different reasons that neither look like a bug: .needs-route paints no
       background of its own (the white belongs to .needs-route-copy, which is
       position: relative + z-index: 3, so it covers anything negative beneath
       it), and .company-card is only a stacking context while its .reveal
       animation still holds opacity: 0 - once revealed it stops being one, and
       a negative child drops behind the card's own white background. Raising
       the content is the layering that survives both. The host card already
       clips (overflow: hidden), which is what crops this to a corner sticker
       rather than a floating triangle. */
    .card-chevron {
      --chev-tint: color-mix(in srgb, var(--brand-razeen) 34%, var(--brand-white));
      --chev-line: var(--brand-sweihan);
      position: absolute;
      z-index: 0;
      /* `inset: auto` FIRST - this plain `.card-chevron` (0,1,0) loses the
         cascade to sdeira-sections.css's blanket `.card-chevron.card-chevron
         { inset: 0 }` (0,2,0), which always wins regardless of file load
         order since its specificity is higher. That rule pins top/right to
         0; this rule's own left/bottom below never cleared them, so the
         sticker inherited all four sides and stretched across most of the
         card instead of anchoring a small corner mark - flagged from a
         screenshot of the homepage's own "Direct routes" cards, 28 Aug 2026.
         Same bug, same fix, as every project/company card family in
         sdeira-sections.css. */
      inset: auto;
      left: -7%;
      bottom: -8%;
      width: min(62%, 300px);
      aspect-ratio: 434 / 281;
      opacity: .78;
      pointer-events: none;
      transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
    }

    .card-chevron svg {
      width: 100%;
      height: 100%;
      overflow: visible;
    }

    /* Mirrored for LTR, matching the established precedent for this exact
       component: .business-needs-routes .card-chevron in sdeira-sections.css
       already does this (left: -7% -> right: -7%, plus scaleX(-1) on the
       artwork so the drawing itself flips corner rather than just sliding to
       the other one - a position-only mirror would leave a shape whose own
       straight edges no longer line up with the card's corner). That earlier
       decision was recorded as scoped to its own page; this is the matching,
       separate decision for the homepage's card family (.company-card,
       .project-card--secondary), made by the site owner, 12 Aug 2026. */
    html[dir="ltr"] .card-chevron {
      left: auto;
      right: -7%;
    }

    html[dir="ltr"] .card-chevron svg {
      transform: scaleX(-1);
    }

    html[dir="ltr"] :is(.needs-route, .company-card, .project-card--secondary):is(:hover, :focus-within) .card-chevron {
      transform: translate3d(-14px, -10px, 0);
    }

    /* The copy has to out-rank the sticker explicitly: in-flow text paints
       BEFORE positioned z-index: 0 elements, so without this the chevron
       would cover the words rather than sit behind them. .company-num is
       excluded because it is the screen-reader-only number and relies on
       position: absolute for its clip - handing it position: relative would
       drop it back into the visible layout. */
    .needs-route-copy > :not(.card-chevron),
    .company-card > :not(.card-chevron, .company-num) {
      position: relative;
      z-index: 1;
    }

    :is(.needs-route, .company-card, .project-card--secondary):is(:hover, :focus-within) .card-chevron {
      transform: translate3d(14px, -10px, 0);
    }

    /* The card sticker is drawn in flat white line, in BOTH states, and at
       full strength, on every card family that carries it.

       Line first. Sweihan hairlines measure 1.28 on the #cb6c2e hover fill and
       read as dirt rather than as drawing, so the hover state had to change
       anyway; plain white in both states is what keeps the drawing one shape
       that fills in, instead of a shape that also changes colour mid-gesture.
       No alpha on the line itself - the SVG's own per-path stroke-opacity
       (.55-.65) is already the depth in this drawing, and stacking a second
       transparency on top of it was what greyed the whole thing out.

       Then strength. The shared class rests at .78 and lifts to .94; here it
       is 1 throughout. The rest state is the state a visitor actually spends
       time looking at, and fading the identity mark to three-quarters there
       bought nothing - the drawing is already quiet by weight (1px lines) and
       by size. Only the position still moves on hover.

       Consequence, stated rather than discovered later: at rest the panel is
       white, so the white lines read only where they cross the coloured
       wedge. That is the intended reading - a soft mark that resolves fully
       once the panel fills. */
    :is(.needs-route, .project-card--secondary, .company-card) .card-chevron,
    :is(.needs-route, .project-card--secondary, .company-card):is(:hover, :focus-within) .card-chevron {
      --chev-line: var(--brand-white);
      --chev-tint: rgba(255, 255, 255, .30);
      opacity: 1;
    }

    /* Deliberately smaller than the shared default. At min(62%, 300px) the
       sticker reached the middle of the card and left no room for the copy to
       grow: one more line of body text and the words would have run into the
       drawing. Now that all three card families carry it, this is the size -
       kept as a scoped rule rather than folded into .card-chevron only
       because that class is also the one the shared default documents. */
    :is(.needs-route, .project-card--secondary, .company-card) .card-chevron {
      width: min(40%, 180px);
    }

    @media (prefers-reduced-motion: reduce) {
      .card-chevron { transition: none; }
    }

    .needs-route:focus-visible {
      outline: 2px solid var(--brand-black);
      outline-offset: 4px;
    }

    .needs-route:focus-visible {
      outline: 2px solid var(--brand-black);
      outline-offset: 4px;
    }

    .needs-route-copy {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      min-height: 0;
      padding: clamp(22px, 2.3vw, 30px);
      min-width: 0;
    }

    .needs-route-audience {
      display: block;
      margin-bottom: 12px;
      color: var(--label);
      font-size: .84rem;
      font-weight: 700;
      line-height: 1.45;
    }

    .needs-route h3 {
      margin: 0;
      min-block-size: 2.5em;
      color: var(--ink);
      font-size: clamp(1.25rem, 1.7vw, 1.65rem);
      line-height: 1.25;
      text-wrap: balance;
    }

    .needs-route p {
      flex: 1 1 auto;
      margin: 12px 0 0;
      min-block-size: 3.3em;
      color: var(--muted);
      line-height: 1.65;
      text-wrap: balance;
    }

    .needs-route-action {
      /* Placement only; appearance and motion come from .action-link. */
      margin-top: auto;
      padding-top: 20px;
      color: var(--ink);
      align-self: flex-start;
      width: auto;
      max-width: calc(100% - 1.5em);
      white-space: nowrap;
    }

    .needs-route-action i.ph {
      color: currentColor;
    }

    @media (max-width: 920px) {
      .needs-layout {
        grid-template-columns: 1fr;
        gap: 42px;
      }

      .needs-intro h2 {
        max-width: none;
      }
    }

    @media (max-width: 620px) {
      .needs {
        padding-block: 68px;
      }

      .needs-routes {
        grid-template-columns: 1fr;
      }

      .needs-route {
        grid-template-rows: 168px 1fr;
        min-height: 0;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .needs-route-media img,
      .needs-route-action i {
        transition: none;
      }
    }

    /* Temporary decision previews for the direct-routes section. Both use the
       same routes and photography; only the hierarchy changes, so the choice
       is about the layout rather than different content. */
    .needs-prototypes {
      padding-block: clamp(84px, 10vw, 148px);
      background: var(--surface-base);
      color: var(--ink);
    }

    .needs-prototypes-intro {
      max-width: 760px;
      margin: 0 auto clamp(48px, 6vw, 76px);
      text-align: center;
    }

    .needs-prototypes-intro .kicker { justify-content: center; }
    .needs-prototypes-intro h2 { margin: 14px 0 12px; font-size: clamp(2rem, 4vw, 3.35rem); line-height: 1.18; }
    .needs-prototypes-intro p { margin: 0; color: var(--muted); text-wrap: balance; }

    .needs-prototype + .needs-prototype {
      margin-top: clamp(76px, 10vw, 148px);
      padding-top: clamp(76px, 10vw, 148px);
      border-top: 1px solid var(--surface-sunken-strong);
    }

    .needs-prototype-head {
      position: static !important;
      inset: auto !important;
      transform: none !important;
      max-width: 760px;
      margin: 0 auto;
      padding: 0;
      text-align: center;
    }

    .needs-prototype-head .kicker { justify-content: center; }
    .needs-prototype-head h3 { margin: 14px 0 12px; font-size: clamp(2rem, 4vw, 3.2rem); line-height: 1.18; }
    .needs-prototype-head p { margin: 0; color: var(--muted); text-wrap: balance; }

    .needs-prototype-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      gap: clamp(16px, 2vw, 24px);
      margin-top: clamp(38px, 5vw, 64px);
    }

    .needs-prototype-tile {
      display: grid;
      grid-template-rows: auto auto;
      min-width: 0;
      min-height: 0;
      align-self: start;
      overflow: hidden;
      background: #fff;
      color: var(--ink);
      text-decoration: none;
    }

    .needs-prototype-media,
    .needs-prototype-tile-media,
    .needs-prototype-row-media {
      position: relative;
      overflow: hidden;
      background: var(--brand-black);
    }

    .needs-prototype-media::after,
    .needs-prototype-tile-media::after,
    .needs-prototype-row-media::after {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(180deg, transparent 35%, rgba(23, 22, 20, .32));
      pointer-events: none;
    }

    .needs-prototype-media::before,
    .needs-prototype-tile-media::before,
    .needs-prototype-row-media::before {
      content: "";
      position: absolute;
      z-index: 1;
      inset-block: -20%;
      inset-inline-start: -5%;
      width: 62%;
      background: linear-gradient(var(--brand-stripe-gradient-angle),
        transparent 0 17%, rgba(255, 255, 255, .72) 17% 21%,
        transparent 21% 40%, rgba(201, 151, 55, .8) 40% 47%,
        transparent 47% 64%, rgba(220, 105, 40, .75) 64% 72%, transparent 72%);
      pointer-events: none;
    }

    .needs-prototype-tile img,
    .needs-prototype-row img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform var(--dur-slow) var(--ease-out);
    }

    .needs-prototype-tile .needs-prototype-media {
      aspect-ratio: 16 / 9;
    }

    .needs-prototype-copy,
    .needs-prototype-tile-copy {
      display: flex;
      flex-direction: column;
      min-height: 290px;
      padding: clamp(22px, 2.4vw, 30px);
    }

    .needs-prototype-copy small,
    .needs-prototype-row-copy small { color: var(--label); font-size: .82rem; font-weight: 700; line-height: 1.45; }
    .needs-prototype-copy strong { margin: 12px 0 0; font-size: clamp(1.28rem, 1.7vw, 1.55rem); line-height: 1.3; text-wrap: balance; }
    .needs-prototype-copy em { flex: 1 1 auto; margin: 14px 0 0; color: var(--muted); font-size: .94rem; font-style: normal; line-height: 1.7; text-wrap: balance; }

    .needs-prototype-copy b,
    .needs-prototype-row-copy b,
    .needs-prototype-link {
      position: relative;
      display: inline-flex;
      align-self: flex-start;
      max-width: calc(100% - 1.5em);
      margin-top: 24px;
      color: var(--ink);
      font-size: .92rem;
      font-weight: 700;
      white-space: nowrap;
    }

    .needs-prototype-copy b::after,
    .needs-prototype-row-copy b::after,
    .needs-prototype-link::after { content: ""; position: absolute; inset-inline: 0; bottom: -5px; block-size: 2px; background: currentColor; transform-origin: right; transform: scaleX(.38); transition: transform var(--dur-base) var(--ease-out); }
    .needs-prototype-copy b i,
    .needs-prototype-row-copy b i,
    .needs-prototype-link i { position: absolute; inset-inline-end: -1.45em; opacity: 0; transform: translateX(7px); transition: opacity 180ms var(--ease-out), transform 240ms var(--ease-out); }

    .needs-prototype-tile:is(:hover, :focus-visible) img,
    .needs-prototype-row:is(:hover, :focus-visible) img { transform: scale(var(--zoom)); }
    .needs-prototype-tile:is(:hover, :focus-visible) b::after,
    .needs-prototype-row:is(:hover, :focus-visible) b::after,
    .needs-prototype-tile:is(:hover, :focus-visible) .needs-prototype-link::after,
    .needs-prototype-row:is(:hover, :focus-visible) .needs-prototype-link::after { transform: scaleX(1); }
    .needs-prototype-tile:is(:hover, :focus-visible) b i,
    .needs-prototype-row:is(:hover, :focus-visible) b i,
    .needs-prototype-tile:is(:hover, :focus-visible) .needs-prototype-link i,
    .needs-prototype-row:is(:hover, :focus-visible) .needs-prototype-link i { opacity: 1; transform: none; }

    .needs-prototype-stream { display: grid; gap: clamp(24px, 3vw, 40px); margin-top: clamp(38px, 5vw, 64px); }

    .needs-prototype-row {
      display: grid;
      grid-template-columns: minmax(360px, 1.1fr) minmax(320px, .9fr);
      align-items: stretch;
      min-width: 0;
      color: var(--ink);
      text-decoration: none;
    }

    /* Horizontal alternative: every route uses the same 16:9 image field.
       The identity cuts are deliberately warm-white and translucent, so they
       belong to the page surface rather than competing with the photography. */
    .needs-prototype-row-media {
      min-height: 0;
      aspect-ratio: 16 / 9;
    }

    .needs-prototype-row-media::after {
      background: linear-gradient(180deg, rgba(23, 22, 20, .04), rgba(23, 22, 20, .16));
    }

    .needs-prototype-row-media::before {
      inset-block: -12%;
      inset-inline-start: -7%;
      width: 70%;
      background: linear-gradient(var(--brand-stripe-gradient-angle),
        transparent 0 19%, rgba(250, 246, 239, .38) 19% 23%,
        transparent 23% 43%, rgba(201, 151, 55, .16) 43% 49%,
        transparent 49% 69%, rgba(220, 105, 40, .12) 69% 76%, transparent 76%);
    }

    .needs-prototype-row:nth-child(1) .needs-prototype-row-media::before {
      width: 38%;
      background: linear-gradient(var(--brand-stripe-gradient-angle), transparent 0 42%, rgba(250, 246, 239, .42) 42% 49%, transparent 49%);
    }

    .needs-prototype-row:nth-child(2) .needs-prototype-row-media::before {
      width: 56%;
      background: linear-gradient(var(--brand-stripe-gradient-angle), transparent 0 25%, rgba(250, 246, 239, .38) 25% 32%, transparent 32% 57%, rgba(201, 151, 55, .14) 57% 64%, transparent 64%);
    }

    .needs-prototype-row:nth-child(3) .needs-prototype-row-media::before {
      width: 73%;
    }

    .needs-prototype-row:nth-child(4) .needs-prototype-row-media::before {
      inset-inline-start: 30%;
      width: 46%;
      background: linear-gradient(var(--brand-stripe-gradient-angle), transparent 0 25%, rgba(250, 246, 239, .42) 25% 33%, transparent 33% 58%, rgba(220, 105, 40, .12) 58% 65%, transparent 65%);
    }

    .needs-prototype-row-copy {
      position: relative;
      z-index: 2;
      display: flex;
      flex-direction: column;
      align-self: center;
      min-height: min(74%, 300px);
      margin-inline-start: clamp(-96px, -7vw, -44px);
      padding: clamp(30px, 4vw, 58px);
      background: #fff;
      box-shadow: none;
    }

    .needs-prototype-row-copy strong { margin: 12px 0 0; font-size: clamp(1.55rem, 2.4vw, 2.35rem); line-height: 1.2; text-wrap: balance; }
    .needs-prototype-row-copy > small {
      display: inline-flex;
      align-self: flex-start;
      padding: 6px 10px;
      border-radius: var(--r);
      background: var(--surface-sunken);
      color: var(--brand-jais);
      font-size: .78rem;
      font-weight: 800;
      line-height: 1.35;
    }
    .needs-prototype-row-copy em {
      margin: 18px 0 0;
      color: var(--muted);
      font-style: normal;
      line-height: 1.8;
      text-wrap: balance;
    }
    .needs-prototype-row-copy b,
    .needs-prototype-row .needs-prototype-link { margin-top: auto; padding-top: 26px; }

    @media (max-width: 700px) {
      .needs-prototype-grid { grid-template-columns: 1fr; }
      .needs-prototype-row { grid-template-columns: 1fr; }
      .needs-prototype-row-copy { margin: -36px 18px 0; min-height: 0; }
    }

    @media (prefers-reduced-motion: reduce) {
      .needs-prototype-tile img,
      .needs-prototype-row img,
      .needs-prototype-link,
      .needs-prototype-link i { transition: none; }
    }

    /* Direct routes: approved horizontal composition. The former grid and
       review alternatives have been consolidated into this one live pattern:
       a calm warm background, a concise centred introduction and four
       substantial routes.  The image is deliberately taller than 16:9 so the
       photography has enough presence without turning the content card into a
       floating overlay. */
    .needs {
      padding-block: clamp(84px, 10vw, 144px);
      background: #F6E9D6;
      color: var(--ink);
    }

    .needs-layout { display: block; }

    /* The section head starts at the content edge like every other one on the
       page, instead of being centred on its own. All three properties are
       logical, so the same rule reads left here and right on the Arabic page
       with no direction branch: text-align: start, margin-inline: 0 rather
       than auto, and flex-start on the kicker row. The 760px cap stays - it
       limits the line length, it was never what centred the block.
       (Port log item 41.) */
    .needs-intro {
      max-width: 760px;
      margin-inline: 0;
      padding: 0;
      text-align: start;
    }

    .needs-intro .kicker { justify-content: flex-start; }
    .needs-intro h2 {
      max-width: none;
      margin: 14px 0 12px;
      font-size: clamp(2.25rem, 4.4vw, 3.55rem);
      line-height: 1.16;
    }
    .needs-intro p { max-width: 55ch; margin-inline: 0; }

    .needs-routes {
      display: grid;
      grid-template-columns: 1fr;
      gap: clamp(28px, 3.6vw, 52px);
      margin-top: clamp(42px, 5.5vw, 74px);
    }

    .needs-route {
      display: grid;
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: minmax(clamp(330px, 40vw, 470px), auto);
      align-items: center;
      min-height: clamp(330px, 40vw, 470px);
      direction: rtl;
      color: var(--ink);
      background: transparent;
      isolation: isolate;
    }

    .needs-route-media {
      grid-area: 1 / 1;
      justify-self: end;
      align-self: center;
      z-index: 1;
      width: min(72%, 800px);
      min-height: 0;
      aspect-ratio: 16 / 9;
      background: var(--surface-sunken);
    }

    .needs-route:nth-child(even) .needs-route-media { justify-self: start; }

    .needs-route-copy {
      grid-area: 1 / 1;
      justify-self: start;
      direction: ltr;
      position: relative;
      z-index: 3;
      align-self: center;
      /* THE PANEL'S HEIGHT IS ITS CONTENT'S, and stays that way. A reserved
         minimum was tried here on 21 August 2026 and rejected the same hour:
         it makes every panel the height of the tallest one, which is a lot of
         empty ground under a two-line card. The card lost about 47px when the
         review removed its sentence; what that cost was the separation
         between the title and the action, and that is fixed on
         .needs-route-action below, where it belongs. */
      width: min(48%, 520px);
      min-height: 0;
      margin: 0;
      padding: clamp(28px, 3.4vw, 46px);
      background: var(--surface-raised);
      box-shadow: none;
      /* THE PANEL IS THE CHEVRON'S CLIP, AND BOTH OF THESE WERE LOST IN THE
         PORT. .card-chevron parks itself outside the panel (left/right -7%,
         bottom -8%) and its <svg> is overflow: visible, so its line paths draw
         up to 300px past the box - the sticker is only a corner sticker
         because its host crops it. Without overflow: hidden the whole drawing
         floats free, across the photograph and out under the card, which is
         what the page showed. Nothing errors and no rule about the chevron is
         wrong: the crop lives here, on a selector that never mentions it.
         border-radius went with it in the same omission; every other card
         panel on both pages carries var(--r). */
      overflow: hidden;
      border-radius: var(--r);
    }

    .needs-route:nth-child(even) .needs-route-copy { justify-self: end; }

    .needs-route-audience {
      display: inline-flex;
      align-self: flex-start;
      width: fit-content;
      margin: 0;
      padding: 6px 10px;
      background: var(--surface-sunken);
      color: var(--brand-jais);
      font-size: .78rem;
      font-weight: 800;
      line-height: 1.35;
    }
    .needs-route-copy > strong {
      min-block-size: 0;
      margin: 14px 0 0;
      color: var(--ink);
      font-size: clamp(1.55rem, 2.4vw, 2.35rem);
      font-weight: 400;
      line-height: 1.2;
      text-wrap: balance;
    }
    .needs-route-copy > em {
      flex: 0 1 auto;
      min-block-size: 0;
      margin: 18px 0 0;
      color: var(--muted);
      font-size: 1rem;
      font-style: normal;
      line-height: 1.8;
      text-wrap: balance;
    }
    .needs-route-action {
      align-self: flex-start;
      /* Was clamp(18px, 2vw, 26px), which read as the title's third line once
         the sentence between them was removed. The action is a separate part
         of the card and needs to look like one. */
      margin-top: clamp(30px, 3.6vw, 54px);
      padding-top: 0;
    }

    @media (max-width: 700px) {
      .needs-route {
        display: flex;
        flex-direction: column;
        min-height: 0;
      }
      .needs-route-media { width: 100%; aspect-ratio: 16 / 9; }
      .needs-route-copy {
        width: calc(100% - 36px);
        margin: -42px auto 0;
        min-height: 0;
      }
    }


    /* English mirror: the shared Arabic component layer above intentionally
       relies on logical properties. These few physical motion cues need an
       explicit LTR counterpart so arrows, underline origins, and decorative
       movement follow the English reading direction. */
    html[dir="ltr"] :is(.action-link, .sector-card-action)::after {
      transform-origin: left center;
    }

    /* The compact hero cards use flex now, but the title still carries an
       align-self:end value from their earlier grid layout. Short English
       labels therefore drift right while wrapped labels appear left-aligned. */
    html[dir="ltr"] .hero-sectors .sector-card-body {
      align-items: flex-start;
      text-align: start;
    }

    html[dir="ltr"] .hero-sectors :is(.sector-card-mark, .sector-card-title, .sector-card-sub) {
      align-self: flex-start;
      text-align: start;
    }

    html[dir="ltr"] .about-content,
    html[dir="ltr"] .about-copy {
      direction: ltr;
    }

    /* Mirror the editorial About composition for LTR: copy leads from the
       left, while the photograph and its identity cuts move to the right. */
    html[dir="ltr"] .about-layout {
      direction: rtl;
    }

    html[dir="ltr"] .about-badge {
      right: auto;
      left: -36px;
      direction: ltr;
      text-align: start;
    }

    /* Same reset, current component. .about-badge above was migrated to the
       shared .split-badge (sdeira-sections.css) and this reset was never
       ported with it: .about-layout is deliberately flipped to
       direction: rtl just above so its grid keeps the mirrored photo-right,
       copy-left composition, and that flip inherits into .split-badge with
       nothing to stop it - text-align: start then resolves to right instead
       of left. sdeira-sections.css already positions the badge with physical
       left/right and its own [dir="rtl"] override, so only direction and text
       alignment need restating here, not position. Site owner flagged,
       12 Aug 2026. */
    html[dir="ltr"] .split-badge {
      direction: ltr;
      text-align: start;
    }

    html[dir="ltr"] #companiesTitle {
      max-width: 18ch;
    }

    html[dir="ltr"] #newsTitle {
      max-width: 26ch;
      text-wrap: balance;
    }

    @media (max-width: 980px) {
      html[dir="ltr"] .about-badge {
        right: auto;
        left: 24px;
      }
    }

    @media (max-width: 600px) {
      html[dir="ltr"] .about-badge {
        right: auto;
        left: 14px;
      }
    }

    /* .section-view-all shares .action-link's underline-grow treatment, so its
       icon follows the same rotate-to-straight motion rather than a slide. */

    html[dir="ltr"] :is(.action-link, .sector-card-action) > i.ph {
      transform: rotate(-35deg);
    }

    html[dir="ltr"] :is(.action-link, .sector-card-action):is(:hover, :focus-visible) > i.ph,
    html[dir="ltr"] :is(.news-card, .project-card, .sector-card, .company-card, .needs-route):is(:hover, :focus-within) :is(.action-link, .sector-card-action) > i.ph {
      transform: rotate(0deg);
    }

    html[dir="ltr"] .company-card:hover::before,
    html[dir="ltr"] .company-card:focus-within::before {
      transform: translate3d(-6px, 0, 0);
    }

    html[dir="ltr"] .projects-copy {
      margin-inline-start: 0;
      margin-inline-end: auto;
      text-align: left;
    }

    html[dir="ltr"] .project-card--feature .project-card-img::after {
      background: linear-gradient(90deg, rgba(var(--image-overlay-rgb), .74), rgba(var(--image-overlay-rgb), .20) 68%, rgba(var(--image-overlay-rgb), .48));
    }

    html[dir="ltr"] .project-card--secondary,
    html[dir="ltr"] .project-card--secondary .project-card-body {
      background: var(--surface-raised);
    }

    html[dir="ltr"] :is(.project-cards, .news-grid).is-filtered-view {
      grid-auto-rows: 1fr;
    }

    html[dir="ltr"] .project-cards.is-filtered-view .project-card,
    html[dir="ltr"] .news-grid.is-filtered-view .news-card {
      height: 100%;
    }

    html[dir="ltr"] .project-cards.is-filtered-view .project-card--secondary {
      margin-top: 0;
      border-inline-start: 0;
    }

    html[dir="ltr"] .companies-grid {
      grid-auto-rows: 1fr;
    }

    html[dir="ltr"] .company-card {
      height: 100%;
    }

    /* Footer markup uses .foot-socials. Keep the social links visibly
       interactive without changing the footer layout or their hit area. */
    .foot-socials {
      display: flex;
      align-items: center;
      gap: 16px;
    }

    .foot-socials a {
      inline-size: 40px;
      block-size: 40px;
      display: grid;
      place-items: center;
      /* No outline on the tile. The system separates surfaces by tone, not by
         a line, and on the footer's true black a .3 white hairline was the
         most visible thing in the row. The .08 fill is the tone step, and it
         is what the hover state grows out of. */
      border: 0;
      border-radius: var(--r);
      color: var(--icon-on-dark);
      background: rgba(255, 255, 255, .08);
      transition: background-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out),
        transform var(--dur-fast) var(--ease-out);
    }

    .foot-socials a:is(:hover, :focus-visible) {
      background-color: var(--brand-razeen);
      color: var(--brand-black);
      transform: scale(1.06);
    }

    .foot-socials i.ph {
      font-size: var(--ic-sm);
      line-height: 1;
    }

    /* The homepage navigation exposes its two real content hierarchies without
       sending visitors to placeholder pages. */
    .menu > .nav-disclosure {
      position: relative;
      flex: 0 0 auto;
    }

    /* Chromium's anonymous details-content wrapper has zero block-size when
       its only child is the absolutely positioned desktop panel. Its default
       overflow would otherwise clip the open hierarchy. */
    .nav-disclosure[open]::details-content {
      overflow: visible;
    }

    @supports selector(.nav-disclosure::details-content) {
      @media (min-width: 1281px) {
        .nav-disclosure[open]::details-content {
          position: absolute;
          z-index: 4;
          inset-block-start: 100%;
          inset-inline-start: 0;
        }

        .nav-disclosure[open] > .nav-submenu {
          position: relative;
          z-index: auto;
          inset-block-start: 10px;
          inset-inline-start: auto;
        }
      }
    }

    .nav-disclosure > summary {
      min-block-size: 44px;
      display: flex;
      align-items: center;
      gap: 6px;
      color: #fff;
      font-size: clamp(.86rem, .95vw, .95rem);
      font-weight: 500;
      white-space: nowrap;
      list-style: none;
      cursor: pointer;
      /* The open trigger's own state (chevron rotation, underline) must not
         outlast the close animation, or the trigger reads as still-open while
         its panel is visibly leaving. */
      transition:
        background var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

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

    /* The label is a direct link inside the summary; keep its generic
       nav-link underline from duplicating the summary state line. */
    .nav-disclosure > summary > a::after {
      display: none;
    }

    .nav-disclosure > summary::after {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      inset-block-end: 2px;
      inline-size: 0;
      block-size: 1.5px;
      background: var(--accent);
      transition: inline-size var(--dur-base) var(--ease-out);
    }

    .nav-disclosure > summary i.ph {
      font-size: var(--ic-xs);
      transition: transform var(--dur-fast) var(--ease-out);
    }

    .nav-disclosure:is([open], :has(.nav-submenu a.active)):not(.is-closing) > summary::after {
      inline-size: 100%;
    }

    .nav-disclosure[open]:not(.is-closing) > summary i.ph {
      transform: rotate(180deg);
    }

    .nav-disclosure > summary:focus-visible {
      outline: 3px solid var(--brand-razeen);
      outline-offset: 3px;
    }

    header.scrolled .nav-disclosure > summary {
      color: var(--ink);
    }

    /* One rule for every dropdown, both hierarchies and both viewports: a white
       panel, rows separated by space, and the fill as the only state signal
       WITHIN the panel. This is the same decision already documented for the
       tab lists, so the navigation stops being the one place that also draws
       divider lines between rows.
       The panel's own edge is a separate question: a --surface-raised panel
       drawn on a --surface-raised section - a scrolled header over a white
       "pad--raised" block, for one - has no edge at all. No box-shadow per
       the token file; the site's elevation is tonal-step, so this is the
       same 1px --line hairline every raised card and form field already
       uses for the same separation. Mirrors sdeira-v2.css. */
    .nav-submenu {
      position: absolute;
      z-index: 4;
      inset-block-start: calc(100% + 10px);
      inset-inline-start: 0;
      inline-size: max-content;
      min-inline-size: var(--nav-submenu-min);
      display: flex;
      flex-direction: column;
      gap: 2px;
      padding: 8px;
      background: var(--surface-raised);
      border: 1px solid var(--line);
      border-radius: var(--r);
    }

    .menu .nav-submenu a {
      min-block-size: 42px;
      padding-inline: 12px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      color: var(--ink);
      font-size: .88rem;
      white-space: normal;
      transition:
        background-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }

    /* Mirrors the Arabic page's reveal-on-hover row icon: the icon glyph and
       the rest-state offset are both physical, not logical, so the English
       (LTR) row points the opposite way and slides in from the opposite side
       to land on the same "arrives on hover" motion. */
    .nav-submenu-hover-icon {
      flex: 0 0 1em;
      color: inherit;
      font-size: 1em;
      line-height: 1;
      opacity: 0;
      pointer-events: none;
      transform: translateX(-4px);
      transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    .menu .nav-submenu i.nav-submenu-hover-icon { font-size: 1em !important; }

    .menu .nav-submenu a:is(:hover, :focus-visible) .nav-submenu-hover-icon {
      opacity: 1;
      transform: translateX(0);
    }

    .menu .nav-submenu a::after {
      display: none;
    }

    .menu .nav-submenu a:is(:hover, :focus-visible, .active) {
      background: var(--accent);
      color: #fff;
    }

    .menu .nav-submenu a:focus-visible {
      outline: 3px solid var(--brand-razeen);
      outline-offset: -3px;
    }

    .nav-submenu--companies .company-nav-link {
      justify-content: flex-start;
      gap: 12px;
    }

    .company-nav-mark {
      /* V3 geometry: a dedicated 96px logo column, 32px-high container,
         reading-start aligned. */
      inline-size: 96px;
      block-size: 32px;
      display: grid;
      place-items: center start;
      flex: 0 0 96px;
      overflow: hidden;
    }

    .company-nav-mark svg {
      inline-size: 31px;
      block-size: 26px;
    }

    .company-nav-mark--eskan {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 3px;
    }

    .company-nav-mark--eskan svg {
      inline-size: 20px;
      block-size: 25px;
      flex: 0 0 20px;
    }

    .company-nav-mark--eskan b,
    .company-nav-mark--eskan small {
      display: block;
      color: var(--brand-black);
      font-family: var(--font-display);
      line-height: 1;
    }

    .company-nav-mark--eskan b { font-size: .72rem; }
    .company-nav-mark--eskan small { margin-top: 2px; font-size: .54rem; }

    .company-nav-mark img {
      /* Height-led sizing so every mark keeps its own aspect ratio inside the
         32px container; width follows height and is capped by the 96px column
         (V3 per-brand heights below). */
      inline-size: auto;
      block-size: 30px;
      max-inline-size: 100%;
      object-fit: contain;
      object-position: left center;
    }

    /* V3 per-brand logo heights (English/LTR). */
    .company-nav-mark--eskan img { block-size: 32px; }
    .company-nav-mark--khadamat img { block-size: 30px; }
    .company-nav-mark--laundry img { block-size: 20px; }

    .company-nav-mark--khadamat {
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: .72rem;
      font-weight: 600;
      line-height: 1;
      text-align: center;
    }

    .company-nav-mark--khadamat small {
      display: block;
      margin-top: 2px;
      font-size: .58rem;
    }

    .company-nav-mark--zoad img {
      /* zoad-logo-mark.png is the mark alone now, not the full lockup on
         its own canvas - contain shows the whole thing instead of cropping
         into a wordmark that is no longer there. V3: 28px-high mark. */
      inline-size: auto;
      block-size: 28px;
      object-fit: contain;
      object-position: left center;
    }

    [dir="rtl"] .company-nav-mark--zoad img { object-position: right center; }

    .company-nav-mark--laundry {
      color: var(--brand-black);
      font-family: var(--font-display);
      font-size: .7rem;
      font-weight: 600;
      line-height: 1;
      text-align: center;
    }

    .company-nav-link .nav-submenu-hover-icon { margin-inline-start: auto; }

    /* Desktop dropdown. The panel is a floating surface, so it moves through
       opacity and transform only, on --dur-base and the single easing curve.
       The movement itself is driven from the script (see setDisclosure); what
       stays here is the part that is a state, not a frame. */
    @media (min-width: 1181px) {
      /* A panel on its way out must not answer the pointer, or a hover that is
         leaving would immediately re-open it. */
      .nav-disclosure.is-closing {
        pointer-events: none;
      }

      .nav-disclosure.is-closing > .nav-submenu {
        pointer-events: none;
      }

      /* Bridges the 10px gap under the trigger, so travelling down into the
         panel is never read as leaving the trigger. Invisible by design: it
         adds reach, not a surface. */
      .nav-submenu::before {
        content: "";
        position: absolute;
        inset-inline: 0;
        inset-block-end: 100%;
        block-size: 10px;
      }
    }

    .sector-card[id],
    .company-card[id] {
      scroll-margin-top: 104px;
    }

    @media (max-width: 1280px) {
      .menu > .nav-disclosure {
        inline-size: 100%;
        border-block-end: 1px solid var(--line);
        opacity: 0;
        transform: translateX(10px);
        transition:
          opacity var(--dur-base) var(--ease-out),
          transform var(--dur-base) var(--ease-out);
      }

      .menu.open > .nav-disclosure {
        opacity: 1;
        transform: translateX(0);
      }

      .nav-disclosure > summary {
        min-block-size: 54px;
        padding-inline: 4px 12px;
        justify-content: space-between;
        color: var(--ink);
        font-family: var(--font-display);
        font-size: 1.05rem;
        font-weight: 600;
      }

      .nav-disclosure > summary::after {
        display: none;
      }

      .nav-disclosure[open] > summary {
        background: var(--surface-sunken);
        color: var(--accent-text);
      }

      .nav-submenu {
        position: static;
        min-inline-size: 0;
        inline-size: 100%;
        padding: 4px 14px 12px;
        background: var(--surface-sunken);
        border: 0;
        border-radius: var(--r);
      }

      .menu .nav-submenu a {
        min-block-size: 44px;
        padding-inline: 10px;
        font-size: .92rem;
      }

      /* Accordion motion, mobile drawer only. The panel height is driven from
         JS (measured scrollHeight), so opening one hierarchy while another is
         still closing reads as one continuous movement instead of the instant
         snap that looked like a flicker. `is-closing` returns the summary to
         its resting look right away, while the element keeps `open` until the
         collapse finishes so its content stays rendered and animatable. */
      .menu .nav-submenu {
        overflow: hidden;
      }

      .menu .nav-disclosure.is-animating > .nav-submenu {
        will-change: block-size;
        transition:
          block-size var(--dur-base) var(--ease-out),
          opacity var(--dur-fast) var(--ease-out);
      }

      .menu .nav-disclosure > summary {
        transition:
          background var(--dur-base) var(--ease-out),
          color var(--dur-base) var(--ease-out);
      }

      .menu .nav-disclosure.is-closing > summary {
        background: transparent;
        color: var(--ink);
      }

      .menu .nav-disclosure.is-closing > summary i.ph {
        transform: none;
      }

    }

    @media (prefers-reduced-motion: reduce) {
      .nav-disclosure,
      .nav-disclosure > summary,
      .nav-disclosure > summary i.ph {
        transition: none !important;
      }
    }

    /* --- About visual: one height, one place ---------------------------------
       min-height is gone from .about-visual and the photograph is 500px, so the
       section is shorter. The content column beside it is much shorter than the
       photograph, so the photograph was setting the whole section height alone.

       This fixed-height mechanic (500px desktop, 430px <=560px, one variable
       rather than eight disagreeing declarations) is REMOVED here, not ported
       - it never actually sat with the role the way the AR comment claimed;
       brace-depth showed it was still inside @layer legacy the whole time.
       .about-visual now takes aspect-ratio: var(--media-wide) instead, in the
       true SYSTEM LAYER below the close of this layer block, matching the AR
       fix of the same date. See that file's own comment for the reasoning. */

    /* --- About copy: kill a dormant auto margin -----------------------------
       The About paragraphs started up to 363px inside the column while the H2
       above them started flush at the edge, so the section read as if the copy
       had a large indent that appeared and disappeared with the viewport.

       Cause, and it is a cascade trap rather than a styling choice. An early
       rule set

         .about-copy { max-width: 820px; margin-inline-start: auto; }

       and at the time 820px was wider than the column, so the auto margin
       resolved to 0 and did nothing. A later refinement pass narrowed the block
       to `max-width: 62ch` for a proper reading measure but never reset the
       margin. The auto then had leftover space to absorb, and absorbed all of
       it, pushing the block off the edge its heading sits on. Measured start gap
       before this fix, identical on this page and the Arabic one: 32px at 1180,
       89px at 1280, 144px at 1400, 136px at 1600, 124px at 1920, and 363px at
       980 where the layout is a single wide column. That is why it looked
       intermittent.

       62ch stays: a paragraph should not run the full 901px of the column. Only
       the margin is wrong, so only the margin is reset, and it is reset last so
       the value cannot be undone by a later breakpoint. */
    .about-copy {
      margin-inline-start: 0;
    }

    } /* end @layer legacy */

    /* =========================================================================
       SYSTEM LAYER (unlayered - see the note above @layer legacy)
       Ported piece by piece from sdeira-v2.html's system layer as each fix is
       carried over; see docs/ar-to-en-port-log.md for what has and has not
       landed here yet.
       ====================================================================== */

    /* --- About visual: the shared master ratio ------------------------------
       Site owner instruction, 15 Aug 2026, ported from the AR fix of the same
       date: var(--media-wide) (4:3) replaces the fixed-height mechanic that
       used to live in @layer legacy above (see the note left at its old
       location). A proportional box instead of a constant one. */
    .about-visual {
      aspect-ratio: var(--media-wide);
    }

    .about-visual > img {
      height: 100%;
    }

    /* --- Sector-hover media: the portfolio preview ratio -------------------
       V3 change request: the preview panel is 16:9 again (measured 803x602 at
       1440px as 4:3, becomes 803x452 at 16:9). The base rule already says
       16/9; this unlayered override used to pin it to the shared --media-wide
       4:3 master, so it now matches the base instead of drifting. */
    .sector-hover-visual {
      aspect-ratio: 16 / 9;
    }

    /* needs-route-media is deliberately NOT on var(--media-wide): site owner
       reviewed the rendered 4:3 card, 16 Aug 2026, and asked for 16:9 back
       here specifically - see the matching AR comment for the reasoning.
       Reverted the same way in the business overview variant
       (.business-needs-routes .needs-route-media in sdeira-sections.css) and
       the design-system demo (.ds-route-card-media in design-system/ds.css)
       so the one component does not drift into two ratios. */

    /* --- Type roles: headings ------------------------------------------------
       One semantic heading level, one responsive size across the homepage. The
       !important flags these rules used to carry are gone: being unlayered is
       enough. */
    h1, .type-display { font-size: var(--type-display); line-height: var(--leading-display); }
    h2, .type-section { font-size: var(--type-section); line-height: var(--leading-section); }

    /* --- Type roles: everything that is not a heading -------------------------
       Ported from sdeira-v2.html's system layer verbatim (port log item 7): the
       same six roles, the same selector lists, the same three exclusions
       (wordmark small text, the --figure role, and the opening-row data cells).
       See that file's system layer for the full reasoning; nothing here is
       English-specific. */

    /* Lead: the one intro paragraph that follows a section heading. */
    :is(.sec-head, .impact-head, .process-head, .story-head, .partners-head,
        .news-head, .projects-copy, .value-head, .needs-intro, .needs-prototypes-intro,
        .impact-alt-copy, .about-copy, .cta-inner, .hero-content-copy, .sector-hover-copy) p,
    .hero p,
    .cta p,
    .type-lead {
      font-size: var(--type-lead);
      line-height: var(--leading-lead);
    }

    /* Body: running copy anywhere in the page or the footer brand block. */
    main p,
    footer .foot-brand p,
    .type-body {
      font-size: var(--type-body);
      line-height: var(--leading-body);
    }

    /* Action: buttons and inline action links inside page content. */
    :is(.btn, .more, .action-link, .section-view-all, .news-all, .news-form button,
        .projects-footer-cta, .sector-feature-link, .needs-route-action,
        .project-card-action, .news-card .more, .project-filter, .news-filter,
        .project-tab, .foot-col a, .foot-col .foot-pending, .needs-prototype-link),
    .cta-action > span:not(.cta-action-note),
    .type-action {
      font-size: var(--type-action);
    }

    /* Control: compact chrome. Kept as its own tier because folding it into the
       action role would grow the header controls by 16 to 25 percent and put the
       navigation at risk of wrapping at the widths where it is already tight. */
    :is(.menu > a, .nav-cta, .lang, .menu-lang, .menu-contact, .sector-card-action,
        .nav-disclosure > summary, .menu .nav-submenu a),
    .type-control {
      font-size: var(--type-control);
      gap:6px;
    }

    /* Meta: kickers, eyebrows, category labels and data rows. Same grouping the
       --label colour role uses, so size and colour describe one thing. */
    :is(.kicker, .impact-kicker, .process-kicker, .story-kicker, .partners-kicker,
        .sector-feature-kicker, .eyebrow, .project-type, .news-category,
        .needs-route-audience, .partner-domain, .impact-note, .impact-label,
        .service-card .service-meta, .service-pending, .hero-sectors-label),
    .news-card .date,
    .impact-alt-stat p,
    .type-meta {
      font-size: var(--type-meta);
    }

    /* --- Card badges: primary orange, no fill --------------------------------
       Ported from sdeira-v2.html (port log item 14). The small category label
       inside a repeated card now carries the primary action orange with no
       background, padding or border - the colour and weight are the whole
       treatment. .needs-route-audience was the only one of these that had an
       actual chip behind it (a --surface-sunken fill with 6px/10px padding,
       still declared in @layer legacy above); that fill is removed here by
       being unlayered, not by deleting the legacy declaration.

       .impact-label and .needs-prototype-copy small are included even though
       they don't render today (both sections are currently hidden), so they
       match the moment those sections go live rather than being missed later.

       NOT included: section kickers (.kicker and its family) stay on the
       neutral --label tone - they are section headings, not card badges.

       Two measured facts recorded in the token file next to --badge-text: this
       does not clear AA (Sweihan runs 2.80-3.35 across the surfaces these
       badges actually sit on, all below the 4.5 normal-text minimum), and the
       bold weight cannot render (only the Regular file is licensed, so
       --badge-weight is set for when the licensed Bold file arrives, not for
       a visible change today). Both are Arabic-page decisions already made;
       nothing here reopens them. */
    :is(.project-type,
        .news-card .date,
        .needs-route-audience,
        .partner-domain,
        .service-card .service-meta,
        .impact-label,
        .needs-prototype-copy small) {
      color: var(--badge-text);
      background: var(--badge-fill);
      /* Size is part of the role, same as the colour and the weight: each of
         these selectors used to carry its own font-size and the badge ended up
         the smallest text on the page wearing the loudest colour. */
      font-size: var(--badge-size);
      font-weight: var(--badge-weight);
      padding: 0;
      border: 0;
    }

    /* Caption: fine print. Notes and the copyright line. */
    :is(.copy, .cta-action-note),
    .type-caption {
      font-size: var(--type-caption);
    }

    /* --- Sector card description: reserve two lines --------------------------
       Ported from sdeira-v2.html (port log item 10): one description per sector
       card, all reserved to the same height so titles, icons and action links
       share one baseline across the strip. max-inline-size is what MAKES the
       text wrap to two lines; min-block-size alone would leave short
       descriptions on one line inside a two-line box. No line-clamp, no
       ellipsis: the measure is chosen so nothing needs truncating.

       --card-sub-measure IS RE-MEASURED HERE, NOT COPIED FROM ARABIC. English
       runs longer per word than Arabic, so the 17.5ch window that works there
       does not apply. Measured (single-line width, this page's own five
       descriptions, this font): 51.14 / 52.15 / 37.10 / 35.64 / 31.58ch.
       Window is [longest/2, shortest) = [26.1, 31.6)ch. Verified empirically,
       not just by the formula: forced max-inline-size across 22 to 35ch at
       360/400/430/440/480/640/980/1280/1600px and read the actual rendered
       line count per card. 29.5ch (mid-window) holds all five cards at
       exactly two lines from 440px up.

       BELOW 440px THE WINDOW DOES NOT HOLD. Card width itself drops under
       ~210px and the two longest descriptions need a third line regardless of
       measure (tested up to 44ch with no change - the card's own width, not
       the measure, is the constraint at that point). Per this item's own
       instruction ("may need --card-sub-lines: 3"), the line count itself
       steps up for that narrow range instead of truncating anything. */
    .sector-card-sub {
      --card-sub-measure: 29.5ch;
      max-inline-size: var(--card-sub-measure);
      /*min-block-size: calc(var(--card-sub-lines) * 1lh);*/
      /* A tone step below the title, so the two read as heading and support
         rather than as one block of white. The system's secondary tone on
         dark, declared rather than expressed as an opacity, and legible
         because the veil above was fixed in the same change. */
      color: var(--muted-on-dark);
    }

    /* Hover still lifts it to full white, so the tone step reads as a resting
       state rather than as a permanently dimmer paragraph. */
    .sector-card:is(:hover, :focus-within) .sector-card-sub {
      color: var(--brand-white);
    }

    @media (max-width: 440px) {
      .sector-card-sub {
        --card-sub-lines: 3;
      }
    }

    /* --- Sector card icon: fade out in place on hover ------------------------
       Ported from sdeira-v2.html (port log item 13b). The icon used to share
       the title/description's translateY(-32px) hover shift, which slid it out
       through the top edge of the card once resting height shrank (item 13a):
       the icon sits close to the top, and that shift put it past the edge,
       where overflow: hidden cut it off mid-travel. The title and description
       keep the shift, since that is what clears room for the action link; only
       the icon separates into its own opacity/scale fade that never has to
       reach an edge. */
    .hero-sectors .sector-card .sector-card-mark {
      transition:
        opacity var(--dur-fast) var(--ease-out),
        transform var(--dur-base) var(--ease-out);
    }

    .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-mark {
      opacity: 0;
      transform: translateY(-6px) scale(.94);
    }

    @media (prefers-reduced-motion: reduce) {
      .hero-sectors .sector-card .sector-card-mark {
        transition: none;
      }

      .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-mark {
        transform: none;
      }
    }

    /* ===== LINK HOVER: ONE COLOUR ROLE FOR THE WHOLE PAGE =====
       Ported from sdeira-v2.html (port log item 19). A text link and every
       icon inside it move to the warm accent together on hover and on
       keyboard focus. The icon needs no rule of its own: the two link
       families already inherit it (.sector-card-action i.ph is currentColor)
       and the growing underline is background: currentColor, so one colour
       declaration carries the word, the pictogram and the rule.

       Excluded on purpose, each for a measured reason:
         - the filled buttons (.btn-primary, .nav-cta, .cta-action, the active
           drawer link). They sit ON the Sweihan fill, where the same orange
           measures 1.00 and vanishes. Fill plus tone step stays their state.
         - .logo and .menu-logo. Recolouring a logo on hover is a brand
           violation, not a hover state.
         - .news-image-link, which wraps a photograph and has no text to tint.
         - the icon-tile links (.socials a, .foot-socials a, .scroll-top).
           Their state is a fill on the tile, and they already have one.
         - the drawer and submenu links (.menu > a, .menu .nav-submenu a,
           .company-nav-link). Measured: their hover state is already a FILL,
           and .nav-submenu a fills with Sweihan itself, so orange text landed
           on orange at 1.00 and the label disappeared. Fill is their state. */
    :is(.action-link,
        .sector-card-action,
        .more,
        .needs-route,
        .section-view-all,
        .news-all):is(:hover, :focus-visible) {
      color: var(--link-hover);
    }

    /* The same role, resolved for the other surface family. Sweihan measures
       3.08 on Black #414042, so a link there would DIM on hover instead of
       lifting; Razeen measures 5.22 and is already the system's accent for
       dark surfaces. These are the links that sit on the dark cards, the dark
       scrim over photography, and the footer.

       The footer belongs here and it is easy to miss: its background is
       rgba(23, 22, 20, .8), which composites dark but is translucent, so a
       naive check for an opaque ancestor walks straight past it and reports
       the light page body underneath. */
    :is(.hero-sectors .sector-card-action,
        .project-card .action-link,
        .action-link.project-card-action,
        .foot-col a,
        .foot-contact,
        .skip-link):is(:hover, :focus-visible) {
      color: var(--link-hover-on-dark);
    }

    /* An icon inside a hovered link follows the link. Both families already
       inherit, but the footer contact icon is pinned to Razeen at rest, so it
       needs telling explicitly or the word moves and the pictogram does not. */
    :is(.action-link, .sector-card-action, .more, .needs-route,
        .foot-contact, .foot-col a):is(:hover, :focus-visible) > i.ph,
    :is(.news-card, .project-card, .company-card, .needs-route):is(:hover, :focus-within)
      :is(.action-link, .more, .needs-route-action) > i.ph {
      color: inherit;
    }

    /* Card-level hover has to agree with link-level hover, or moving the
       pointer from the card body onto the link itself changes the colour
       mid-gesture. These four fire when the CARD is hovered, so they must
       resolve to the same two roles. */
    :is(.news-card, .project-card--secondary, .company-card, .needs-route):is(:hover, :focus-within)
      :is(.action-link, .more, .needs-route-action) {
      color: var(--link-hover);
    }

    .project-card:not(.project-card--secondary):is(:hover, :focus-within) .action-link {
      color: var(--link-hover-on-dark);
    }

    /* The sector card fills, so it answers the way every filling card answers:
       white. Razeen measures 3.40 at its best on the finished sector wipe and
       white measures 6.58 at its worst. The card-level selector is what matters here - the whole
       card is the target, so the pointer lands on the link itself only by
       accident, and a link that changed colour on that accident would be the
       one part of the card answering a different question from the rest. */
    .hero-sectors .sector-card:is(:hover, :focus-within) .sector-card-action {
      color: var(--brand-white);
    }

    /* --- Company card: one radius, and the corner mark stays inside ----------
       The mark is sized past the card's own corner on purpose, but the card
       clips it rather than letting it bleed onto its neighbours in the tight
       2-column grid. overflow: hidden is what the legacy
       .company-card, .service-card rule this page inherits already sets;
       restated here with the radius so both hold regardless of which of
       .company-card's several redeclarations in @layer legacy happens to
       cascade last (matches sdeira-v2.html). */
    .company-card {
      overflow: hidden;
      border-radius: var(--r);
    }

    /* --- Project meta follows the surface it sits on --------------------------
       .row-item-meta (sdeira-sections.css) sets colour: var(--label) directly
       on the element the text and the icon both live in, and it is unlayered,
       so it always wins over the @layer legacy rules that turn
       .project-card--feature/.project-card--secondary:hover white regardless
       of specificity. The icon needs its own line too - i.ph sets colour
       directly on itself rather than inheriting - but the label text
       ("Mussafah, Abu Dhabi") was reported still reading Jais-dark on the
       feature card's photo scrim even after the icon-only version of this fix
       landed, because that version never touched the parent. Site owner
       flagged, 12 Aug 2026 (ported from the Arabic fix). */
    .project-card--feature .project-meta,
    .project-card--secondary:is(:hover, :focus-within) .project-meta,
    .project-card--feature .project-meta i.ph,
    .project-card--secondary:is(:hover, :focus-within) .project-meta i.ph {
      color: var(--brand-white);
    }

    /* The rule above is written for the feature card's normal dark-scrim
       state and doesn't know about .is-filtered-view, so once that state
       demotes the card to the same white surface as its siblings, the (also
       unlayered, so equally undefeated by anything in @layer legacy) white
       rule above kept winning by being later/more specific - meta text and
       icon stayed white on white. Same fix shape as the .project-type one
       below: a higher-specificity unlayered override for the filtered state
       specifically, matching the surviving secondary card's own --icon/--label
       tokens instead of the dark-surface white. Found by diffing every
       computed property against .project-card--secondary. Site owner
       flagged, 12 Aug 2026. */
    .project-cards.is-filtered-view .project-card--feature .project-meta,
    .project-cards.is-filtered-view .project-card--feature .project-meta i.ph {
      color: var(--icon);
    }

    .project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within)
      .project-meta,
    .project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within)
      .project-meta i.ph {
      color: var(--brand-white);
    }

    /* .project-card--feature .project-type (below, further down this file)
       sets --badge-text-on-dark unconditionally for the same reason as the
       meta rule above - written for the normal dark-scrim state, unlayered,
       so it keeps winning even once .is-filtered-view puts this card on a
       white surface where the secondary card's kicker actually reads
       --badge-text (the accent-strong orange), not the on-dark gold. Site
       owner flagged, 12 Aug 2026. */
    .project-cards.is-filtered-view .project-card--feature .project-type {
      color: var(--badge-text);
    }

    /* --- A filtered-out project card must actually disappear ------------------
       .project-card.is-filtered-out { display: none; } lives in @layer legacy.
       sdeira-sections.css's .project-card-base.project-card-base sets
       display: flex at equal specificity and loads after this file, and it
       carries no @layer - same rule as the icon fix above: unlayered always
       beats layered regardless of specificity or source order. The card never
       collapsed: it kept flex layout and its grid track, so a filter for one
       type still rendered every card, including ones tagged for a different
       type. Doubling the class matches sdeira-sections.css's own specificity
       trick rather than reaching for !important. Site owner flagged, 12 Aug
       2026 (ported from the Arabic fix). */
    .project-card.is-filtered-out.is-filtered-out {
      display: none;
    }

    /* --- Filled dropdown item: the label is white ----------------------------
       A submenu link is also `.menu a`, so once the header gains .scrolled,
       `header.scrolled .menu a.active` (0,3,2) out-specifies the plain hover
       rule above (0,3,1) and would repaint the label in --accent-text instead
       of white while it sits on the solid --accent fill - correct for the
       top-level nav item that rule targets, never meant to reach into the
       dropdown. Being unlayered is what fixes it: the system layer wins by
       position, not specificity, so this can stay a plain statement of the
       role instead of a selector race (matches sdeira-v2.html). */
    .menu .nav-submenu a:is(:hover, :focus-visible, .active) {
      color: var(--brand-white);
    }

    /* Subsidiary cards sit on pure White instead of the cream --surface-base,
       so the four read as one clean block against the section behind them.
       The tonal step that separates them from the page is the grid gap
       showing the darker surface through, not a shadow (port log item 32). */
    .company-card {
      background: var(--brand-white);
    }

    /* Pausing the rail (port log item 21) stops the interval, but the active
       line's fill animation is CSS and keeps running on its own clock unless
       told to stop, which would make the bar keep filling while the slide
       behind it holds still - the pause itself would read as a fault.
       Unlayered so it holds at every viewport, since the rail is defined
       more than once above. */
    .hero.is-slider-paused .hero-slide-line.active::before {
      animation-play-state: paused;
    }

    /* The date's icon used to sit on --icon (a neutral grey) while the date
       text itself already reads --badge-text (orange), so the two halves of
       one label were read as two different elements. Tying the icon to
       currentColor means it always follows whatever the text colour is,
       with no colour of its own to fall out of sync (port log item 31). */
    .news-card .date::before {
      color: currentColor;
    }

    /* --- News card: stretched link ------------------------------------------
       Ported from the Arabic homepage in the same change: the
       whole card is clickable, not just its three separate <a> tags (the
       image, the title, "read more"), which all point at the same story
       anyway. Hosted on the title link because .news-image-link sits in its
       own overflow: hidden box and would clip a pseudo aimed at the full card;
       .news-body carries no overflow rule, so the title link reaches
       .news-card cleanly. inset: 0 matches .news-card's own box, so its own
       overflow: hidden never clips it either. No z-index games needed for the
       other two links: the hover state is keyed off .news-card:hover /
       :focus-within, true the moment the pointer is anywhere over this pseudo
       too. Keyboard order and each link's own href are untouched. */
    .news-card {
      position: relative;
    }

    .news-card h3 a {
      position: static;
    }

    .news-card h3 a::after {
      content: "";
      position: absolute;
      inset: 0;
    }

    /* --- News card image: var(--media-wide), fixed, not a height clamp ------
       Ported from the Arabic homepage in the same change. A ROLE that holds
       at every viewport, matching every other media field on the page
       (.needs-route-media and its siblings). 4:3 since 15 Aug 2026, was a
       literal 16:9 - moved onto the token so this and .is-filtered-view's
       demoted feature card (above) cannot drift apart again. The last
       @layer legacy pass on this selector sizes the image purely by height
       (var(--news-media-height)), independent of the card's own width, and
       .news-grid is auto-fit, so that width changes as the grid gains or
       drops a column - the crop ratio drifted with it instead of holding one
       shape. Scoped off .news-card--feature: that card's image is stretched
       to match its text column's height (align-items: stretch on a
       two-column split), a genuinely different layout with no comparable
       "card width changes, so the ratio should too" problem to fix. */
    .news-card:not(.news-card--feature) .img {
      aspect-ratio: var(--media-wide);
      block-size: auto;
    }

    /* --- Card hover: the white panel steps to the dark tone ----------------
       The subsidiary cards and the direct-route cards fill on hover, the way
       a dropdown entry does (.menu .nav-submenu a fills on hover). Only the
       WHITE PANEL fills: on a direct-route card the photograph sits in its
       own .needs-route-media and is deliberately left alone, so the surface
       moves and the image does not.

       WHY BRAND BLACK AND NOT THE SWEIHAN ORANGE THE DROPDOWN USES. Measured
       in the browser, white on Sweihan is 3.35:1. That clears AA for large
       text only, which is why the hero can set a display headline on an
       orange block and be correct - but these cards carry a 13px label and a
       body paragraph, and both would fail AA (4.5) on that fill. White on
       Brand Black measures 10.31:1, so every size on the card passes AA and
       AAA. No shade was invented to get there: darkening Sweihan would be a
       brand-extension decision, and Black is already one of the eight and
       already this page's dark surface (hero sectors, the feature project
       card, the footer).

       Only background-color and colour transition. Nothing here moves,
       resizes or re-lays-out the card, so the pointer never chases content. */
    .company-card,
    .needs-route .needs-route-copy {
      transition: background-color var(--dur-base) var(--ease-out);
    }

    /* --- The fill sweeps in behind one straight diagonal edge ---------------
       One hover fill for every card family: the panel does not cross-fade to
       its new colour, a straight-edged front sweeps across it, the same
       gesture the hero sector strip already uses.

       THE EDGE IS PARALLEL TO .card-chevron, AND THAT WAS THE WHOLE BUG. Four
       earlier versions all clipped the layer to the sector strip's
       parallelogram, polygon(22% 0, 100% 0, 78% 100%, 0 100%), whose leading
       edge falls DOWN-LEFT. The chevron sticker in the card's bottom-left
       corner is drawn the other way: its lines were measured off the live SVG
       with getPointAtLength + getScreenCTM and every one of them slopes
       DOWN-RIGHT at +0.90 to +0.97, about 43 degrees. So the front and the
       sticker it was supposed to be growing out of were crossing each other,
       and no amount of re-parking the layer fixed that - it just moved which
       corner the mismatch showed up in. Slide it horizontally and the panel
       fills from the top; slide it diagonally and a wedge sweeps the middle;
       scale it from the corner and a triangle grows. All four were rejected.

       Built as a hard-stop gradient rather than a clipped, transformed box,
       because a gradient stop IS a straight line perpendicular to the
       gradient axis by construction, at any box size. A transformed polygon
       only reads as one straight front when the translation happens to be
       perpendicular to the leading edge, which depends on each card's aspect
       ratio - three of the four failures above are that geometry going wrong
       in a different place.

       --wipe-angle points the axis up and to the right, so the fill starts at
       the bottom-left corner (the chevron's corner) and its front travels out
       across the panel staying parallel to the sticker. 43deg is the measured
       chevron slope, not a chosen number: keep them equal or the two lines
       diverge visibly.

       --wipe-p is registered with @property, which is what makes a percentage
       inside a gradient stop animatable at all. Without the registration the
       browser treats it as an unanimatable token and the fill snaps in - which
       is the reduced-motion behaviour anyway, so the degradation is the
       correct one rather than a broken state.

       Layering is wipe 0 / chevron 1 / copy 2 (see the two rules below that
       raise the other two). A pseudo-element is the LAST child in paint order
       at an equal z-index, so at 0 the wipe would have covered .card-chevron
       and the sticker would have vanished exactly when the fill arrived.

       Both hosts were measured before relying on inset: 0 - .company-card and
       .needs-route-copy were already position: relative with overflow: hidden;
       .project-card--secondary .project-card-body measured static/visible, so
       the rule further below gives it both. Without them the layer resolves
       against a further ancestor and paints straight across the card, the same
       failure the ribbon frame hit on this very component. */
    @property --wipe-p {
      syntax: "<percentage>";
      inherits: false;
      initial-value: 0%;
    }

    /* The front also DENSIFIES as it travels, from the sticker's own strength
       to solid. The chevron is translucent at rest - its wedges carry .72 and
       .74 in the SVG itself - so a fill that started at full strength read as
       a different material arriving over the sticker rather than as the
       sticker's own colour spreading. Starting at 72% and resolving to 100%
       makes the first frame of the fill exactly the tone already sitting in
       the corner, and the last frame the opaque panel the copy is measured
       against. Registered as a percentage for the same reason --wipe-p is:
       unregistered it cannot animate. */
    @property --wipe-op {
      syntax: "<percentage>";
      inherits: false;
      initial-value: 72%;
    }

    /* THE TRAVELLING PANEL, not a grown gradient - same rewrite as
       .project-card-copy::after (sdeira-sections.css) and for the same
       reason: the gradient-stop version (--wipe-p, a registered @property)
       is a discrete-value animation on an interruptible transition. Mouse
       out mid-hover, a fast pointer pass, or a background tab losing its
       rAF tick all freeze the diagonal edge PARTWAY across the panel -
       observed live on the homepage's own Khadamat/company/subsidiary
       cards, screenshot flagged 7 Sep 2026: a permanent maroon wedge
       sitting mid-panel with no hover active, exactly the defect already
       fixed once for the project cards and never ported to this family.
       transform-only animation is compositor-side and cannot freeze at a
       partial fill - its mid-flight shape is the whole panel arriving,
       never a diagonal crossing live text. Same fill token, same rest/
       hover endpoints, same duration; only the mechanism changes. */
    .company-card::after,
    .needs-route .needs-route-copy::after,
    .project-card--secondary .project-card-body::after {
      content: "";
      position: absolute;
      z-index: -1;
      inset: -1px -40%;
      background: color-mix(in srgb, var(--wipe-fill) var(--wipe-op, 72%), transparent);
      clip-path: polygon(22% 0, 100% 0, 78% 100%, 0 100%);
      transform: translate3d(78%, 0, 0);
      transition: transform var(--dur-slow) var(--ease-out);
      pointer-events: none;
    }

    [dir="rtl"] .company-card::after,
    [dir="rtl"] .needs-route .needs-route-copy::after,
    [dir="rtl"] .project-card--secondary .project-card-body::after {
      clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
      transform: translate3d(-78%, 0, 0);
    }

    .company-card:is(:hover, :focus-within)::after,
    .needs-route:is(:hover, :focus-within) .needs-route-copy::after,
    .project-card--secondary:is(:hover, :focus-within) .project-card-body::after {
      --wipe-op: 100%;
      transform: none;
    }

    /* The filtered feature card body uses the shared project-card gradient
       wipe, same as .project-card-copy::after (sdeira-sections.css): a
       registered --wipe-p percentage driving the --route-card-wipe-angle
       gradient, not the transform-based travelling panel the other three
       families use. Direction mirrors through the token (315deg here / 45deg
       in RTL), so no per-dir block is needed. */
    .project-cards.is-filtered-view .project-card--feature .project-card-body::after {
      content: "";
      position: absolute;
      z-index: 0;
      inset: 0;
      --wipe-fill: var(--accent-deep);
      --wipe-p: 0%;
      background: linear-gradient(var(--route-card-wipe-angle), var(--wipe-fill) 0 var(--wipe-p), transparent var(--wipe-p) 100%);
      clip-path: none;
      transform: none;
      transition: --wipe-p var(--dur-slow) var(--ease-out);
      pointer-events: none;
    }

    .project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within) .project-card-body::after {
      --wipe-p: 100%;
      --wipe-op: 100%;
      transform: none;
    }

    /* Snap rather than grow. This file already silences the chevron and the
       sector-card marks for the same reason. */
    @media (prefers-reduced-motion: reduce) {
      .company-card::after,
      .needs-route .needs-route-copy::after,
      .project-card--secondary .project-card-body::after,
      .project-cards.is-filtered-view .project-card--feature .project-card-body::after {
        transition: none;
      }
    }

    /* --- The photograph's band stops at the photograph -------------------
       .ribbon-frame is the identity band drawn ON a photograph, and it is
       correctly built: it is inset: 0 inside .project-card-img, which is
       position: relative with overflow: hidden, and all three boxes measure
       identical (1164.1 -> 1534.1 at 1400). Nothing escapes its clip, so every
       geometric check of the band passes.

       The band still painted outside the photograph, and the reason is paint
       order rather than geometry. .project-card-body is pulled up over the
       bottom edge of the photo, so its opaque surface covers the last ~20px of
       the image - but .ribbon-frame carries z-index: 2 and the body did not
       carry one at all, so the band painted OVER that surface. The result is a
       diagonal hairline that leaves the photo and runs across the white card
       body, which is what the site owner flagged (2026-08-08): the card line
       must never appear outside the image.

       Fixed by stating what was previously left implicit - the card's copy
       surface is content and outranks a decoration on the photograph above it.
       Raising the body is preferred over lowering the band, because the band's
       z-index: 2 is also what keeps it above the photo itself; lowering it
       would fix this overlap by weakening the rule that puts the band on the
       photograph in the first place.

       Scoped to --secondary deliberately. On the feature card the copy sits ON
       the photograph by design and the two layers are meant to share it, so it
       is not the same relationship and is left alone.

       Measured on BOTH pages before and after: this was never English-only.
       The same rule, applied to the Arabic page, changes its render too. */
    .project-card--secondary .project-card-body,
    .project-cards.is-filtered-view .project-card--feature .project-card-body {
      position: relative;
      z-index: 3;
    }

    /* The chevron and the copy both sit above the travelling layer. Raised
       here rather than at .card-chevron's own rule in @layer legacy, so the
       whole three-level stack is stated in one place. */
    .needs-route .card-chevron,
    .company-card .card-chevron,
    .project-card--secondary .card-chevron,
    .project-cards.is-filtered-view .project-card--feature .card-chevron {
      z-index: 1;
    }

    .needs-route-copy > :not(.card-chevron),
    .company-card > :not(.card-chevron, .company-num),
    .project-card--secondary .project-card-body > :not(.card-chevron),
    .project-cards.is-filtered-view .project-card--feature .project-card-body > :not(.card-chevron) {
      position: relative;
      z-index: 2;
    }

    /* The containing block and the clip for everything above. Measured
       static/overflow: visible before this rule; the other two hosts already
       had both. */
    .project-card--secondary .project-card-body,
    .project-cards.is-filtered-view .project-card--feature .project-card-body {
      position: relative;
      overflow: hidden;
    }

    /* Same fill role as the route card, so the copy reverses the same way and
       on the same delay. .project-type is included deliberately: it is the
       orange badge role, and orange-on-#cb6c2e measures 1.28. */
    .project-card--secondary:is(:hover, :focus-within) .project-card-body :is(.project-type, h3, p, .project-meta, .project-card-action),
    .project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within) .project-card-body :is(.project-type, h3, p, .project-meta, .project-card-action) {
      color: var(--brand-white);
    }

    .project-card--secondary .project-card-body :is(.project-type, h3, p, .project-meta, .project-card-action),
    .project-cards.is-filtered-view .project-card--feature .project-card-body :is(.project-type, h3, p, .project-meta, .project-card-action) {
      transition: color var(--dur-slow) var(--ease-out);
    }

    /* The action links are on the same clock too. They inherit a 120ms colour
       step from the shared link role, which is correct for a link on a static
       surface and wrong for one riding a 480ms fill: measured at 0.12s on all
       three families before this rule. transition-property is left alone -
       these links also animate opacity and visibility elsewhere - so only the
       colour leg is retimed, via the longhands. */
    :is(.needs-route, .company-card, .project-card--secondary, .project-cards.is-filtered-view .project-card--feature)
      :is(.action-link, .more, .needs-route-action, .project-card-action) {
      transition-property: opacity, visibility, color;
      transition-duration: var(--dur-base), var(--dur-base), var(--dur-slow);
      transition-timing-function: var(--ease-out);
    }


    /* The cards fill with #cb6c2e, at the client's explicit direction, so the
       panel agrees with the photograph beside it instead of dropping to the
       neutral dark.

       FLAGGED, NOT SILENT: this is a ninth colour. It is a deep Sweihan and
       the token file's rule is that a derived shade is a brand-extension
       decision for the identity owner, so it is written here as a card-local
       value and deliberately NOT added to sdeira-tokens.css - nothing else on
       the site may reach for it until the identity owner rules on it.

       Contrast was measured rather than assumed, and this fill DOES NOT clear
       AA: white on #cb6c2e is 3.67:1, against the 4.5 needed for the 13px
       audience label and the body paragraph. It clears the 3.0 large-text
       threshold, so only the card heading is compliant. The value is the
       client's explicit choice, made after seeing #a86133 (4.75:1, compliant)
       live on the page, so it is recorded here rather than quietly corrected.
       Brand Black, which the subsidiary cards used until they were moved onto
       this fill for consistency, is 10.31:1, and the nearest deeper tone of
       this same hue that would pass is about #a85a24.
       Razeen is 1.86:1 here and cannot be the accent on this fill - see the
       action-link rule further down. */
    /* The fill is the wipe layer's colour, not the card's own background: a
       background-color that changed on hover would land in --dur-base under a
       front still travelling on --dur-slow, and the wipe would have nothing
       left to reveal.

       ONE fill for all three families. The subsidiary cards used Brand Black
       here, which is the higher-contrast choice (white on it is 10.31:1), and
       they were moved onto #cb6c2e at the client's explicit direction so the
       three card families read as one system rather than as two. The AA
       shortfall recorded above therefore now applies to the subsidiary cards
       too: their body copy sits at 3.67:1. Reverting is one value in this
       rule, not a restructure. */
    .company-card::after,
    .needs-route .needs-route-copy::after,
    .project-card--secondary .project-card-body::after,
    .project-cards.is-filtered-view .project-card--feature .project-card-body::after {
      --wipe-fill: var(--surface-brand-deep);
    }

    /* --- Route card: only the panel is the hit area ------------------------
       The card is one <a> wrapping the photograph and the copy panel, and the
       whole rectangle used to be clickable - including the empty column beside
       the panel, where nothing invites a click and the pointer turning into a
       hand reads as a bug.

       Done with pointer-events rather than by re-nesting the markup: the
       anchor has to stay the grid container (it owns the two-track layout and
       the mirrored even/odd placement), so moving it inside the panel would
       mean rebuilding the layout around a new element for a hit-area change.
       Events still bubble from the panel to the anchor, so the link, its hover
       fill and the image zoom all still fire - from the panel only. That is
       the deliberate part: the whole card responds as one, but only from the
       surface that reads as clickable. Keyboard focus is untouched, the anchor
       is still focusable, and :focus-within drives the same state. */
    .needs-route {
      pointer-events: none;
    }

    .needs-route .needs-route-copy {
      pointer-events: auto;
    }

    /* Selected by POSITION, not by tag name. These two cards are written with
       different elements than they used to be (the route card's copy is
       small/strong/em where it was span/h3/p), so a selector listing tags
       silently stops matching the moment the markup is re-authored - which is
       exactly what happened here, and it fails invisibly: the fill still
       lands and the text just stays dark on dark. Every direct child of the
       panel is copy and should reverse, except the two that carry their own
       colour role: the action link (Razeen, below) and the decorative
       chevron. */
    /* Anything that reverses UNDER the wipe runs on the wipe's own clock:
       same duration, same easing, no delay, in both directions. Two earlier
       versions of this are wrong and were both seen on the page. Colour on
       --dur-base with the wipe on --dur-slow finishes at half the distance,
       so the copy goes white over a panel the fill has not reached; adding a
       delay to compensate only moves the mismatch, it stays a step function
       under a sweep. Sharing the clock is what makes the two read as one
       change. */
    .company-card > *:not(.action-link):not(.card-chevron):not(.company-logo),
    .needs-route .needs-route-copy > *:not(.needs-route-action):not(.card-chevron) {
      transition: color var(--dur-slow) var(--ease-out);
    }

    .company-card:is(:hover, :focus-within)
      > *:not(.action-link):not(.card-chevron):not(.company-logo),
    .needs-route:is(:hover, :focus-within)
      .needs-route-copy > *:not(.needs-route-action):not(.card-chevron) {
      color: var(--brand-white);
    }

    /* The subsidiary marks are brand assets in their own colours - Khadamat
       green, Your Laundry blue, Zoad dark - and every one of them clashes on
       the filled panel. brightness(0) invert(1) renders each as a solid white
       silhouette, which is the reversed/mono form a brand system already
       expects on a saturated surface (this repo ships khadamat-logo-white.webp
       for exactly that reason). Done as a filter rather than four more PNGs so
       there is one behaviour to maintain and no second copy of a brand asset
       to keep in sync. Eskan's mark is inline SVG painted from
       --company-accent, so it reverses by swapping the variable instead. */
    /* On the fill's clock, same as the copy. */
    .company-card .company-logo img {
      transition: filter var(--dur-slow) var(--ease-out);
    }

    .company-card:is(:hover, :focus-within) .company-logo img {
      filter: brightness(0) invert(1);
    }

    /* THE ZOAD EXCEPTIONS ARE GONE, 28 Aug 2026. Site owner's rule: a logo
       never sits on a brand colour, only on white. Every one of these rules
       existed to work around artwork that carried its own ground - the card
       used the navy mark on an opaque canvas, so the generic
       brightness(0) invert(1) every other card logo takes would have whitened
       the canvas into a blank rectangle, and a second white file was
       cross-faded over it on hover instead.

       The mark is now the WORDMARK, cut from the client's own
       ZOAD Logo / Blueberry Full Colour: navy ink on transparent, no ground.
       The shared filter works on it, so Zoad takes the same treatment as every
       other company here. Do not reintroduce a per-brand hover copy: if a
       supplied logo carries a coloured panel, the panel comes off the ASSET. */

    .company-card:is(:hover, :focus-within) .company-logo svg {
      --company-accent: var(--brand-white);
      --company-accent-2: rgba(255, 255, 255, .72);
    }

    /* Two places the copy rule above cannot reach, both hardcoding a colour
       of their own rather than inheriting:

       1. Eskan has no image mark. Its lockup is live text, so the filter and
          the SVG variable swap both miss it and it stays Brand Black on the
          fill. It is the wordmark's own declared colour that has to move.
       2. .company-card > h3 small is Jais by declaration, so it survives the
          white assignment its own <h3> parent receives and reads as a grey
          line under a white heading.

       Both ride the fill's clock, same as every other colour on these cards. */
    /* Eskan's stripe mark carries its own three teals as literal fills, so
       the --company-accent swap above is a no-op on it. Same treatment the
       image marks get, for the same reason: on the fill it reads as a solid
       white silhouette. A filter rather than three fill overrides so the
       reversal stays one behaviour across every mark on these cards. */
    .company-card .company-logo--eskan svg {
      transition: filter var(--dur-slow) var(--ease-out);
    }

    .company-card:is(:hover, :focus-within) .company-logo--eskan svg {
      filter: brightness(0) invert(1);
    }

    /* --- The same reversal in the nav dropdown -------------------------------
       The port of the Arabic side's fix; see the long note at the matching
       block in sdeira-v2.css for why each mark takes the mechanism it takes.
       In short: the dropdown row paints the same fill the company cards paint
       and was leaving every subsidiary mark in its own brand colours on it.

       This uses the same .company-nav-link / .company-nav-mark names as the
       shared English header and the Arabic source component. Measured alpha
       decides the mechanism, and
       the English header carries a different Khadamat crop and the English
       Your Laundry lockup, both transparent like their Arabic counterparts.
       Zoad's file is the same 100%-opaque source in both headers. */
    .company-nav-mark :is(img, svg) {
      transition: filter var(--dur-fast) var(--ease-out);
    }

    .company-nav-mark--eskan :is(b, small) {
      transition: color var(--dur-fast) var(--ease-out);
    }

    .company-nav-link:is(:hover, :focus-visible, .active) .company-nav-mark :is(img, svg) {
      filter: brightness(0) invert(1);
    }

    .company-nav-link:is(:hover, :focus-visible, .active) .company-nav-mark--eskan :is(b, small) {
      color: var(--brand-white);
    }

    /* The Zoad nav exceptions are removed with the card's, 28 Aug 2026: the
       mark is the wordmark now, navy ink on transparent, so the shared
       brightness(0) invert(1) two rules above works on it. See the note at
       .company-logo--zoad. */

    .company-card .company-logo--eskan,
    .company-card .company-logo--eskan-wordmark,
    .company-card .company-logo--eskan-wordmark small,
    .company-card > h3 small {
      transition: color var(--dur-slow) var(--ease-out);
    }

    .company-card:is(:hover, :focus-within) .company-logo--eskan,
    .company-card:is(:hover, :focus-within) .company-logo--eskan-wordmark,
    .company-card:is(:hover, :focus-within) .company-logo--eskan-wordmark small,
    .company-card:is(:hover, :focus-within) > h3 small {
      color: var(--brand-white);
    }

    /* Card-level hover has to agree with link-level hover, or moving the
       pointer from the card body onto the link itself changes the colour
       mid-gesture. These fire when the CARD is hovered, so they must
       resolve to the same two roles. */
    :is(.news-card, .project-card--secondary):is(:hover, :focus-within)
      :is(.action-link, .more) {
      color: var(--link-hover);
    }

    /* The on-dark role, for the surface that is actually dark. Razeen is the
       system's measured on-dark accent at 5.22 on Brand Black, which is why
       the dark feature project card sits here. The subsidiary cards used to
       be in this group and left it when their fill changed - see the white
       rule below. */
    .project-card:not(.project-card--secondary):is(:hover, :focus-within) .action-link {
      color: var(--link-hover-on-dark);
    }

    /* Every card that fills with #cb6c2e takes white for its action link, not
       Razeen: Razeen measures 1.86:1 on that fill and would read as a smudge
       rather than as an accent. White measures 3.67:1 - see the fill rule for
       what that does and does not clear. The subsidiary cards joined this
       group when their fill changed, which is the same reasoning that moved
       them out of the light group in the first place: the surface decides the
       role, not the component. */
    .needs-route:is(:hover, :focus-within),
    .needs-route:is(:hover, :focus-within)
      :is(.action-link, .more, .needs-route-action),
    .company-card:is(:hover, :focus-within)
      :is(.action-link, .more) {
      color: var(--brand-white);
    }

    /* --- About section: one full-height panel, not two stacked sections -----
       The Aryam metric rail used to live in its own section below (.impact-alt),
       duplicating the About copy as a second, separately-scrolled block. Its
       markup now lives inside #about instead, right after .about-values, so
       the whole thing reads as one section: photo, copy, then the metric rail.
       min-block-size holds it at the viewport height shown in the approved
       reference composition; centering keeps the layout balanced on taller
       viewports where the content is shorter than 100vh. Unlayered so it holds
       regardless of which @layer legacy breakpoint rule sets .about's padding. */
    .about {
      min-block-size: 100vh;
      display: flex;
      align-items: center;
    }

    .about > .wrap {
      width: 100%;
    }

    @media (max-width: 640px) {
      .about {
        min-block-size: 0;
      }
    }

    /* ===== CTA SECTION: HERO RIBBONS =====
       Same mark as .hero-glass, same reason: the hero and the closing CTA are
       the two full-bleed photographic surfaces on the page, so they carry the
       same identity treatment rather than one of them being bare.

       The bands are quieter here than the raw colour suggests. Colour, weight
       and alpha are the hero's, measured identical; what made these read
       louder is stacking. The hero's scrim is a pseudo-element at the same
       z-index as .hero-glass, so it paints AFTER the bands and mutes them; the
       CTA's scrim sits at z-index -1, so bands at 0 land on top of it at full
       strength. Sinking them under the scrim instead was tried and rejected by
       measurement on the Arabic page: the hero's scrim is a gradient bottoming
       out at .44, while the CTA's is a flat .76 black, which erased the mark
       completely rather than quieting it. So the residual strength is applied
       directly. The hero's bands survive its scrim at 1 - alpha, i.e. between
       .28 and .56 depending on height; the CTA wrapper uses that quietest .28
       endpoint so the mark reads like the hero at its lightest. */
    .cta-glass {
      position: absolute;
      z-index: 0;
      opacity: .28;
      inset: 0;
      overflow: hidden;
      pointer-events: none;
    }

    .cta-glass span {
      position: absolute;
      top: -10%;
      height: 120%;
      width: 60px;
      border: 1px solid var(--brand-sweihan);
      border-radius: var(--r);
      background: color-mix(in srgb, var(--brand-sweihan) 8%, transparent);
      transform: skewX(-24deg);
    }

    .cta-glass .r1 { inset-inline-start: 68%; }
    .cta-glass .r2 { inset-inline-start: 78%; }

    /* Steps back so the group reads as depth, not three equals. */
    .cta-glass .r3 {
      inset-inline-start: 88%;
      border-color: color-mix(in srgb, var(--brand-sweihan) 55%, transparent);
    }

    @media (max-width: 920px) {
      .cta-glass { display: none; }
    }

    /* ===== SECTION IDENTITY BANDS (the ambient case) =====
       .section-glass is the one component for a group of identity bands drawn
       behind a section's own content. .news-glass is the same component under
       its original name - it was the first and for a while the only place this
       treatment existed, and the markup still writes that class - so it is
       carried in every selector here rather than being given a second
       definition. Anything new writes .section-glass.

       The wrapper clips itself (inset: 0 + overflow: hidden) instead of asking
       the host section to clip. A skewed band throws its corners well past its
       own box, so something must clip it, but making that the SECTION's job
       would silently cut off any content a section deliberately lets hang
       outside its padding - .about is exactly that case (see .ribbon-frame's
       note, same trap one level down). So the host contributes only a
       stacking context; the decoration contains its own overflow. */
    :is(.news-section, .about, .needs, .featured-projects, .value-sections) {
      position: relative;
      isolation: isolate;
    }

    /* The content rides above the bands. Nothing here changes layout: .wrap is
       already a block at its natural place in flow, and the bands are absolute,
       so this is a paint order statement only. */
    :is(.news-section, .about, .needs, .featured-projects, .value-sections) > .wrap {
      position: relative;
      z-index: 1;
    }

    :is(.section-glass, .news-glass) {
      position: absolute;
      z-index: 0;
      inset: 0;
      overflow: hidden;
      pointer-events: none;
    }

    /* One geometry for every section identity band. The vertical overfill
       absorbs the skew so the visible mark reaches both section edges. */
    :is(.hero-glass, .cta-glass, .section-glass, .news-glass) span {
      top: var(--identity-band-top);
      height: var(--identity-band-height);
      width: var(--identity-band-width);
    }

    /* The two photographic surfaces share the identity-band geometry, including
       the system radius; only their photographic surface strength differs. */
    :is(.hero-glass, .cta-glass) span {
      border-width: var(--identity-band-border);
      background: color-mix(in srgb, var(--brand-sweihan) var(--identity-band-fill), transparent);
    }

    /* The ambient tone, from the token file. This is the tone the news section
       has always carried; naming it is what lets the rest of the page reach it
       without re-deciding how quiet "quiet" is per section. The radius is the
       system's one value rather than the hero's pill: on a flat ground the band
       is a cut in the surface, not a bar laid on top of it. */
    :is(.section-glass, .news-glass) span {
      position: absolute;
      border: var(--identity-band-border) solid
        color-mix(in srgb, var(--brand-sweihan) var(--identity-band-line-ambient), transparent);
      border-radius: var(--r);
      background: color-mix(in srgb, var(--brand-sweihan) var(--identity-band-fill-ambient), transparent);
      transform: skewX(-24deg);
    }

    /* PLACEMENT. Three positions along the inline axis, written as one scale so
       a section picks an edge rather than three numbers. The bands are a group
       with a fixed internal step (10% of the section width between neighbours);
       what varies per section is only where the group starts.

       inset-inline-start is logical on purpose here even though decorative
       geometry on this site is normally physical: this is the one decoration
       that has no fixed relationship to the text beside it, so mirroring it in
       this English mirror is correct rather than a hazard. The SKEW stays
       physical - the mark has one slant and the language never flips it. */
    :is(.section-glass, .news-glass) span { inset-inline-start: calc(var(--band-origin, 68%) + var(--band-step, 0) * 10%); }
    :is(.section-glass, .news-glass) :is(.r1, .b1) { --band-step: 0; }
    :is(.section-glass, .news-glass) :is(.r2, .b2) { --band-step: 1; }
    :is(.section-glass, .news-glass) :is(.r3, .b3) { --band-step: 2; }

    /* Two origins, alternated down the page. A section that repeats the same
       corner as the one above it stops reading as texture and starts reading
       as a repeated stamp, which is the specific way this kind of decoration
       goes wrong. --start opens the group just past the leading edge, so its
       first band is half off-screen and the group reads as continuing beyond
       the page rather than as three bars placed in a corner. */
    .section-glass--start { --band-origin: -4%; }
    .section-glass--end { --band-origin: 68%; }

    /* AMBIENT DRIFT. The bands rise and settle, ~14px over --dur-ambient, on
       the site's one easing curve with `alternate` supplying the return - so
       there is no second curve and no keyframe doing the easing by hand.

       The skew is restated inside the keyframes because transform is one
       property: a translate written here would otherwise replace the skew set
       above and the bands would snap upright on the first frame.

       Negative delays are what stagger the group. A positive delay would hold
       all three still at the start position for the first several seconds and
       then start them one by one, which is visible; a negative delay starts
       each band already partway through its own cycle, so the group is never
       in phase and never seen beginning. */
    @keyframes bandDrift {
      from { transform: skewX(-24deg) translate3d(0, 0, 0); }
      to   { transform: skewX(-24deg) translate3d(0, -14px, 0); }
    }

    :is(.section-glass, .news-glass) span {
      animation: bandDrift var(--dur-ambient) var(--ease-out) infinite alternate;
      animation-delay: calc(var(--band-step, 0) * var(--dur-ambient) / -3);
    }

    /* Below this width the section is a single column and the bands would sit
       under the text rather than beside it. */
    @media (max-width: 920px) {
      .section-glass,
      .news-glass { display: none; }
    }

    @media (prefers-reduced-motion: reduce) {
      :is(.section-glass, .news-glass) span {
        animation: none;
      }
    }

    /* ===== CTA ROUTES: THE PLATFORM BUTTON RESPONSE =====
       These three are buttons, so they answer hover the way every other
       button on the site does: the diagonal wipe travels in and the surface
       resolves to Sweihan with a white label. They had drifted to a plain
       background-colour swap to --accent-deep with the wipe switched off
       (display: none), which is the one thing the system explicitly does not
       do - a direct colour swap is a step function where every other action
       is a sweep.

       The wipe carries the colour on its own: these routes rest on a dark
       surface, so the wipe IS Sweihan and nothing swaps underneath it. The
       .btn-primary arrangement does not transfer here - that button is
       already Sweihan at rest, so its dark overlay is the tone-step. A route
       that is dark at rest needs the opposite: reaching the accent by sweep,
       not by a 120ms background jump followed by a second colour arriving
       over 480ms. Two colour events for one gesture is what read as a fault.

       So there is no background-color transition at all here. Only the label
       colour is on a clock, and it is already white in both states. Same
       geometry, same duration, same 55ms lead-in as every other button. */
    .cta-action {
      position: relative;
      isolation: isolate;
      overflow: hidden;
      transition: color var(--dur-fast) var(--ease-out);
    }

    .cta-action::before {
      content: "";
      display: block;
      position: absolute;
      z-index: -1;
      inset: -1px -40%;
      background: var(--brand-sweihan);
      opacity: 1;
      clip-path: polygon(22% 0, 100% 0, 78% 100%, 0 100%);
      transform: translate3d(78%, 0, 0);
      transition: transform var(--dur-slow) var(--ease-out) 55ms;
      pointer-events: none;
    }

    /* The first route rests on Sweihan already, so a Sweihan wipe would be
       invisible on it. It takes a tone-step instead: Sweihan carried 30%
       toward Brand Black.

       Not the Liwa mix this section used to carry. Liwa is a red, and mixing
       58% of it into Sweihan lands on a genuinely red surface next to an
       orange one - it read as a second hue arriving, not as the same button
       going deeper. Black is the system's documented tone-step direction and
       it moves lightness without moving hue.

       The 30% is not a taste value: it is the exact strength of the shared
       rgba(65, 64, 66, .30) overlay every other button on the site wipes in,
       written as an opaque colour because this one sits on an opaque surface.
       Measured in the browser, it resolves to #AB6233 and white on it is
       4.66:1 - clearing the 4.5 AA floor, which the Sweihan rest surface
       does not. */
    .cta-action:first-child::before {
      background: color-mix(in srgb, var(--brand-black) 30%, var(--brand-sweihan));
    }

    /* Hover restates the RESTING surface rather than declaring nothing: a
       @layer legacy rule still swaps these to --accent-deep on hover, and the
       only way to hold the surface still is to name the value it already has.
       Restated per route because the two rest surfaces differ. */
    .cta-action:is(:hover, :focus-visible) {
      background-color: rgba(43, 41, 41, .92);
      border-color: rgba(255, 255, 255, .22);
      color: var(--brand-white);
    }

    .cta-action:first-child:is(:hover, :focus-visible) {
      background-color: var(--accent);
      border-color: var(--accent);
    }

    .cta-action:is(:hover, :focus-visible)::before {
      transform: none;
    }

    @media (prefers-reduced-motion: reduce) {
      .cta-action::before { transition: none; }
    }

    /* ===== .btn-ghost: THE ONE FILLED BUTTON THIS AUDIT MISSED =====
       The shared filled-button hover rule sets background: var(--brand-sweihan)
       for .btn-primary, .nav-cta, .news-form button and .btn-ghost alike. For
       .btn-primary and the others that is a no-op - they already rest on
       Sweihan, so only the dark tone-step wipe is visible, which is correct.

       .btn-ghost rests transparent. For it that same declaration is not a
       no-op: it is the button's own background-color racing to solid Sweihan
       over --dur-fast (120ms), fully opaque, well ahead of the shared 480ms
       diagonal wipe - and painting OVER that wipe, since a box's own
       background paints below its own ::before in the same stacking context.
       The wipe finishes invisibly under a surface that already snapped to
       colour four times faster. Same fault as the one already fixed on
       .cta-action, just unaudited here.

       Fix mirrors that one: the box's own background never changes, and the
       wipe itself is opaque Sweihan instead of the shared dark wash, so the
       sweep is the only way the colour arrives. */
    .btn-ghost::before {
      background: var(--brand-liwa);
      opacity: 1;
    }

    .btn.btn-ghost:is(:hover, :focus-visible) {
      background: transparent;
    }


    .menu-close {
      display: none;
    }

    /* The marker takes the language control's own class rather than a copy of
       its look: same geometry, same 44px target height, same colour in both
       header states, same scrolled treatment. It sits directly beside that
       control in the bar, so anything less than literally the same definition
       would drift the moment either one is retuned.

       It stays a marker, not a control. pointer-events: none is what keeps the
       hover and focus states .lang carries from firing on something that has
       nowhere to go - the site has no accessibility panel and no destination
       for this to open, and a box that answers a pointer and then does nothing
       is worse than one that never invited the pointer. If a real control
       arrives, this line is what comes out. */
    .nav-icon--accessibility {
      pointer-events: none;
    }

    /* .lang disappears at 980 (the drawer carries .menu-lang instead) and again
       at 420. Neither applies to this: it has no text to make room for, no
       counterpart inside the drawer, and it was visible at those widths before
       it adopted the class. Restated rather than left to inherit the hiding. */
    /* 1180, not the Arabic file's 980: this page's drawer opens at 1180 and
       .nav-actions > .lang is hidden from there down, so the restore has to
       start where the hiding does. */
    @media (max-width: 1280px) {
      .nav-actions > .nav-icon--accessibility {
        display: inline-flex;
      }
    }

    @media (max-width: 420px) {
      .nav-icon--accessibility {
        display: inline-flex;
      }
    }

    /* The drawer owns its header while open. Keeping a static header marker
       visible over the backdrop makes it look detached from both surfaces. */
    @media (max-width: 1280px) {
      body.menu-open .nav-icon--accessibility {
        visibility: hidden;
      }

      body.menu-open :is(.ai-chat-toggle, .ai-chat-panel) {
        visibility: hidden;
        pointer-events: none;
      }

      .menu-close {
        display: grid;
        place-items: center;
      }
    }

    /* ===== CARD CHEVRON: THE OPPOSITE CORNER, THE SAME SLANT ================
       The sticker rests in the corner of the card that the copy does NOT
       occupy. On the Arabic page that is bottom-left, because the copy and its
       action link are right-aligned; this page mirrors the copy, so its action
       link sits bottom-left and the sticker takes the bottom-right. The
       collision is measured, not theoretical: put back at bottom-left here,
       the mark's coloured wedge crosses 100x28 of the action link's words and
       100x23 of the lead's last line at 1280. Confirmed as the intended
       corner by the site owner on 2026-08-07.

       THE DRAWING IS MIRRORED TOO, AT THE SITE OWNER'S EXPLICIT DIRECTION
       (2026-08-08), AND THIS REVERSES WHAT THIS COMMENT USED TO SAY.

       What it used to say, and why it was wrong in practice: `--brand-stripe-
       angle` and the rule it encodes are explicit - the Sdeira mark has one
       physical slant, and language direction may move a stripe group to the
       opposite edge but must never mirror or change the angle. So the corner
       moved and the SVG was left untouched, measured at slope +0.89 off the
       live SVG on both pages.

       What that produced on the page: the sticker is a right triangle whose
       two straight legs are meant to BE the card's corner - on the Arabic page
       its vertical leg lies on the card's left edge and its horizontal leg on
       the bottom edge, hypotenuse facing into the panel. Move that same,
       unflipped drawing to the bottom-right and the legs do not follow. The
       vertical leg now stands in the middle of the panel as a hard straight
       cut, the hypotenuse runs out through the card's right edge, and the tip
       is chopped by overflow: hidden. The mark stops reading as a corner
       sticker and reads as a wedge hanging off the corner. Nothing errors, the
       angle is preserved exactly as the rule demanded, and the component is
       still visibly wrong - which is what the owner flagged.

       FLAGGED, NOT SILENT: scaleX(-1) on the <svg> is a departure from the
       token file's stripe rule, taken deliberately and scoped to this one
       component on this one page. It is not licence to mirror any other
       stripe group, hero strip or identity band; those keep the single
       physical slant. If the identity owner rules the other way, the revert is
       this one declaration plus the wipe angle below.

       THE CORNER IS NOT THE SAME QUESTION AS THE CLIP, and conflating them is
       how this component broke. The sticker parks OUTSIDE the panel and its
       <svg> is overflow: visible; it reads as a corner mark only because the
       host crops it. That crop lives on .needs-route-copy, which never
       mentions the chevron - see the rule up in @layer legacy. Moving the
       corner cannot fix a missing crop and a missing crop is not a wrong
       corner, though on the page they look like one fault.

       CONSEQUENCE FOR THE WIPE, and mirroring the drawing is what resolves it.
       The travelling fill is a hard-stop gradient whose front is perpendicular
       to its axis, and on the Arabic page 43deg is the sticker's own measured
       slope, so front and drawing stay parallel - parallelism is the whole
       reason that number is 43 and not a chosen value.

       While the drawing was NOT mirrored, this page could not have both
       parallelism and a fill that starts at the sticker. Project the corners
       of any W x H panel onto the 43deg axis, (0.682, -0.731):

         bottom-left  -0.731H            <- always the minimum, so always 0%
         top-right    +0.682W            <- always the maximum, so always 100%
         bottom-right  0.682W - 0.731H   \  strictly between the two, at every
         top-left      0                 /  aspect ratio, without exception

       A parallel front could therefore only ever originate at the bottom-left
       or the top-right - never at the corner this page's sticker sits in, at
       any panel size. That was a real constraint and it was recorded honestly;
       what it was not is a law about the corner. It was a consequence of the
       drawing keeping the Arabic slope in the mirrored corner.

       Mirror the drawing and the slope becomes -0.89, and the axis that is
       perpendicular to it is the mirror of 43deg about the vertical, which is
       360 - 43 = 317deg. NOT 180 - 43 = 137deg: 137 and 317 differ by a half
       turn, so they draw the SAME front line and travel it in OPPOSITE
       directions. Both are parallel to the mirrored drawing; only one starts
       in its corner. 137deg was tried and rendered - the front is correctly
       parallel and the fill enters from the top-left and runs toward the
       sticker, which is the same wrong reading this page already had.

       317deg has direction (-0.682, -0.731) in screen coordinates. Reproject
       the corners onto it:

         bottom-right -0.682W - 0.731H   <- now the minimum, so now 0%
         top-left      0                 <- now the maximum, so now 100%

       so the fill both stays parallel to the sticker AND grows out of it, the
       same reading the Arabic page has. The two requirements stopped competing
       the moment the drawing was allowed to mirror; keep 43deg and 317deg in
       step with their respective slopes or the front and the lines diverge
       visibly. See the --wipe-angle override further down. */
    :is(.needs-route, .project-card--secondary, .company-card) .card-chevron {
      left: auto;
      right: -7%;
    }

    /* The flip itself. It goes on the <svg>, not on .card-chevron, because the
       host carries the hover translate - putting both on one element would
       make the mirror multiply into the travel and send the sticker the wrong
       way on hover. Two independent transforms on two elements, each stating
       one thing. */
    :is(.needs-route, .project-card--secondary, .company-card) .card-chevron svg {
      transform: scaleX(-1);
    }

    /* --- Company card: one decoration, not two -------------------------------
       ::before was the sdeira-mark watermark in this page's top-right corner.
       The card carries .card-chevron instead, and two brand marks on one card
       read as clutter rather than as identity - the decorative vocabulary
       allows one mark per surface. Retired on the Arabic side already; this is
       the matching port, and it is what removes the faint diagonal stripes
       above the logo. Stated here rather than at any of its redeclarations in
       @layer legacy, because unlayered is the only place that holds regardless
       of which of them cascades last. The hover cue it used to provide moved
       with it: .card-chevron carries the same step. */
    .company-card::before {
      display: none;
    }

    /* Toward the card's interior, which is the other way round from here. */
    :is(.needs-route, .company-card, .project-card--secondary):is(:hover, :focus-within) .card-chevron {
      transform: translate3d(-14px, -10px, 0);
    }

    /* ---- The menu control's colour -----------------------------------------
       The burger's three bars became a single Phosphor glyph (.ph-list) in the
       markup, but every rule that had ever given it a colour was written
       against `.burger span` and set a BACKGROUND, not a colour. Nothing
       errored: the glyph simply fell through to the inherited document ink and
       painted #414042 on the dark bar, beside a language control at
       rgba(255,255,255,.84). Measured at 375: search #414042, accessibility
       marker white, burger #414042.

       It is a header control, so it takes the control colour set - the same
       four states .lang and .nav-search carry, in both header states. Colour
       only: no background on hover, because unlike those two this one is not a
       text-and-icon pill and a wash behind a bare glyph reads as a second
       button appearing. Here rather than in @layer legacy because it has to
       hold at every viewport, and the span rules it replaces are scattered
       across the breakpoint blocks. */
    .burger {
      color: rgba(255, 255, 255, .84);
      transition: color var(--dur-fast) var(--ease-out);
    }

    .burger:is(:hover, :focus-visible) {
      color: var(--brand-white);
    }

    header.scrolled .burger {
      color: var(--muted);
    }

    header.scrolled .burger:is(:hover, :focus-visible) {
      color: var(--accent-text);
    }

    /* ---- The bar's icon controls are one set ---------------------------------
       Three icon-only controls sit at the end of the bar and were three
       different boxes: the two markers 32px wide (16px glyph + 8px padding each
       side) and the burger 44px. With a 4px gap that put 20px of air between one
       pair of glyphs and 26px between the next, which reads as a spacing mistake
       because it is one.

       44px is the number to standardise on, not 32: it is the touch target the
       burger already carries for WCAG 2.5.8, and the one the markers should have
       had. Equal boxes plus one gap makes the ink spacing fall out even -
       14 + 4 + 14 - rather than being tuned per pair. */
    :is(.nav-search, .nav-icon--accessibility, .nav-icon--search, .burger) {
      min-inline-size: 44px;
    }

    /* Optical alignment, which the equal boxes above do NOT give on their own.
       A 44px box around a 16px glyph carries 14px of internal padding, so the
       outermost control's INK sat 14px further in than the logo's, which is an
       image flush to its own box edge. Measured at 375 before this: logo ink
       28px from the page edge, burger ink 42px. The boxes were aligned; the
       marks were not, and the mark is what the eye lines up.

       The 44px target is not given up to fix it - the box keeps its size and is
       pulled outward by exactly its own padding, so the ink lands on the nav's
       content edge and the hit area grows outward rather than shrinking. Logical
       property, so RTL and LTR both get it from this one line: the burger is the
       last child in both, which is the inline-end edge in both.

       Not applied to .nav-cta, which takes over as the last visible child at
       1280 and up: it is a filled button whose box edge IS its ink, so it is
       already flush and pulling it would overhang the bar.

       CLAMPED TO --hd-pad (site owner flagged, 12 Aug 2026, ported from the
       Arabic fix). The formula above assumed --icon-control sits around 32px,
       giving a small pull that fits inside --hd-pad's 10-14px with room to
       spare. But --icon-control clamps to its 16px floor at every width the
       burger is actually visible, which fixes the pull at a constant -14px -
       bigger than --hd-pad at every one of those widths, so the button's own
       box overhung the pill's rounded edge instead of just its ink reaching
       the content edge. max() keeps whichever pull is smaller in magnitude,
       so the box can never protrude past the pill regardless of viewport. */
    .burger {
      margin-inline-end: max(calc((var(--icon-control) - 44px) / 2), calc(-1 * var(--hd-pad)));
    }

    /* ---- The about badge's supporting line -------------------------------
       WHITE AT 72% ON THE SWEIHAN FILL MEASURED 2.45. Solid white on that same
       fill is 3.35, which is the brand's own ceiling and a separate, recorded
       question (see --badge-text in the token file) - but the alpha was ours,
       it cost a third of what contrast the fill does allow, and it bought
       nothing: this is the only line of copy inside the badge, so there was no
       hierarchy for it to sit under. The token file's section 11 already
       forbids body-size text below full white on a translucent dark layer;
       this is the same rule on a coloured one. */
    .about-badge .t {
      color: var(--brand-white);
    }

    /* ---- SCALE FLOOR APPLIED TO WHAT PREDATES IT --------------------
       A full-page audit found 40-odd sizes outside the ten roles, which is
       the drift CLAUDE.md describes in this file. Most of those are card
       headings sitting between 16.8 and 30px where the card role is 31.4px -
       real drift, but snapping them moves layout across half the homepage and
       that is a design change, not a cleanup. It is recorded, not done here.

       WHAT IS DONE HERE IS THE FLOOR. Nothing on the site may render below
       --type-caption (.875rem). These six were under it - 10.8px, 12px,
       12.3px, 12.5px and 12.9px - and every one is a label, a counter or a
       supporting line, which is --type-meta's own job. So this assigns the
       ROLE rather than inventing a size, which is why no number appears below.

       In the SYSTEM LAYER because it is a role assertion that must hold at
       every viewport: these selectors are redefined across several @layer
       legacy breakpoints, so a rule placed among them would win at some widths
       and lose at others. */
    :is(.scroll-hint span,
        .story-achievement span,
        .company-card h3 small,
        .company-num,
        .service-num,
        .sector-hover-copy span,
        .partner-stat small,
        .sector-card-sub) {
      font-size: var(--type-meta);
    }

    /* White-label fills use the accessible role; dark badges use Razeen. */
    :is(.btn-primary, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a),
    :is(.btn-primary, .news-form button, .nav-cta,
      .projects-footer .projects-footer-cta, .sector-hover-copy a):is(:hover, :focus-visible),
    .why-footer a.btn.btn-primary,
    .why-footer a.btn.btn-primary:is(:hover, :focus-visible),
    header.scrolled .nav-cta,
    header.scrolled .nav-cta:is(:hover, :focus-visible) {
      background: var(--accent-fill);
      border-color: var(--accent-fill);
    }

    :is(.project-filter, .news-filter).is-active,
    .about-badge,
    .cta-action {
      background: var(--accent-fill);
    }

    .project-card--feature .project-type {
      color: var(--badge-text-on-dark);
    }

    /* ---- EVERY HEADING AND FIGURE ON THIS PAGE, ON THE SCALE ---------------
       __typecheck.js found 29 selectors on this page rendering a size that is
       not one of the roles - 40-odd nodes, from 14.4px to 97.8px. Every one is
       a local font-size that predates the scale, and together they are why the
       homepage and the generated pages can look like two different products
       even when every colour matches.

       ASSIGNED BY WHAT THE ELEMENT IS, NOT BY WHICH ROLE IS NEAREST. A card
       title takes --type-card whether it currently measures 37.7 or 20.3,
       because the point is that all ten card titles are one size afterwards.
       Nearest-fit would have preserved the spread it was written to remove.

       In the SYSTEM LAYER because these selectors are redefined across many
       @layer legacy breakpoints - .sector-card-title alone appears in five -
       so a rule placed among them wins at some widths and loses at others.
       This is the same reasoning the file's own two-layer note gives. */

    /* Card titles. Nine components, one role. .sector-hover-copy h3 was
       promoted out of this group on 2026-08-12: it is a single-item
       spotlight headline in a hover-preview panel, not a repeated card
       title, and now carries its own --type-feature role next to its
       selector's other declarations - see the comment there. */
    :is(.openings-intro h3,
        .company-card h3,
        .why-card-body h3,
        .service-card h3,
        .story-item h3,
        .project-card-body h3,
        .process-step h3,
        .sector-card-title,
        .about-values-head h3,
        .needs-route-copy strong,
        .news-card h3 a,
        .news-card h3) {
      font-size: var(--type-card);
      line-height: var(--leading-card);
    }

    /* News titles are complete headlines, not excerpts. The legacy two-line
       clamp cuts text mid-title once the shared card role is applied. */
    .news-card h3 a{
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow: hidden;
      text-overflow: ellipsis;
      /* word-break: break-word; */
    }

    .news-card .news-body p {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      word-break: break-word;
    }

    /* Supporting headings: a partner name, a footer column, the small headings
       that sat between 15.8 and 19.8px. --type-label is the heading role
       directly below card and the token file calls it exactly this - heading
       metadata. */
    :is(.partner-card h3,
        .foot-col h3,
        .foot-col h4) {
      font-size: var(--type-label);
      line-height: var(--leading-label);
    }

    /* Figures. Not headings - see --figure-size in the token file. */
    :is(.story-year,
        .verified-figure,
        .process-num,
        .partner-stat strong,
        .about-badge .big) {
      font-size: var(--figure-size);
    }

    /* A figure written as a bidi-isolated numeral inherits the figure size from
       its host rather than carrying one of its own. */
    :is(.verified-figure, .partner-stat strong, .about-badge .big) bdi {
      font-size: inherit;
    }

    /* Supporting lines that sat just off body and lead. */
    :is(.about-badge .t, .about-badge .label, .opening-row strong) {
      font-size: var(--type-body);
      line-height: var(--leading-body);
    }

    :is(.partner-logo span, .impact-alt-stat span) {
      font-size: var(--type-action);
    }

    /* The remainder, once the first pass exposed what the class-less parents
       actually were. `div > h3` and `div > strong` in the audit output are
       these; a selector is only as useful as the name above it.

       A RUNG DOWN, NOT A NEW NUMBER. --figure-size (up to 4rem) is sized for
       a figure that stands alone - the about badge, a timeline year. These
       four sit side by side in one strip, each over its own label and its own
       sentence, and at 64px the numeral swamped both. The answer is the rung
       below on the same ladder - --type-card, the h3 rung, spelled by its
       canonical name rather than the --type-h3 alias so the type linter reads
       it as a role. Not a local clamp: this component stays on the scale and
       moves with it. */
    .impact-alt-stat strong,
    .impact-alt-stat strong bdi {
      font-size: var(--type-card);
    }

    :is(.opening-announcement h3,
        .partner-card .partner-logo,
        .news-subscribe-copy h3,
        .partners-trust-copy h3) {
      font-size: var(--type-label);
      line-height: var(--leading-label);
    }

    .story-achievement strong {
      font-size: var(--type-body);
      line-height: var(--leading-body);
    }


/* =============================================================================
   THE SAND GROUND ON THE HOMEPAGE
   -----------------------------------------------------------------------------
   Two sections here sit on --surface-sunken: "Start with Your Need" and the
   companies band. Section 5b of the token file makes that colour a ground
   rather than a fill, so these two carry a texture rather than a flat tint.
   What that texture IS moved on 21 Aug 2026 (PATTERN CLEAN-UP, PASS 2,
   sdeira-liwa.css) from the site's diagonal stripe language to the p.43
   solid-a.svg mark at 5% opacity - this rule used to still read the retired
   --ground-sand hatch underneath and only rendered correctly because
   sdeira-liwa.css, loaded last, overrode it. That split is closed 31 Aug
   2026: the value that actually ships is now the one written here, and
   sdeira-liwa.css's override of this selector is gone with it.

   WHAT THEY GAVE UP FOR IT, on the site owner's instruction: each carried a
   .section-glass--start group, three placed identity bands, and that decoration
   had no job on a sand section. The ground already IS those bands - the same
   two ambient strengths, repeated across the whole panel instead of parked in
   one corner - so the glass was the same idea drawn a second, louder time in
   one place. The markup is removed from both homepages, not just hidden.

   .section-glass itself is untouched and still runs on the two sections that
   sit on --surface-base: that ground stays plain, so a placed group is the only
   identity those sections get.

   Unlayered, like everything in this part of the file, so it lands regardless
   of what @layer legacy says about these two selectors at any width. */
:is(.needs, .value-sections)::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  background: url("../images/patterns/solid-a.svg?v=032800d78a7d41e0") no-repeat center / cover;
  opacity: 0.05;
  pointer-events: none;
}

/* ===== THE CLOSING BAND'S ROUTES ARE BUTTONS, AND EXACTLY ONE IS PRIMARY
   =====================================================================
   These started life as three diagonal CARDS and were rewritten as actions,
   and each stage left its geometry behind in @layer legacy. The rewrite that
   turned them into buttons gave all three the --accent-fill so they would
   respond identically on hover. Responding identically was right; being
   identical was not. The system offers exactly TWO action levels -
   .btn-primary and .btn-ghost - and a page closes on ONE primary. Three
   filled buttons in a row is three answers to "which one do I press".

   So this is the same component the generated pages already draw, at the same
   two levels: see .cta-action / .cta-action--ghost in sdeira-sections.css,
   which carries the identical rule set for every page that loads that sheet.
   The homepages cannot link it (they carry their own cascade), so the values
   are read from it rather than invented here.

   THE GEOMETRY IS THE BUTTON FAMILY'S, TO THE NUMBER: 48px tall, 0 22px of
   padding, --type-action at weight 800, one radius token, --ic-lg for the
   mark and --ic-sm for the arrow. That replaces this component's three
   off-scale values - a 51px height, a 1.02rem label and a 1.15rem icon, all
   three recorded as "outside the scale" in design-system/index.html. The
   button family is 48px and this is a button.

   The row is a centred flex line, each route flex: 0 0 auto, so the three sit
   together as a set of buttons instead of the 1000px+ orange band the legacy
   `repeat(3, minmax(0, 1fr))` grid drew for a ~180px label. The legacy
   `grid-template-columns: ... !important` at 621px still wins that property -
   an important declaration in a layer beats an unlayered normal one - which
   is exactly why this switches the display mode instead of arguing with it.
   Wrapping replaces the 620px one-column rule for free.

   BOTH LEVELS WIPE TO ONE COLOUR, so the hover vocabulary stays one motion
   and one tone step: one step of Brand Black into --accent-fill. #B85D22
   carries white at 4.54 and the wipe resolves to #94542C, which carries it at
   5.89 - both clear AA, so no label dips through the gesture. The ghost
   promotes to that solid on hover, which is why hovering the secondary can
   never make it look like the resting primary. */
.cta-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  max-width: none;
}

.cta-action,
.cta-action:first-child,
.cta-action:last-child {
  flex: 0 0 auto;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: auto;
  min-height: 48px;
  min-block-size: 48px;
  padding: 0 22px;
  border: 1px solid transparent;
  border-radius: var(--r);
  background: var(--accent-fill);
  color: var(--brand-white);
  font-size: var(--type-action);
  font-weight: 800;
  line-height: var(--leading-label);
  text-align: center;
}

/* THE SECOND AND THIRD ROUTES ARE NOT SECOND PRIMARIES. A transparent control
   with a white outline is the site's one sanctioned border, sanctioned
   precisely because this band sits over photography and an outline is what
   gives a transparent control a hit area there.

   Written at the same three-selector width as the rule above so it beats the
   :first-child / :last-child forms on source order rather than losing to
   their higher specificity. */
.cta-action--ghost,
.cta-action--ghost:first-child,
.cta-action--ghost:last-child {
  border-color: var(--brand-white);
  background: transparent;
}

/* The mark and the arrow are on the icon scale, by token. */
.cta-action > i.ph.cta-action-mark:not(.cta-arrow) {
  font-size: var(--ic-lg);
  color: var(--brand-white);
}

.cta-action .cta-arrow {
  margin-inline-start: 0;
  font-size: var(--ic-sm);
}

.cta-action::before,
.cta-action:first-child::before {
  display: none;
}

/* Contact routes mirror the approved header CTA interaction: the resting ghost
   cards stay transparent, then the orange surface wipes in from left to right
   on hover, focus, or press. */
#contact .cta-action::before {
  content: "";
  display: block;
  position: absolute;
  z-index: -1;
  inset: -1px -40%;
  background: rgba(65, 64, 66, .30);
  opacity: 1;
  clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
  transform: translate3d(-78%, 0, 0);
  transition: transform var(--dur-slow) var(--ease-out) 55ms;
  pointer-events: none;
}

#contact .cta-action:is(:hover, :focus-visible, :active) {
  background: var(--brand-sweihan);
  border-color: var(--brand-sweihan);
  color: var(--brand-white);
}

#contact .cta-action:is(:hover, :focus-visible, :active)::before {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  #contact .cta-action::before { transition: none; }
}

/* The resting surface does not move on hover - the wipe is the whole state.
   These two rules exist only to defeat the legacy pair that changed the
   border to --accent and dropped routes 2 and 3 back to a dark card surface. */
.cta-action:is(:hover, :focus-visible),
.cta-action:first-child:is(:hover, :focus-visible) {
  border-color: transparent;
  background-color: var(--accent-fill);
  color: var(--brand-white);
}

.cta-action--ghost:is(:hover, :focus-visible, :active),
.cta-action--ghost:first-child:is(:hover, :focus-visible, :active),
.cta-action--ghost:last-child:is(:hover, :focus-visible, :active) {
  border-color: var(--accent-fill);
  background-color: transparent;
}

/* Button hover is one animated wipe, not a competing background swap. */
.cta-action { transition: color var(--dur-slow) var(--ease-out); }
.cta-action--ghost { background-color: transparent; }
.cta-action::before,
.cta-action:first-child::before {
  display: block;
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1px -40%;
  background: var(--accent-fill);
  clip-path: polygon(22% 0, 100% 0, 78% 100%, 0 100%);
  transform: translate3d(78%, 0, 0);
  transition: transform var(--dur-slow) var(--ease-out) 55ms;
  pointer-events: none;
}
.cta-action:first-child::before { background: color-mix(in srgb, var(--brand-black) 30%, var(--accent-fill)); }
.cta-action:is(:hover, :focus-visible)::before,
.cta-action:first-child:is(:hover, :focus-visible)::before { transform: none; }
.cta-action:is(:hover, :focus-visible) { background-color: var(--accent-fill); }
.cta-action--ghost:is(:hover, :focus-visible) { background-color: transparent; }

/* Ghost buttons keep their transparent surface; the wipe supplies the hover fill. */
.btn-ghost { transition: color var(--dur-slow) var(--ease-out), border-color var(--dur-slow) var(--ease-out); }
.btn-ghost:is(:hover, :focus-visible) { background-color: transparent; }

/* THE ENGLISH HOMEPAGE HEADER/NAV == THE SUB-PAGES. This whole block implements
   the shared group header exactly as the sub-page component
   (assets/css/sdeira-subpage.css) does: the same floating surface, the same
   one-size pill, the same dark inks, the same dropdown/drawer geometry and the
   same controls. Everything here is UNLAYERED, so it beats the legacy homepage
   rules in @layer legacy above at every width, and the breakpoints match the
   sub-page file (compact at 981+, drawer at <=1280) with no reversion to
   larger values at 1500+. */
header {
  --hd-gap: clamp(6px, .6vw, 8px);
  --hd-pad: clamp(6px, .6vw, 8px);
  --cta-h: clamp(34px, 2.6vw, 40px);
  /* Single shared logo height across rest and scrolled states and widths
     (V3 change request): --header-logo-height lives in the token file. */
  --logo-h: var(--header-logo-height);
  padding: var(--hd-gap);
  background: transparent;
  backdrop-filter: none;
}

header.scrolled {
  --logo-h: var(--header-logo-height);
  background: transparent;
  backdrop-filter: none;
}

.nav {
  position: relative;
  isolation: isolate;
  gap: 18px;
  /* Same pill gutters as the Arabic homepage and every sub-page. */
  padding: var(--hd-pad);
}

/* Readability scrim over the hero, identical to the sub-page gradient. The
   white strip below covers the bar itself; what remains below the bar is the
   same fade the sub-page draws. */
header::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  block-size: 230px;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(0, 0, 0, .62) 0%,
    rgba(0, 0, 0, .58) 40%,
    rgba(0, 0, 0, .3) 72%,
    transparent 100%);
  transition: opacity var(--dur-base) var(--ease-out);
}

header.scrolled::before { opacity: 0; }

/* The floating pill and the bar->pill transition, from the sub-page: the strip
   is fully shaped at rest, so only paint moves; the geometry transition is what
   lets the full-width strip collapse back to the pill without popping. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 1px solid transparent;
  border-radius: var(--r);
  background: rgba(255, 255, 255, 0);
  backdrop-filter: blur(0px) saturate(100%);
  -webkit-backdrop-filter: blur(0px) saturate(100%);
  transition:
    left var(--dur-base) var(--ease-out),
    right var(--dur-base) var(--ease-out),
    margin-inline var(--dur-base) var(--ease-out),
    top var(--dur-base) var(--ease-out),
    bottom var(--dur-base) var(--ease-out),
    border-radius var(--dur-base) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out),
    backdrop-filter var(--dur-base) var(--ease-out);
}

header:not(.scrolled) .nav::before {
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  top: calc(-1 * var(--hd-gap));
  bottom: calc(-1 * var(--hd-gap));
  border-radius: 0;
  background: var(--brand-white);
  border-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

header.scrolled .nav::before {
  background: rgba(255, 255, 255, .82);
  border-color: var(--line);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
}

/* Dark inks at every scroll position (the bar is always white), matching the
   sub-page. The active item is ink at rest and --accent-text once scrolled,
   exactly as the sub-page resolves it. The search/burger ink is handled
   sitewide by sdeira-nav-controls.css. */
.logo { color: var(--charcoal); }
.menu a { color: var(--ink); }
.menu a.active { color: var(--ink); }
header.scrolled .menu a.active { color: var(--accent-text); }
.nav-disclosure > summary { color: var(--ink); padding-inline: 6px; }
.lang { color: var(--muted); }

/* Logo sizing, from the sub-page: a 440px cap at rest, compact 180px on any
   desktop (no reversion above 1500), 180/42 inside the drawer, and the two
   phone steps. */
.logo img,
#navLogo {
  max-width: 440px;
}

/* Menu spacing, from the sub-page. */
.menu { gap: clamp(12px, 1.55vw, 20px); }

/* Dropdown: the sub-page's fixed 250px panel and its accent-fill row state.
   The legacy max-content / min-260 variant is overridden here. */
.nav-submenu {
  inline-size: max-content;
  
}

.menu .nav-submenu a:is(:hover, :focus-visible, .active) {
  background: var(--accent-fill);
  color: #fff;
}

/* The reveal-on-hover row icon, from the sub-page (slides from 4px to 0). */
.nav-submenu-hover-icon {
  transform: translateX(4px);
}
.menu .nav-submenu a:is(:hover, :focus-visible) .nav-submenu-hover-icon {
  transform: translateX(0);
}

/* Drawer rows take the shared control type size, like the sub-page. */
.menu > a:not(.menu-logo) { font-size: var(--type-control); }

/* Desktop compact values (1281 and up): logo 220, menu gap 22, actions gap 8,
   CTA padding 20. Because this block is unlayered it also wins over any legacy
   "roomier above 1500" values, exactly as the sub-page does. */
@media (min-width: 1281px) {
  header :is(.logo img, #navLogo) { max-width: 220px; }
  .menu { gap: 22px; }
  .nav-actions { gap: 8px; }
  .nav-cta { padding-inline: 20px; }
}

/* Below 1180: tighten before the drawer. */
@media (max-width: 1180px) {
  .menu { gap: 22px; }
  .nav-actions { gap: 8px; }
  .nav-cta { padding: 0 20px; }
}

/* Drawer breakpoint (<=1280): the same drawer as the sub-page - same panel
   width/height, same resting surface, same corner art, same rows, same open
   disclosure fill, same backdrop, same burger behaviour. */
@media (max-width: 1280px) {
  .menu { gap: 0; }

  header :is(.logo img, #navLogo) {
    max-width: 180px;
    height: 42px;
  }

  .menu.open {
    background: var(--offwhite);
  }

  .menu::after {
    inset-inline-start: -34px;
    inset-block-end: 54px;
    inline-size: 160px;
    aspect-ratio: 1;
    background: url("../images/brand/sdeira-mark.png") center / contain no-repeat;
  }

  .menu.open .menu-lang {
    color: var(--charcoal);
    font-weight: 700;
    font-size: var(--type-control);
  }

  .menu.open .menu-contact {
    color: #fff;
    border-radius: var(--r);
    font-weight: 800;
  }

  .menu.open .menu-contact:hover {
    background: var(--brand-razeen);
    border-color: var(--brand-razeen);
    color: var(--brand-black);
  }

  /* Disclosures inside the drawer: full-width rows that push their siblings,
     with the accent-fill open state - the sub-page's drawer vocabulary. */
  .menu > .nav-disclosure {
    inline-size: 100%;
    border-block-end: 1px solid var(--line);
    opacity: 0;
    transform: translateX(10px);
    transition:
      opacity var(--dur-base) var(--ease-out),
      transform var(--dur-base) var(--ease-out);
  }
  .menu.open > .nav-disclosure {
    opacity: 1;
    transform: translateX(0);
  }
  .nav-disclosure > summary {
    min-block-size: 54px;
    padding-inline: 4px 12px;
    justify-content: space-between;
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 600;
  }
  .nav-disclosure > summary::after { display: none; }
  .nav-disclosure[open]:not(.is-closing) > summary {
    background: var(--accent-fill);
    color: #fff;
  }
  .nav-disclosure[open]:not(.is-closing) > summary a { color: inherit; }

  /* Mobile submenu: static, full-width, white, in flow - the sub-page's. */
  .menu .nav-submenu {
    position: static;
    inline-size: 100%;
    padding: 4px 14px 12px;
    background: #fff;
    border-radius: var(--r);
    overflow: hidden;
  }
  .menu .nav-submenu a {
    min-block-size: 44px;
    padding-inline: 10px;
  }
}

/* Phone steps, from the sub-page. */
@media (max-width: 720px) {
  .menu.open .menu-lang { gap: 9px; }
}

@media (max-width: 560px) {
  header :is(.logo img, #navLogo) {
    max-width: min(42vw, 146px);
    height: var(--logo-h);
  }
  .nav-actions { gap: 6px; }
}

@media (max-width: 420px) {
  .nav { gap: 10px; }
  header :is(.logo img, #navLogo) {
    max-width: min(39vw, 146px);
  }
  .lang { display: none; }
  .nav-actions { gap: 4px; }
}

/* Filtered feature cards are peers of the secondary cards. Keep their copy
   surface and hover tone on the same system step. */
.project-cards.is-filtered-view .project-card--feature .project-card-body {
  background: var(--surface-raised);
  transition: background-color var(--dur-base) var(--ease-out);
}

.project-cards.is-filtered-view .project-card--feature:is(:hover, :focus-within) .project-card-body {
  background: var(--surface-raised);
}

/* The drawer has its own identity mark. Hide the page header mark while the
   drawer is open so it does not sit above the backdrop as a second header. */
@media (max-width: 1280px) {
  body.menu-open .nav > .logo {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
}

/* ===== FOOTER GRID: TWO COMFORTABLE ROWS ON WIDE SCREENS ==================
   Five footer groups in one line made the brand copy and each navigation list
   read as narrow columns. Keep the brand block as the visual anchor spanning
   both rows, while the four destination groups breathe as a 2x2 set. The
   existing 2-column/1-column responsive rules remain the compact states. */
@media (min-width: 981px) {
  footer .foot-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: start;
  }

  footer .foot-brand {
    grid-row: span 2;
  }
}

@media (max-width: 980px) {
  footer .foot-brand {
    grid-row: auto;
  }
}

/* The lower footer line carries three distinct jobs: copyright, social
   channels, and legal routes. Give each a stable place instead of squeezing
   them into one flex row; the legal row becomes the quiet second line. */
.foot-bottom {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "copy socials"
    "legal legal";
  align-items: center;
  row-gap: 14px;
}

.foot-bottom .copy { grid-area: copy; }
.foot-bottom .foot-socials { grid-area: socials; }

.foot-legal {
  grid-area: legal;
  display: flex;
  flex-wrap: wrap;
  gap: 18px 24px;
  align-items: center;
}

.foot-legal a {
  color: var(--muted-on-dark);
  font-size: var(--type-caption);
  font-weight: 400;
  transition: color var(--dur-fast) var(--ease-out);
}

.foot-legal a:is(:hover, :focus-visible) {
  color: var(--link-hover-on-dark);
}

@media (max-width: 560px) {
  .foot-bottom {
    grid-template-columns: 1fr;
    grid-template-areas:
      "copy"
      "legal"
      "socials";
    justify-items: start;
  }
}

/* ===== DRAWER CONTACT: MATCH THE HERO BUTTON RESPONSE ======================
   The desktop header CTA already gets this shared wipe from
   sdeira-nav-controls.css. The mobile drawer's contact link had remained a
   flat colour swap, so it now uses the same filled resting surface and dark
   diagonal hover/focus wipe. Filter and tab pills stay on their documented
   colour-only hover contract: they are selection controls, not CTAs. */
.menu.open .menu-contact {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-color: var(--accent-fill);
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.menu.open .menu-contact::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1px -40%;
  background: var(--surface-brand-deep);
  clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
  transform: translate3d(-78%, 0, 0);
  transition: transform var(--dur-slow) var(--ease-out) 55ms;
  pointer-events: none;
}

.menu.open .menu-contact:is(:hover, :focus-visible) {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--brand-white);
}

.menu.open .menu-contact:is(:hover, :focus-visible)::before {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .menu.open .menu-contact,
  .menu.open .menu-contact::before {
    transition: none;
  }
}

/* ===== CTA ROUTES: RESTING SURFACE + WIPE ONLY =============================
   Several older breakpoint rules still assign a new background on hover. The
   route set must not snap to orange: the resting surface stays put and the
   pseudo-element is the only colour that travels. These selectors deliberately
   repeat the component's resting values at the final cascade position so the
   legacy declarations cannot reintroduce the jump. */
#contact .cta-action,
#contact .cta-action:first-child,
#contact .cta-action:last-child {
  transition: color var(--dur-slow) var(--ease-out),
              border-color var(--dur-slow) var(--ease-out);
  background-color: var(--accent-fill);
  border-color: transparent;
}

#contact .cta-action--ghost,
#contact .cta-action--ghost:first-child,
#contact .cta-action--ghost:last-child {
  background-color: transparent;
  border-color: var(--brand-white);
}

#contact .cta-action::before,
#contact .cta-action:first-child::before {
  display: block;
  z-index: 0;
  background: var(--surface-brand-deep);
  opacity: 1;
  /* Match the English hero button: the wipe is parked at the reading-end
     side and enters in the same direction as the primary control above. */
  clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
  transform: translate3d(-78%, 0, 0);
  transition: transform var(--dur-slow) var(--ease-out) 55ms;
}

/* #contact .cta-action:first-child::before {
  background: color-mix(in srgb, var(--brand-black) 30%, var(--accent-fill));
} */

#contact .cta-action > * {
  position: relative;
  z-index: 1;
}

/* Restate the same surface only to defeat the legacy hover swap; no colour
   transition runs on the host, so the wipe remains the sole visible change. */
#contact .cta-action:is(:hover, :focus-visible, :active),
#contact .cta-action:first-child:is(:hover, :focus-visible, :active) {
  background-color: var(--accent-fill);
  border-color: transparent;
}

#contact .cta-action--ghost:is(:hover, :focus-visible, :active),
#contact .cta-action--ghost:first-child:is(:hover, :focus-visible, :active),
#contact .cta-action--ghost:last-child:is(:hover, :focus-visible, :active) {
  background-color: transparent;
  border-color: var(--accent-fill);
}

#contact .cta-action:is(:hover, :focus-visible, :active)::before,
#contact .cta-action:first-child:is(:hover, :focus-visible, :active)::before {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  #contact .cta-action,
  #contact .cta-action::before,
  #contact .cta-action:first-child::before {
    transition: none;
  }
}

/* The drawer CTA follows the same no-snap rule and now rests on the approved
   primary fill instead of the old charcoal exception. */
.menu.open .menu-contact {
  background-color: var(--accent-fill);
  border-color: transparent;
  transition: color var(--dur-slow) var(--ease-out);
}

.menu.open .menu-contact:is(:hover, :focus-visible) {
  background-color: var(--accent-fill);
  border-color: transparent;
}

/* ===== CANONICAL BUTTON WIPE ===============================================
   Every filled/ghost button on the English homepage shares this state model:
   its resting surface is stable, while the diagonal layer is the only colour
   that travels on hover or keyboard focus. Keeping this unlayered rule last
   defeats the legacy breakpoint declarations above without changing geometry. */
:is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
    .projects-footer .projects-footer-cta, .sector-hover-copy a) {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: color var(--dur-slow) var(--ease-out),
              border-color var(--dur-slow) var(--ease-out),
              min-height var(--dur-base) var(--ease-out),
              padding var(--dur-base) var(--ease-out);
}

:is(.btn-primary, .nav-cta, .news-form button,
    .projects-footer .projects-footer-cta, .sector-hover-copy a) {
  background-color: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--brand-white);
}

:is(.btn-ghost) {
  background-color: transparent;
}

:is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
    .projects-footer .projects-footer-cta, .sector-hover-copy a)::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1px -40%;
  background: var(--surface-brand-deep);
  clip-path: polygon(78% 0, 0 0, 22% 100%, 100% 100%);
  transform: translate3d(-78%, 0, 0);
  transition: transform var(--dur-slow) var(--ease-out) 55ms;
  pointer-events: none;
}

:is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
    .projects-footer .projects-footer-cta, .sector-hover-copy a):is(:hover, :focus-visible) {
  background-color: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--brand-white);
}

/* The hero control carries both `.btn` and `.btn-ghost`. Keep the compound
   selector here so its specificity defeats the older `.btn.btn-ghost:hover`
   rule that otherwise repaints the host before the wipe can arrive. */
.btn.btn-ghost:is(:hover, :focus-visible),
:is(.btn-ghost):is(:hover, :focus-visible) {
  background-color: transparent;
}

:is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
    .projects-footer .projects-footer-cta, .sector-hover-copy a):is(:hover, :focus-visible)::before {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  :is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
      .projects-footer .projects-footer-cta, .sector-hover-copy a),
  :is(.btn-primary, .btn-ghost, .nav-cta, .news-form button,
      .projects-footer .projects-footer-cta, .sector-hover-copy a)::before {
    transition: none;
  }
}

/* --- Hero sector cards: black veil -> Jais, site owner 25 Aug 2026 --------
   Ported from docs/prototypes/a-liwa/theme.css (Direction A, approved same
   day for both a-liwa and b-khatim - identical five-card treatment either
   way): the identity owner asked that black not be used on the five hero
   sector cards. The veil moves off a black-based curve onto Jais
   (#59595C, rgb 89 89 92) at roughly two-thirds of the same weights, and the
   label band the veil sits above moves with it. Unlayered so it beats every
   breakpoint's own .hero-sectors/.sector-card-veil declaration in
   @layer legacy without duplicating each one. */
.hero-sectors .sector-card-veil {
  background: linear-gradient(180deg,
    rgba(89, 89, 92, .03) 0%,
    rgba(89, 89, 92, .04) 10%,
    rgba(89, 89, 92, .06) 20%,
    rgba(89, 89, 92, .09) 30%,
    rgba(89, 89, 92, .15) 40%,
    rgba(89, 89, 92, .22) 50%,
    rgba(89, 89, 92, .28) 55%,
    rgba(89, 89, 92, .34) 60%,
    rgba(89, 89, 92, .41) 65%,
    rgba(89, 89, 92, .47) 70%,
    rgba(89, 89, 92, .54) 80%,
    rgba(89, 89, 92, .59) 90%,
    rgba(89, 89, 92, .62) 100%);
}

.hero-sectors {
  background: linear-gradient(180deg,
    rgba(89, 89, 92, 0) 0%,
    rgba(89, 89, 92, .33) 30%,
    rgba(89, 89, 92, .45) 100%);
}

/* Site owner, 26 Aug 2026: the closing Contact band's glass panel (.cta-inner)
   was exactly as tall as .cta itself, so the photograph it sits on never
   showed above or below it - the panel read as a flat fill across the whole
   section, the opposite of "seen through glass". .cta gets real padding-block
   (the shared --sec-pad token, not a new value) so the section is taller than
   its content; .cta already centres .cta-inner with `display: grid;
   align-items: center`, so that surplus height becomes visible photograph
   margin above and below the panel with no other change needed. Unlayered so
   it wins over every @layer legacy breakpoint's own zero padding on .cta. */
.cta {
  padding-block: var(--sec-pad);
}
