/* ==========================================================================
   GulfFrame — core stylesheet
   Shared by index.html (en, ltr) and ar/index.html (ar, rtl).
   Logical properties throughout, so one sheet serves both directions.

   Layout policy:
     · nothing is positioned outside its container — no negative insets
     · one 8px spacing scale, used everywhere
     · a decisive type hierarchy: one large thing per view, the rest small

   Motion policy (ui-ux-pro-max §7):
     · transform / opacity only — never width, height, top or left
     · ease-out entering, 150-300ms for micro-interactions
     · 40ms stagger between siblings
     · every ambient loop is off under prefers-reduced-motion
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Dark, premium. Surfaces are solid rather than translucent so the live
     previews, the grain layer and the glows never bleed through a card.
     Every pair below was checked against the dark background, not inferred
     from the old light theme — 4.5:1 for text, 3:1 for the quiet labels. */
  --bg:          #06070A;
  --bg-2:        #0B0D12;
  --surface:     #0F1117;
  --surface-2:   #14161E;

  --line:        rgba(255, 255, 255, 0.08);
  --line-strong: rgba(255, 255, 255, 0.17);

  --ink:     #F1F3F7;
  --text:    #E7E9EF;
  --muted:   #9AA1B1;                       /* 7.1:1 on --surface */
  --muted-2: #7A8191;                       /* 4.8:1 on --surface */

  --accent:       #2FE3B0;                  /* mint — the CTA, the one action */
  --accent-hover: #5CF0C7;
  --accent-ink:   #04140F;                  /* text that sits on the accent */
  --accent-wash:  rgba(47, 227, 176, 0.10);
  --accent-line:  rgba(47, 227, 176, 0.30);

  /* Cyan is the cold half of the pair: it never carries an action, only light
     — rays, rules, the constellation, the far edge of a gradient. Keeping it
     out of the buttons is what stops the palette reading as neon. */
  --cyan:      #22D3EE;
  --cyan-wash: rgba(34, 211, 238, 0.10);
  --cyan-line: rgba(34, 211, 238, 0.26);

  /* One hue per service — lifted and desaturated for the dark surface rather
     than inverted from the light set. */
  --c-green:  #2FE3B0;
  --c-indigo: #8E8DFA;
  --c-coral:  #FF8E70;
  --c-plum:   #E58FD4;
  --c-ocean:  #5CC8F0;
  --c-bronze: #E8B96F;

  --sand:      #E8C48A;
  --sand-wash: rgba(232, 196, 138, 0.10);
  --sand-hi:   #FBEBC8;                     /* the lit edge of the gold sweep */
  --sand-glow: rgba(232, 196, 138, 0.30);

  /* ---- Spacing: a single 8px scale. Nothing off-grid. ------------------- */
  --s-1: 0.25rem;   /*  4 */
  --s-2: 0.5rem;    /*  8 */
  --s-3: 0.75rem;   /* 12 */
  --s-4: 1rem;      /* 16 */
  --s-5: 1.5rem;    /* 24 */
  --s-6: 2rem;      /* 32 */
  --s-7: 3rem;      /* 48 */
  --s-8: 4rem;      /* 64 */

  /* On a near-black background a shadow reads as depth only if it is nearly
     opaque; the hairline border is what actually separates a card. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 3px 10px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.45), 0 12px 32px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5), 0 28px 64px rgba(0, 0, 0, 0.45);
  --glow:      0 0 0 1px var(--accent-line), 0 0 48px rgba(47, 227, 176, 0.11);

  --font-display: "Instrument Serif", "Times New Roman", Georgia, serif;
  --font-sans:    "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  /* The HUD voice: every small uppercase label on the page. System stack, so
     it costs nothing to load. */
  --font-mono:    ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --maxw:      1280px;
  --measure:   58ch;                          /* comfortable reading width */
  --gutter:    clamp(1.25rem, 4vw, 2.5rem);
  --section-y: clamp(4.5rem, 9vw, 8rem);

  --radius:    18px;
  --radius-sm: 12px;
  --radius-lg: 24px;

  --t-micro: 200ms;
  --t-ui:    320ms;
  --t-enter: 640ms;
  --ease:     cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --spring:   cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* The Arabic page mirrors the English pairing rather than flattening it: a
   high-contrast display face for headlines, a clean sans for everything else.
   Amiri is the Naskh counterpart to Instrument Serif — without it every Arabic
   headline fell back to the UI sans, which is why the Arabic side read as the
   plainer of the two even though the markup was identical.

   Amiri is never used for emphasis by slanting it: Arabic has no italic, so
   .h2 em and .display em are set upright further down and carry their emphasis
   in the accent colour alone. */
html[lang="ar"] {
  --font-display: "Amiri", "IBM Plex Sans Arabic", ui-serif, Georgia, serif;
  --font-sans:    "IBM Plex Sans Arabic", ui-sans-serif, system-ui, sans-serif;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; min-width: 0; }   /* min-width:0 stops grid blowouts */

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

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: -0.011em;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, iframe, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
ul { list-style: none; }

a, button, [role="button"], input, select, textarea { touch-action: manipulation; }

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

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  /* Film grain. On black it has to add light, so it screens rather than
     multiplies — multiply would simply disappear. */
  opacity: 0.03;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
}

.skip-link {
  position: absolute;
  inset-inline-start: var(--s-4);
  top: -100px;
  z-index: 200;
  padding: var(--s-3) var(--s-4);
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: 8px;
  font-weight: 700;
  transition: top var(--t-micro);
}
.skip-link:focus { top: var(--s-4); }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); position: relative; }
.section--tight { padding-block: clamp(2.5rem, 5vw, 4rem); }
.section--edge { border-top: 1px solid var(--line); }

/* --------------------------------------------------------------------------
   4. Typography — one large thing per view, everything else quiet
   -------------------------------------------------------------------------- */
.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.032em;
  font-size: clamp(2.15rem, 4.5vw, 3.9rem);
}
/* Retuned for Amiri. The old values were set against IBM Plex Sans Arabic,
   which is optically large — Amiri is the opposite, so the Arabic headline had
   to come back up to hold the same weight on the page as the English one.
   Weight stays at 400 to match: Amiri ships 400 and 700 only, and 600 would be
   synthesised into a smeared fake bold. The extra leading is for the dots and
   diacritics a Naskh face carries above and below the baseline. */
html[lang="ar"] .display {
  font-weight: 400;
  line-height: 1.36;
  letter-spacing: 0;
  font-size: clamp(2rem, 4.2vw, 3.6rem);
}
.display em { font-style: italic; color: var(--accent); text-shadow: 0 0 44px rgba(47, 227, 176, 0.20); }
html[lang="ar"] .display em { font-style: normal; }

.h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.7vw, 2.15rem);
  line-height: 1.14;
  letter-spacing: -0.018em;
}
html[lang="ar"] .h2 { font-weight: 400; line-height: 1.5; letter-spacing: 0; font-size: clamp(1.45rem, 2.6vw, 2.1rem); }
.h2 em { font-style: italic; color: var(--accent); text-shadow: 0 0 40px rgba(47, 227, 176, 0.18); }
html[lang="ar"] .h2 em { font-style: normal; }

.h3 { font-size: 1.02rem; font-weight: 700; line-height: 1.35; letter-spacing: -0.012em; }

.lede {
  font-size: 1.06rem;
  color: var(--muted);
  line-height: 1.72;
  max-width: var(--measure);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--s-4);
}
html[lang="ar"] .eyebrow { font-family: var(--font-sans); letter-spacing: 0; font-size: 0.78rem; font-weight: 700; }
.eyebrow::before {
  content: "";
  width: 22px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent));
}

.section-head { max-width: 46ch; margin-bottom: var(--s-8); }
.section-head .lede { margin-top: var(--s-4); }

/* --------------------------------------------------------------------------
   5. Ambient motion utilities
   -------------------------------------------------------------------------- */
.float {
  animation: float var(--float-d, 8s) ease-in-out infinite;
  animation-delay: var(--float-delay, 0s);
}
@keyframes float {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, var(--float-y, -8px), 0); }
}

/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--accent);
  --btn-fg: var(--accent-ink);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 46px;
  padding: 0.75rem 1.4rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid transparent;
  border-radius: 100px;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform var(--t-ui) var(--spring), background var(--t-micro),
              border-color var(--t-micro), color var(--t-micro), box-shadow var(--t-ui);
}
.btn:hover { transform: translateY(-2px); background: var(--accent-hover); box-shadow: var(--shadow-md); }
.btn:active { transform: scale(0.97); transition-duration: 90ms; }

.btn svg { width: 16px; height: 16px; flex: none; }
.btn .arrow { transition: transform var(--t-ui) var(--ease); }
.btn:hover .arrow { transform: translateX(3px); }
[dir="rtl"] .btn .arrow { transform: scaleX(-1); }
[dir="rtl"] .btn:hover .arrow { transform: scaleX(-1) translateX(3px); }

.btn::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: -70%;
  width: 50%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.24), transparent);
  transform: skewX(-18deg);
  transition: transform 620ms var(--ease);
  pointer-events: none;
}
.btn:hover::before { transform: translateX(360%) skewX(-18deg); }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--ink); border-color: var(--line-strong); box-shadow: none; }
.btn--ghost:hover { background: var(--surface); border-color: var(--accent); color: var(--accent); box-shadow: var(--shadow-sm); }

.btn--wa { --btn-bg: #1FAF54; --btn-fg: #fff; }
.btn--wa:hover { --btn-bg: #199445; }

.btn--sm { min-height: 42px; padding: 0.55rem 1.05rem; font-size: 0.83rem; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }

.link { display: inline-flex; align-items: center; gap: var(--s-1); font-weight: 700; font-size: 0.9rem; color: var(--accent); position: relative; }
.link::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  bottom: -3px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-ui) var(--ease);
}
.link:hover::after { transform: scaleX(1); }

/* --------------------------------------------------------------------------
   7. Header
   -------------------------------------------------------------------------- */
.header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background var(--t-ui), border-color var(--t-ui);
}
.header.is-stuck {
  background: rgba(6, 7, 10, 0.72);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border-bottom-color: var(--line);
}

/* Scroll progress — the one piece of chrome that tells you where you are. */
.header__progress {
  position: absolute;
  inset-block-end: -1px;
  inset-inline-start: 0;
  height: 1.5px;
  width: 100%;
  background: linear-gradient(90deg, var(--accent), var(--sand));
  transform: scaleX(var(--progress, 0));
  transform-origin: left;
  opacity: 0;
  transition: opacity var(--t-ui);
  pointer-events: none;
}
.header.is-stuck .header__progress { opacity: 1; }

.header__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--s-5); height: 68px; }

.logo { display: inline-flex; align-items: center; gap: var(--s-2); font-weight: 800; font-size: 0.96rem; letter-spacing: -0.03em; flex: none; color: var(--ink); }
.logo__mark { width: 26px; height: 26px; flex: none; color: var(--accent); transition: transform 600ms var(--spring); }
.logo:hover .logo__mark { transform: rotate(90deg); }
.logo__mark .frame { stroke: var(--accent); }
.logo span { color: var(--muted-2); font-weight: 500; }

.nav { display: flex; align-items: center; gap: var(--s-6); }
.nav__link { position: relative; font-size: 0.86rem; font-weight: 600; color: var(--muted); transition: color var(--t-micro); }
.nav__link::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  bottom: -5px;
  width: 100%;
  height: 1.5px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-ui) var(--ease);
}
.nav__link:hover { color: var(--accent); }
.nav__link:hover::after { transform: scaleX(1); }

.header__actions { display: flex; align-items: center; gap: var(--s-2); }

.lang {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  min-height: 42px;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
  background: var(--surface);
  transition: color var(--t-micro), border-color var(--t-micro), transform var(--t-ui) var(--spring);
}
.lang:hover { color: var(--accent); border-color: var(--accent); transform: translateY(-2px); }
.lang:active { transform: scale(0.97); }
.lang svg { width: 13px; height: 13px; }

.burger {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  cursor: pointer;
}
.burger span { display: block; position: relative; width: 15px; height: 1.5px; background: var(--ink); transition: background var(--t-micro); }
.burger span::before, .burger span::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  width: 100%; height: 1.5px;
  background: var(--ink);
  transition: transform var(--t-ui) var(--ease);
}
.burger span::before { top: -5px; }
.burger span::after  { top: 5px; }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { transform: translateY(5px) rotate(45deg); }
.burger[aria-expanded="true"] span::after  { transform: translateY(-5px) rotate(-45deg); }

.mobile-nav {
  position: fixed;
  inset: 68px 0 0;
  z-index: 99;
  background: var(--bg);
  padding: var(--s-6) var(--gutter) var(--s-7);
  display: flex;
  flex-direction: column;
  transform: translateY(-10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-ui), transform var(--t-ui) var(--ease), visibility var(--t-ui);
  overflow-y: auto;
}
.mobile-nav.is-open { opacity: 1; visibility: visible; transform: none; }

.mobile-nav a.mobile-nav__link {
  font-family: var(--font-display);
  font-size: 1.6rem;
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--t-ui) var(--ease-out), transform var(--t-ui) var(--ease-out);
}
.mobile-nav.is-open a.mobile-nav__link { opacity: 1; transform: none; }
.mobile-nav.is-open a:nth-child(1) { transition-delay: 50ms; }
.mobile-nav.is-open a:nth-child(2) { transition-delay: 90ms; }
.mobile-nav.is-open a:nth-child(3) { transition-delay: 130ms; }
.mobile-nav.is-open a:nth-child(4) { transition-delay: 170ms; }
.mobile-nav.is-open a:nth-child(5) { transition-delay: 210ms; }
.mobile-nav.is-open a:nth-child(6) { transition-delay: 250ms; }
.mobile-nav.is-open a:nth-child(7) { transition-delay: 290ms; }
html[lang="ar"] .mobile-nav a.mobile-nav__link { font-size: 1.35rem; font-weight: 600; }
.mobile-nav .btn { margin-top: var(--s-5); }

body.is-locked { overflow: hidden; }

/* ==========================================================================
   8. HERO
   Composition is a triangle: small eyebrow, one dominant headline, then the
   CTA — with a single preview balancing it. Nothing bleeds past the wrap.
   ========================================================================== */
.hero {
  position: relative;
  padding-block: clamp(4.5rem, 7.5vw, 5.75rem) clamp(1.75rem, 3.5vw, 2.5rem);
  overflow: hidden;
}

/* Optional footage layer — see README. */
.hero__video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.14;
  filter: saturate(0.7);
  pointer-events: none;
}

/* Two soft fields only. Three was noise. */
.hero__aurora { position: absolute; inset: -15% -5%; z-index: 0; pointer-events: none; filter: blur(70px); opacity: 0.75; }
.hero__aurora i { position: absolute; display: block; border-radius: 50%; }
.hero__aurora i:nth-child(1) {
  width: 42vw; height: 42vw;
  inset-block-start: 0%; inset-inline-start: -6%;
  background: radial-gradient(circle, rgba(47, 227, 176, 0.22), transparent 68%);
  animation: drift-a 48s var(--ease) infinite alternate;
}
.hero__aurora i:nth-child(2) {
  width: 34vw; height: 34vw;
  inset-block-start: -6%; inset-inline-end: 2%;
  background: radial-gradient(circle, rgba(232, 196, 138, 0.20), transparent 68%);
  animation: drift-b 42s var(--ease) infinite alternate;
}
@keyframes drift-a { to { transform: translate3d(6%, 8%, 0) scale(1.12); } }
@keyframes drift-b { to { transform: translate3d(-8%, 10%, 0) scale(1.08); } }

.hero__grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(70% 60% at 50% 30%, #000 8%, transparent 72%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 30%, #000 8%, transparent 72%);
  opacity: 0.6;
}

/* Three motes, well inside the frame. */
.hero__motes { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.hero__motes i {
  position: absolute;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--sand);
  opacity: 0.45;
  animation: mote var(--d, 18s) ease-in-out infinite;
  animation-delay: var(--dl, 0s);
}
.hero__motes i:nth-child(1) { inset-block-start: 26%; inset-inline-start: 14%; --d: 17s; }
.hero__motes i:nth-child(2) { inset-block-start: 64%; inset-inline-start: 30%; --d: 21s; --dl: -6s; background: var(--accent); }
.hero__motes i:nth-child(3) { inset-block-start: 20%; inset-inline-end: 22%; --d: 24s; --dl: -11s; background: var(--c-ocean); }
@keyframes mote {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 0.45; }
  50%      { transform: translate3d(-10px, -46px, 0) scale(0.8); opacity: 0.2; }
}

/* Volumetric rays. A slow conic sweep, blurred to nothing and masked to a
   soft oval, so it reads as light in the room rather than as a graphic. */
.hero__rays {
  position: absolute;
  top: -34%;
  left: 50%;
  width: 130vw;
  aspect-ratio: 1;
  z-index: 0;
  transform: translateX(-50%);
  background: conic-gradient(from 200deg at 50% 50%,
      transparent 0deg,
      rgba(47, 227, 176, 0.11) 14deg,
      transparent 30deg,
      transparent 48deg,
      rgba(34, 211, 238, 0.09) 62deg,
      transparent 78deg,
      transparent 296deg,
      rgba(47, 227, 176, 0.07) 316deg,
      transparent 336deg);
  filter: blur(46px);
  mask-image: radial-gradient(58% 52% at 50% 42%, #000 10%, transparent 74%);
  -webkit-mask-image: radial-gradient(58% 52% at 50% 42%, #000 10%, transparent 74%);
  animation: rays 52s linear infinite;
  pointer-events: none;
}
@keyframes rays { to { transform: translateX(-50%) rotate(360deg); } }

.hero .wrap { position: relative; z-index: 1; }

.hero__inner { display: grid; gap: clamp(2rem, 4vw, 3rem); align-items: center; }
@media (min-width: 940px) { .hero__inner { grid-template-columns: 1fr 1fr; } }

.hero__copy { max-width: 34rem; }
.hero__title { margin-bottom: var(--s-5); }

/* Masked line reveal */
.rl { display: block; overflow: hidden; padding-block: 0.05em; }
.rl > span { display: block; transform: translateY(105%); transition: transform 0.9s var(--ease-out); }
.hero.is-ready .rl > span { transform: translateY(0); }
.hero.is-ready .rl:nth-child(2) > span { transition-delay: 0.08s; }
.hero.is-ready .rl:nth-child(3) > span { transition-delay: 0.16s; }
.hero.is-ready .rl:nth-child(4) > span { transition-delay: 0.24s; }

/* Rotating word — hidden sizer holds the box so the line never reflows. */
.rotator {
  position: relative;
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
  /* Gold, not mint. The rotating word is the one thing on the page that moves
     while you read it, so it should not wear the colour that everywhere else
     means "press this" — keeping mint for actions alone is what stops the
     accent going soft. Gold reads warmer and more expensive against the
     near-black, and at ~11:1 it is more legible here than the mint was. */
  color: var(--sand);
  font-style: italic;
  text-shadow: 0 0 46px var(--sand-glow);
}
html[lang="ar"] .rotator { font-style: normal; }
/* The hidden sizer holds the grid cell at the width of the longest word, so
   the line never reflows. The visible words are start-aligned inside it, which
   is what lets the underline below be the width of the word rather than the
   width of the box. */
.rotator__sizer { visibility: hidden; grid-area: 1 / 1; white-space: nowrap; }
.rotator__item {
  position: relative;
  grid-area: 1 / 1;
  justify-self: start;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(100%);
  transition: transform 0.7s var(--ease-out), opacity 0.45s ease;
}
.rotator__item.is-current { opacity: 1; transform: translateY(0); }
.rotator__item.is-leaving { opacity: 0; transform: translateY(-100%); }

/* Rides the current word, so it measures the word — and restarts with it. */
.rotator__item.is-current::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0.02em;
  height: 2px;
  border-radius: 2px;
  /* Opens from the middle and runs out to both ends at once, then closes back
     to the middle. Centre origin means it needs no direction-specific rule —
     it reads the same in English and in Arabic. */
  background: linear-gradient(90deg, var(--sand), var(--sand-hi), var(--sand));
  transform-origin: center;
  animation: sweep 3.2s var(--ease) infinite;
}
@keyframes sweep {
  0%, 8%    { transform: scaleX(0); }
  22%, 78%  { transform: scaleX(1); }
  95%, 100% { transform: scaleX(0); }
}

.hero__fade { opacity: 0; transform: translateY(14px); transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out); }
.hero.is-ready .hero__fade { opacity: 1; transform: none; }
.hero.is-ready .hero__fade--2 { transition-delay: 0.42s; }
.hero.is-ready .hero__fade--3 { transition-delay: 0.50s; }

.dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #1FAF54;
  flex: none;
  box-shadow: 0 0 0 0 rgba(31, 175, 84, 0.5);
  animation: pulse 2.4s infinite;
}
@keyframes pulse {
  70%  { box-shadow: 0 0 0 7px rgba(31, 175, 84, 0); }
  100% { box-shadow: 0 0 0 0  rgba(31, 175, 84, 0); }
}

/* --- Hero visual: ONE preview. No stacking, no negative offsets. --------- */
.hero__visual { position: relative; opacity: 0; transform: translateY(22px); transition: opacity 0.9s var(--ease-out) 0.28s, transform 0.9s var(--ease-out) 0.28s; }
.hero.is-ready .hero__visual { opacity: 1; transform: none; }

/* A single chip, tucked inside the frame's bounds. */
.chip {
  position: absolute;
  z-index: 4;
  inset-block-end: var(--s-4);
  inset-inline-end: var(--s-4);
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 0.4rem 0.75rem;
  background: rgba(11, 13, 18, 0.86);
  backdrop-filter: blur(10px);
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--ink);
  box-shadow: var(--shadow-md);
  white-space: nowrap;
  max-width: calc(100% - var(--s-6));
  overflow: hidden;
  text-overflow: ellipsis;
}
.chip svg { width: 13px; height: 13px; color: var(--accent); flex: none; }

/* --- Stat strip ---------------------------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 1px;
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.stat { background: var(--surface); padding: var(--s-4); transition: background var(--t-ui); }
.stat:hover { background: var(--surface-2); }
.stat__n {
  font-family: var(--font-display);
  font-size: 1.75rem;
  line-height: 1;
  color: var(--accent);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
html[lang="ar"] .stat__n { font-weight: 700; }
.stat__l { margin-top: var(--s-2); font-size: 0.78rem; color: var(--muted); line-height: 1.4; }

/* ==========================================================================
   8b. BRIEF DOCK
   A single dark console on the ivory — the one high-contrast object on the
   page, so the eye lands on it after the headline. Collapsed it is a status
   bar; expanded it is a composer that hands the brief to WhatsApp.

   The panel opens with grid-template-rows 0fr -> 1fr rather than an animated
   height: same visual result, no layout thrash, and it is the pattern the
   FAQ already uses.
   ========================================================================== */
.dock { position: relative; max-width: 34rem; margin-top: var(--s-3); }

.dock__shell {
  position: relative;
  display: flex;
  flex-direction: column-reverse;   /* bar stays put, composer grows above it */
  padding: var(--s-2);
  border-radius: 18px;
  background: linear-gradient(180deg, #1D1D25 0%, #101016 100%);
  border: 1px solid rgba(255, 255, 255, 0.09);
  color: #fff;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 18px 42px rgba(20, 20, 26, 0.26);
  transition: box-shadow var(--t-ui) var(--ease);
}
.dock.is-open .dock__shell {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 0 0 3px var(--accent-wash),
    0 22px 50px rgba(20, 20, 26, 0.3);
}

/* A light travels the top edge every few seconds. One detail, not five. */
.dock__shell::before {
  content: "";
  position: absolute;
  top: 0;
  left: -40%;
  width: 40%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--sand), transparent);
  opacity: 0.75;
  animation: dock-sweep 7s var(--ease) infinite;
  pointer-events: none;
}
@keyframes dock-sweep {
  0%, 55%  { transform: translateX(0); }
  100%     { transform: translateX(350%); }
}

.dock__bar { display: flex; align-items: center; gap: var(--s-3); }

.dock__avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.11);
}
.dock__avatar svg { width: 19px; height: 19px; color: #fff; }

.dock__id { flex: 1; min-width: 0; }
.dock__name { font-size: 0.85rem; font-weight: 700; line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.dock__status {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.56);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dock__status .dot { width: 5px; height: 5px; box-shadow: none; animation: none; }
.dock.is-working .dock__status .dot { background: var(--sand); }
.dock.is-listening .dock__status .dot { background: #E4574B; animation: pulse 1.4s infinite; }
.dock__status span[data-dock-status] { overflow: hidden; text-overflow: ellipsis; }
.dock__status.is-swap span[data-dock-status] { animation: dock-swap 260ms var(--ease-out); }
@keyframes dock-swap { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.dock__actions { display: flex; align-items: center; gap: var(--s-1); flex: none; }

.dock__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: 36px;
  padding-inline: 0.55rem;
  background: transparent;
  border: 0;
  border-radius: 10px;
  color: #fff;
  font-size: 0.79rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--t-micro), transform var(--t-ui) var(--spring);
}
.dock__btn:hover { background: rgba(255, 255, 255, 0.11); }
.dock__btn:active { transform: scale(0.95); }
.dock__btn svg { width: 15px; height: 15px; flex: none; }
.dock__btn kbd {
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.12);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.64rem;
  font-weight: 600;
}
.dock__btn--go { background: var(--accent); }
.dock__btn--go:hover { background: #12705F; }
.dock.is-listening .dock__btn--mic { background: #E4574B; }

/* Icon swaps with the mode, exactly as the source component does. */
.dock .i-send { display: none; }
.dock.is-open .i-send { display: block; }
.dock.is-open .i-chat { display: none; }

.dock__composer { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 380ms var(--ease); }
.dock.is-open .dock__composer { grid-template-rows: 1fr; }
.dock__composer > div { position: relative; overflow: hidden; }

.dock__input {
  width: 100%;
  height: 108px;
  padding: 0.55rem 0.6rem;
  padding-inline-end: 2.2rem;
  background: transparent;
  border: 0;
  outline: none;
  resize: none;
  color: #fff;
  font-size: 16px;                  /* 16px stops iOS zooming on focus */
  line-height: 1.55;
}
.dock__input::placeholder { color: rgba(255, 255, 255, 0.35); }

.dock__close {
  position: absolute;
  top: 0.35rem;
  inset-inline-end: 0.35rem;
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  background: transparent;
  border: 0;
  border-radius: 7px;
  color: rgba(255, 255, 255, 0.5);
  cursor: pointer;
  transition: background var(--t-micro), color var(--t-micro);
}
.dock__close:hover { background: rgba(255, 255, 255, 0.11); color: #fff; }
.dock__close svg { width: 13px; height: 13px; }

.dock :focus-visible { outline-color: var(--sand); outline-offset: 2px; }

.dock__hint { margin-top: var(--s-2); font-size: 0.72rem; color: var(--muted-2); }

/* Shortcut keys mean nothing without a keyboard, and the labels are the first
   thing to go when the bar runs out of room. */
@media (hover: none) { .dock__btn kbd { display: none; } }
@media (max-width: 420px) { .dock__btn__t { display: none; } }

/* --------------------------------------------------------------------------
   9. Language chips
   -------------------------------------------------------------------------- */
.langs { position: relative; z-index: 1; margin-top: var(--s-6); padding-top: var(--s-5); border-top: 1px solid var(--line); }
.langs__label { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--muted-2); margin-bottom: var(--s-3); }
html[lang="ar"] .langs__label { letter-spacing: 0; text-transform: none; font-size: 0.76rem; }

.langs__list { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.langs__list li {
  padding: 0.32rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--surface);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--t-enter) var(--ease-out), transform var(--t-enter) var(--ease-out),
              color var(--t-micro), border-color var(--t-micro);
}
.langs__list li:hover { color: var(--accent); border-color: var(--accent-line); }
/* Twenty chips, so the step is 26ms rather than 40 — the cascade still reads
   as a wave but finishes in half a second instead of dragging on. */
.langs.is-in li { opacity: 1; transform: none; }
.langs.is-in li:nth-child(1)  { transition-delay:   0ms; }
.langs.is-in li:nth-child(2)  { transition-delay:  26ms; }
.langs.is-in li:nth-child(3)  { transition-delay:  52ms; }
.langs.is-in li:nth-child(4)  { transition-delay:  78ms; }
.langs.is-in li:nth-child(5)  { transition-delay: 104ms; }
.langs.is-in li:nth-child(6)  { transition-delay: 130ms; }
.langs.is-in li:nth-child(7)  { transition-delay: 156ms; }
.langs.is-in li:nth-child(8)  { transition-delay: 182ms; }
.langs.is-in li:nth-child(9)  { transition-delay: 208ms; }
.langs.is-in li:nth-child(10) { transition-delay: 234ms; }
.langs.is-in li:nth-child(11) { transition-delay: 260ms; }
.langs.is-in li:nth-child(12) { transition-delay: 286ms; }
.langs.is-in li:nth-child(13) { transition-delay: 312ms; }
.langs.is-in li:nth-child(14) { transition-delay: 338ms; }
.langs.is-in li:nth-child(15) { transition-delay: 364ms; }
.langs.is-in li:nth-child(16) { transition-delay: 390ms; }
.langs.is-in li:nth-child(17) { transition-delay: 416ms; }
.langs.is-in li:nth-child(18) { transition-delay: 442ms; }
.langs.is-in li:nth-child(19) { transition-delay: 468ms; }
.langs.is-in li:nth-child(20) { transition-delay: 494ms; }

/* A right-to-left name inside a left-to-right list keeps its own direction. */
.langs__list li[dir="rtl"] { unicode-bidi: isolate; }

/* ==========================================================================
   10. Browser frame — shared by the hero and the portfolio

   The live site renders at a 1600px desktop viewport and is scaled down to
   the card. JS measures the box with getBoundingClientRect (fractional) and
   adds a hair of overscan, so the render always reaches all four edges with
   no sub-pixel seam. See fitFrame() in main.js.
   ========================================================================== */
.browser {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}

.browser__bar {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: var(--s-1);
  height: 30px;
  padding-inline: var(--s-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.browser__bar i { width: 7px; height: 7px; border-radius: 50%; background: var(--line-strong); flex: none; }
.browser__url {
  margin-inline-start: var(--s-2);
  font-size: 0.62rem;
  color: var(--muted-2);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  direction: ltr;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.browser__mode {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-2);
  flex: none;
}
html[lang="ar"] .browser__mode { letter-spacing: 0; text-transform: none; font-size: 0.64rem; }
.browser__mode svg { width: 11px; height: 11px; }

.browser__viewport { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-2); }

.browser__viewport iframe {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  width: 1600px;
  height: 1000px;
  /* The global `iframe { max-width: 100% }` reset would clamp this to the
     card's width — around 450px — and the embedded site would then render
     its own mobile breakpoint. The frame must stay a true 1600px desktop
     viewport; scaling it down is the transform's job, not the box model's. */
  max-width: none;
  border: 0;
  transform-origin: top left;
  transform: scale(var(--fit-scale, 1)) translateY(var(--pan, 0px));
  transition: opacity 0.7s ease;
  pointer-events: none;
  opacity: 0;
}
[dir="rtl"] .browser__viewport iframe { transform-origin: top right; }

/* Once loaded the preview scrolls itself, so the whole page is seen without
   the visitor having to hover — and it works the same on a phone. */
.browser__viewport iframe.is-loaded { opacity: 1; }

.browser__skeleton {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--bg-2);
  font-family: var(--font-display);
  font-size: 2.2rem;
  color: var(--accent);
  opacity: 0.45;
  transition: opacity 0.5s;
  overflow: hidden;
}
.browser__skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 20%, rgba(255, 255, 255, 0.07) 50%, transparent 80%);
  animation: shimmer 1.9s linear infinite;
}
@keyframes shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.browser.is-ready .browser__skeleton { opacity: 0; }

/* --------------------------------------------------------------------------
   11. Marquee
   -------------------------------------------------------------------------- */
.marquee {
  border-block: 1px solid var(--line);
  padding-block: var(--s-3);
  overflow: hidden;
  background: var(--surface);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track { display: flex; gap: var(--s-7); width: max-content; animation: marquee 62s linear infinite; }
[dir="rtl"] .marquee__track { animation-direction: reverse; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }

.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-7);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted-2);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}
html[lang="ar"] .marquee__item { text-transform: none; letter-spacing: 0; }
.marquee__item::after { content: ""; width: 4px; height: 4px; border-radius: 50%; background: var(--sand); }

/* ---- The capability lens (#capabilities) ---------------------------------
   The same trick as the marquee above — a track holding three copies of its
   content, translated by exactly one third — but run twice, in two stacked
   layers. The base layer has a hole punched through it by a radial mask; the
   reveal layer is clipped to precisely that hole and scaled about the same
   point, so what appears inside the glass is a magnified copy of what was
   already there rather than a second, larger set of tags.

   Both layers read --lx / --ly, which js/main.js writes as the glass is
   dragged. Nothing else moves, so a drag costs two custom-property writes.

   Note the tags carry margin-inline-end rather than the track carrying gap:
   the loop shifts by a third of the track, so every copy has to be exactly a
   third of it. A gap on the track sits *between* the three copies, which
   makes each copy a third minus two-thirds of a gap — a four-pixel stutter
   once a loop. Margin belongs to the tag and divides cleanly. */
.lens {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
  gap: clamp(var(--s-5), 3.5vw, var(--s-7));
  align-items: center;
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.lens__stage {
  --lx: 0px;
  --ly: 0px;
  --glass: 116px;
  --lr: calc(var(--glass) * 0.325);   /* matches r="33" in the 100-unit viewBox */
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg-2);
  border: 1px solid var(--line);
}

/* No min-height, and the base layer sits in normal flow: the rows give the
   stage its height instead of being centred inside a taller box. That is what
   removes the dead band above and below them — the section is as tall as the
   words in it and no taller, at every width, however many rows you add. */
.lens__layer {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding-block: var(--s-4);
}
.lens__layer--base { position: relative; }
.lens__layer--mag  { position: absolute; inset: 0; }
.lens__track {
  display: flex;
  width: max-content;
  animation: lens-run var(--dur, 38s) linear infinite;
}
.lens__set { display: flex; }
.lens__row--reverse .lens__track { animation-direction: reverse; }
[dir="rtl"] .lens__track { animation-direction: reverse; }
[dir="rtl"] .lens__row--reverse .lens__track { animation-direction: normal; }

/* The rows never pause. Stopping them under the pointer would freeze the thing
   the visitor came to look at at exactly the moment they reach for the glass.

   --shift is one set's width in pixels, measured and written by js/main.js.
   It cannot be a percentage: how far the track must travel to land the next
   copy exactly where the last one started is one set, and a set is a different
   fraction of the track in each language — Arabic labels are shorter, so
   Arabic needs more copies to cover the stage and each one is a smaller slice
   of the whole. The percentage fallback is only for a track js never reached.

   --run is which way it travels, and it has to flip for RTL. The track is
   anchored to the row's inline start, so in LTR it begins at the left edge and
   overhangs to the right, and travelling left keeps content under the stage. In
   RTL it is anchored right and overhangs to the LEFT — travel left there and the
   track's trailing edge is dragged into frame, leaving a set-width of nothing
   behind it. Because a set is always at least as wide as the stage, that is not
   a small gap: the row starts completely empty and the visitor waits a whole
   loop for words to arrive. It only showed on the reversed rows, so the Arabic
   page opened with half its rows blank. */
.lens__track            { --run: -1; }
[dir="rtl"] .lens__track { --run:  1; }
@keyframes lens-run { to { transform: translateX(calc(var(--run) * var(--shift, 33.3333%))); } }

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  flex: none;
  margin-inline-end: var(--s-3);
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 600;
  white-space: nowrap;
}
.tag svg { width: 15px; height: 15px; flex: none; color: var(--muted-2); }

/* Only punch the hole once js has put a glass on the stage — without it there
   is nothing to look through, and a hole would just be a bite out of the row. */
.lens__stage.is-live > .lens__layer--base {
  -webkit-mask-image: radial-gradient(circle var(--lr) at calc(50% + var(--lx)) calc(50% + var(--ly)), transparent 99%, #000 100%);
          mask-image: radial-gradient(circle var(--lr) at calc(50% + var(--lx)) calc(50% + var(--ly)), transparent 99%, #000 100%);
}

/* Clip on the outer box, scale on the inner one. Doing both on a single
   element would scale the clip circle along with the content. */
.lens__clip {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  clip-path: circle(var(--lr) at calc(50% + var(--lx)) calc(50% + var(--ly)));
}
.lens__layer--mag {
  transform: scale(1.24);
  transform-origin: calc(50% + var(--lx)) calc(50% + var(--ly));
}
.lens__clip .tag {
  background: var(--surface-2);
  border-color: var(--accent-line);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.lens__clip .tag svg { color: var(--accent); }

.lens__glass {
  position: absolute;
  /* Physical left, not inset-inline-start: --lx is a physical offset, because
     the mask and clip-path that consume it are positioned physically too.
     One coordinate space for all three is what keeps RTL honest. */
  top: 50%;
  left: 50%;
  z-index: 4;
  width: var(--glass);
  height: var(--glass);
  padding: 0;
  border: 0;
  background: none;
  cursor: grab;
  touch-action: none;                 /* the glass is dragged; the page still scrolls around it */
  transform: translate(calc(-50% + var(--lx)), calc(-50% + var(--ly)));
  filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.55));
  transition: filter var(--t-ui) var(--ease);
}
.lens__glass svg { display: block; width: 100%; height: 100%; }
.lens__glass:active { cursor: grabbing; }
.lens__glass:hover, .lens__glass:focus-visible { filter: drop-shadow(0 0 18px rgba(47, 227, 176, 0.4)); }
.lens__glass:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 50%; }

.lens__fade {
  position: absolute;
  inset-block: 0;
  z-index: 3;
  width: 14%;
  pointer-events: none;
}
.lens__fade--start { inset-inline-start: 0; background: linear-gradient(90deg,  var(--bg-2), transparent); }
.lens__fade--end   { inset-inline-end: 0;   background: linear-gradient(270deg, var(--bg-2), transparent); }
[dir="rtl"] .lens__fade--start { background: linear-gradient(270deg, var(--bg-2), transparent); }
[dir="rtl"] .lens__fade--end   { background: linear-gradient(90deg,  var(--bg-2), transparent); }

.lens__caption { padding-inline: var(--s-3); padding-block: var(--s-4); }
.lens__caption p { color: var(--muted); margin-block: var(--s-3) var(--s-5); }

/* --------------------------------------------------------------------------
   12. Cards & grids
   -------------------------------------------------------------------------- */
/* Three across, and only three: at 1280px an auto-fit grid finds room for a
   fourth column and the cards get cramped. Two on a tablet, one on a phone. */
.grid { display: grid; gap: var(--s-5); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

@media (min-width: 640px) { .grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .grid--3 { grid-template-columns: repeat(3, 1fr); gap: var(--s-5); } }

.card {
  --card-accent: var(--accent);
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s-6);
  overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
  transition: border-color var(--t-ui), transform var(--t-ui) var(--ease), box-shadow var(--t-ui);
}
.card:hover {
  border-color: color-mix(in srgb, var(--card-accent) 28%, transparent);
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
}

/* Cursor bloom. main.js feeds --mx / --my on pointermove. */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 0%),
              color-mix(in srgb, var(--card-accent) 10%, transparent), transparent 70%);
  opacity: 0;
  transition: opacity var(--t-ui);
  pointer-events: none;
}
.card:hover::before { opacity: 1; }

.card::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  background: var(--card-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-enter) var(--ease);
}
.card:hover::after { transform: scaleX(1); }
.card > * { position: relative; z-index: 1; }

.card__icon {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 10px;
  background: color-mix(in srgb, var(--card-accent) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-accent) 22%, transparent);
  color: var(--card-accent);
  margin-bottom: var(--s-4);
  transition: transform var(--t-ui) var(--spring);
}
.card:hover .card__icon { transform: translateY(-2px) scale(1.05); }
.card__icon svg { width: 18px; height: 18px; }

.card p { color: var(--muted); font-size: 0.95rem; margin-top: var(--s-2); line-height: 1.6; }

.card__list { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--line); display: grid; gap: var(--s-2); }
.card__list li { display: flex; align-items: flex-start; gap: var(--s-3); font-size: 0.88rem; color: var(--muted); line-height: 1.5; }
.card__list li::before {
  content: "";
  flex: none;
  width: 4px; height: 4px;
  margin-top: 0.6em;
  border-radius: 50%;
  background: var(--card-accent);
}

/* The card's own call to action, into its service page. A real button —
   a text link at the bottom of a card does not read as somewhere to go. */
.card__cta {
  width: 100%;
  margin-top: var(--s-5);
  --btn-fg: var(--card-accent);
  border-color: color-mix(in srgb, var(--card-accent) 34%, transparent);
}
.card__cta:hover {
  background: color-mix(in srgb, var(--card-accent) 12%, transparent);
  border-color: var(--card-accent);
  color: var(--card-accent);
  box-shadow: var(--shadow-sm), 0 0 22px color-mix(in srgb, var(--card-accent) 22%, transparent);
}
.card__cta svg { width: 15px; height: 15px; }
[dir="rtl"] .card__cta svg { transform: scaleX(-1); }
.card { display: flex; flex-direction: column; }
.card__list { flex: 1; }

/* The services grid is a menu, not a brochure: six titles and a way in. The
   detail lives on the service page one click away, where somebody who has
   already chosen a service will actually read it — rather than six paragraphs
   competing on the homepage before anyone has decided anything.

   Centred because a card holding three short things has no left edge worth
   aligning to, and margin-top:auto on the button keeps every card's call to
   action on the same line however many lines its title runs to. */
#services .card { align-items: center; text-align: center; }
#services .card .h3 { margin-block-end: var(--s-5); }
#services .card__cta { margin-top: auto; }

.step__n {
  font-family: var(--font-display);
  font-size: 2rem;
  line-height: 1;
  color: var(--card-accent);
  opacity: 0.3;
  margin-bottom: var(--s-3);
  transition: opacity var(--t-ui);
}
.card:hover .step__n { opacity: 0.65; }
html[lang="ar"] .step__n { font-weight: 700; }

#process .card:nth-child(1) { --card-accent: var(--c-green); }
#process .card:nth-child(2) { --card-accent: var(--c-ocean); }
#process .card:nth-child(3) { --card-accent: var(--c-indigo); }
#process .card:nth-child(4) { --card-accent: var(--c-plum); }

/* ---- Deliverables (#deliverables) ----------------------------------------
   Six cards, one per service, each showing the thing the client actually ends
   up holding rather than a sentence about it. Every artefact below is drawn in
   CSS and inline SVG — no screenshots, no stock images — so they restyle with
   the brand, stay sharp at any zoom, and cost nothing to load.

   Each card takes its service's hue on --card-accent, the same variable the
   service cards and the service pages use, so a colour is a service across the
   whole site rather than a decoration chosen per component. */
.specs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: var(--s-5);
}

.spec {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--t-ui) var(--ease), transform var(--t-ui) var(--ease);
}
.spec:hover { border-color: var(--card-accent, var(--accent-line)); transform: translateY(-3px); }

.spec__art {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  padding: var(--s-5);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--card-accent, var(--accent)) 9%, transparent), transparent 70%),
    var(--bg-2);
  border-block-end: 1px solid var(--line);
}
/* The grid behind every artefact — the one motif all six share. */
.spec__art::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(70% 70% at 50% 50%, #000, transparent);
          mask-image: radial-gradient(70% 70% at 50% 50%, #000, transparent);
}
.spec__art > * { position: relative; width: 100%; }

.spec__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  flex: 1;
  padding: var(--s-5);
}
.spec__body h3 { display: flex; align-items: center; gap: var(--s-2); }
.spec__body h3::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 2px;
  background: var(--card-accent, var(--accent));
  flex: none;
}
.spec__body p { color: var(--muted); font-size: 0.94rem; }

/* The file list is the payload: what you can open, upload, or hand to someone
   who is not us. It is set in the HUD voice because it is data, not prose. */
.spec__files { list-style: none; display: flex; flex-wrap: wrap; gap: var(--s-2); margin-block-start: auto; }
.spec__files li {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 9px;
  white-space: nowrap;
}
html[lang="ar"] .spec__files li { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.72rem; }

/* ---- artefact 1: the brand suite ---------------------------------------- */
.art-brand { display: grid; gap: var(--s-3); }
.art-brand__marks { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2); }
.art-brand__mark {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--card-accent, var(--accent));
}
.art-brand__mark:nth-child(2) { background: var(--card-accent, var(--accent)); color: var(--accent-ink); }
.art-brand__mark svg { width: 46%; height: 46%; }
.art-brand__swatches { display: flex; gap: 5px; }
.art-brand__swatches span { flex: 1; height: 15px; border-radius: 4px; }
.art-brand__type {
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--ink);
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
}
.art-brand__type small { font-family: var(--font-mono); font-size: 0.56rem; color: var(--muted-2); letter-spacing: 0.08em; }

/* ---- artefact 2: the site ------------------------------------------------ */
.art-site { border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; background: var(--surface); }
.art-site__bar { display: flex; align-items: center; gap: 5px; padding: 7px 9px; background: var(--surface-2); border-block-end: 1px solid var(--line); }
.art-site__bar i { width: 6px; height: 6px; border-radius: 50%; background: var(--line-strong); }
.art-site__url { flex: 1; height: 11px; border-radius: 999px; background: var(--bg-2); margin-inline-start: 5px; }
.art-site__page { padding: var(--s-3); display: grid; gap: 7px; }
.art-site__hero { height: 40px; border-radius: 6px; background: linear-gradient(100deg, color-mix(in srgb, var(--card-accent, var(--accent)) 40%, transparent), transparent); }
.art-site__line { height: 6px; border-radius: 3px; background: var(--line-strong); }
.art-site__line--short { width: 55%; }
.art-site__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.art-site__cols span { height: 20px; border-radius: 4px; background: var(--bg-2); border: 1px solid var(--line); }

/* ---- artefact 3: the search result --------------------------------------- */
.art-serp { display: grid; gap: var(--s-3); }
.art-serp__rank {
  justify-self: start;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
  background: var(--card-accent, var(--accent));
  border-radius: 999px;
  padding: 3px 9px;
}
.art-serp__card { border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); padding: var(--s-3); display: grid; gap: 6px; }
.art-serp__url { font-family: var(--font-mono); font-size: 0.6rem; color: var(--card-accent, var(--accent)); }
.art-serp__title { color: var(--ink); font-size: 0.86rem; font-weight: 700; }
.art-serp__line { height: 5px; border-radius: 3px; background: var(--line-strong); }
.art-serp__line--short { width: 62%; }

/* ---- artefact 4: the month of posts -------------------------------------- */
/* Nine square tiles want a square box, but the art well is 16:10 — left to fill
   the width, the bottom row falls outside it and gets sliced. Drive this one off
   the height instead and let the width follow. */
.art-posts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  width: auto;
  height: 100%;
  aspect-ratio: 1;
  justify-self: center;
}
.art-posts span {
  aspect-ratio: 1;
  border-radius: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
}
.art-posts span:nth-child(2),
.art-posts span:nth-child(4),
.art-posts span:nth-child(9) {
  background: linear-gradient(140deg, color-mix(in srgb, var(--card-accent, var(--accent)) 55%, transparent), transparent);
  border-color: transparent;
}

/* ---- artefact 5: the cut ------------------------------------------------- */
.art-cut { display: grid; gap: var(--s-3); }
.art-cut__frame {
  position: relative;
  aspect-ratio: 16 / 7;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: linear-gradient(140deg, color-mix(in srgb, var(--card-accent, var(--accent)) 26%, transparent), var(--surface));
  display: grid;
  place-items: center;
}
.art-cut__play {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--card-accent, var(--accent));
  display: grid;
  place-items: center;
}
.art-cut__play svg { width: 12px; height: 12px; color: var(--accent-ink); }
.art-cut__timeline { display: flex; gap: 4px; align-items: center; }
.art-cut__timeline span { height: 12px; border-radius: 3px; background: var(--surface); border: 1px solid var(--line); }
.art-cut__timeline span:nth-child(1) { flex: 3; }
.art-cut__timeline span:nth-child(2) { flex: 5; background: color-mix(in srgb, var(--card-accent, var(--accent)) 35%, transparent); border-color: transparent; }
.art-cut__timeline span:nth-child(3) { flex: 2; }
.art-cut__timeline span:nth-child(4) { flex: 4; }

/* ---- artefact 6: the languages ------------------------------------------- */
.art-langs { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.art-langs span {
  font-size: 0.76rem;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 10px;
  line-height: 1.4;
}
.art-langs span:first-child { color: var(--accent-ink); background: var(--card-accent, var(--accent)); border-color: transparent; font-weight: 700; }

/* --------------------------------------------------------------------------
   13. Work / portfolio
   -------------------------------------------------------------------------- */
/* ==========================================================================
   THE DECK

   The portfolio swipes. Four slides on a scroll-snapping track: a finger on a
   phone, a drag or the arrows on a desktop, arrow keys from the keyboard. Each
   slide shows the top of the real site — the first screen a visitor would have
   judged it on — and nothing scrolls by itself.
   ========================================================================== */
.console {
  position: relative;
  margin-top: var(--s-6);
  padding: clamp(1rem, 2.5vw, 1.75rem);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(34, 211, 238, 0.05), transparent 55%),
    rgba(11, 13, 18, 0.55);
  overflow: hidden;
}
.console::before {
  content: ;
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 48px 48px;
  mask-image: radial-gradient(80% 70% at 50% 40%, #000, transparent 78%);
  -webkit-mask-image: radial-gradient(80% 70% at 50% 40%, #000, transparent 78%);
  opacity: 0.5;
  pointer-events: none;
}
.console > * { position: relative; z-index: 1; }

.console__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--line);
}

.console__label {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-2);
}
html[lang=ar] .console__label { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.76rem; }
.console__label b { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }

/* --- Controls ----------------------------------------------------------- */
.deck__nav { display: flex; align-items: center; gap: var(--s-2); }

.deck__hint {
  margin-inline-end: var(--s-2);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}
html[lang=ar] .deck__hint { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.72rem; }
@media (max-width: 620px) { .deck__hint { display: none; } }

.deck__arrow {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: border-color var(--t-micro), color var(--t-micro), transform var(--t-ui) var(--spring), opacity var(--t-micro);
}
.deck__arrow:hover { border-color: var(--accent); color: var(--accent); }
.deck__arrow:active { transform: scale(0.94); }
.deck__arrow[disabled] { opacity: 0.3; cursor: default; }
.deck__arrow[disabled]:hover { border-color: var(--line-strong); color: var(--ink); }
.deck__arrow svg { width: 16px; height: 16px; }
[dir=rtl] .deck__arrow svg { transform: scaleX(-1); }

/* --- The track ----------------------------------------------------------- */
.deck { position: relative; }

.deck__track {
  --slide: 86%;
  display: flex;
  gap: var(--s-4);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  padding-bottom: var(--s-2);
  cursor: grab;
}
.deck__track::-webkit-scrollbar { display: none; }
.deck__track.is-dragging { cursor: grabbing; scroll-behavior: auto; scroll-snap-type: none; }
.deck__track.is-dragging * { pointer-events: none; }
@media (min-width: 700px)  { .deck__track { --slide: 56%; } }
@media (min-width: 1100px) { .deck__track { --slide: 42%; } }
@media (prefers-reduced-motion: reduce) { .deck__track { scroll-behavior: auto; } }

/* Snapped to the start, not the centre. With a peek layout a centred snap
   can never bring the first or last slide to the middle, so the index would
   never settle on 01 or 04. The trailing spacer is what lets the last slide
   reach the start edge. */
.deck__track::after {
  content: "";
  flex: 0 0 calc(100% - var(--slide) - var(--s-4));
}

.slide {
  flex: 0 0 var(--slide);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
  opacity: 0.55;
  transition: opacity 450ms var(--ease), border-color 450ms var(--ease), box-shadow 450ms var(--ease);
}
.slide.is-current {
  opacity: 1;
  border-color: var(--accent-line);
  box-shadow: var(--shadow-lg), 0 0 34px rgba(47, 227, 176, 0.10);
}

.slide__frame { position: relative; }
.slide .browser { border: 0; border-radius: 0; border-bottom: 1px solid var(--line); box-shadow: none; }
.slide .browser__viewport { aspect-ratio: 16 / 11; }

.slide__n {
  position: absolute;
  inset-block-end: var(--s-3);
  inset-inline-end: var(--s-3);
  font-family: var(--font-mono);
  font-size: 1.5rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  opacity: 0.25;
  transition: opacity var(--t-ui), color var(--t-ui);
  pointer-events: none;
}
.slide.is-current .slide__n { color: var(--accent); opacity: 0.9; text-shadow: 0 0 18px rgba(47, 227, 176, 0.4); }

.slide__body { padding: var(--s-6); display: flex; flex-direction: column; gap: var(--s-3); flex: 1; }
.slide__body p { color: var(--muted); font-size: 0.93rem; line-height: 1.68; }
.slide__body .btn { margin-top: auto; align-self: flex-start; }

/* --- Dots ---------------------------------------------------------------- */
.deck__dots {
  display: flex;
  justify-content: center;
  gap: var(--s-2);
  margin-top: var(--s-5);
}
.deck__dot {
  width: 34px; height: 4px;
  padding: 0;
  border: 0;
  border-radius: 100px;
  background: var(--line-strong);
  cursor: pointer;
  transition: background var(--t-ui), width var(--t-ui) var(--ease);
}
.deck__dot:hover { background: var(--muted-2); }
.deck__dot.is-on { width: 52px; background: linear-gradient(90deg, var(--accent), var(--cyan)); }

/* The dot itself is 4px tall; the finger target around it is not. */
.deck__dot { position: relative; }
.deck__dot::after { content: ; position: absolute; inset: -20px -6px; }

/* ==========================================================================
   13b. ORBIT — the stack, circling

   Each logo sits on an arm anchored at the ring's centre and travels by a
   single transform:

       rotate(θ) translateY(-R) rotate(-θ)

   The two rotations cancel at every point of the interpolation, so the net
   effect is a pure translation around a circle — the tile is never actually
   rotated and its layer is never resampled. A rotating parent carrying a
   counter-rotating child disagrees with itself by a fraction of a pixel every
   frame, and that is what reads as shaking.

   main.js re-drives these through the Web Animations API with a whole-pixel
   radius; this stays as the no-JS fallback.

   Physical left / transform are deliberate here rather than logical
   properties: the composition is symmetrical, so it reads identically in both
   directions and the maths stays the same.
   ========================================================================== */
.orbit {
  /* Only the vw term and the ceiling grew. The floor is what governs a phone,
     where the outer ring plus a tile has to fit inside a ~335px column — raise
     that and the logos start getting sliced at the edge. Ratios are held at
     0.5 / 0.75 / 1 so the composition scales rather than distorts. */
  --r1: clamp(7.5rem, 25vw, 14rem);
  --r2: clamp(11rem, 37vw, 21rem);
  --r3: clamp(15rem, 50vw, 28rem);
  --tile: 46px;
  position: relative;
  width: 100%;
  height: calc(var(--r3) + var(--tile) + 4px);
  isolation: isolate;
}

.orbit__glow,
.orbit__ring,
.orbit__globe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.orbit__glow {
  width: var(--r2); height: var(--r2);
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-wash), transparent 62%);
  filter: blur(26px);
  pointer-events: none;
}

.orbit__globe {
  width: calc(var(--r1) * 0.62);
  aspect-ratio: 1;
  z-index: 2;
  pointer-events: none;
}
.orbit__globe canvas { width: 100%; height: 100%; }

.orbit__ring { border: 1px solid var(--line); border-radius: 50%; }
.orbit__ring--1 { width: var(--r1); height: var(--r1); border-color: var(--accent-line); --ring: var(--r1); }
.orbit__ring--2 { width: var(--r2); height: var(--r2); --ring: var(--r2); }
.orbit__ring--3 { width: var(--r3); height: var(--r3); --ring: var(--r3); }

/* The arm does not move — it is an anchor at the ring's centre that hands its
   start angle down to the tile. */
.orbit__arm {
  position: absolute;
  top: 50%; left: 50%;
  width: 0; height: 0;
}

.orbit__chip {
  position: absolute;
  top: 0; left: 0;
  margin: calc(var(--tile) / -2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tile);
  height: var(--tile);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  color: #C9CFDC;
  animation: orbit-cw var(--dur, 24s) linear infinite;
  will-change: transform;
  backface-visibility: hidden;
}
.orbit__ring--2 .orbit__chip { animation-name: orbit-ccw; }
.orbit__chip svg { width: 20px; height: 20px; }
.orbit__chip--accent { border-color: var(--accent-line); box-shadow: var(--shadow-md), var(--glow); }

@keyframes orbit-cw {
  from { transform: rotate(var(--a))                translateY(calc(var(--ring) / -2)) rotate(calc(-1 * var(--a))); }
  to   { transform: rotate(calc(var(--a) + 360deg)) translateY(calc(var(--ring) / -2)) rotate(calc(-1 * var(--a) - 360deg)); }
}
@keyframes orbit-ccw {
  from { transform: rotate(var(--a))                translateY(calc(var(--ring) / -2)) rotate(calc(-1 * var(--a))); }
  to   { transform: rotate(calc(var(--a) - 360deg)) translateY(calc(var(--ring) / -2)) rotate(calc(-1 * var(--a) + 360deg)); }
}

@media (max-width: 620px) {
  .orbit { --tile: 32px; }
  .orbit__chip svg { width: 15px; height: 15px; }
}

/* --------------------------------------------------------------------------
   14. Split feature block
   -------------------------------------------------------------------------- */
.split { display: grid; gap: clamp(2.5rem, 5vw, 4rem); align-items: start; }
@media (min-width: 860px) { .split { grid-template-columns: 1fr 1fr; } }

.checklist { display: grid; gap: var(--s-4); margin-top: var(--s-5); }
.checklist li {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--t-enter) var(--ease-out), transform var(--t-enter) var(--ease-out);
}
.checklist.is-in li { opacity: 1; transform: none; }
.checklist.is-in li:nth-child(1) { transition-delay: 0ms; }
.checklist.is-in li:nth-child(2) { transition-delay: 40ms; }
.checklist.is-in li:nth-child(3) { transition-delay: 80ms; }
.checklist.is-in li:nth-child(4) { transition-delay: 120ms; }
.checklist.is-in li:nth-child(5) { transition-delay: 160ms; }
.checklist.is-in li:nth-child(6) { transition-delay: 200ms; }
.checklist svg { flex: none; width: 17px; height: 17px; margin-top: 0.25em; color: var(--accent); }
.checklist strong { display: block; font-size: 0.93rem; font-weight: 700; }
.checklist span { font-size: 0.86rem; color: var(--muted); line-height: 1.55; }

/* --------------------------------------------------------------------------
   15. FAQ
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--line); max-width: 72ch; }
.faq__item { border-bottom: 1px solid var(--line); }

.faq__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  min-height: 54px;
  padding-block: var(--s-4);
  background: none;
  border: 0;
  cursor: pointer;
  text-align: start;
  font-size: 0.97rem;
  font-weight: 700;
  letter-spacing: -0.012em;
  transition: color var(--t-micro);
}
.faq__q:hover { color: var(--accent); }

.faq__sign { flex: none; position: relative; width: 18px; height: 18px; }
.faq__sign::before, .faq__sign::after {
  content: "";
  position: absolute;
  inset-inline-start: 50%;
  top: 50%;
  background: var(--accent);
  transform: translate(-50%, -50%);
  transition: transform var(--t-ui) var(--ease), opacity var(--t-micro);
}
.faq__sign::before { width: 12px; height: 1.5px; }
.faq__sign::after  { width: 1.5px; height: 12px; }
.faq__item.is-open .faq__sign::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }

.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 380ms var(--ease); }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { color: var(--muted); font-size: 0.89rem; padding-bottom: var(--s-5); line-height: 1.65; }

/* --------------------------------------------------------------------------
   16. Contact & form
   -------------------------------------------------------------------------- */
.contact { display: grid; gap: clamp(2.5rem, 5vw, 3.5rem); align-items: start; }
@media (min-width: 900px) { .contact { grid-template-columns: 0.8fr 1fr; } }

.contact__list { display: grid; gap: var(--s-3); margin-top: var(--s-6); }

.contact__row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 60px;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color var(--t-micro), transform var(--t-ui) var(--ease), box-shadow var(--t-ui);
}
.contact__row:hover { border-color: var(--accent-line); transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.contact__row:active { transform: scale(0.99); }
.contact__row svg { width: 17px; height: 17px; color: var(--accent); flex: none; }
.contact__row small { display: block; font-size: 0.7rem; color: var(--muted-2); }
.contact__row b { font-size: 0.89rem; font-weight: 700; }
.contact__row .ltr { direction: ltr; display: inline-block; unicode-bidi: embed; }

.form {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--s-5);
  display: grid;
  gap: var(--s-4);
  box-shadow: var(--shadow-sm);
}

.field { display: grid; gap: var(--s-2); }
@media (min-width: 600px) { .form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); } }

.field label { font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.field label span { color: var(--accent); }

.field input, .field select, .field textarea {
  width: 100%;
  min-height: 46px;
  padding: 0.7rem 0.9rem;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  font-size: 16px;                 /* 16px stops iOS zooming on focus */
  transition: border-color var(--t-micro), background var(--t-micro), box-shadow var(--t-micro);
}
.field textarea { resize: vertical; min-height: 96px; }
.field input::placeholder, .field textarea::placeholder { color: var(--muted-2); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239AA1B1' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 14px;
  padding-inline-end: 2.2rem;
  cursor: pointer;
}
[dir="rtl"] .field select { background-position: left 0.85rem center; padding-inline-end: 0.9rem; padding-inline-start: 2.2rem; }

.form .btn { width: 100%; }
.form__note { font-size: 0.74rem; color: var(--muted-2); text-align: center; line-height: 1.5; }

/* The submit status. It is the only place on the page where a colour carries
   meaning on its own, so it always says what happened in words too — the tone
   is reinforcement, never the message. */
#form-status { font-size: 0.82rem; font-weight: 600; }
#form-status[data-tone="good"] { color: var(--accent); }
#form-status[data-tone="bad"]  { color: var(--c-coral); }

/* Send and WhatsApp are two doors to the same room, not a button and its
   fallback, so they share a row and neither is visually demoted. */
.form .btn-row { margin-block-start: var(--s-2); }
.form .btn-row .btn { flex: 1 1 14rem; justify-content: center; }

.hp { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* --------------------------------------------------------------------------
   17. CTA band
   -------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(2rem, 4.5vw, 3.25rem);
  text-align: center;
  overflow: hidden;
  background: radial-gradient(70% 120% at 50% 0%, var(--sand-wash), transparent 60%), var(--surface);
}
.cta-band .h2 { max-width: 22ch; margin-inline: auto; }
.cta-band .lede { margin: var(--s-4) auto 0; }
.cta-band .btn-row { justify-content: center; margin-top: var(--s-5); }

/* --------------------------------------------------------------------------
   18. Footer
   -------------------------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--line);
  padding-block: var(--s-7) var(--s-5);
  margin-top: var(--section-y);
  background: var(--surface);
}
.footer__top { display: grid; gap: var(--s-6); padding-bottom: var(--s-6); }
@media (min-width: 760px) { .footer__top { grid-template-columns: 1.5fr 1fr 1fr; } }

.footer p { color: var(--muted); font-size: 0.86rem; margin-top: var(--s-3); max-width: 36ch; line-height: 1.6; }

.footer h4 { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--muted-2); margin-bottom: var(--s-3); }
html[lang="ar"] .footer h4 { letter-spacing: 0; text-transform: none; font-size: 0.78rem; }

.footer__links { display: grid; gap: var(--s-2); }
.footer__links a { font-size: 0.85rem; color: var(--muted); transition: color var(--t-micro), transform var(--t-micro) var(--ease); display: inline-block; }
.footer__links a:hover { color: var(--accent); transform: translateX(3px); }
[dir="rtl"] .footer__links a:hover { transform: translateX(-3px); }

/* Every wipe-in underline starts from the reading edge, both directions. */
[dir="rtl"] .nav__link::after,
[dir="rtl"] .link::after,
[dir="rtl"] .card::after,
[dir="rtl"] .header__progress { transform-origin: right; }

.footer__bottom {
  border-top: 1px solid var(--line);
  padding-top: var(--s-5);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  justify-content: space-between;
  font-size: 0.78rem;
  color: var(--muted-2);
}

/* --------------------------------------------------------------------------
   19. Floating WhatsApp
   -------------------------------------------------------------------------- */
.fab {
  position: fixed;
  inset-block-end: 18px;
  inset-inline-end: 18px;
  z-index: 90;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 46px;
  padding: 0.7rem 1.1rem;
  border-radius: 100px;
  background: #1FAF54;
  color: #fff;
  font-size: 0.85rem;
  font-weight: 700;
  box-shadow: 0 6px 22px rgba(31, 175, 84, 0.32);
  transform: translateY(80px);
  opacity: 0;
  transition: transform 0.45s var(--ease), opacity var(--t-ui), background var(--t-micro);
}
.fab.is-visible { transform: none; opacity: 1; }
.fab:hover { background: #199445; }
.fab:active { transform: scale(0.95); }
.fab svg { width: 18px; height: 18px; flex: none; }

@media (max-width: 520px) {
  .fab { padding: 0.8rem; inset-block-end: 14px; inset-inline-end: 14px; }
  .fab span { display: none; }
}

/* --------------------------------------------------------------------------
   20. Scroll reveal
   -------------------------------------------------------------------------- */
[data-reveal] { opacity: 0; transform: translateY(18px); transition: opacity var(--t-enter) var(--ease-out), transform var(--t-enter) var(--ease-out); }
[data-reveal].is-in { opacity: 1; transform: none; }

/* The eyebrow's rule draws itself in behind the label as the section arrives.
   One small thing that moves per section — the rest simply settles. */
/* Scoped to revealable containers only: a rule that starts collapsed must
   have something that is guaranteed to un-collapse it. */
[data-reveal] .eyebrow::before { transform: scaleX(0); transform-origin: left; transition: transform 700ms var(--ease) 160ms; }
[dir="rtl"] [data-reveal] .eyebrow::before { transform-origin: right; }
[data-reveal].is-in .eyebrow::before { transform: scaleX(1); }

/* Slides arrive with the section rather than sitting there waiting. */
.console[data-reveal] .slide { opacity: 0; transform: translateY(14px); transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out); }
.console[data-reveal].is-in .slide { opacity: 0.55; transform: none; }
.console[data-reveal].is-in .slide.is-current { opacity: 1; }
.console[data-reveal].is-in .slide:nth-child(1) { transition-delay: 80ms; }
.console[data-reveal].is-in .slide:nth-child(2) { transition-delay: 160ms; }
.console[data-reveal].is-in .slide:nth-child(3) { transition-delay: 240ms; }
.console[data-reveal].is-in .slide:nth-child(4) { transition-delay: 320ms; }

/* --------------------------------------------------------------------------
   21. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  /* The vertical studio mark needs a gutter to live in; below this width the
     content has taken it. */
  .hero__side { display: none; }
}

@media (max-width: 900px) {
  .nav { display: none; }
  .burger { display: inline-flex; }

  /* The quote button stays on the phone. It used to be hidden along with the
     nav, which left the device most of this traffic arrives on with no call to
     action in the header at all — the only way to convert was to find the
     WhatsApp bubble or scroll to the bottom of the page. It loses its arrow and
     some padding to earn the room, not its label. */
  .header__actions .btn { padding-inline: 0.85rem; }
  .header__actions .btn .arrow { display: none; }

  /* One column, and the visual leads — the orbit is the thing that makes
     someone stop, and on a phone it has to arrive before the fold does. */
  .hero__inner { grid-template-columns: 1fr; }
  .hero__visual { order: -1; }
  .hero__copy { max-width: none; }
  .dock { max-width: none; }

  /* The lens caption drops under the stage rather than beside it. */
  .lens { grid-template-columns: 1fr; }
  .lens__caption { padding-block-end: var(--s-3); }
}

@media (max-width: 760px) {
  .lens__stage { --glass: 96px; }
}

@media (max-width: 480px) {
  /* Smaller tags, and a glass small enough that a thumb dragging it does not
     cover the thing it is magnifying. The stage height follows the rows. */
  .lens__stage { --glass: 84px; }
  .tag { font-size: 0.76rem; padding: var(--s-2) var(--s-3); }

  /* Collapse the language switch to its globe. Something has to give at this
     width, and it should be the control a visitor uses once — not the one the
     whole page is asking them to press. The aria-label carries the name, so
     nothing is lost to a screen reader. */
  .lang { font-size: 0; gap: 0; padding-inline: 0.6rem; }
  .lang svg { width: 15px; height: 15px; }
  .header__actions .btn { font-size: 0.78rem; padding-inline: 0.7rem; }
}

@media (max-width: 620px) {
  .hero__cta .btn { width: 100%; }
  .btn-row { width: 100%; }
  .panel .btn { width: 100%; }
  .hero__motes { display: none; }
  .stat { padding: var(--s-4); }
}

/* --------------------------------------------------------------------------
   21b. Depth pass

   Light is the only material this palette has. Everything below adds it in one
   of three ways — a hairline that fades at both ends, an accent that glows when
   it is doing something, or a surface that lifts on approach. Nothing here
   changes layout, so nothing here can shift the page.
   -------------------------------------------------------------------------- */

/* Section rules dissolve at the edges instead of hitting the gutter. */
.section--edge { border-top: 0; }
.section--edge::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-strong) 20%, var(--line-strong) 80%, transparent);
  pointer-events: none;
}

/* Anchor targets clear the fixed header instead of hiding under it. */
:target, section[id], #top { scroll-margin-top: 88px; }

.btn:hover { box-shadow: var(--shadow-md), 0 0 46px rgba(47, 227, 176, 0.16); }
.btn--ghost:hover { box-shadow: var(--shadow-sm), 0 0 22px rgba(47, 227, 176, 0.12); }
.btn--wa:hover { box-shadow: var(--shadow-md), 0 0 30px rgba(31, 175, 84, 0.28); }

.card:hover { box-shadow: var(--shadow-md), 0 0 0 1px color-mix(in srgb, var(--card-accent) 18%, transparent); }
.card__icon { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); }

.stat { position: relative; }
.stat__n { transition: text-shadow var(--t-ui); }
.stat:hover .stat__n { text-shadow: 0 0 24px rgba(47, 227, 176, 0.4); }




.contact__row:hover { box-shadow: var(--shadow-sm), 0 0 22px rgba(47, 227, 176, 0.08); }

.cta-band {
  border-color: var(--line-strong);
  background:
    radial-gradient(80% 130% at 50% 0%, rgba(47, 227, 176, 0.10), transparent 62%),
    radial-gradient(60% 100% at 50% 100%, var(--sand-wash), transparent 60%),
    var(--surface);
  box-shadow: var(--shadow-lg);
}
.cta-band::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline: 15%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0.7;
}

/* The pointer carries a light with it. Same trick as the service cards —
   main.js feeds --mx / --my, the surface does the rest. */
.cta-band::after,
.rail__item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%),
              rgba(47, 227, 176, 0.09), transparent 70%);
  opacity: 0;
  transition: opacity var(--t-ui);
  pointer-events: none;
}
.cta-band:hover::after, .rail__item:hover::after { opacity: 1; }
.cta-band > * { position: relative; z-index: 1; }
.rail__item > * { position: relative; z-index: 1; }

/* A quiet line of reassurance directly under a call to action. */
.assure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-2) var(--s-5);
  margin-top: var(--s-5);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted-2);
}
html[lang="ar"] .assure { font-family: var(--font-sans); text-transform: none; letter-spacing: 0; font-size: 0.78rem; }
.assure span { display: inline-flex; align-items: center; gap: var(--s-2); }
.assure svg { width: 13px; height: 13px; color: var(--accent); flex: none; }

/* --------------------------------------------------------------------------
   20b. Service pages

   Each service gets its own page carrying the site's accent for that service
   (set as --card-accent on <body>), so the six read as one family rather than
   six separate templates.
   -------------------------------------------------------------------------- */
.hero--sub {
  padding-block: clamp(6.5rem, 11vw, 9rem) clamp(2.5rem, 5vw, 4rem);
  text-align: start;
}
.hero--sub .display { font-size: clamp(1.9rem, 3.8vw, 3.1rem); max-width: 18ch; }
.hero--sub .lede { margin-top: var(--s-5); font-size: 1.02rem; }
.hero--sub .btn-row { margin-top: var(--s-6); }

.crumbs {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-6);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}
html[lang="ar"] .crumbs { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.76rem; }
.crumbs a { transition: color var(--t-micro); }
.crumbs a:hover { color: var(--accent); }
.crumbs [aria-current] { color: var(--card-accent, var(--accent)); }

.sub__head { position: relative; z-index: 1; max-width: 52ch; }

/* The bullets carry their own mark, so the list can be read at a glance
   before a word of it is read properly. The tile is the service's colour. */
.checklist svg {
  width: 34px; height: 34px;
  padding: 8px;
  margin-top: 0;
  border-radius: 10px;
  background: color-mix(in srgb, var(--card-accent, var(--accent)) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-accent, var(--accent)) 24%, transparent);
  color: var(--card-accent, var(--accent));
  transition: transform var(--t-ui) var(--spring), background var(--t-micro);
}
.checklist li:hover svg { transform: translateY(-2px) scale(1.04); }
.hero--sub ~ .section .checklist strong { font-size: 0.95rem; line-height: 1.5; }

/* A reason card: mark, then numeral, then the sentence. */
.hero--sub ~ .section .card__icon { margin-bottom: var(--s-4); }
.hero--sub ~ .section .step__n { font-size: 1.4rem; margin-bottom: var(--s-2); opacity: 0.45; }

.sub__icon {
  display: grid;
  place-items: center;
  width: 54px; height: 54px;
  margin-bottom: var(--s-5);
  border-radius: 15px;
  background: color-mix(in srgb, var(--card-accent, var(--accent)) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-accent, var(--accent)) 30%, transparent);
  color: var(--card-accent, var(--accent));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.sub__icon svg { width: 25px; height: 25px; }

/* On a service page the accent follows the service, not the site. */
.hero--sub .eyebrow { color: var(--card-accent, var(--accent)); }
.hero--sub .eyebrow::before { background: linear-gradient(90deg, transparent, var(--card-accent, var(--accent))); }

/* A card that is a link to another service. */
.card--link {
  display: flex;
  flex-direction: column;
  min-height: 148px;
}
.card--link .h3 { margin-top: var(--s-2); }
.card__go {
  margin-top: auto;
  padding-top: var(--s-4);
  color: var(--card-accent);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity var(--t-ui), transform var(--t-ui) var(--ease);
}
.card--link:hover .card__go { opacity: 1; transform: none; }
[dir="rtl"] .card__go svg { transform: scaleX(-1); }
.card__go svg { width: 17px; height: 17px; }

/* --- Who it is for, said plainly, right under the call to action --------- */
.icp {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
}
.icp__label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-inline-end: var(--s-1);
}
html[lang="ar"] .icp__label { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.74rem; }
.icp a {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 30px;
  padding: 0.25rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.02);
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--muted);
  transition: color var(--t-micro), border-color var(--t-micro), background var(--t-micro);
}
.icp a:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-wash); }
.icp svg { width: 13px; height: 13px; }

/* The line under a primary button that answers "and then what?" */
.cta-note {
  margin-top: var(--s-3);
  font-size: 0.78rem;
  color: var(--muted-2);
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.cta-note svg { width: 14px; height: 14px; color: var(--accent); flex: none; }

/* Keep going: the end of a section offers the next one instead of a dead end. */
.onward {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-6);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
.onward a {
  flex: 1 1 220px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 62px;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color var(--t-micro), background var(--t-micro), transform var(--t-ui) var(--ease);
}
.onward a:hover { border-color: var(--accent-line); background: var(--surface-2); transform: translateY(-2px); }
.onward small {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: 0.2rem;
}
html[lang="ar"] .onward small { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.7rem; }
.onward b { font-size: 0.92rem; font-weight: 700; }
.onward svg { width: 16px; height: 16px; color: var(--accent); flex: none; }
[dir="rtl"] .onward svg { transform: scaleX(-1); }

/* --------------------------------------------------------------------------
   21b2. HUD

   The instrument panel around the orbit and the portfolio stage: corner
   brackets, a telemetry column, a vertical studio mark and a scroll cue.
   Every one of these is decoration — none carries information the page does
   not already state in words.
   -------------------------------------------------------------------------- */
.hud { position: relative; }

.hud__corner {
  position: absolute;
  width: 16px; height: 16px;
  border: 1px solid var(--accent-line);
  pointer-events: none;
  opacity: 0.8;
}
.hud__corner--tl { top: 0; left: 0;  border-right: 0; border-bottom: 0; }
.hud__corner--tr { top: 0; right: 0; border-left: 0;  border-bottom: 0; }
.hud__corner--bl { bottom: 0; left: 0;  border-right: 0; border-top: 0; }
.hud__corner--br { bottom: 0; right: 0; border-left: 0;  border-top: 0; }

/* Telemetry: three facts the page makes elsewhere, set as instrument text. */
.hud__read {
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  display: grid;
  gap: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
  pointer-events: none;
}
html[lang="ar"] .hud__read { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.68rem; }
.hud__read li { display: flex; align-items: center; gap: 0.4rem; }
.hud__read li::before {
  content: "";
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.7;
}
.hud__read li:nth-child(2)::before { background: var(--cyan); }
.hud__read li:nth-child(3)::before { background: var(--sand); }

/* A dashed ring that turns against everything else. */
.hud__dial {
  position: absolute;
  top: 50%; left: 50%;
  width: calc(var(--r3) + 2.6rem);
  aspect-ratio: 1;
  margin: calc((var(--r3) + 2.6rem) / -2);
  border-radius: 50%;
  border: 1px dashed rgba(255, 255, 255, 0.07);
  animation: dial 90s linear infinite;
  pointer-events: none;
}
@keyframes dial { to { transform: rotate(-360deg); } }

/* Vertical studio mark down the edge of the hero. */
.hero__side {
  position: absolute;
  inset-block-start: 42%;
  inset-inline-start: clamp(0.5rem, 2vw, 1.5rem);
  z-index: 1;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted-2);
  opacity: 0.5;
  writing-mode: vertical-rl;
  pointer-events: none;
  user-select: none;
}
[dir="rtl"] .hero__side { writing-mode: vertical-lr; }

/* Scroll cue. A real link, so the keyboard gets the same shortcut. */
.hero__scroll {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted-2);
  transition: color var(--t-micro);
}
html[lang="ar"] .hero__scroll { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; font-size: 0.74rem; }
.hero__scroll:hover { color: var(--accent); }
.hero__scroll svg { width: 13px; height: 13px; animation: nudge 2.4s var(--ease) infinite; }
@keyframes nudge {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }
  30%           { transform: translateY(4px); opacity: 1; }
}

/* --------------------------------------------------------------------------
   21c. Atmosphere

   Three things make the page feel inhabited rather than printed: a field of
   light behind everything, type that arrives out of focus, and controls that
   lean towards the pointer. All three are switched off wholesale under
   prefers-reduced-motion further down.
   -------------------------------------------------------------------------- */

/* The constellation. Fixed behind the whole document; main.js draws it.
   Named starfield, not field — .field is the form row. */
.starfield {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* Only the two flow-level landmarks need lifting above the field. The header
   and the mobile menu are already fixed and already have their own z-index —
   giving them position:relative here dropped them back into the flow, and the
   invisible menu then pushed the whole page down by its own height. */
main, .footer { position: relative; z-index: 1; }

/* --- Kinetic headline ---------------------------------------------------
   Words arrive out of focus and settle. Split by word, never by letter:
   Arabic letters join, and cutting between them would break the script. */
.hero__title.is-kinetic .rl { overflow: visible; }
.hero__title.is-kinetic .rl > span { transform: none; transition: none; }

.hero__title .w,
.hero__title.is-kinetic .rotator {
  opacity: 0;
  filter: blur(12px);
  transform: translateY(0.3em);
  transition: opacity 0.75s var(--ease-out), filter 0.75s var(--ease-out), transform 0.75s var(--ease-out);
  transition-delay: calc(var(--wi, 0) * 55ms);
}
.hero__title .w { display: inline-block; }
.hero.is-ready .hero__title .w,
.hero.is-ready .hero__title.is-kinetic .rotator { opacity: 1; filter: blur(0); transform: none; }

/* --- Magnetic controls ---------------------------------------------------
   --bx / --by come from the pointer (main.js), --lift from the hover state.
   Keeping them in separate variables is what lets the two combine instead of
   one overwriting the other. */
.btn {
  transform: translate3d(var(--bx, 0px), calc(var(--by, 0px) + var(--lift, 0px)), 0);
  transition: transform 240ms var(--ease-out), background var(--t-micro),
              border-color var(--t-micro), color var(--t-micro), box-shadow var(--t-ui), scale 140ms var(--ease);
}
.btn:hover { --lift: -2px; transform: translate3d(var(--bx, 0px), calc(var(--by, 0px) + var(--lift, 0px)), 0); }
.btn:active { scale: 0.97; transition-duration: 90ms; }

/* --- Depth on the orbit ---------------------------------------------------
   Each ring answers the pointer by a different amount, which is the whole
   trick: parallax is what makes a flat stack read as space. */
.orbit__ring, .orbit__globe {
  transition: transform 500ms var(--ease-out);
}
.orbit__ring--1 { transform: translate(calc(-50% + var(--px, 0px) * 0.30), calc(-50% + var(--py, 0px) * 0.30)); }
.orbit__ring--2 { transform: translate(calc(-50% + var(--px, 0px) * 0.62), calc(-50% + var(--py, 0px) * 0.62)); }
.orbit__ring--3 { transform: translate(calc(-50% + var(--px, 0px) * 1.00), calc(-50% + var(--py, 0px) * 1.00)); }
.orbit__globe   { transform: translate(calc(-50% + var(--px, 0px) * 0.14), calc(-50% + var(--py, 0px) * 0.14)); }

/* --- Glass ---------------------------------------------------------------
   Desktop only. The blur is what lets the constellation show through a card;
   on a phone it is a lot of compositing for an effect nobody leans in to see. */
@media (min-width: 900px) {
  .card, .rail__item, .form, .cta-band, .contact__row, .stat, .langs__list li {
    backdrop-filter: blur(12px) saturate(125%);
    -webkit-backdrop-filter: blur(12px) saturate(125%);
  }
  .card, .rail__item, .contact__row { background-color: rgba(15, 17, 23, 0.66); }
  .form { background-color: rgba(15, 17, 23, 0.74); }
  .stat { background-color: rgba(15, 17, 23, 0.6); }
  .langs__list li { background-color: rgba(15, 17, 23, 0.5); }
}

/* --- Cold light on the cool surfaces ------------------------------------- */
.header__progress { background: linear-gradient(90deg, var(--accent), var(--cyan)); }
.orbit__ring--2 { border-color: var(--cyan-line); }
.section--edge::before {
  background: linear-gradient(90deg, transparent, var(--line-strong) 20%, var(--cyan-line) 50%, var(--line-strong) 80%, transparent);
}
/* Symmetrical, because the line grows out of its own centre: a two-stop
   gradient would leave one arm dark and the other lit. Gold, to match the word
   it sits under — this rule is the one that actually paints the underline, so
   the base rule further up will not show if these two disagree. */
.rotator__item.is-current::after { background: linear-gradient(90deg, var(--sand), var(--sand-hi) 50%, var(--sand)); }
.dock__shell::before { background: linear-gradient(90deg, transparent, var(--cyan), transparent); }

/* --- Stats: a cascade, not a block ---------------------------------------
   The strip keeps [data-reveal] purely to receive .is-in from the observer;
   the movement belongs to the cells. */
.stats[data-reveal] { opacity: 1; transform: none; }
.stat {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--t-enter) var(--ease-out), transform var(--t-enter) var(--ease-out), background var(--t-ui);
}
.stats.is-in .stat { opacity: 1; transform: none; }
.stats.is-in .stat:nth-child(1) { transition-delay:  60ms; }
.stats.is-in .stat:nth-child(2) { transition-delay: 120ms; }
.stats.is-in .stat:nth-child(3) { transition-delay: 180ms; }
.stats.is-in .stat:nth-child(4) { transition-delay: 240ms; }

/* --------------------------------------------------------------------------
   21d. Small screens, last word

   These override rules that appear later in the file than section 21, so they
   have to sit after them. Anything here is either about fitting a phone or
   about a finger being wider than a cursor.
   -------------------------------------------------------------------------- */
@media (max-width: 760px) {
  /* Instrument text is the first thing to go when the panel gets small. */
  .hud__read { display: none; }
  .hud__corner { width: 12px; height: 12px; }
}

@media (max-width: 939px) {
  /* Stacked, the console has no width to spare — a turned frame would only
     throw away pixels the preview needs. It sits flat and square on. */
  .console { padding: var(--s-4) var(--s-3); }
  .rail { padding-inline-start: var(--s-3); }
  .rail__n { font-size: 1.1rem; }
}

@media (max-width: 480px) {
  .hero__scroll { display: none; }
}

/* A finger is ~9mm across. Everything it has to hit gets 44px on touch. */
@media (hover: none), (max-width: 620px) {
  .dock__btn { min-height: 44px; }
  .dock__close { width: 34px; height: 34px; }
  .rail__item { min-height: 66px; }
  .faq__q { min-height: 58px; }
  .btn--sm, .lang { min-height: 44px; }
  .logo { padding-block: 0.5rem; }        /* hit area, not visible weight */
}

/* --------------------------------------------------------------------------
   22. Motion & print
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  .rl > span, .hero__fade, .hero__visual { opacity: 1 !important; transform: none !important; }
  .langs__list li, .checklist li, .stat, .slide { opacity: 1 !important; transform: none !important; }
  .eyebrow::before { transform: scaleX(1) !important; }
  .hero__title .w, .hero__title .rotator { opacity: 1 !important; filter: none !important; transform: none !important; }
  .hero__aurora, .hero__motes, .hero__video, .hero__rays, .starfield { display: none; }

  /* No magnet, no parallax — the pointer moves nothing. */
  .btn, .btn:hover { transform: none; }
  .orbit__ring, .orbit__globe { transform: translate(-50%, -50%); }

  /* The dock still opens — it just opens instantly, which is the point. */
  .dock__shell::before { display: none; }

  /* Tiles hold their start angles instead of travelling. */
  .orbit__chip {
    animation: none;
    transform: rotate(var(--a)) translateY(calc(var(--ring) / -2)) rotate(calc(-1 * var(--a)));
  }
  .orbit__glow { display: none; }

  /* The capability rows stop where they were authored instead of snapping to
     the end of one loop. The glass still works — dragging it is the visitor's
     own motion, not ours. */
  .lens__track { animation: none; transform: none; }
}

@media print {
  .header, .fab, .mobile-nav, .hero__aurora, .hero__motes,
  .hero__grid, .hero__visual, .hero__video, .orbit, body::after { display: none !important; }
  /* The site is dark on screen; on paper it has to go back to ink on white. */
  body { background: #fff; color: #111; }
  .card, .project, .form, .footer, .cta-band, .stat, .marquee { background: #fff !important; }
  .lede, .card p, .panel p, .footer p, .faq__a p { color: #333; }
  .h2 em, .display em, .eyebrow { color: #111; }
}
