/* ==========================================================================
   QX Digital — site styles
   Built on logical properties throughout so the Arabic RTL layout mirrors
   automatically from a single stylesheet. Never use left/right here.
   ========================================================================== */

:root {
  /* Brand hues — see qx-brand-tokens.css */
  --violet: #8B5CFF;
  --indigo: #5566FF;
  --blue: #2F8BFF;
  --cyan: #3ED8EC;

  --violet-deep: #6B3BE8;
  --indigo-deep: #3B45DE;
  --blue-deep: #1A6FDC;
  --cyan-deep: #0FA2BC;

  /* Surfaces */
  /* Surfaces. Three tones on one axis: the dark is the brand violet taken
     almost to black, the lights are the navbar off-white and one step down.
     Both ends carry red, so they belong to each other. */
  --ink: #221C42;
  --ink-raised: #2C2554;
  --ink-line: #3A3168;
  --paper: #FFFFFF;
  --paper-raised: #F5F5F5;
  --paper-line: #E6E6E6;

  /* Navbar only — bone white. Deliberately a different surface from the
     page, so the bar reads as a distinct layer above the content. */
  --offwhite: #FFFFFF;
  --offwhite-line: #E6E6E6;

  /* Text */
  --on-dark: #EAF3FF;
  --on-dark-muted: #93A9C4;
  --on-light: #0D1B2A;
  --on-light-muted: #566A81;

  --gradient: linear-gradient(135deg, var(--violet) 0%, var(--indigo) 45%, var(--blue) 80%, var(--cyan) 100%);
  --gradient-deep: linear-gradient(135deg, var(--violet-deep) 0%, var(--indigo-deep) 45%, var(--blue-deep) 80%, var(--cyan-deep) 100%);

  /* Type */
  --font-display: "Space Grotesk", "IBM Plex Sans", system-ui, sans-serif;
  --font-body: "IBM Plex Sans", system-ui, sans-serif;

  --shell: 1200px;
  --gutter: clamp(20px, 5vw, 56px);
  --radius: 14px;
}

/* Arabic swaps both roles to the harmonised Plex Arabic cut. */
html[lang="ar"] {
  --font-display: "IBM Plex Sans Arabic", system-ui, sans-serif;
  --font-body: "IBM Plex Sans Arabic", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--on-light);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; display: block; }

a { color: inherit; }

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

.shell {
  max-inline-size: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  inset-block-start: -60px;
  inset-inline-start: var(--gutter);
  z-index: 200;
  background: var(--cyan);
  color: var(--ink);
  padding: 10px 18px;
  border-radius: 0 0 8px 8px;
  font-weight: 600;
  transition: inset-block-start .2s;
}
.skip-link:focus { inset-block-start: 0; }

/* ---------------------------------------------------------------- type ---- */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0 0 .5em;
}
html[lang="ar"] h1,
html[lang="ar"] h2,
html[lang="ar"] h3,
html[lang="ar"] h4 {
  letter-spacing: 0;
  line-height: 1.35;
}

h1 { font-size: clamp(2.4rem, 5.6vw, 4.15rem); }
h2 { font-size: clamp(1.85rem, 3.6vw, 2.85rem); }
h3 { font-size: clamp(1.15rem, 1.7vw, 1.4rem); }

p { margin: 0 0 1.1em; }

.eyebrow {
  font-family: var(--font-body);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--blue-deep);
  margin: 0 0 1rem;
}
html[lang="ar"] .eyebrow { letter-spacing: 0; font-size: .9rem; }
.on-ink .eyebrow { color: #FFFFFF; }

.lede {
  font-size: clamp(1.05rem, 1.5vw, 1.22rem);
  color: var(--on-light-muted);
  max-inline-size: 62ch;
  font-weight: 300;
}
.on-ink .lede { color: var(--on-dark-muted); }

.measure { max-inline-size: 68ch; }

/* --------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  padding: 14px 26px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: .97rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
}
.btn:hover { transform: translateY(-2px); }

.btn-primary {
  background: var(--gradient-deep);
  color: #fff;
  box-shadow: 0 6px 22px rgba(59, 69, 222, .28);
}
.btn-primary:hover { box-shadow: 0 10px 30px rgba(59, 69, 222, .38); }

.on-ink .btn-primary {
  background: var(--gradient);
  box-shadow: 0 6px 24px rgba(85, 102, 255, .35);
}

.btn-ghost {
  border-color: var(--paper-line);
  color: var(--on-light);
  background: transparent;
}
.btn-ghost:hover { border-color: var(--blue-deep); }

.on-ink .btn-ghost {
  border-color: var(--ink-line);
  color: var(--on-dark);
}
.on-ink .btn-ghost:hover { border-color: var(--cyan); }

/* The arrow flips with direction so it always points "forward". */
.btn .arrow { transition: transform .18s ease; }
html[dir="rtl"] .btn .arrow { transform: scaleX(-1); }
.btn:hover .arrow { transform: translateX(3px); }
html[dir="rtl"] .btn:hover .arrow { transform: scaleX(-1) translateX(3px); }

/* ---------------------------------------------------------------- header -- */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 100;
  background: rgba(17, 29, 50, .72);
  backdrop-filter: blur(18px) saturate(140%);
  border-block-end: 1px solid rgba(126, 156, 205, .20);
  transition: box-shadow .25s ease, border-color .25s ease;
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  min-block-size: 82px;
}

.brand { flex: none; }
.brand img { block-size: 50px; inline-size: auto; }

.site-nav {
  display: flex;
  gap: 6px;
  margin-inline-start: 14px;
  align-items: center;
}

.site-nav a {
  padding: 9px 16px;
  border-radius: 999px;
  color: var(--on-dark-muted);
  text-decoration: none;
  font-size: .96rem;
  font-weight: 500;
  transition: color .18s, background .18s;
}
.site-nav a:hover { color: var(--on-dark); background: rgba(255, 255, 255, .06); }
.site-nav a[aria-current="page"] { color: var(--on-dark); background: rgba(85, 102, 255, .18); }

.header-actions { display: flex; align-items: center; gap: 12px; margin-inline-start: auto; }

.lang-toggle {
  background: transparent;
  border: 1px solid var(--ink-line);
  color: var(--on-dark);
  border-radius: 999px;
  padding: 8px 16px;
  font-family: var(--font-body);
  font-size: .88rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color .18s, color .18s;
}
.lang-toggle:hover { border-color: var(--cyan); color: var(--cyan); }

.header-actions .btn { padding: 11px 22px; font-size: .9rem; }

.nav-toggle {
  display: none;
  margin-inline-start: auto;
  background: transparent;
  border: 1px solid var(--ink-line);
  border-radius: 10px;
  padding: 9px 11px;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  inline-size: 20px;
  block-size: 2px;
  background: var(--on-dark);
  margin: 4px 0;
  transition: transform .2s, opacity .2s;
}

@media (max-width: 960px) {
  .nav-toggle { display: block; }
  .site-nav {
    position: absolute;
    inset-block-start: 100%;
    inset-inline: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    background: var(--ink);
    border-block-end: 1px solid var(--ink-line);
    padding: 14px var(--gutter) 22px;
    margin: 0;
    display: none;
  }
  .site-nav.open { display: flex; }
  .site-nav a { padding: 13px 14px; }
  .header-actions {
    order: 3;
    margin-inline-start: 10px;
  }
  .header-actions .btn { display: none; }
}

/* ------------------------------------------------------------------ hero -- */

.on-ink { background: var(--ink); color: var(--on-dark); }

.hero {
  position: relative;
  overflow: hidden;
  /* Banner sits under a scrim that is heaviest on the copy side and lightest
     over the mark, so the headline keeps its contrast without flattening the
     image where nothing is written. The ink colour underneath shows through
     the scrim, which pulls the image's navy toward the site's violet. */
  background-color: var(--ink);
  background-image: url("../img/hero-poster.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  padding-block: clamp(38px, 4.6vw, 60px) clamp(34px, 4vw, 52px);
  isolation: isolate;
  /* The footage is 16:9 and fills the hero edge to edge (`cover` on
     .hero-video), so this height decides how much of the frame survives the
     crop: about half the frame at 52vh on a 1080p screen. Raise 52vh to keep
     more of the shot, lower it for a shorter band; it is the only number to
     touch. The vw term caps the height on wide short windows, and on phones
     both terms fall below the content height, so this does nothing there. */
  min-block-size: min(52vh, 34vw);
  display: flex;
  align-items: center;
}

/* SIGNATURE: two beams crossing behind the headline — the logo's X, at
   architectural scale. Violet enters from one top corner, cyan from the
   other; they intersect just behind the type. */
.beams {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}
.beam {
  position: absolute;
  inline-size: 165%;
  block-size: 190px;
  inset-block-start: 8%;
  inset-inline-start: -30%;
  filter: blur(52px);
  opacity: .72;
  transform-origin: center;
}
.beam-violet {
  background: linear-gradient(90deg, transparent, #A987FF, transparent);
  transform: rotate(24deg);
  animation: drift-a 16s ease-in-out infinite alternate;
}
.beam-cyan {
  background: linear-gradient(90deg, transparent, var(--cyan), transparent);
  transform: rotate(-24deg);
  opacity: .58;
  animation: drift-b 19s ease-in-out infinite alternate;
}
@keyframes drift-a {
  from { transform: rotate(24deg) translateY(-14px); }
  to   { transform: rotate(24deg) translateY(22px); }
}
@keyframes drift-b {
  from { transform: rotate(-24deg) translateY(18px); }
  to   { transform: rotate(-24deg) translateY(-16px); }
}

/* No bottom fade. A 130px gradient to --paper used to soften the join when the
   hero was a flat dark ground; over live footage it reads as fog sitting on the
   picture. The hero now meets the page on a clean edge. */
.hero .shell { position: relative; inline-size: 100%; }

.hero-grid {
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(32px, 6vw, 80px);
  align-items: center;
}
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-visual { order: -1; max-inline-size: 320px; }
}

.hero h1 .stop { color: var(--cyan); }

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-block-start: 34px;
}

.hero-visual img { inline-size: 100%; }

/* ------------------------------------------------------------- sections --- */

section { padding-block: clamp(64px, 9vw, 112px); }

.section-head { max-inline-size: 70ch; margin-block-end: clamp(36px, 5vw, 60px); }

/* SIGNATURE: the crossing mark, reused as a section rule. */
.cross-rule {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-block-end: 26px;
}
.cross-rule::after {
  content: "";
  flex: 1;
  block-size: 1px;
  background: linear-gradient(90deg, var(--paper-line), transparent);
}
html[dir="rtl"] .cross-rule::after {
  background: linear-gradient(270deg, var(--paper-line), transparent);
}
.on-ink .cross-rule::after {
  background: linear-gradient(90deg, var(--ink-line), transparent);
}
html[dir="rtl"] .on-ink .cross-rule::after {
  background: linear-gradient(270deg, var(--ink-line), transparent);
}
.cross-rule svg { flex: none; inline-size: 18px; block-size: 18px; }

/* ------------------------------------------------------------------ grid -- */

/* min() so the track can fall back to the container width. A bare
   minmax(320px, 1fr) cannot shrink below 320px, so on a 320px screen the
   column stayed 320px inside a 280px container and pushed the page sideways. */
.grid-3 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: clamp(20px, 3vw, 34px);
}
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: clamp(20px, 3vw, 30px);
}

.pillar h3 { margin-block-start: 18px; }
.pillar p { color: var(--on-light-muted); margin: 0; }
.on-ink .pillar p { color: var(--on-dark-muted); }

.pillar-num {
  font-family: var(--font-display);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--blue-deep);
  padding-block-end: 14px;
  border-block-end: 2px solid;
  border-image: var(--gradient-deep) 1;
  display: inline-block;
  min-inline-size: 46px;
}
.on-ink .pillar-num { color: var(--cyan); border-image: var(--gradient) 1; }

/* ----------------------------------------------------------------- cards -- */

.card {
  background: var(--paper);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  padding: clamp(24px, 3vw, 34px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
  position: relative;
  overflow: hidden;
}
.card::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 3px;
  background: var(--gradient-deep);
  transform: scaleX(0);
  transform-origin: inline-start;
  transition: transform .28s ease;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 40px rgba(40, 30, 20, .10);
  border-color: transparent;
}
.card:hover::before { transform: scaleX(1); }
.card h3 { margin: 0; }
.card p { color: var(--on-light-muted); margin: 0; font-size: .97rem; }

.card-tag {
  align-self: flex-start;
  /* was .72rem = 11.5px, which is below the 12px floor where phone text
     starts to strain. Nudged up; the tracking and caps carry the label look. */
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--violet-deep);
  background: rgba(107, 59, 232, .09);
  padding: 5px 11px;
  border-radius: 999px;
}
html[lang="ar"] .card-tag { letter-spacing: 0; text-transform: none; font-size: .8rem; }

.card-more {
  margin-block-start: auto;
  padding-block-start: 8px;
  min-block-size: 44px;
  font-weight: 600;
  font-size: .93rem;
  color: var(--blue-deep);
  display: inline-flex;
  align-items: center;
  gap: .45em;
}
html[dir="rtl"] .card-more .arrow { transform: scaleX(-1); }

.alt { background: var(--paper-raised); }

/* ------------------------------------------------------- product detail --- */

.product-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 68px);
  align-items: center;
  padding-block: clamp(44px, 6vw, 72px);
  border-block-start: 1px solid var(--paper-line);
}
.product-row:first-of-type { border-block-start: 0; }
@media (max-width: 820px) { .product-row { grid-template-columns: 1fr; } }

.product-panel {
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  background: var(--ink);
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  border: 1px solid var(--ink-line);
}
.product-panel .glow {
  position: absolute;
  inline-size: 140%;
  block-size: 140px;
  filter: blur(52px);
  opacity: .55;
}
.product-panel svg { position: relative; inline-size: 46%; block-size: auto; }

/* Image panel. The panel keeps its 4/3 box so row heights stay identical to
   any SVG panel beside it, but the image is contained rather than cropped —
   nothing gets cut off. The panel takes the images' own white ground so the
   letterboxing is invisible; the artwork reads as floating in the card. */
/* No card at all — no background, no border, no corner radius. The image is
   blended into the page instead of sitting in a container.
   `multiply` makes a white image background vanish against the white page:
   white x white = white, so only the artwork survives. The soft mask feathers
   whatever edge is left so there is no rectangle to see. */
.product-panel.has-image {
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
}
/* Absolutely positioned so the box is exactly the panel, then padded — a
   replaced element's object-fit resolves inside its content box, so this
   contains the image with an inset margin and cannot overflow. Percentage
   max-block-size does not constrain reliably against an aspect-ratio parent. */
.product-panel.has-image img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  box-sizing: border-box;
  object-fit: contain;
  /* White image backgrounds disappear against the white page: white x white
     is white, so only the artwork survives. The photograph, which has a dark
     background of its own, carries a feathered alpha edge baked into the file
     instead — CSS masking would have bitten into the contained illustrations
     before it reached the photo's edge. */
  mix-blend-mode: multiply;
}

.spec-list { list-style: none; margin: 18px 0 0; padding: 0; }
.spec-list li {
  position: relative;
  padding-inline-start: 26px;
  margin-block-end: 10px;
  color: var(--on-light-muted);
  font-size: .97rem;
}
.spec-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .62em;
  inline-size: 9px;
  block-size: 9px;
  border-radius: 2px;
  background: var(--gradient-deep);
}

/* ------------------------------------------------------------------ form -- */

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }
.field-wide { grid-column: 1 / -1; }

label {
  display: block;
  font-size: .87rem;
  font-weight: 600;
  margin-block-end: 7px;
  color: var(--on-light);
}
.req { color: var(--violet-deep); }

input, select, textarea {
  inline-size: 100%;
  padding: 13px 15px;
  border: 1px solid var(--paper-line);
  border-radius: 10px;
  background: var(--paper);
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--on-light);
  transition: border-color .18s, box-shadow .18s;
}
textarea { resize: vertical; min-block-size: 130px; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--blue-deep);
  box-shadow: 0 0 0 3px rgba(26, 111, 220, .14);
}

.form-note {
  font-size: .87rem;
  color: var(--on-light-muted);
  margin-block-start: 16px;
}

.form-status {
  margin-block-start: 16px;
  padding: 13px 16px;
  border-radius: 10px;
  font-size: .93rem;
  display: none;
}
.form-status.show { display: block; }
.form-status.ok { background: rgba(15, 162, 188, .1); color: #0B6E80; }
.form-status.err { background: rgba(232, 59, 59, .09); color: #A32222; }

.contact-aside {
  background: var(--paper-raised);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  padding: clamp(24px, 3vw, 34px);
}
.contact-aside dt {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--on-light-muted);
  margin-block-start: 20px;
}
html[lang="ar"] .contact-aside dt { letter-spacing: 0; text-transform: none; font-size: .85rem; }
.contact-aside dt:first-child { margin-block-start: 0; }
.contact-aside dd { margin: 4px 0 0; font-weight: 500; }
.contact-aside a { text-decoration: none; color: var(--blue-deep); }


/* ---------------------------------------------------------------- footer -- */

.site-footer {
  background: var(--ink);
  color: var(--on-dark-muted);
  padding-block: 22px 16px;
  border-block-start: 1px solid var(--ink-line);
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) auto;
  gap: 32px;
  align-items: start;
  padding-block-end: 18px;
  /* was var(--ink-line), a dark violet that barely separated the two rows */
  border-block-end: 1px solid rgba(255, 255, 255, .42);
}
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; gap: 20px; } }
.site-footer img { block-size: 42px; inline-size: auto; margin-block-end: 12px; }
.site-footer h4 {
  color: var(--on-dark);
  font-size: .82rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  margin-block-end: 14px;
}
html[lang="ar"] .site-footer h4 { letter-spacing: 0; text-transform: none; font-size: .95rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-block-end: 9px; }
.site-footer a { text-decoration: none; transition: color .18s; }
.site-footer a:hover { color: var(--cyan); }
.footer-base {
  padding-block-start: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  /* space-between was left over from when a second item sat beside it; with
     one child it just pinned the line to the start edge */
  justify-content: center;
  text-align: center;
  font-size: .86rem;
}
.footer-base span { color: #FFFFFF; }

/* Anything the client still has to supply is flagged, not silently faked. */
.placeholder {
  border-block-end: 1px dashed currentColor;
  opacity: .75;
}

/* ------------------------------------------------------- late additions -- */

/* The header sits on ink but keeps its translucency, so it gets the
   on-dark button treatment explicitly rather than via .on-ink. */
.site-header .btn-primary {
  background: var(--gradient);
  box-shadow: 0 6px 24px rgba(85, 102, 255, .32);
}
.site-header .btn-primary:hover { box-shadow: 0 10px 30px rgba(85, 102, 255, .44); }

.pillar-icon { inline-size: 44px; block-size: 44px; }

.float { animation: float 7s ease-in-out infinite alternate; }
@keyframes float {
  from { transform: translateY(-8px); }
  to   { transform: translateY(8px); }
}

/* Alternating product rows. Order flips rather than direction, so this
   stays correct in RTL without a second rule. */
@media (min-width: 821px) {
  .product-row.flip .product-panel { order: -1; }
}

.product-row h2 { margin-block: 14px 12px; }

/* Hero headline words sit on their own lines at large sizes. */
.hero h1 span { display: inline-block; margin-inline-end: .28em; }

/* The header is one flex row: lockup, hamburger, language button. The lockup
   is 4.4:1, so its height drives its width four-and-a-bit times over, and at
   38px it was still claiming 167px of a 320px screen. With a 28px gap either
   side of the hamburger the row measured 387px against a 375px viewport, so
   the page scrolled sideways and every full-width child below inherited the
   wider document — which is why cards and form fields looked broken too. One
   overflowing row, a whole page of symptoms.

   Both the lockup and the gaps step down together; measured to fit 320px with
   room to spare. */
@media (max-width: 560px) {
  .header-inner { gap: 14px; min-block-size: 70px; }
  .brand img { block-size: 36px; }
  .lang-toggle { padding: 10px 12px; font-size: .82rem; }
}
@media (max-width: 390px) {
  .header-inner { gap: 9px; }
  .brand img { block-size: 30px; }
  .lang-toggle { padding: 10px 9px; font-size: .78rem; }
}

/* Touch targets. WCAG 2.5.5 asks for 44px; the language button sat at 34,
   the hamburger at 42 and the lockup link at 38 — all missable with a thumb.
   Setting a minimum leaves the visual size alone wherever it already passed. */
.lang-toggle {
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.brand {
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
}
.site-nav a { min-block-size: 44px; display: flex; align-items: center; }

/* The hamburger must keep its `display: none` above the mobile breakpoint —
   giving it a display value out here made it visible at every width, and its
   84px silently pushed the header past 1024px. Size it inside the query that
   turns it on instead. */
@media (max-width: 960px) {
  .nav-toggle {
    min-block-size: 44px;
    display: inline-flex;
    /* column, because the three bars are 20px-wide blocks — as flex items in a
       row they sat side by side as three dashes, and the icon measured 84px
       instead of 44px, which was what still pushed a 320px screen sideways. */
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }
}

/* Contact details are links but rendered 20px tall inside their definition
   list — under the 24px floor even for a mouse, and a hard tap on a phone. */
.contact-aside dd a { display: inline-block; padding-block: 12px; }


/* --------------------------------------------------- navbar treatments -- */

.logo-on-light { display: none; }

/* Option B — light bar. Add `light` to the <header> class on all three
   pages: <header class="site-header light">. Everything below follows. */
.site-header.light {
  background: rgba(255, 255, 255, .88);
  border-block-end: 1px solid transparent;
}
/* Over the hero the bar needs nothing; over white content it would vanish, so
   it earns a shadow instead of a tint. Colour told you it was a layer before;
   elevation tells you now, and only when it matters. */
.site-header.light.scrolled {
  border-block-end-color: var(--paper-line);
  box-shadow: 0 6px 24px rgba(20, 16, 45, .07);
}
.site-header.light .logo-on-dark { display: none; }
.site-header.light .logo-on-light { display: block; }

.site-header.light .site-nav a { color: var(--on-light-muted); }
.site-header.light .site-nav a:hover {
  color: var(--on-light);
  background: rgba(13, 27, 42, .06);
}
.site-header.light .site-nav a[aria-current="page"] {
  color: var(--on-light);
  background: rgba(26, 111, 220, .12);
}

.site-header.light .lang-toggle {
  border-color: var(--offwhite-line);
  color: var(--on-light);
}
.site-header.light .lang-toggle:hover {
  border-color: var(--blue-deep);
  color: var(--blue-deep);
}

.site-header.light .btn-primary {
  background: var(--gradient-deep);
  box-shadow: 0 6px 20px rgba(59, 69, 222, .26);
}

.site-header.light .nav-toggle { border-color: var(--offwhite-line); }
.site-header.light .nav-toggle span { background: var(--on-light); }

@media (max-width: 960px) {
  .site-header.light .site-nav {
    background: var(--offwhite);
    border-block-end: 1px solid var(--offwhite-line);
  }
}

/* --------------------------------------------------------- split hero -- */

.hero-split {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
}
@media (max-width: 900px) {
  .hero-split { grid-template-columns: 1fr; gap: clamp(22px, 4vw, 34px); }
  .hero-mark { justify-self: center; max-inline-size: 300px; }
}
/* Stacked, the headline and the mark both want the full width, so the hero
   grows fast. Pull the padding in rather than shrinking the type. */
@media (max-width: 620px) {
  .hero { padding-block: 34px 34px; }
  .hero-mark { max-inline-size: 250px; }
}

/* The company line leads; the tagline supports it underneath. */
.hero-copy h1 {
  font-size: clamp(1.8rem, 3.2vw, 2.8rem);
  margin: 0 0 clamp(14px, 1.8vw, 20px);
  color: #FFFFFF;
  max-inline-size: 21ch;
}
html[lang="ar"] .hero-copy h1 { max-inline-size: 24ch; }

/* The homepage headline is a 13-word sentence; the other pages' are four or
   five words. Sharing one size meant this one ran to six lines, so it gets a
   smaller step of its own rather than dragging the short headlines down with
   it. The measure is opened up too — the column, not the cap, should decide
   where it wraps. */
.hero-copy h1[data-i18n="hero.tagline"] {
  font-size: clamp(1.35rem, 1.95vw, 1.8rem);
  max-inline-size: 40ch;
}

.hero-tagline {
  margin: 0;
  font-size: clamp(1.02rem, 1.35vw, 1.2rem);
  font-weight: 300;
  line-height: 1.6;
  /* brighter than the muted grey used elsewhere: this one sits over a busy
     image, and a lighter sub-headline buys a lighter scrim, which shows more
     of the banner */
  color: #E6EEF7;
  max-inline-size: 44ch;
}
html[lang="ar"] .hero-tagline { max-inline-size: 48ch; line-height: 1.85; }

.hero-copy .hero-actions { margin-block-start: clamp(26px, 3.4vw, 40px); }

.hero-mark { line-height: 0; }

/* Push only the mark out to the section edge. The shell caps content at
   1200px and centres it, so on a wider screen there is dead margin either
   side; this slides the mark across that margin and stops a gutter's width
   from the edge. A transform is used rather than a negative margin so the
   mark keeps its size and its grid slot — the copy column, the beams and
   every other section are untouched. Mirrored for RTL, since transforms are
   physical and do not flip on their own. Only above the stacking breakpoint,
   where the two columns sit side by side. */
@media (min-width: 901px) {
  .hero-mark {
    transform: translateX(max(0px, calc((100vw - var(--shell)) / 2)));
  }
  html[dir="rtl"] .hero-mark {
    transform: translateX(min(0px, calc((var(--shell) - 100vw) / 2)));
  }

  /* Same idea for the copy, in the opposite direction. The shell caps content
     at 1200px, so on a wider screen the headline starts a long way in from the
     banner's edge; this slides it back across part of that dead margin. A
     fraction rather than the whole of it — the mark goes all the way out, the
     copy only leans that way, and the gutter still keeps it off the edge.
     Transform rather than margin, so nothing reflows and the buttons keep
     their hit areas. --hero-pull is the only number to touch: 0 leaves the
     copy where it was, 1 takes it as far out as the mark. */
  .hero-copy {
    --hero-pull: .6;
    --hero-copy-shift: calc(var(--hero-pull) * max(0px, (100vw - var(--shell)) / 2));
    transform: translateX(calc(-1 * var(--hero-copy-shift)));
  }
  html[dir="rtl"] .hero-copy {
    transform: translateX(var(--hero-copy-shift));
  }
}
.hero-mark img { inline-size: 100%; block-size: auto; }

.sr-only {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ---------------------------------------------------- footer contact -- */

.footer-contact { justify-self: end; }
html[dir="rtl"] .footer-contact { justify-self: start; }
@media (max-width: 760px) {
  .footer-contact { justify-self: start; }
  html[dir="rtl"] .footer-contact { justify-self: end; }
}

.footer-cta {
  display: inline-flex;
  align-items: center;
  gap: .7em;
  padding: 13px 24px;
  border: 1px solid var(--ink-line);
  border-radius: 999px;
  color: #FFFFFF;
  text-decoration: none;
  font-weight: 600;
  font-size: .97rem;
  transition: border-color .18s, color .18s, transform .18s;
}
.footer-cta:hover {
  border-color: var(--cyan);
  color: var(--cyan);
  transform: translateY(-2px);
}
.footer-cta svg { inline-size: 20px; block-size: 20px; flex: none; }
html[dir="rtl"] .footer-cta .arrow { transform: scaleX(-1); }

.footer-address {
  margin-block-start: 0;
  margin-block-end: 0;
  font-size: .92rem;
  max-inline-size: 72ch;
  color: #FFFFFF;
}

/* Service cards are not links, so they drop the lift-and-underline hover the
   product cards use. The gradient rule stays as a static accent. */
.card-static { cursor: default; }
.card-static::before { transform: scaleX(1); opacity: .55; }
.card-static:hover {
  transform: none;
  box-shadow: none;
  border-color: var(--paper-line);
}
.card-static h3 { margin-block-end: 4px; }
.card-static .spec-list { margin-block-start: 6px; }
.card-static .spec-list li:last-child { margin-block-end: 0; }

/* Stacked, the footer's three blocks pile up; pull the rhythm in further. */
@media (max-width: 760px) {
  .site-footer { padding-block: 20px 14px; }
  .site-footer img { block-size: 38px; margin-block-end: 10px; }
  .footer-grid { padding-block-end: 18px; }
  .footer-base { padding-block-start: 14px; gap: 8px; }
}


/* The beams were carrying the hero on a flat ground. Over a detailed image
   they only add haze, so they drop back to a tint that warms the banner's
   navy toward the brand violet. */
.hero .beams { display: none; }

/* ------------------------------------------------------- hero video -- */

/* Negative z-index keeps both layers above the hero's own background (the
   poster) and below the copy. No colour is applied to the video itself —
   the scrim is neutral black, so it dims without shifting hue. */
.hero-video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  /* Full bleed, edge to edge. `cover` scales the frame to fill the hero and
     crops whatever the height cannot hold — the trade for having no bars at
     the sides. The shot is composed centrally, so a centre crop keeps the
     globe. Raise the hero's min-block-size to show more of the frame. */
  object-fit: cover;
  z-index: -2;
  pointer-events: none;
}
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(0, 0, 0, .66) 0%,
    rgba(0, 0, 0, .60) 46%,
    rgba(0, 0, 0, .38) 74%,
    rgba(0, 0, 0, .22) 100%);
}
html[dir="rtl"] .hero-scrim {
  background: linear-gradient(to left,
    rgba(0, 0, 0, .66) 0%,
    rgba(0, 0, 0, .60) 46%,
    rgba(0, 0, 0, .38) 74%,
    rgba(0, 0, 0, .22) 100%);
}

/* Motion sensitivity: drop the video, leaving the hero's own poster background
   full-bleed underneath. */
@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
}

/* ------------------------------------------------------ bidi isolation -- */

/* The copyright line stays English on the Arabic site, and English text in an
   RTL paragraph gets reordered: the © and the closing full stop are
   bidi-neutral, so the algorithm resolves them to the paragraph direction and
   throws them to the opposite visual end — ".QX Digital. All rights reserved
   2026 ©". The dir="ltr" attribute in the markup is what fixes it (the HTML UA
   stylesheet gives any [dir] element unicode-bidi: isolate); this rule states
   it explicitly so a later refactor cannot quietly drop it. Same treatment for
   Latin contact details, which are always read left to right. */
[dir="ltr"] {
  direction: ltr;
  unicode-bidi: isolate;
}
html[dir="rtl"] .footer-base { text-align: center; }

/* Honeypot. Off-screen rather than display:none — some bots skip fields that
   are outright hidden, but fill anything they can find in the DOM. */
.hp {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------- offer bands -------- */
/* Full-width alternating bands on the homepage — each product/service arrives
   as its own chapter on scroll. Reuses the product-row geometry: two columns,
   copy one side, panel the other, flipping every other band. On phones both
   collapse to a single column with the panel on top. */
.offer-bands { margin-block-start: clamp(28px, 4vw, 44px); }
.offer-band {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: clamp(28px, 5vw, 68px);
  align-items: center;
  padding-block: clamp(40px, 5.5vw, 68px);
  border-block-start: 1px solid var(--paper-line);
}
.offer-band:first-child { border-block-start: 0; }
/* flip: panel moves to the copy side and vice-versa, so bands alternate. */
.offer-band.flip .offer-copy { order: 2; }
.offer-band .offer-copy h3 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin-block: 12px 12px; }

/* branded panel for services, which have no photo of their own. Same dark 4/3
   box as the product image panels, with the crossing-beam motif inside. */
.offer-svg-panel { aspect-ratio: 4 / 3; }
/* voice panel now holds a real image — sized to match the other image panels
   (text-led ratio above), capped so it never dominates or overflows in RTL. */
.offer-svg-panel.has-image { overflow: hidden; border-radius: 16px; max-block-size: 300px; align-self: center; }
.offer-svg-panel.has-image img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

@media (max-width: 820px) {
  .offer-band { grid-template-columns: 1fr; gap: clamp(20px, 4vw, 30px); }
  /* panel always on top when stacked, regardless of flip. */
  .offer-band .offer-copy { order: 2 !important; }
  .offer-band .product-panel { order: 1; }
}

/* ============================================ offer sections (homepage) === */
/* Each product/service is now its OWN full-width section rather than a band
   inside one section. Backgrounds alternate white / raised-white so each reads
   as a distinct chapter, and each reveals on scroll. */
.offer-sec { background: var(--paper); padding-block: clamp(48px, 7vw, 92px); overflow-x: clip; }
.offer-sec.alt { background: var(--paper-raised); }
.offer-intro { padding-block: clamp(44px, 6vw, 76px) clamp(20px, 3vw, 32px); }

/* the two-column band inside each section (reuses offer-band geometry) */
.offer-sec .offer-band { overflow-x: clip;
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: clamp(30px, 5vw, 72px);
  align-items: center;
  border: 0;           /* sections carry the separation now, not a border */
  padding-block: 0;
}
.offer-sec .offer-band.flip .offer-copy { order: 2; }
.offer-sec .offer-copy h3 { font-size: clamp(1.6rem, 3.2vw, 2.3rem); margin-block: 12px 14px; }

/* the extra supporting points under a product's lede */
.offer-points { list-style: none; margin: 6px 0 0; padding: 0; }
.offer-points li {
  position: relative;
  padding-inline-start: 26px;
  margin-block: 10px;
  color: var(--text-secondary, #4A4A55);
  line-height: 1.5;
}
.offer-points li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .5em;
  inline-size: 12px; block-size: 12px;
  background: linear-gradient(135deg, #6B3BE8, #3ED8EC);
  clip-path: polygon(0 0, 100% 50%, 0 100%, 30% 50%);
}

@media (max-width: 820px) {
  .offer-sec .offer-band { overflow-x: clip; grid-template-columns: 1fr; gap: clamp(22px, 4vw, 32px); }
  .offer-sec .offer-band .offer-copy { order: 2 !important; }
  .offer-sec .offer-band .product-panel { order: 1; }
}

/* ---------------------------------------------------- QX models grid ----- */
.models-head { margin-block: clamp(40px, 6vw, 68px) clamp(20px, 3vw, 30px); text-align: center; }
.models-head h3 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin: 0 0 8px; }
.models-head .lede { margin-inline: auto; max-inline-size: 56ch; }

.models-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: clamp(16px, 2vw, 22px);
}
.model-card {
  border-radius: var(--radius);
  padding: clamp(20px, 2.4vw, 28px);
  color: var(--on-dark);
  background: linear-gradient(155deg, #2C2554, #221C42);
  border: 1px solid var(--ink-line);
  min-block-size: 210px;
  display: flex;
  flex-direction: column;
}

/* Hover / focus / active interaction: the card lifts and gains a violet-cyan
   glow. This is a pointer interaction, separate from the scroll entrance above.
   A short box-shadow+border transition is added so it feels responsive; the
   reveal keeps its own longer opacity/transform timing. Once revealed (.in),
   hovering translates the card up; before reveal the entrance owns transform. */
.model-card {
  transition: opacity .7s cubic-bezier(.2,.7,.3,1),
              transform .7s cubic-bezier(.2,.7,.3,1),
              box-shadow .25s ease,
              border-color .25s ease;
  cursor: pointer;
}
.model-card.in {
  transition: transform .28s cubic-bezier(.2,.7,.3,1),
              box-shadow .28s ease,
              border-color .28s ease;
}
.model-card.in:hover,
.model-card.in:focus-visible,
.model-card.in:active {
  transform: translateY(-8px);
  border-color: #6B5BE8;
  box-shadow: 0 16px 40px rgba(107, 59, 232, .35),
              0 0 0 1px rgba(62, 216, 236, .5),
              0 0 28px rgba(62, 216, 236, .28);
  outline: none;
}

/* QX model line: clear sequential entrance — each card animates in turn as the
   grid enters the viewport, so the reveal reads as a deliberate cascade rather
   than all six at once. Delays stack on top of the base reveal transition. */
.models-grid .model-card[data-reveal] { transition-delay: 0s; }
.models-grid .model-card[data-reveal]:nth-child(1) { transition-delay: .00s; }
.models-grid .model-card[data-reveal]:nth-child(2) { transition-delay: .10s; }
.models-grid .model-card[data-reveal]:nth-child(3) { transition-delay: .20s; }
.models-grid .model-card[data-reveal]:nth-child(4) { transition-delay: .30s; }
.models-grid .model-card[data-reveal]:nth-child(5) { transition-delay: .40s; }
.models-grid .model-card[data-reveal]:nth-child(6) { transition-delay: .50s; }

/* ASR family leans violet, TTS family leans blue-cyan — a quiet way to tell
   the two lines apart without another label. */
.model-card.asr { background: linear-gradient(155deg, #3A2A78, #241A54); }
.model-card.tts { background: linear-gradient(155deg, #1E3A78, #17245C); }
.model-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-block-end: auto; }
.model-icon {
  inline-size: 46px; block-size: 46px;
  display: grid; place-items: center;
  border-radius: 12px;
  background: rgba(255,255,255,.08);
  color: #7FE8F5;
  flex: none;
}
.model-icon svg { inline-size: 26px; block-size: 26px; }
.mtags { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.mtag {
  font-size: .72rem; font-weight: 600;
  padding: 4px 10px; border-radius: 999px;
  background: rgba(255,255,255,.1);
  color: var(--on-dark);
  white-space: nowrap;
}
.model-card h4 { margin: 18px 0 8px; font-size: 1.15rem; display: flex; flex-direction: column; gap: 2px; }
.model-card h4 .mvar { font-weight: 500; color: #7FE8F5; font-size: .95rem; }
.model-card p { margin: 0; color: var(--on-dark-muted); line-height: 1.5; font-size: .95rem; }

/* ------------------------------------------------ reveal on scroll ------- */
/* Each section starts shifted and transparent, then eases into place when it
   enters the viewport (class added by an IntersectionObserver). Alternating
   sections come from alternating sides for variety. */
[data-reveal] {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity .7s cubic-bezier(.2,.7,.3,1), transform .7s cubic-bezier(.2,.7,.3,1);
  will-change: opacity, transform;
}
/* Vertical-only reveal: translateX pushed sections past the viewport edge,
   which caused a sideways scrollbar and broke the observer. A gentle rise
   reads just as well and never overflows. The left/right classes still exist
   for a subtle stagger via transition-delay rather than direction. */
[data-reveal].reveal-right { transition-delay: .06s; }

/* copy slides from the leading edge, panel from the trailing edge, so the two
   halves of a band arrive as a pair. Horizontal offset is small and the parent
   section clips overflow (overflow-x: clip), so this never scrolls the page. */
[data-reveal].reveal-from-start { transform: translateX(-30px); }
[data-reveal].reveal-from-end   { transform: translateX(30px); transition-delay: .12s; }
html[dir="rtl"] [data-reveal].reveal-from-start { transform: translateX(30px); }
html[dir="rtl"] [data-reveal].reveal-from-end   { transform: translateX(-30px); }
[data-reveal].in { opacity: 1; transform: none; }
/* RTL reset must match the specificity of the RTL direction rules above, or the
   revealed element keeps its sideways shift and gets clipped by overflow-x:clip
   (this was cutting off the Arabic Voice copy and image). */
html[dir="rtl"] [data-reveal].reveal-from-start.in,
html[dir="rtl"] [data-reveal].reveal-from-end.in { transform: none; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ------------------------------------------- deployment blocks (voice) --- */
/* On-prem + edge sit under the models grid, inside the voice section. Each is
   a heading plus a 2x2 feature list — a different layout from the product
   sections above, so the page keeps varying rather than repeating one shape. */
.dep-block { margin-block-start: clamp(40px, 6vw, 64px); }
.dep-head { max-inline-size: 60ch; margin-block-end: clamp(20px, 3vw, 30px); }
.dep-head h4 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); margin: 8px 0 10px; }

.dep-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(16px, 2.4vw, 26px);
}
.dep-item { display: flex; gap: 14px; align-items: flex-start; }
.dep-check {
  flex: none;
  inline-size: 34px; block-size: 34px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: rgba(107, 59, 232, .08);
}
.dep-check svg { inline-size: 20px; block-size: 20px; }
.dep-item h5 { margin: 2px 0 4px; font-size: 1.05rem; }
.dep-item p { margin: 0; color: var(--text-secondary, #4A4A55); line-height: 1.5; }

/* -------------------------------------- deployment: centered layouts ----- */
.dep-head-center { max-inline-size: 62ch; margin-inline: auto; text-align: center; }
.dep-head-center h4 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin: 0 0 10px; }
.dep-head-center .lede { margin-inline: auto; }

/* on-prem: 4 cards, centered, with a CTA button beneath */
.dep-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(18px, 2.4vw, 30px);
  margin-block: clamp(28px, 4vw, 44px);
}
.dep-card { text-align: start; }
.dep-card-icon {
  display: inline-grid; place-items: center;
  inline-size: 46px; block-size: 46px;
  border-radius: 11px;
  background: rgba(107, 59, 232, .08);
  margin-block-end: 14px;
}
.dep-card-icon svg { inline-size: 26px; block-size: 26px; }
.dep-card h5 { margin: 0 0 8px; font-size: 1.15rem; }
.dep-card p { margin: 0; color: var(--text-secondary, #4A4A55); line-height: 1.5; }
.dep-cta { text-align: center; margin-block-start: clamp(20px, 3vw, 34px); }

/* edge: 4 image-style cards, each a coloured media panel + body */
.edge-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(16px, 2vw, 24px);
  margin-block: clamp(28px, 4vw, 44px);
}
.edge-card {
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--paper-line);
  display: flex;
  flex-direction: column;
}
.edge-card-media {
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
}
.edge-card-media svg { inline-size: 40%; block-size: auto; opacity: .95; }

/* real media (the uploaded video + images) fills the 4/3 panel, cover-cropped
   so nothing letterboxes. The gradient panels above keep their SVG glyph; these
   override for the cards that carry a photo or clip. */
.edge-media-img, .edge-media-video { padding: 0; background: #0d1b2a; }
.edge-media-img img,
.edge-media-video video {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}
.edge-card-body { padding: clamp(16px, 2vw, 22px); }
.edge-card-body h5 { margin: 0 0 8px; font-size: 1.1rem; }
.edge-card-body p { margin: 0; color: var(--text-secondary, #4A4A55); line-height: 1.5; }

/* edge stat row: three big figures */
.edge-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 3vw, 40px);
  text-align: center;
  margin-block-start: clamp(20px, 3vw, 32px);
}
.edge-stat-v {
  display: block;
  font-family: "Space Grotesk", system-ui, sans-serif;
  font-size: clamp(1.8rem, 4vw, 2.8rem);
  font-weight: 700;
  line-height: 1;
  background: linear-gradient(120deg, #6B3BE8, #3ED8EC);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.edge-stat-l { display: block; margin-block-start: 8px; color: var(--text-secondary, #4A4A55); font-size: .95rem; }

@media (max-width: 620px) {
  .edge-stats { grid-template-columns: 1fr; gap: 20px; }
}

/* ============================================ tab picker (What we offer) === */
/* Vertical tabs on the leading side; the detail panel swaps per item. Each
   panel varies its own layout (image beside text, split, stats, callout,
   points) so clicking through reveals genuinely different shapes. */
.tab-picker {
  display: grid;
  grid-template-columns: 250px 1fr;
  gap: clamp(18px, 3vw, 30px);
  margin-block-start: clamp(28px, 4vw, 44px);
}
.tp-tabs { display: flex; flex-direction: column; gap: 8px; }
.tp-tab {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 15px;
  border-radius: 11px;
  border: 1px solid var(--paper-line);
  background: var(--paper);
  cursor: pointer;
  color: var(--text-secondary, #4A4A55);
  font-size: .95rem; font-weight: 600;
  text-align: start;
  transition: background .2s, color .2s, border-color .2s;
  min-block-size: 48px;
}
.tp-tab:hover { border-color: var(--violet-deep, #6B3BE8); }
.tp-tab.on {
  background: linear-gradient(135deg, #6B3BE8, #3ED8EC);
  border-color: transparent;
  color: #fff;
}
.tp-tab-ic { flex: none; inline-size: 26px; block-size: 26px; display: grid; place-items: center; }
.tp-tab-ic svg { inline-size: 22px; block-size: 22px; }
/* tab glyphs are white-on-gradient when active; give them ink otherwise */
.tp-tab:not(.on) .tp-tab-ic svg [stroke="#fff"] { stroke: var(--violet-deep, #6B3BE8); }
.tp-tab:not(.on) .tp-tab-ic svg [fill="#fff"] { fill: var(--violet-deep, #6B3BE8); }

.tp-panel {
  border: 1px solid var(--paper-line);
  border-radius: 14px;
  overflow: hidden;
  background: var(--paper);
  min-block-size: 280px;
  position: relative;
}
.tp-panel-item { transition: opacity .28s ease; }
.tp-panel-item[hidden] { display: none; }
.tp-pad { padding: clamp(20px, 2.6vw, 30px); }

.tp-eyebrow { font-size: .72rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--violet-deep, #6B3BE8); }
.tp-title { font-size: clamp(1.4rem, 2.8vw, 2rem); font-weight: 700; margin: 10px 0 12px; color: var(--ink, #221C42); }
.tp-body { font-size: 1rem; color: var(--text-secondary, #4A4A55); line-height: 1.7; margin: 0 0 16px; }

.tp-pts { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.tp-pts li { position: relative; padding-inline-start: 20px; font-size: .92rem; color: var(--text-secondary, #4A4A55); line-height: 1.5; }
.tp-pts li::before { content: ""; position: absolute; inset-inline-start: 0; inset-block-start: .5em; inline-size: 9px; block-size: 9px; background: linear-gradient(135deg, #6B3BE8, #3ED8EC); clip-path: polygon(0 0, 100% 50%, 0 100%, 30% 50%); }

/* image beside text; side classes set the order and mirror in RTL via order */
.tp-imgrow { display: grid; align-items: stretch; }
.tp-imgrow.img-right { grid-template-columns: 1.25fr 1fr; }
.tp-imgrow.img-left  { grid-template-columns: 1fr 1.25fr; }
.tp-imgrow .tp-txt { padding: clamp(20px, 2.6vw, 30px); }
.tp-imgrow .tp-pic { display: grid; place-items: center; padding: 20px; min-block-size: 220px; }
.tp-imgrow .tp-pic svg { inline-size: 44%; block-size: auto; }
.tp-imgrow.img-left .tp-txt { order: 2; }
.tp-imgrow.img-left .tp-pic { order: 1; }
/* the tp-pic can hold a real <img> later; it fills the cell cover-cropped */
.tp-pic img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

/* split: text + dark glyph side */
.tp-split { display: grid; grid-template-columns: 1.3fr 1fr; }
.tp-side { background: linear-gradient(150deg, #2C2554, #221C42); display: grid; place-items: center; padding: 22px; }
.tp-side svg { inline-size: 42%; block-size: auto; }

/* stats strip */
.tp-stats { display: flex; flex-wrap: wrap; gap: clamp(18px, 3vw, 34px); margin-block-start: 8px; }
.tp-stat b { display: block; font-family: "Space Grotesk", system-ui, sans-serif; font-size: clamp(1.6rem, 3.4vw, 2.4rem); font-weight: 700; line-height: 1; background: linear-gradient(120deg, #6B3BE8, #3ED8EC); -webkit-background-clip: text; background-clip: text; color: transparent; }
.tp-stat span { display: block; margin-block-start: 6px; font-size: .85rem; color: var(--text-secondary, #4A4A55); }

/* callout: quote-style headline claim */
.tp-callout { border-inline-start: 3px solid; border-image: linear-gradient(#6B3BE8, #3ED8EC) 1; padding-block: 8px; padding-inline: 18px 0; margin: 0 0 16px; font-size: 1.15rem; line-height: 1.6; color: var(--ink, #221C42); font-style: italic; }

@media (max-width: 820px) {
  .tab-picker { grid-template-columns: 1fr; }
  .tp-tabs { flex-direction: row; flex-wrap: wrap; }
  .tp-tab { flex: 1 1 auto; min-inline-size: 140px; }
}
@media (max-width: 560px) {
  .tp-pts { grid-template-columns: 1fr; }
  .tp-imgrow.img-right, .tp-imgrow.img-left { grid-template-columns: 1fr; }
  .tp-imgrow.img-left .tp-txt, .tp-imgrow.img-left .tp-pic { order: 0; }
  .tp-imgrow .tp-pic { min-block-size: 170px; }
  .tp-split { grid-template-columns: 1fr; }
}

/* ============================================ offer full sections ========= */
/* Each product/service is its own full-width section (scrolled, not tabbed),
   each keeping its VARIED design — image-beside-text, split, stats, callout,
   or points. NO card frame: the content sits directly on the page like the
   Voice section, so the media panel (rounded) floats against the page rather
   than inside a bordered box. Reveal-on-scroll is on the section. */
.offer-full { padding-block: clamp(36px, 5vw, 60px); }
.offer-card {
  background: transparent;
  border: 0;
  border-radius: 0;
}

/* the text half needs no inset now the card padding is gone — drop it to the
   page gutter so copy lines up with the section heading above. */
.offer-full .tp-imgrow .tp-txt,
.offer-full .tp-pad { padding-inline: 0; }
.offer-full .tp-imgrow .tp-txt { padding-block: 0; }

/* the media panels keep their own rounded corners and float on the page.
   Text leads (≈1.7:1) so the panel reads as a supporting element, not an equal
   half, and the height is trimmed so it doesn't tower. Capped max width so it
   doesn't sprawl on very wide screens. When a real photo replaces the glyph the
   proportion still holds. */
.offer-full .tp-imgrow.img-right { grid-template-columns: 1.7fr 1fr; }
.offer-full .tp-imgrow.img-left  { grid-template-columns: 1fr 1.7fr; }
.offer-full .tp-split { grid-template-columns: 1.7fr 1fr; }
.offer-full .tp-imgrow .tp-pic,
.offer-full .tp-split .tp-side {
  border-radius: 16px;
  overflow: hidden;            /* clip the <img> to the rounded corners */
  min-block-size: 240px;
  max-block-size: 300px;
  align-self: center;
}
/* round the image itself too, so it's clipped even if a parent's overflow is
   overridden elsewhere */
.offer-full .tp-imgrow .tp-pic img { border-radius: 16px; }
.offer-full .tp-imgrow .tp-pic svg,
.offer-full .tp-split .tp-side svg { inline-size: 26%; }
.offer-full .tp-title { font-size: clamp(1.7rem, 3.4vw, 2.5rem); }

/* a touch more gap between text and media now there's no card holding them. */
.offer-full .tp-imgrow { gap: clamp(28px, 5vw, 64px); }
.offer-full .tp-split { gap: clamp(28px, 5vw, 64px); }

@media (max-width: 820px) {
  .offer-full .tp-imgrow .tp-pic,
  .offer-full .tp-split .tp-side { min-block-size: 200px; }
  /* stack on mobile — these need .offer-full scope to beat the ratio rules
     above, which are also .offer-full-scoped (higher specificity than the
     generic .tp-imgrow mobile rule). */
  .offer-full .tp-imgrow.img-right,
  .offer-full .tp-imgrow.img-left,
  .offer-full .tp-split { grid-template-columns: 1fr; }
  .offer-full .tp-imgrow.img-left .tp-txt,
  .offer-full .tp-imgrow.img-left .tp-pic { order: 0; }
}

/* ------------------------------------------- LLMs bespoke tri-column ----- */
/* LLMs gets its own three-column layout (like the reference): heading + intro
   on the leading side, a non-clickable feature list in the middle, and the
   image with a caption beneath on the trailing side. The other nine sections
   keep their varied designs. Mirrors correctly in Arabic via logical props. */
.llm-tri {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr 1.1fr;
  gap: clamp(24px, 3.5vw, 48px);
  align-items: start;
}
.llm-lead .tp-body { margin-block-end: 0; }

/* middle: feature list (display only — not interactive) */
.llm-feat-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.llm-feat {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--paper-line);
  border-radius: 11px;
  background: var(--paper);
  font-weight: 600;
  color: var(--ink, #221C42);
  font-size: .98rem;
}
.llm-feat-ic { flex: none; inline-size: 22px; block-size: 22px; display: grid; place-items: center; }
.llm-feat-ic svg { inline-size: 20px; block-size: 20px; }

/* trailing: image + caption below */
.llm-visual { display: flex; flex-direction: column; gap: 16px; }
.llm-pic {
  border-radius: 16px;
  min-block-size: 200px;
  display: grid;
  place-items: center;
}
.llm-pic svg { inline-size: 30%; block-size: auto; }

/* real LLM image fills the panel, cover-cropped, keeping the rounded corners */
.llm-pic.has-image { padding: 0; overflow: hidden; background: #0d1b2a; }
.llm-pic.has-image img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.llm-cap h4 { margin: 0 0 8px; font-size: 1.1rem; color: var(--ink, #221C42); }
.llm-cap p { margin: 0; color: var(--text-secondary, #4A4A55); line-height: 1.6; font-size: .95rem; }

@media (max-width: 980px) {
  .llm-tri { grid-template-columns: 1fr 1fr; }
  .llm-visual { grid-column: 1 / -1; flex-direction: row; align-items: stretch; }
  .llm-visual .llm-pic { flex: 1; }
  .llm-visual .llm-cap { flex: 1; align-self: center; }
}
@media (max-width: 620px) {
  .llm-tri { grid-template-columns: 1fr; }
  .llm-visual { flex-direction: column; }
}

/* ============================================ sectors we serve ============ */
/* Four sector cards after Custom Software, before "How we engage". Cards carry
   a dark treatment (like the model cards) so they read as a distinct band on
   the light section ground, matching the reference's card feel on-brand. */
.sectors-sec { padding-block: clamp(48px, 7vw, 88px); background: var(--paper); }
.sectors-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(18px, 2.4vw, 28px);
  margin-block-start: clamp(28px, 4vw, 44px);
}
@media (max-width: 560px) { .sectors-grid { grid-template-columns: 1fr; } }
.sector-card {
  border-radius: var(--radius);
  padding: clamp(28px, 3vw, 40px);
  background: var(--paper);
  border: 1px solid var(--paper-line);
  min-block-size: 240px;
  display: flex;
  flex-direction: column;
}
.sector-icon {
  inline-size: 58px; block-size: 58px;
  display: grid; place-items: center;
  border-radius: 14px;
  background: #EEEDFE;
  margin-block-end: auto;
}
.sector-icon svg { inline-size: 32px; block-size: 32px; }
.sector-card h3 { margin: 22px 0 10px; font-size: 1.45rem; color: var(--ink, #221C42); }
.sector-card p { margin: 0; color: var(--text-secondary, #4A4A55); line-height: 1.6; font-size: 1rem; }

/* ------------------------------------------- contact page: about band ---- */
.contact-about { padding-block: clamp(36px, 5vw, 56px); }
.contact-about-card {
  background: linear-gradient(155deg, #2C2554, #221C42);
  border: 1px solid var(--ink-line);
  border-radius: 18px;
  padding: clamp(30px, 4vw, 52px);
  max-inline-size: 66rem;
  margin-inline: auto;
  text-align: center;
  box-shadow: 0 18px 44px rgba(34, 28, 66, .16);
}
.contact-about-lead {
  margin: 0 0 12px;
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  font-weight: 700;
  line-height: 1.35;
  color: var(--on-dark, #EAF3FF);
  max-inline-size: 52ch;
  margin-inline: auto;
}
.contact-about-sub {
  margin: 0;
  font-size: clamp(1rem, 1.8vw, 1.15rem);
  line-height: 1.65;
  color: var(--on-dark-muted, #93A9C4);
  max-inline-size: 68ch;
  margin-inline: auto;
}

/* ============================================ product overview cards ====== */
/* Dark premium cards at the top of the Products page — an at-a-glance overview
   of the product line, with the same lift+glow interaction and staggered
   viewport entrance as the QX model line. The detailed sections stay below. */
.pcards-sec { padding-block: clamp(48px, 7vw, 88px); }
.pcards-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(16px, 2.2vw, 24px);
  margin-block-start: clamp(28px, 4vw, 44px);
}
@media (max-width: 720px) { .pcards-grid { grid-template-columns: 1fr; } }

.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius);
  padding: clamp(24px, 2.8vw, 34px);
  background: var(--paper);
  border: 1px solid var(--paper-line);
  color: var(--ink, #221C42);
  text-decoration: none;
  min-block-size: 240px;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(34, 28, 66, .04);
  /* reveal keeps its long timing; hover uses a short one (added on .in) */
  transition: opacity .7s cubic-bezier(.2,.7,.3,1),
              transform .7s cubic-bezier(.2,.7,.3,1),
              box-shadow .25s ease, border-color .25s ease;
}
/* a faint family tint on the icon tile keeps the AI vs governance distinction
   without darkening the whole card */
.pcard.asr .pcard-icon { background: #EEEBFE; }
.pcard.tts .pcard-icon { background: #E7EFFC; }

/* staggered entrance — cascade the five cards in as the grid enters view */
.pcards-grid .pcard[data-reveal]:nth-child(1) { transition-delay: .00s; }
.pcards-grid .pcard[data-reveal]:nth-child(2) { transition-delay: .08s; }
.pcards-grid .pcard[data-reveal]:nth-child(3) { transition-delay: .16s; }
.pcards-grid .pcard[data-reveal]:nth-child(4) { transition-delay: .24s; }
.pcards-grid .pcard[data-reveal]:nth-child(5) { transition-delay: .32s; }
.pcards-grid .pcard[data-reveal]:nth-child(6) { transition-delay: .40s; }

/* hover / focus / active: lift + violet-cyan glow (matches the model cards) */
.pcard.in {
  transition: transform .28s cubic-bezier(.2,.7,.3,1),
              box-shadow .28s ease, border-color .28s ease;
}
.pcard.in:hover, .pcard.in:focus-visible, .pcard.in:active {
  transform: translateY(-8px);
  border-color: #6B5BE8;
  box-shadow: 0 18px 40px rgba(107, 59, 232, .18),
              0 0 0 1px rgba(107, 59, 232, .35),
              0 6px 18px rgba(62, 216, 236, .16);
  outline: none;
}

.pcard-top { display: flex; align-items: flex-start; justify-content: space-between; margin-block-end: 20px; }
.pcard-icon {
  inline-size: 52px; block-size: 52px;
  display: grid; place-items: center;
  border-radius: 13px;
  background: #EEEDFE;
  flex: none;
}
.pcard-icon svg { inline-size: 30px; block-size: 30px; }
.pcard-icon svg [stroke="#7FE8F5"] { stroke: #6B3BE8; }
.pcard-icon svg [fill="#7FE8F5"] { fill: #6B3BE8; }
.pcard-eyebrow { font-size: .72rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--violet-deep, #6B3BE8); }
.pcard-name { font-size: clamp(1.3rem, 2.4vw, 1.7rem); font-weight: 700; margin: 8px 0 10px; color: var(--ink, #221C42); line-height: 1.2; }
.pcard-body { font-size: .96rem; line-height: 1.6; color: var(--text-secondary, #4A4A55); margin: 0 0 18px; }
.pcard-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: auto; }
.pcard-tag {
  font-size: .74rem; font-weight: 600;
  padding: 5px 11px;
  border-radius: 999px;
  background: var(--paper-raised, #F5F5F5);
  border: 1px solid var(--paper-line);
  color: var(--text-secondary, #4A4A55);
}
html[dir="rtl"] .pcard.in:hover html[dir="rtl"] .pcard.in:hover 
/* ---- dark variant of the product cards (used on the Services page) ------- */
/* Same card, dark treatment to match the QX model line. Scoped to .pcards-dark
   so the Products page cards stay white. */
.pcards-dark .pcard {
  background: linear-gradient(155deg, #2C2554, #221C42);
  border: 1px solid var(--ink-line);
  color: var(--on-dark, #EAF3FF);
  box-shadow: none;
}
.pcards-dark .pcard.asr { background: linear-gradient(155deg, #3A2A78, #241A54); }
.pcards-dark .pcard.tts { background: linear-gradient(155deg, #1E3A78, #17245C); }
.pcards-dark .pcard-icon { background: rgba(255,255,255,.08); }
.pcards-dark .pcard-icon svg [stroke="#7FE8F5"] { stroke: #7FE8F5; }
.pcards-dark .pcard-icon svg [fill="#7FE8F5"] { fill: #7FE8F5; }
.pcards-dark .pcard-eyebrow { color: #7FE8F5; }
.pcards-dark .pcard-name { color: var(--on-dark, #EAF3FF); }
.pcards-dark .pcard-body { color: var(--on-dark-muted, #93A9C4); }
.pcards-dark .pcard-tag {
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.12);
  color: #C7D6EA;
}
/* dark-appropriate hover glow (brighter cyan ring, like the model cards) */
.pcards-dark .pcard.in:hover,
.pcards-dark .pcard.in:focus-visible,
.pcards-dark .pcard.in:active {
  border-color: #6B5BE8;
  box-shadow: 0 16px 40px rgba(107, 59, 232, .35),
              0 0 0 1px rgba(62, 216, 236, .5),
              0 0 28px rgba(62, 216, 236, .28);
}

/* When a CTA links to #contact-form, leave room for the sticky navbar so the
   form heading isn't tucked right under it. */
#contact-form { scroll-margin-top: 110px; }
