/* ============================================================
   Gravity — "Be the Center of Gravity" landing layer.
   Colours are sampled straight out of the supplied artwork:
     base     #0e1124   alternate #121734
     gradient #ef8f20 → #d31d53 → #462d93   (Asset 46 bar)
     horizon  cold blue rim over the page colour  (Asset 94)
   Loaded after style.css, and only by index.html.

   Everything visible here is driven by content.json → landing,
   so the section labels are live text (translatable, themeable)
   rather than the English artwork they were cut from.
   ============================================================ */

:root,
:root[data-theme="dark"] {
  --g-orange: #ef8f20;
  --g-pink:   #d31d53;
  --g-purple: #462d93;
  --g-magenta:#b80c6f;
  --g-grad:   linear-gradient(140deg, var(--g-orange), var(--g-pink) 52%, var(--g-purple));
  --g-tint:   linear-gradient(150deg, #1e2f8f, #2560a8 52%, #16215e);  /* mosaic wash */

  /* TEXT gradient ≠ fill gradient. Measured against this base (WCAG 2.2 §1.4.3,
     3:1 for large text): orange 7.67:1, pink 3.62:1, purple 1.83:1 — the purple
     end fails on its own, before anything is placed behind it. So type uses
     only the half of the ramp that clears the bar. */
  --g-grad-text: linear-gradient(140deg, var(--g-orange), var(--g-pink) 96%);

  --g-space:  #0e1124;   /* base */
  --g-panel:  #121734;   /* alternate — panels, cards, tiles */
  --g-line:   rgba(255,255,255,.09);
  --g-tile:   rgba(255,255,255,.035);

  /* artwork cut as white-on-transparent needs no help on a dark page */
  --g-artfix: none;
  --g-logofix: grayscale(1) invert(1) brightness(1.15) contrast(1.1);
  --g-logo-op: .5;
  --g-logo-blend: screen;

  /* map the old tokens so inherited sections follow along */
  --bg: var(--g-space);  --card: var(--g-panel);  --surface: var(--g-panel);
  --ink: rgba(255,255,255,.92);  --title: #fff;  --navy: #fff;
  --muted: rgba(255,255,255,.55);
  --orange: var(--g-orange); --pink: var(--g-pink); --purple: var(--g-purple);
  --grad: var(--g-grad);
}

/* ---------- light theme ----------
   The same layout on paper: the artwork is white-on-transparent, so every
   cut-out gets knocked to ink, and the horizon becomes a warm brand arc
   instead of a cold glow (light can't glow on white). */
:root[data-theme="light"] {
  --g-space:  #f5f6fc;
  --g-panel:  #ffffff;
  --g-line:   rgba(20,26,58,.11);
  --g-tile:   #ffffff;

  --g-artfix: brightness(0) saturate(100%) invert(11%) sepia(38%) saturate(2200%) hue-rotate(219deg);
  --g-logofix: grayscale(1) contrast(1.05);
  --g-logo-op: .48;
  --g-logo-blend: multiply;

  --bg: var(--g-space);  --card: var(--g-panel);  --surface: var(--g-panel);
  --ink: #2c3357;  --title: #141a3a;  --navy: #141a3a;
  --muted: #626a8a;

  /* the ramp inverts on paper: orange drops to 2.26:1 here while purple rises
     to 9.47:1, so the legible half is the opposite end */
  --g-grad-text: linear-gradient(140deg, var(--g-pink), var(--g-purple) 96%);
}

html, body { background: var(--g-space); color: var(--ink); }
body, .section, .about, .services, .work, .events, .simulator, .pulse, .contact { background: transparent; }
.section { position: relative; }

/* ---------- motion primitives ---------- */
.gf-rise    { opacity: 0; transform: translateY(40px); transition: opacity .9s cubic-bezier(.2,.7,.3,1), transform .9s cubic-bezier(.2,.7,.3,1); }
.gf-rise.in { opacity: 1; transform: none; }
.gf-rise.d1 { transition-delay: .1s; }  .gf-rise.d2 { transition-delay: .2s; }
.gf-rise.d3 { transition-delay: .3s; }  .gf-rise.d4 { transition-delay: .4s; }
@media (prefers-reduced-motion: reduce) { .gf-rise { opacity: 1; transform: none; transition: none; } }

/* ---------- section label ----------
   Was a row of English PNGs. Live text instead: it translates, it inherits
   the theme, and the admin can edit it. Latin keeps the wide tracking of the
   artwork; Arabic gets a fraction of it, because Arabic joins. */
.gf-lbl {
  display: block; text-align: center; margin: 0 auto clamp(1.6rem, 3vw, 2.6rem);
  font-family: "Poppins", sans-serif; font-weight: 400;
  font-size: clamp(.82rem, 1.35vw, 1.12rem); letter-spacing: .42em;
  color: var(--title); padding-inline-start: .42em;   /* tracking adds a trailing gap */
}
.gf-lbl b { font-weight: 700; letter-spacing: .42em; }
html[lang="ar"] .gf-lbl,
html[lang="ar"] .gf-lbl b {
  font-family: var(--font-ar); letter-spacing: .1em;
  font-size: clamp(1rem, 1.7vw, 1.4rem);
}

.gf-wrap { max-width: 1180px; margin: 0 auto; padding: 0 clamp(1.2rem, 4vw, 3rem); }

/* ============================================================
   THE STAGE — hero, figures and horizon, pinned while it plays
   ============================================================ */
/* The section is several screens tall and its inner sticks to the viewport.
   That scroll distance is what the sequence is timed against: without it the
   headline hand-off and all three figures went by in a few pixels of scroll
   and were simply never seen. */
.gf-stage { position: relative; height: 340vh; }
.gf-stage-in {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: block;
}
/* every layer is stacked in the same box */
.gf-stage-in > * { position: absolute; inset: 0; }

.gf-hero {
  z-index: 3; display: grid; align-items: center;
  padding: clamp(4rem, 8vw, 7rem) 0 22vh;   /* clear of the horizon */
}
/* the helmet grows past its column as it centres, so it must not be clipped */
.gf-hero, .gf-hero-inner { overflow: visible; }
.gf-helmet { will-change: transform; }
/* the tell, from the third tap of the knock — enough to know it is counting,
   not enough to look like a control */
.gf-helmet .hat { transition: filter .3s ease; }
.gf-helmet.knock .hat { filter: drop-shadow(0 0 26px rgba(211,29,83,.75)); }

/* ---------- the hand-off to the dashboard ----------
   The helmet pushes toward the viewer while the brand colour closes over the
   page. !important on the transform because JS owns that property for the
   scroll sequence and would otherwise keep overwriting it mid-flight. */
.gf-helmet.launching {
  transform: scale(1.9) !important;
  transition: transform .7s cubic-bezier(.5,0,.75,0);
}
.gf-helmet.launching .hat { filter: drop-shadow(0 0 60px rgba(211,29,83,.95)); }
.gf-warp {
  position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  background: var(--g-grad); opacity: 0;
  transition: opacity .62s ease-in;
}
.gf-warp.on { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .gf-helmet.launching { transition: none; transform: none !important; }
  .gf-warp { transition: none; }
}
.gf-hero-inner {
  position: relative; max-width: 1240px; margin: 0 auto; width: 100%;
  padding: 0 clamp(1.2rem, 4vw, 3rem);
  display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 2rem;
}
/* The helmet sits ON the enlarged brand mark. Both files are cropped to their
   artwork (mark 989×1199, helmet 630×675) so these percentages mean what they
   say — the helmet covers 64% of the mark's width, 12% in from its left. */
.gf-helmet {
  position: relative; justify-self: start;
  width: min(560px, 42vw); aspect-ratio: 989 / 1199;
}
.gf-helmet .mark {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none;
}
.gf-helmet .hat {
  position: absolute; left: 12%; top: 10%; width: 64%; z-index: 2;
  filter: drop-shadow(0 26px 44px rgba(0,0,0,.55));
}
:root[data-theme="light"] .gf-helmet .hat { filter: drop-shadow(0 26px 44px rgba(20,26,58,.28)); }

.gf-headimg { justify-self: end; width: min(560px, 40vw); position: relative; }
.gf-headimg img { width: 100%; display: block; filter: var(--g-artfix); }
/* The supplied lockup is white lettering with the script "of" already in the
   brand gradient. Knocking the file to ink for the light theme flattens that
   accent too, so the gradient "of" is laid back over the top. Its box was
   measured off the artwork: 169×272 at 0,110 in a 605×383 file, which is
   exactly the of.png asset — hence the round numbers below. Only applied when
   the default headline is in place; a replaced lockup gets no overlay. */
.gf-headimg .of {
  position: absolute; left: 0; top: 28.72%; width: 27.93%;
  display: none; pointer-events: none;
}
:root[data-theme="light"] .gf-headimg.stock .of { display: block; }
/* keeps its own colour; the drift animation from .gf-headimg img still applies
   to both layers with the same timing, so the overlay never drifts apart */
.gf-headimg .of img { filter: none; }
/* live-text fallback when no headline artwork is set for this language */
.gf-headtext {
  font-family: "Poppins", sans-serif; font-weight: 800; color: var(--title);
  font-size: clamp(2.2rem, 5vw, 4rem); line-height: 1.04; letter-spacing: -.02em; margin: 0;
}
html[lang="ar"] .gf-headtext { font-family: var(--font-ar); letter-spacing: 0; }

/* ---------- hero motion ----------
   layers breathe on their own and lean with the pointer; the wrapper carries the
   pointer offset so the idle float underneath is never fought over */
.gf-par { will-change: transform; transition: transform .5s cubic-bezier(.2,.8,.3,1); }
.gf-helmet .hat  { animation: gfFloat 7s ease-in-out infinite; }
.gf-helmet .mark { animation: gfFloat 9s ease-in-out infinite reverse; }
@keyframes gfFloat {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -14px, 0); }
}
/* the float lives on the img so JS can own the wrapper's transform for the
   pointer lean — otherwise the two would overwrite each other */
.gf-headimg img { animation: gfDrift 11s ease-in-out infinite; }
@keyframes gfDrift {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -9px, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .gf-helmet .hat, .gf-helmet .mark, .gf-headimg img { animation: none; }
  .gf-par { transition: none; }
}

/* magnetic pull on the primary buttons */
.btn-gradient { will-change: transform; }
@media (max-width: 820px) {
  /* stack, and give the helmet its own room so the mark never sits on the type */
  .gf-hero-inner { grid-template-columns: 1fr; justify-items: center; gap: clamp(2rem, 8vw, 3.5rem); }
  .gf-helmet, .gf-headimg { justify-self: center; }
  .gf-helmet { width: min(320px, 62vw); }
  .gf-headimg { width: min(440px, 84vw); }
  .gf-hero { min-height: auto; padding-top: clamp(6rem, 18vw, 8rem); }
}

/* ============================================================
   THE FIGURE  +  the horizon it climbs out of
   ============================================================ */
/* Live text filled with the brand gradient, rising from behind the limb as the
   section scrolls. Type rather than artwork so the figures swap cleanly and
   always sit dead centre. */
/* The figures sit just above the limb and clip their own overflow, so each one
   travels up out of nothing — that is the "from behind the horizon" read.
   Above the helmet (z3), because by the time they arrive the helmet has grown
   to fill the stage and would otherwise cover them. */
.gf-stat {
  z-index: 4; display: grid; align-content: center; justify-items: center;
  text-align: center; pointer-events: none;
}
/* A guaranteed backdrop. Display type over the artwork measured 1.04:1 against
   the magenta wedge — the figure was mathematically invisible there, whatever
   colour it was. This pools the page colour under it so the contrast is a
   known quantity rather than whatever pixel happens to be behind. */
.gf-stat::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(42% 30% at 50% 50%,
    rgb(14 17 36 / var(--gf-scrim, .62)) 26%, rgb(14 17 36 / calc(var(--gf-scrim, .62) * .48)) 55%, rgba(14,17,36,0) 78%);
}
:root[data-theme="light"] .gf-stat::before {
  background: radial-gradient(42% 30% at 50% 50%,
    rgb(245 246 252 / var(--gf-scrim, .66)) 26%, rgb(245 246 252 / calc(var(--gf-scrim, .66) * .5)) 55%, rgba(245,246,252,0) 78%);
}
/* on paper the halo has to be ink, not white */
:root[data-theme="light"] .gf-statwrap { --gf-stroke-col: var(--g-space); }
.gf-statwrap { overflow: hidden; padding-bottom: .5rem; width: 100%; }

/* ---------- the two beats never share the screen ----------
   Driven by an attribute, not by the animation: with prefers-reduced-motion the
   transforms are skipped, and the headline used to sit at full opacity while
   the figure rose straight through it. */
.gf-stage[data-phase="hero"]    .gf-stat  { opacity: 0; }
.gf-stage[data-phase="figures"] .gf-headimg { opacity: 0 !important; visibility: hidden; }
.gf-stat { transition: opacity .5s ease; }
.gf-headimg { transition: opacity .5s ease, visibility .5s; }
.gf-statwrap .num,
.gf-statwrap .word {
  display: block; direction: ltr; font-family: "Poppins", sans-serif;
  background: var(--g-grad-text); -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  /* A white outline, painted BEHIND the fill so it haloes the letterform
     instead of eating into it. This is what carries the contrast now: the
     stroke is 18.68:1 on the base whatever the gradient underneath is doing,
     so the figure separates from the artwork on its own. */
  -webkit-text-stroke: var(--gf-stroke, .035em) var(--gf-stroke-col, #fff);
  paint-order: stroke fill;
  /* far enough to clear the WRAPPER, not just itself: the wrapper is taller
     than the figure (it also holds the word), so 115% of the figure's own
     height left a sliver of it showing above the clip at rest */
  transform: translateY(165%); transition: transform 1.1s cubic-bezier(.16,.9,.24,1);
}
html[lang="ar"] .gf-statwrap .word { direction: rtl; font-family: var(--font-ar); letter-spacing: .1em; }
.gf-statwrap .num {
  font-weight: 800; font-size: clamp(5.5rem, 19vw, 15rem); line-height: .86; letter-spacing: -.04em;
}
/* The word takes no gradient and no outline. Arabic joins — an outline closes
   up the counters and thickens the connectors until the word turns to mush —
   and at this size it is normal text, which wants 4.5:1, a bar the pink end of
   the ramp misses at 3.62:1. Solid white is 18.68:1 and leaves the script
   intact. The figure above keeps the gradient and the halo; it is display type
   and behaves differently. */
.gf-statwrap .word {
  margin-top: .6rem; font-weight: 700;
  font-size: clamp(1.1rem, 2.8vw, 2rem); letter-spacing: .46em;
  background: none; color: #fff; -webkit-text-fill-color: #fff;
  -webkit-text-stroke: 0;
}
:root[data-theme="light"] .gf-statwrap .word { color: var(--title); -webkit-text-fill-color: var(--title); }
.gf-statwrap.in .num,
.gf-statwrap.in .word { transform: none; }
.gf-statwrap.in .word { transition-delay: .16s; }

/* ============================================================
   PARTNERS — one tile, one size, whatever the file looks like
   ============================================================ */
.gf-partners { padding: clamp(2rem, 5vw, 3.5rem) 0 clamp(3rem, 6vw, 5rem); }
/* A grid, not a wrapping flex row: columns line up down the page and the last
   row starts on the same edge as every other one. */
.gf-plogos {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(.7rem, 1.6vw, 1.25rem);
  max-width: 1080px; margin: 0 auto; padding: 0 clamp(1.2rem, 4vw, 3rem);
}
@media (max-width: 860px) { .gf-plogos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .gf-plogos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* the padding is what guarantees containment: the image can never be wider or
   taller than the box it is centred in, whatever its own proportions are */
.gf-plogo {
  position: relative; aspect-ratio: 16 / 9; display: grid; place-items: center;
  padding: 14% 15%; border-radius: 16px; overflow: hidden;
  background: var(--g-tile); border: 1px solid var(--g-line);
  text-decoration: none; color: inherit;
  transition: transform .35s cubic-bezier(.2,.8,.3,1), background .35s ease,
              border-color .35s ease, box-shadow .35s ease;
}
:root[data-theme="light"] .gf-plogo { box-shadow: 0 2px 10px -6px rgba(20,26,58,.3); }
/* most logo files ship on solid white. Inverting turns that box black, and
   screen then drops black entirely — so only the mark itself lands on the page. */
.gf-plogo img {
  max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain;
  filter: var(--g-logofix); opacity: var(--g-logo-op); mix-blend-mode: var(--g-logo-blend);
  transition: opacity .35s ease, filter .35s ease;
}
/* files that carry their own opaque plate can't be knocked out — no filter can
   tell a white background from white type. They're framed as a badge instead,
   which reads as deliberate. JS tags these by sampling the corners. */
/* colour is what keeps a plated logo legible — desaturating a dark plate just
   sinks it into the tile — so these keep their own colour, only dialled back */
.gf-plogo.plate img {
  max-width: 88%; max-height: 88%; border-radius: 10px;
  filter: saturate(.8) contrast(1.02); opacity: .78; mix-blend-mode: normal;
}
:root[data-theme="light"] .gf-plogo.plate img { opacity: .88; }
.gf-plogo:hover {
  transform: translateY(-5px);
  background: rgba(255,255,255,.07); border-color: rgba(211,29,83,.55);
  box-shadow: 0 20px 44px -20px rgba(211,29,83,.6);
}
:root[data-theme="light"] .gf-plogo:hover { background: #fff; box-shadow: 0 22px 40px -22px rgba(211,29,83,.5); }
.gf-plogo:hover img,
.gf-plogo.plate:hover img { opacity: 1; filter: none; mix-blend-mode: normal; }

/* ============================================================
   WHAT G-FORCE DOES — the G over a mosaic of the work
   ============================================================ */
.gf-force { position: relative; padding: clamp(3rem, 7vw, 6rem) 0; overflow: hidden; }
.gf-force-wrap {
  position: relative; width: min(1180px, 94vw); margin: 0 auto;
  min-height: clamp(340px, 40vw, 560px); display: grid; place-items: center;
}
/* The page colour is pooled under the lockup so the gradient G always has
   something to sit on rather than fighting the frames behind it.
   Sits between the strip (z1) and the lockup (z3). */
.gf-force-wrap::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  grid-area: 1 / 1;
  background: radial-gradient(27% 34% at 50% 50%,
    rgba(14,17,36,.88) 34%, rgba(14,17,36,.46) 62%, transparent 80%);
}
:root[data-theme="light"] .gf-force-wrap::before {
  background: radial-gradient(27% 34% at 50% 50%,
    rgba(245,246,252,.86) 34%, rgba(245,246,252,.44) 62%, transparent 80%);
}
/* The G rides on top of the mosaic, smaller than the strip so the work reads.
   The supplied file is a flat white cut-out, so it is used as a MASK over the
   brand gradient rather than painted: the whole lockup is gradient, the FORCE
   lettering stays knocked out, and it needs no per-theme recolouring.
   The shadow lives on the wrapper — filter runs before masking, so a
   drop-shadow on the masked element itself would trace its box, not the G. */
.gf-force-wrap > .lockup-wrap {
  position: relative; z-index: 3; display: block; pointer-events: none;
  width: min(560px, var(--gf-force-size, 46%));
  filter: drop-shadow(0 18px 44px rgba(0,0,0,.5));
  transition: opacity .4s ease;
}
:root[data-theme="light"] .gf-force-wrap > .lockup-wrap {
  filter: drop-shadow(0 18px 44px rgba(20,26,58,.2));
}
/* the path is written here, not passed in a custom property: a url() inside a
   custom property resolves against the stylesheet that substitutes it, so an
   inline --var pointing at "assets/…" became "assets/css/assets/…" */
/* An outline for the lockup. A mask can't take -webkit-text-stroke, so the
   halo is the same mask again, scaled up a touch and filled flat, sitting
   behind the gradient one — the difference between the two reads as a stroke.
   Set to 0 in the panel to switch it off. */
.gf-force-wrap .lockup-wrap::before {
  content: ""; position: absolute; inset: 0;
  background: var(--gf-force-stroke-col, #fff);
  -webkit-mask: url(../img/design/gforce.png) center / contain no-repeat;
          mask: url(../img/design/gforce.png) center / contain no-repeat;
  transform: scale(calc(1 + var(--gf-force-stroke, 0) / 100));
  opacity: var(--gf-force-stroke-on, 0);
}
:root[data-theme="light"] .gf-force-wrap .lockup-wrap::before { --gf-force-stroke-col: var(--g-space); }
.gf-force-wrap .lockup {
  position: relative;                    /* over the halo */
  display: block; width: 100%; aspect-ratio: 1245 / 1299;
  background: var(--g-grad);
  -webkit-mask: url(../img/design/gforce.png) center / contain no-repeat;
          mask: url(../img/design/gforce.png) center / contain no-repeat;
}
/* ---------- the mosaic ----------
   Two rows travelling in opposite directions. Panels come in three shapes and
   each one sits at its own vertical offset, so the strip stacks unevenly the
   way a contact sheet does rather than marching in a straight line. */
/* direction:ltr on purpose. Under RTL a max-content flex row is anchored to the
   right and overflows LEFT, so translating it left walked the whole strip out
   of the clip — the mosaic simply never appeared in Arabic. The panels carry no
   reading order, so pinning the marquee to one direction is the honest fix. */
.gf-reel {
  position: absolute; inset: 0; z-index: 1; direction: ltr;
  display: flex; flex-direction: column;
  justify-content: center; gap: clamp(.5rem, 1vw, .9rem); overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.gf-reel-row { display: flex; align-items: center; gap: clamp(.5rem, 1vw, .9rem); width: max-content; }
.gf-reel-row[data-dir="1"]  { animation: gfReelL 26s linear infinite; }
.gf-reel-row[data-dir="-1"] { animation: gfReelR 34s linear infinite; }
@keyframes gfReelL { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes gfReelR { from { transform: translateX(-50%); } to { transform: translateX(0); } }
.gf-reel:hover .gf-reel-row { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .gf-reel-row { animation: none; } }

/* Every panel is exactly one row tall whatever its shape, and nothing is
   offset vertically — so the two rows stack into a clean rectangle and only
   the widths vary. */
.gf-panel {
  position: relative; flex: none; display: block; overflow: hidden;
  height: clamp(112px, 13.5vw, 186px);
  border-radius: clamp(14px, 1.6vw, 22px); background: var(--g-panel);
  transition: transform .45s cubic-bezier(.2,.8,.3,1), box-shadow .45s ease;
}
.gf-panel.sq   { aspect-ratio: 1 / 1; }
.gf-panel.wide { aspect-ratio: 16 / 9; }
.gf-panel.tall { aspect-ratio: 9 / 16; }
/* `color` blending keeps each frame's own luminosity, and most of this work is
   dark, so the strip needs lifting or it reads as empty blue rectangles.
   Cleared on hover along with the wash. */
.gf-panel img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: brightness(1.12) contrast(.96);
  transition: filter .4s ease;
}
.gf-panel:hover img { filter: none; }
/* Blue, not brand-gradient: the lockup on top is the gradient, and two
   gradients stacked read as one mush. The cold wash pushes the work back and
   lets the G sit forward. Sampled off the horizon plate. */
.gf-panel .tint {
  position: absolute; inset: 0; background: var(--g-tint);
  /* `color`, not `hard-light`: it takes the hue and leaves the luminosity
     alone, so the frames turn blue but stay readable as work. hard-light
     flattened them into solid rectangles. */
  mix-blend-mode: color; opacity: .88;
  transition: opacity .4s ease;
}
/* hovering one panel clears its wash — that frame alone shows true colour */
.gf-panel:hover { transform: scale(1.045); z-index: 3;
  box-shadow: 0 26px 50px -22px rgba(0,0,0,.75); }
.gf-panel:hover .tint { opacity: 0; }
/* and the G steps back so it never covers the frame being looked at */
.gf-force-wrap:has(.gf-panel:hover) > .lockup-wrap { opacity: .22; }

/* ============================================================
   PRODUCTION — play button leans toward the cursor
   ============================================================ */
.gf-prod { padding: clamp(3rem, 7vw, 6rem) 0; }
/* The films are packed into justified rows exactly like the project tiles, so a
   mix of landscape and portrait still fills each row edge to edge and the
   block stays a rectangle. flex-grow IS the aspect ratio — see .gf-tile. */
.gf-vids { display: flex; flex-direction: column; gap: clamp(.9rem, 1.6vw, 1.3rem); }
.gf-screen {
  position: relative; border-radius: 26px; padding: 0;
  background: var(--g-panel); border: 1px solid var(--g-line);
  overflow: hidden; display: grid; place-items: center; cursor: pointer;
  flex: var(--ar, 1.78) 1 0; aspect-ratio: var(--ar, 1.78);
  transition: transform .5s cubic-bezier(.2,.8,.3,1), border-color .4s ease;
}
.gf-screen:hover { transform: translateY(-5px); border-color: rgba(211,29,83,.55); }
.gf-screen > img.poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .38; }
:root[data-theme="light"] .gf-screen > img.poster { opacity: .62; }
/* the film's name, only once there is room for it */
.gf-vcap {
  position: absolute; inset-inline: 0; bottom: 0; padding: 1.1rem 1.3rem;
  background: linear-gradient(transparent, rgba(6,8,26,.9));
  color: #fff; font-weight: 700; font-size: clamp(.82rem, 1.4vw, 1rem); text-align: start;
}
/* drawn, not pasted — the supplied button carries its own black plate */
.gf-play {
  position: relative; width: clamp(84px, 9vw, 118px); aspect-ratio: 1;
  display: grid; place-items: center; border-radius: 50%;
  will-change: transform; transition: transform .18s cubic-bezier(.2,.8,.3,1);
}
.gf-play::before {                       /* gradient ring */
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  padding: 3px; background: var(--g-grad);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
.gf-play::after {                        /* bloom */
  content: ""; position: absolute; inset: -26%; border-radius: 50%; z-index: -1;
  background: radial-gradient(circle, rgba(211,29,83,.5), rgba(70,45,147,.25) 48%, transparent 72%);
  filter: blur(16px);
}
/* PHYSICAL properties on purpose: the page is dir="rtl", and the logical
   equivalents flip the triangle so it points backwards and lands off-centre.
   A triangle's visual mass sits left of its bounding box, so it is nudged
   right by an eighth of its width to read as centred. */
.gf-play b {
  width: 0; height: 0; font-size: clamp(15px, 1.7vw, 22px);
  border-top: .62em solid transparent;
  border-bottom: .62em solid transparent;
  border-left: 1em solid #fff;
  border-right: 0;
  transform: translateX(.13em);
}
.gf-screen:hover .gf-play { transform: scale(1.07); }

/* ============================================================
   PROJECTS — a shaped grid: square, 16:9 and 9:16 tiles
   ============================================================ */
.gf-projects { padding: clamp(3rem, 7vw, 6rem) 0; }
/* ---------- justified rows ----------
   A grid can't hold mixed aspect ratios without leaving holes: a 9:16 tile next
   to a 16:9 one either stretches or gaps. So the tiles are packed into rows the
   way a photo gallery justifies them — each tile's flex-grow IS its aspect
   ratio, so widths come out proportional to aspect and every tile in the row
   lands on exactly the same height. The block is always a clean rectangle,
   and every tile keeps its true shape. */
.gf-grid { display: flex; flex-direction: column; gap: clamp(.9rem, 1.6vw, 1.3rem); }
.gf-prow { display: flex; gap: clamp(.9rem, 1.6vw, 1.3rem); }
.gf-tile {
  position: relative; border-radius: 22px; overflow: hidden; display: block;
  background: var(--g-panel); border: 1px solid var(--g-line);
  text-decoration: none; color: inherit;
  /* grow by aspect, start from zero width — that is what makes the heights match */
  flex: var(--ar, 1) 1 0; aspect-ratio: var(--ar, 1);
  transition: transform .5s cubic-bezier(.2,.8,.3,1), border-color .4s ease;
}
.gf-tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .5;
  transition: transform .8s cubic-bezier(.2,.8,.3,1), opacity .5s ease; }
:root[data-theme="light"] .gf-tile img { opacity: .78; }
.gf-tile:hover { transform: translateY(-6px); border-color: rgba(211,29,83,.6); }
.gf-tile:hover img { transform: scale(1.07); opacity: .92; }
.gf-tile .cap { position: absolute; inset-inline: 0; bottom: 0; padding: 1.3rem 1.4rem;
  background: linear-gradient(transparent, rgba(6,8,26,.94)); opacity: 0; transform: translateY(14px);
  transition: opacity .45s ease, transform .45s ease; }
.gf-tile:hover .cap { opacity: 1; transform: none; }
.gf-tile .cap b { display: block; color: #fff; font-size: 1.02rem; }
.gf-tile .cap span { color: rgba(255,255,255,.6); font-size: .8rem; }
/* rows are packed to a narrower target on small screens — see gfPackRows() */

/* ============================================================
   CUSTOM BLOCKS — sections the admin adds from the panel
   ============================================================ */
.gf-block { padding: clamp(2.5rem, 6vw, 5rem) 0; }
.gf-block-in {
  display: grid; gap: clamp(1.4rem, 3.5vw, 3rem); align-items: center;
  grid-template-columns: 1fr 1fr;
}
.gf-block.text .gf-block-in,
.gf-block.image .gf-block-in { grid-template-columns: 1fr; justify-items: center; text-align: center; }
.gf-block.flip .gf-block-in { direction: ltr; }
.gf-block.flip .gf-block-in > * { direction: rtl; }
html[lang="en"] .gf-block.flip .gf-block-in > * { direction: ltr; }
.gf-block h3 {
  margin: 0 0 .7rem; color: var(--title); font-size: clamp(1.4rem, 3vw, 2.2rem); line-height: 1.25;
}
.gf-block p { margin: 0; color: var(--muted); font-size: clamp(.94rem, 1.5vw, 1.06rem); line-height: 1.85; white-space: pre-line; }
.gf-block .gf-block-art { width: 100%; border-radius: 22px; overflow: hidden; border: 1px solid var(--g-line); }
.gf-block.image .gf-block-art { max-width: 820px; }
.gf-block .gf-block-art img { display: block; width: 100%; height: auto; }
.gf-block .gf-block-cta { display: inline-flex; margin-top: 1.3rem; }
@media (max-width: 780px) { .gf-block-in { grid-template-columns: 1fr; } }

/* ============================================================
   HOW WE CAN HELP — the campaign builder, one slide
   ============================================================ */
.gf-help { padding: clamp(3rem, 7vw, 6rem) 0; }
.gf-help-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(.9rem, 1.8vw, 1.4rem); }
@media (max-width: 860px) { .gf-help-grid { grid-template-columns: 1fr; } }
.gf-col {
  background: var(--g-panel); border: 1px solid var(--g-line); border-radius: 20px;
  padding: clamp(1.1rem, 2.2vw, 1.6rem);
}
.gf-col h4 {
  margin: 0 0 .2rem; color: var(--title); font-size: 1rem; display: flex; align-items: center; gap: .5rem;
}
.gf-col h4 i {
  font-style: normal; width: 26px; height: 26px; border-radius: 8px; flex: none;
  background: var(--g-grad); color: #fff; display: grid; place-items: center;
  font-size: .8rem; font-weight: 800; font-family: "Poppins", sans-serif;
}
.gf-col .hint { color: var(--muted); font-size: .82rem; margin: 0 0 .9rem; }
.gf-opts { display: flex; flex-wrap: wrap; gap: .5rem; }
.gf-opt {
  border: 1px solid var(--g-line); background: var(--g-tile); color: var(--ink);
  border-radius: 999px; padding: .5rem .95rem; font: inherit; font-size: .86rem; cursor: pointer;
  transition: border-color .25s ease, background .25s ease, transform .25s ease;
}
.gf-opt:hover { transform: translateY(-2px); border-color: rgba(211,29,83,.4); }
.gf-opt.on { background: var(--g-grad); border-color: transparent; color: #fff; font-weight: 700; }
.gf-range { width: 100%; accent-color: var(--g-pink); }
.gf-budget { font-family: "Poppins", sans-serif; font-weight: 800; color: var(--title); font-size: 1.5rem; }
.gf-out {
  margin-top: clamp(1rem, 2vw, 1.5rem); background: var(--g-panel);
  border: 1px solid var(--g-line); border-radius: 20px; padding: clamp(1.1rem, 2.4vw, 1.7rem);
  display: grid; grid-template-columns: 1.3fr 1fr; gap: 1.4rem; align-items: center;
}
@media (max-width: 860px) { .gf-out { grid-template-columns: 1fr; } }
.gf-mix { display: flex; flex-direction: column; gap: .6rem; }
.gf-mixrow { display: grid; grid-template-columns: 108px 1fr auto; gap: .6rem; align-items: center; font-size: .86rem; }
.gf-mixrow .bar { height: 9px; border-radius: 99px; background: var(--g-line); overflow: hidden; }
.gf-mixrow .bar i { display: block; height: 100%; width: 0; background: var(--g-grad); border-radius: 99px;
  transition: width .9s cubic-bezier(.2,.8,.3,1); }
.gf-mixrow .v { font-family: "Poppins", sans-serif; font-weight: 700; color: var(--title); min-width: 2.4rem; text-align: end; }
.gf-cta-wrap { text-align: center; }
.gf-started {
  font-size: clamp(1rem, 1.9vw, 1.25rem); font-weight: 800; padding: .85em 2.2em;
  border: 0; border-radius: 999px; cursor: pointer;
  transition: transform .25s ease, filter .25s ease, box-shadow .25s ease;
  box-shadow: 0 18px 40px -20px rgba(211,29,83,.85);
}
.gf-started:hover { transform: translateY(-3px) scale(1.03); filter: brightness(1.08); }
.gf-note { color: var(--muted); font-size: .78rem; margin-top: .6rem; }

/* ============================================================
   CONTACT — the ampersand lockup
   ============================================================ */
.gf-contact { padding: clamp(3.5rem, 8vw, 6rem) 0 clamp(2.5rem, 5vw, 4rem); }
/* "Contact us  &  be the G" — the & is the supplied gradient artwork, the two
   lines are live text so the whole lockup translates and re-themes. */
.gf-clock {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: clamp(.6rem, 2vw, 1.6rem); text-align: center;
}
.gf-clock span {
  font-family: "Poppins", sans-serif; font-weight: 800; color: var(--title);
  font-size: clamp(1.6rem, 5.2vw, 3.6rem); line-height: 1; letter-spacing: -.01em;
}
html[lang="ar"] .gf-clock span { font-family: var(--font-ar); }
.gf-clock img.amp {
  width: clamp(56px, 9vw, 128px); height: auto; display: block;
  animation: gfAmp 6s ease-in-out infinite;
}
@keyframes gfAmp {
  0%, 100% { transform: translateY(0) rotate(0); }
  50%      { transform: translateY(-9px) rotate(-3deg); }
}
@media (prefers-reduced-motion: reduce) { .gf-clock img.amp { animation: none; } }
.gf-cactions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.8rem; justify-content: center; }

/* ---------- inherited sections, retuned to the palette ---------- */
.section-title, .hh-title, h2, h3 { color: var(--title); }
.service-card, .card, .stat, .ev-card, .sim-card, .pulse-card, .client-tile, .wall-logo {
  background: var(--g-panel) !important; border: 1px solid var(--g-line) !important; color: var(--ink);
}
.service-card p, .section-sub, .about-text p, .muted { color: var(--muted); }
.site-header { background: rgba(11,16,41,.84); backdrop-filter: blur(14px); border-bottom: 1px solid var(--g-line); }
.main-nav a { color: var(--ink); } .main-nav a:hover { color: var(--title); }
/* The nav is only a panel on narrow screens, where style.css gives it a light
   card that opened white over the dark page. Scoped to that breakpoint —
   applying it unconditionally painted a white slab behind the desktop links. */
@media (max-width: 860px) {
  .main-nav {
    background: rgba(17,23,53,.98) !important; border: 1px solid var(--g-line);
    backdrop-filter: blur(16px);
  }
  :root[data-theme="light"] .main-nav { background: rgba(255,255,255,.98) !important; }
}
.btn-ghost { color: var(--title); border-color: var(--g-line); }
.btn-ghost:hover { background: var(--g-tile); }
.site-footer { background: #080c20; border-top: 1px solid var(--g-line); }

:root[data-theme="light"] .site-header { background: rgba(255,255,255,.88); }
/* the footer is a dark block by design — its logo is knocked to white and every
   line inside is white-on-navy. Lightening the panel left it white on white. */
:root[data-theme="light"] .site-footer { background: #141a3a; border-top: 0; }
:root[data-theme="light"] .gf-tile .cap { background: linear-gradient(transparent, rgba(10,14,40,.9)); }

/* the footer prints the tagline twice in English — once translated, once as the
   fixed Latin lockup that sits beside the Arabic */
html[lang="en"] .footer-brand .en-tag { display: none; }

/* the panel can drop the G lockup back to a flat fill */
.gf-force-wrap .lockup.flat { background: #fff; }
:root[data-theme="light"] .gf-force-wrap .lockup.flat { background: var(--title); }
