/* ===================================================================================================
   MauriAI — design system v3 (base.css). OWNED BY THE LEAD: builders import these, never edit this file.
   Mobile first. Logical properties everywhere (the Arabic page is right-to-left).
   The world: night (near-black green) with a glow of the logo green, opening onto a light, airy page. One accent: the logo green.
   =================================================================================================== */

:root {
  /* colour */
  --bg: #F7F9F6;            /* the page: warm cream */
  --bg-2: #EEF2EC;          /* a quieter band on the page */
  --surface: #FFFFFF;       /* cards */
  --ink: #0A1410;           /* text */
  --ink-2: #39453F;         /* secondary text */
  --muted: #5F6B64;         /* captions, placeholders */
  --line: rgba(10, 20, 16, .10);
  --line-2: rgba(10, 20, 16, .06);

  --green-950: #050D0A;
  --green-900: #0A1712;     /* the dark band */
  --green-800: #2C5C2D;
  --green-700: #3A7239;     /* brand green: primary buttons, links, active */
  --green-600: #4E8A49;
  --green-500: #67A05F;
  --green-300: #A9D6A1;
  --green-200: #CFE8CA;
  --green-100: #E6F2E3;     /* tints, icon wells */
  --green-50: #F1F8EF;

  --gold-700: #3A7239;
  --gold-600: #4E8A49;
  --gold-500: #8FD483;      /* the only second accent: sparingly (waveform peaks, fine rules, one button on dark) */
  --gold-200: #FFFFFF;
  --gold-100: #EAF5E7;

  --sand-100: #F1F4F0;
  --sand-200: #E6EBE4;
  --sand-300: #D5DDD3;
  --sand-400: #B9C4B7;

  /* on the dark band */
  --on-dark: #F3F7F2;
  --on-dark-2: rgba(243, 247, 242, .70);
  --on-dark-line: rgba(243, 247, 242, .12);

  /* type */
  --font: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-ar: "IBM Plex Sans Arabic", "Manrope", ui-sans-serif, system-ui, sans-serif;
  --fs-display: clamp(2.5rem, 7.2vw + .6rem, 4.9rem);
  --fs-h2: clamp(1.85rem, 3.9vw + .7rem, 3.3rem);
  --fs-h3: clamp(1.2rem, .7vw + 1.05rem, 1.45rem);
  --fs-lead: clamp(1.0625rem, .5vw + .95rem, 1.3125rem);
  --fs-body: 1rem;
  --fs-small: .9375rem;
  --fs-tiny: .8125rem;
  --fs-eyebrow: .8125rem;

  /* space */
  --gutter: clamp(1.25rem, 4.2vw, 3.5rem);
  --max: 1200px;
  --section: clamp(5rem, 10vw, 8rem);
  --gap: clamp(1rem, 1.8vw, 1.5rem);

  /* shape and depth (shadows are tinted with the brand green, never black) */
  --r-s: 10px;
  --r-m: 16px;
  --r-l: 22px;
  --r-xl: 30px;
  --pill: 999px;
  --shadow-1: 0 1px 2px rgba(11, 51, 39, .05), 0 8px 24px rgba(11, 51, 39, .06);
  --shadow-2: 0 2px 4px rgba(11, 51, 39, .05), 0 22px 60px rgba(11, 51, 39, .11);
  --shadow-3: 0 4px 10px rgba(11, 51, 39, .07), 0 40px 100px rgba(11, 51, 39, .16);

  /* motion */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-soft: cubic-bezier(.32, .72, 0, 1);
  --t-fast: .2s;
  --t: .45s;
  --t-slow: .9s;

  --nav-h: 64px;

  /* motion (v4): one family of curves for the whole site. Use these, not ad-hoc beziers. */
  --ease-out: cubic-bezier(.22, 1, .36, 1);          /* things arriving */
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);       /* things moving from A to B (tab pills, sliders) */
  --spring: cubic-bezier(.34, 1.4, .64, 1);          /* a small overshoot (taps, chips) — real spring below where supported */
  --d-1: .16s; --d-2: .28s; --d-3: .48s; --d-4: .8s; /* micro, small, medium, large */

  /* night (the hero, dark panels, the footer) and the glow of the logo green */
  --night: #050D0A; --night-2: #0A1712; --night-3: #11261C; --glow: #67A05F; --glow-hi: #A6F094;
}
@media (min-width: 980px) { :root { --nav-h: 72px; } }

/* ————— reset ————— */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + 12px); }
body {
  font-family: var(--font); font-size: var(--fs-body); line-height: 1.6; color: var(--ink); background: var(--bg);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility;
  overflow-x: clip; min-height: 100dvh;
}
html[lang="ar"] body { font-family: var(--font-ar); line-height: 1.75; }
img, svg, video, canvas { display: block; max-width: 100%; }
img, video { height: auto; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
h1, h2, h3, h4 { font-weight: 500; line-height: 1.08; letter-spacing: -.035em; text-wrap: balance; }
html[lang="ar"] :is(h1, h2, h3, h4) { letter-spacing: 0; line-height: 1.3; font-weight: 600; }
p { text-wrap: pretty; }
:focus-visible { outline: 2.5px solid var(--green-600); outline-offset: 3px; border-radius: 6px; }
::selection { background: var(--green-200); color: var(--ink); }
.skip { position: absolute; inset-inline-start: 12px; top: -60px; z-index: 200; background: var(--ink); color: var(--bg); padding: 10px 16px; border-radius: var(--r-s); transition: top var(--t-fast); }
.skip:focus { top: 12px; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Latin runs inside Arabic text (brand names, English samples) keep the Latin face and direction */
.latin { font-family: var(--font); direction: ltr; unicode-bidi: isolate; letter-spacing: -.01em; }
/* Hassaniya / Arabic samples shown on the French and English pages */
.arabic { font-family: var(--font-ar); direction: rtl; unicode-bidi: isolate; letter-spacing: 0; line-height: 1.7; }

/* ————— layout ————— */
.container { width: 100%; max-width: calc(var(--max) + 2 * var(--gutter)); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section); position: relative; }
.section--tight { padding-block: calc(var(--section) * .62); }
.section--band { background: var(--bg-2); }
.section--dark { background: var(--green-900); color: var(--on-dark); }
.section--dark .lead, .section--dark .muted { color: var(--on-dark-2); }
.section--dark :focus-visible { outline-color: var(--gold-500); }
.grid { display: grid; gap: var(--gap); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 720px) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 960px) { .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ————— type ————— */
.eyebrow { display: inline-flex; align-items: center; gap: .5em; justify-self: start; min-height: 30px; padding: .2em .9em; border-radius: var(--pill); box-shadow: inset 0 0 0 1px var(--line); background: var(--surface); font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .01em; color: var(--ink-2); }
.eyebrow::before { content: ""; inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--green-500); flex: none; }
.section--dark .eyebrow { background: rgba(243, 247, 242, .06); box-shadow: inset 0 0 0 1px var(--on-dark-line); }
html[lang="ar"] .eyebrow { letter-spacing: 0; font-size: .875rem; }
.section--dark .eyebrow { color: var(--on-dark-2); }
.display { font-size: var(--fs-display); letter-spacing: -.045em; line-height: 1.01; }
html[lang="ar"] .display { letter-spacing: 0; line-height: 1.22; }
.h2 { font-size: var(--fs-h2); }
.h3 { font-size: var(--fs-h3); letter-spacing: -.02em; line-height: 1.2; font-weight: 600; }
.lead { font-size: var(--fs-lead); line-height: 1.55; color: var(--ink-2); font-weight: 400; max-width: 34em; }
.muted { color: var(--muted); }
.small { font-size: var(--fs-small); }
.tiny { font-size: var(--fs-tiny); }
/* the standard section header: eyebrow, title, lead — stacked, start-aligned */
.head { display: grid; gap: 1rem; margin-block-end: clamp(2.5rem, 5vw, 4.25rem); max-width: 44rem; }
.head .eyebrow { margin-block-end: .1rem; }

/* ————— buttons ————— */
.btn {
  --btn-bg: var(--ink); --btn-fg: #fff; --btn-bd: transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: .6em; min-height: 48px; padding: .7em 1.35em;
  border-radius: var(--pill); background: var(--btn-bg); color: var(--btn-fg); box-shadow: inset 0 0 0 1.5px var(--btn-bd);
  font-weight: 600; font-size: var(--fs-small); line-height: 1.2; white-space: nowrap; text-align: center;
  transition: transform var(--t-fast) var(--ease), background-color var(--t-fast), box-shadow var(--t-fast);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.btn:hover { --btn-bg: #1C2B23; }
.section--dark .btn:not(.btn--ghost) { --btn-bg: #fff; --btn-fg: var(--night); }
.section--dark .btn:not(.btn--ghost):hover { --btn-bg: #E9F3E6; }
.btn:active { transform: scale(.98); }
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: rgba(10, 20, 16, .16); }
.btn--ghost:hover { --btn-bg: rgba(15, 26, 21, .04); --btn-bd: rgba(15, 26, 21, .32); }
.btn--gold { --btn-bg: var(--gold-200); --btn-fg: var(--green-950); }
.btn--gold:hover { --btn-bg: #E9F3E6; }
.section--dark .btn--ghost { --btn-fg: var(--on-dark); --btn-bd: rgba(244, 241, 232, .28); }
.section--dark .btn--ghost:hover { --btn-bg: rgba(244, 241, 232, .07); --btn-bd: rgba(244, 241, 232, .5); }
.btn--small { min-height: 40px; padding: .5em 1.05em; font-size: var(--fs-tiny); }
.btn--block { width: 100%; }
/* the trailing arrow: put <span class="arrow" aria-hidden="true"></span> inside a .btn or .link (it flips in RTL) */
.arrow { inline-size: 1.05em; block-size: 1.05em; flex: none; background: currentColor; transition: transform var(--t-fast) var(--ease);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 10h12M11 5l5 5-5 5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 10h12M11 5l5 5-5 5'/%3E%3C/svg%3E") center / contain no-repeat; }
[dir="rtl"] .arrow { transform: scaleX(-1); }
:is(.btn, .link):hover .arrow { transform: translateX(3px); }
[dir="rtl"] :is(.btn, .link):hover .arrow { transform: scaleX(-1) translateX(3px); }
.link { display: inline-flex; align-items: center; gap: .5em; font-weight: 600; font-size: var(--fs-small); color: var(--green-700); min-height: 44px; }
.section--dark .link { color: var(--on-dark); }

/* ————— surfaces ————— */
.card { background: var(--surface); border-radius: var(--r-l); box-shadow: inset 0 0 0 1px var(--line-2), var(--shadow-1); padding: clamp(1.25rem, 2.6vw, 2rem); position: relative; }
.card--flat { box-shadow: inset 0 0 0 1px var(--line); }
.card--lift { box-shadow: inset 0 0 0 1px var(--line-2), var(--shadow-2); }
.well { inline-size: 52px; block-size: 52px; flex: none; border-radius: 50%; background: var(--green-100); color: var(--green-700); display: grid; place-items: center; }
.tag { display: inline-flex; align-items: center; min-height: 26px; padding: .1em .75em; border-radius: var(--pill); background: var(--green-100); color: var(--green-800); font-size: var(--fs-tiny); font-weight: 600; }
.tag--gold { background: var(--gold-100); color: var(--gold-700); }
.hairline { block-size: 1px; background: var(--line); border: 0; }
/* a real product clip or still inside a card: rounded, edge-lit, never a pasted box */
.media { border-radius: var(--r-m); overflow: hidden; background: var(--sand-100); box-shadow: inset 0 0 0 1px var(--line-2); position: relative; aspect-ratio: 16 / 9; }
.media > :is(video, img) { inline-size: 100%; block-size: 100%; object-fit: cover; }

/* ————— forms ————— */
.field { display: grid; gap: .4rem; }
.field > label { font-size: var(--fs-tiny); font-weight: 600; color: var(--ink-2); }
.input { inline-size: 100%; min-height: 50px; padding: .75em 1em; border-radius: var(--r-s); background: var(--surface); border: 0; box-shadow: inset 0 0 0 1.5px var(--line); font-size: 1rem; /* 16px: no zoom on iOS */ transition: box-shadow var(--t-fast); }
.input::placeholder { color: var(--muted); }
.input:hover { box-shadow: inset 0 0 0 1.5px rgba(15, 26, 21, .22); }
.input:focus { outline: 0; box-shadow: inset 0 0 0 2px var(--green-600); }
textarea.input { min-height: 120px; resize: vertical; line-height: 1.5; }

/* ————— motion: reveal on scroll (core.js adds .is-in; .is-static shows everything at rest) ————— */
.js:not(.is-static) [data-reveal] { opacity: 0; transform: translateY(12px); transition: opacity .45s var(--ease), transform .45s var(--ease); transition-delay: calc(var(--i, 0) * 45ms); will-change: transform, opacity; }
.js:not(.is-static) [data-reveal].is-in { opacity: 1; transform: none; will-change: auto; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}

/* ————— shared pieces every section draws the same way ————— */
.icon { inline-size: 24px; block-size: 24px; flex: none; }
.well .icon { inline-size: 26px; block-size: 26px; }
.logo { display: inline-flex; align-items: center; gap: .6rem; font-family: "Quicksand", var(--font); font-weight: 500; font-size: 1.5rem; line-height: 1; letter-spacing: -.01em; color: var(--ink); direction: ltr; }
.logo b { font-weight: inherit; color: var(--green-500); }
.logo-mark { inline-size: 34px; block-size: auto; color: var(--green-500); flex: none; }
.section--dark .logo, .on-night .logo { color: #fff; }

/* Hassaniya sample text, with its optional translation line under it (the gloss is empty on the Arabic page) */
.ha { font-family: var(--font-ar); direction: rtl; unicode-bidi: isolate; font-weight: 600; font-size: 1.1875rem; line-height: 1.6; color: var(--ink); letter-spacing: 0; }
.ha--lg { font-size: clamp(1.3rem, 1.2vw + 1.05rem, 1.75rem); }
.gloss { display: block; font-family: var(--font); direction: ltr; font-size: var(--fs-tiny); line-height: 1.45; color: var(--muted); font-weight: 500; }
.gloss:empty { display: none; }
.section--dark .ha { color: var(--on-dark); }
.section--dark .gloss { color: var(--on-dark-2); }

/* the small demo surface inside a card (a waveform turning into text, a chat, a translation) */
.mini { background: var(--bg); border-radius: var(--r-m); box-shadow: inset 0 0 0 1px var(--line-2); padding: clamp(.9rem, 2vw, 1.25rem); }

/* waveform: core.js mountWave(el) fills it with bars; .is-playing makes it breathe. Always left to right. */
.wave { display: flex; align-items: center; gap: clamp(1.5px, .55vw, 3px); block-size: 46px; direction: ltr; min-inline-size: 0; overflow: hidden; }
.wave > i { flex: 1 1 0; min-inline-size: 1.5px; max-inline-size: 4px; block-size: calc(var(--h, .5) * 100%); border-radius: 3px; background: var(--green-500); transform-origin: center; }
.wave > i.g { background: var(--green-800); }
.wave > i.off { background: var(--green-200); }   /* the part not yet played */
.section--dark .wave > i { background: var(--green-500); }
.section--dark .wave > i.g { background: var(--glow-hi); }
.section--dark .wave > i.off { background: rgba(244, 241, 232, .22); }
.wave.is-playing > i { animation: wave-breathe 1s var(--ease-soft) infinite alternate; animation-delay: calc(var(--d, 0) * -1ms); }
@keyframes wave-breathe { from { transform: scaleY(.5); } to { transform: scaleY(1); } }

/* chat bubbles (a column: .chat) */
.chat { display: flex; flex-direction: column; gap: .6rem; }
.bubble { max-inline-size: 86%; padding: .65rem .95rem; border-radius: 18px; background: var(--green-100); align-self: flex-start; border-end-start-radius: 6px; }
.bubble--user { background: var(--sand-100); align-self: flex-end; border-end-start-radius: 18px; border-end-end-radius: 6px; }
.section--dark .bubble { background: rgba(244, 241, 232, .10); }
.section--dark .bubble--user { background: rgba(244, 241, 232, .18); }

/* the round play button used by every audio example */
.playbtn { inline-size: 52px; block-size: 52px; flex: none; border-radius: 50%; background: var(--green-500); color: #fff; display: grid; place-items: center; transition: transform var(--t-fast) var(--ease), background-color var(--t-fast); box-shadow: 0 6px 18px rgba(103, 160, 95, .32); }
.playbtn:hover { background: var(--green-600); }
.playbtn:active { transform: scale(.96); }
.playbtn .icon { inline-size: 22px; block-size: 22px; }
.section--dark .playbtn { background: var(--gold-200); color: var(--green-950); box-shadow: none; }

.section > .container { position: relative; z-index: 1; }

/* a dark rounded panel on the light page: add class="section--dark panel" to a div inside a section */
.panel { position: relative; overflow: hidden; isolation: isolate; border-radius: var(--r-xl); background: var(--night-2); color: var(--on-dark); padding: clamp(1.5rem, 5vw, 4.5rem); }
.panel::before { content: ""; position: absolute; z-index: -1; inset: 0; pointer-events: none;
  background: radial-gradient(70% 90% at 88% -10%, rgba(103, 160, 95, .42), transparent 62%), radial-gradient(60% 70% at 0% 110%, rgba(103, 160, 95, .16), transparent 60%); }
/* the second line of a headline in the logo green (on night: a soft green gradient) */
.accent { color: var(--green-600); }
.section--dark .accent, .on-night .accent { background: linear-gradient(100deg, #8FD483, #67A05F 70%); -webkit-background-clip: text; background-clip: text; color: transparent; }

/* ————— helpers ————— */
.row { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1rem; }
.stack { display: grid; gap: var(--gap); }
.center { text-align: center; margin-inline: auto; }
[hidden] { display: none !important; }

/* a real spring where the browser supports linear() easing */
@supports (transition-timing-function: linear(0, 1)) {
  :root { --spring: linear(0, .009, .035 2.1%, .141 4.4%, .723 12.9%, .938 16.7%, 1.017, 1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%, 1.051 39.6%, 1.017 43.1%, .991, .977 51%, .974 53.8%, .975 57.1%, .997 69.8%, 1.003 76.9%, 1.004 83.8%, 1); }
}


/* ===== nav ===== */
/* nav — the fixed bar, the language switch (also used in the footer) and the phone menu sheet.
   The bar is always light on night: clear over the night hero at the very top, a night glass bar everywhere else.
   Motion (v4): only opacity and transform move, on the shared curves; every state is one class, so a second tap
   in the middle of a change simply turns it round from where it is. */

.nav, .nav-sheet, .footer { --nav-d-line: calc(var(--d-1) * 1.25); /* .2 s: the underlines */ --nav-d-tap: calc(var(--d-1) / 2); /* a press lands at once */ }

/* 1 px sentinel near the top of the page: when it leaves the viewport the bar takes its "scrolled" glass state */
.nav-sentinel { position: absolute; inset-block-start: 20px; inset-inline: 0; block-size: 1px; pointer-events: none; }

.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100; block-size: var(--nav-h); color: var(--on-dark);
  padding-left: var(--nav-lock-l, 0px); padding-right: var(--nav-lock-r, 0px);   /* the width of a scrollbar the open menu took away (nav.js) */
}
.nav :focus-visible, .nav-sheet :focus-visible { outline: 2px solid var(--green-300); outline-offset: 3px; }
/* the bar surface lives on a pseudo-element: the blur never becomes a containing block and only its opacity moves
   (never the blur itself). The hairline is part of it, so the two cross-fade together.
   Dark enough that the light text stays readable over the light sections too. */
.nav::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: rgba(5, 13, 10, .95);                           /* --night, nearly solid: the fallback with no backdrop-filter */
  box-shadow: inset 0 -1px 0 var(--on-dark-line);
  transition: opacity var(--d-2) var(--ease-out);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav::before { background: rgba(5, 13, 10, .9); -webkit-backdrop-filter: saturate(1.4) blur(16px); backdrop-filter: saturate(1.4) blur(16px); }   /* .72 turned grey over the light sections */
}
/* at the very top the hero's night shows through (without JavaScript the bar simply stays solid).
   Open, the bar keeps its glass: the night sheet fades in right under it, so the two arrive as one surface. */
.js .nav:not(.is-scrolled):not(.is-open)::before { opacity: 0; }

.nav-bar { block-size: 100%; display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.nav-home { display: inline-flex; align-items: center; justify-self: start; min-block-size: 44px; border-radius: var(--r-s); flex: none; -webkit-tap-highlight-color: transparent; transition: opacity var(--d-1) var(--ease-out); }
.nav-home:active { opacity: .72; transition-duration: var(--nav-d-tap); }
/* the lockup of the real logo: the mark is 1.48 × the type size wide, the gap .36, the mark centred on the capitals */
.nav-home .logo { font-size: 1.375rem; gap: .36em; }
.nav-home .logo-mark { inline-size: 1.48em; position: relative; inset-block-start: .05em; }

.nav-links { display: none; }
.nav-cta { display: none; }
.nav-end { display: flex; align-items: center; gap: .375rem; margin-inline-end: -.5rem; /* the menu icon lines up with the gutter */ }

/* ————— language switch: a compact segmented control on night (the bar, the sheet, the footer).
   Three equal segments and ONE thumb under the page's language. A tap on another language sends the thumb
   on its way (nav.js sets data-go) while the browser loads that page, where the thumb is already in place. ————— */
.nav-lang {
  --nav-lang-pad: 3px; --nav-lang-at: 0;
  position: relative; isolation: isolate; display: inline-grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: center;
  padding: var(--nav-lang-pad); border-radius: var(--pill); direction: ltr;   /* FR · EN · ع keep one order on every page */
  background: rgba(243, 247, 242, .06); box-shadow: inset 0 0 0 1px var(--on-dark-line);
  transition: opacity var(--d-2) var(--ease-out), visibility 0s;
}
html[lang="en"] .nav-lang { --nav-lang-at: 1; }
html[lang="ar"] .nav-lang { --nav-lang-at: 2; }
html .nav-lang[data-go="fr"] { --nav-lang-at: 0; }
html .nav-lang[data-go="en"] { --nav-lang-at: 1; }
html .nav-lang[data-go="ar"] { --nav-lang-at: 2; }
.nav-lang::before {
  content: ""; position: absolute; z-index: -1; inset-block: var(--nav-lang-pad); left: var(--nav-lang-pad);
  inline-size: calc((100% - 2 * var(--nav-lang-pad)) / 3); border-radius: var(--pill); background: rgba(243, 247, 242, .16);
  transform: translateX(calc(100% * var(--nav-lang-at))); transition: transform var(--d-2) var(--ease-in-out);
}
.nav-lang a {
  position: relative; display: grid; place-items: center; min-inline-size: 40px; block-size: 30px; padding-inline: .5rem;
  border-radius: var(--pill); font-family: var(--font); font-size: .8125rem; font-weight: 600; letter-spacing: .03em; line-height: 1; color: var(--on-dark-2);
  transition: color var(--d-1) var(--ease-out), transform var(--d-3) var(--spring);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.nav-lang a::after { content: ""; position: absolute; inset: -10px -1px; }   /* 44 px+ tall touch target, no visual change */
.nav-lang a::before { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; background: rgba(243, 247, 242, .07); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
.nav-lang a[lang="ar"] { font-family: var(--font-ar); font-size: .9375rem; letter-spacing: 0; padding-block-end: 2px; }
html[lang="fr"] .nav-lang a[hreflang="fr"],
html[lang="en"] .nav-lang a[hreflang="en"],
html[lang="ar"] .nav-lang a[hreflang="ar"],
.nav-lang a[aria-current="true"] { color: var(--surface); }
@media (hover: hover) {
  .nav-lang a:hover { color: var(--on-dark); }
  html[lang="fr"] .nav-lang a:not([hreflang="fr"]):hover::before,
  html[lang="en"] .nav-lang a:not([hreflang="en"]):hover::before,
  html[lang="ar"] .nav-lang a:not([hreflang="ar"]):hover::before { opacity: 1; }
}
.nav-lang a:active { transform: scale(.95); transition-duration: var(--d-1), var(--nav-d-tap); }
.nav-lang a:focus-visible { outline-offset: 2px; }

/* full names (menu sheet): three equal segments across the width */
.nav-lang--full { --nav-lang-pad: 4px; display: grid; inline-size: 100%; }
.nav-lang--full a { block-size: 44px; font-size: .9375rem; letter-spacing: 0; font-weight: 500; }
.nav-lang--full a::after { inset: -4px 0; }
.nav-lang--full a[lang="ar"] { font-size: 1.0625rem; }
.nav-lang--full a:active { transform: scale(.97); }

/* ————— menu button (phone): two bars that turn into a cross (transform only) ————— */
.nav-toggle {
  position: relative; inline-size: 44px; block-size: 44px; flex: none; display: grid; place-items: center; border-radius: 50%; color: var(--on-dark);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation; transition: transform var(--d-3) var(--spring);
}
.nav-toggle::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: rgba(243, 247, 242, .08); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
@media (hover: hover) { .nav-toggle:hover::before { opacity: 1; } }   /* no sticky hover after a tap */
.nav-toggle:active { transform: scale(.92); transition-duration: var(--nav-d-tap); }
.nav-toggle-bars { position: relative; display: block; inline-size: 24px; block-size: 24px; }
.nav-toggle-bars i { position: absolute; left: 4px; inline-size: 16px; block-size: 2px; border-radius: 1px; background: currentColor; transition: transform var(--d-2) var(--ease-out); }
.nav-toggle-bars i:first-child { top: 7px; }
.nav-toggle-bars i:last-child { top: 15px; }
/* the cross of the icon set: corner to corner of the 12 × 12 middle (the bars meet in the centre, turn, and grow by 6 %) */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars i:first-child { transform: translateY(4px) rotate(45deg) scaleX(1.06); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars i:last-child { transform: translateY(-4px) rotate(-45deg) scaleX(1.06); }
/* where the browser can move and turn a thing separately, the change is in two overlapping steps: the bars meet in the
   middle as one line, which then opens into the cross; closing, the cross folds back to one line, which then parts */
@supports (translate: 0px) and (rotate: 0deg) and (scale: 1) {
  .nav-toggle-bars i { transition: translate var(--d-1) var(--ease-in-out) calc(var(--d-1) * .75), rotate var(--d-2) var(--ease-out), scale var(--d-2) var(--ease-out); }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars i { transition: translate var(--d-1) var(--ease-in-out), rotate var(--d-2) var(--ease-out) calc(var(--d-1) * .5), scale var(--d-2) var(--ease-out) calc(var(--d-1) * .5); }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars i:first-child { transform: none; translate: 0 4px; rotate: 45deg; scale: 1.06 1; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars i:last-child { transform: none; translate: 0 -4px; rotate: -45deg; scale: 1.06 1; }
}
html:not(.js) .nav-toggle { display: none; }   /* without JavaScript there is no menu to open */

/* while the sheet is open it carries the language choice: the compact one steps back */
.nav.is-open .nav-end > .nav-lang { opacity: 0; visibility: hidden; transition: opacity var(--d-1) var(--ease-out), visibility 0s linear var(--d-1); }

/* the white pill, in the bar and in the sheet: the hover tint is a layer that fades (the fill itself never changes) */
.nav-cta, .nav-sheet-cta { --btn-bg: var(--surface); --btn-fg: var(--night); position: relative; isolation: isolate; transition: transform var(--d-3) var(--spring); }
.nav-cta:hover, .nav-sheet-cta:hover { --btn-bg: var(--surface); }
.nav-cta::before, .nav-sheet-cta::before { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; background: var(--green-100); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
@media (hover: hover) { .nav-cta:hover::before, .nav-sheet-cta:hover::before { opacity: 1; } }
.nav-cta:active, .nav-sheet-cta:active { transform: scale(.97); transition-duration: var(--nav-d-tap); }
.nav-cta:active::before, .nav-sheet-cta:active::before { opacity: 1; transition-duration: var(--nav-d-tap); }
.nav-sheet-cta .arrow { transition: transform var(--d-2) var(--ease-out); }

/* ————— the menu sheet (phone): night, calm, full screen. The links at the top, the language at the thumb.
   Open: the sheet fades in (.28 s) and its six rows rise one after the other (35 ms apart).
   Close: the whole sheet fades (.16 s) with its rows held where they are; they go back to their start once it is unseen. ————— */
html.nav-open { overflow: hidden; }
html.nav-open body { padding-left: var(--nav-lock-l, 0px); padding-right: var(--nav-lock-r, 0px); }   /* nothing moves when the scrollbar goes */
.nav-sheet {
  position: fixed; inset: 0; z-index: 99; color: var(--on-dark); padding-block-start: var(--nav-h);
  padding-left: var(--nav-lock-l, 0px); padding-right: var(--nav-lock-r, 0px);
  background: radial-gradient(130% 42% at 50% 112%, rgba(103, 160, 95, .3), transparent 72%), var(--night);   /* the hero's glow, low and faint */
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  visibility: hidden; opacity: 0; transition: opacity var(--d-1) var(--ease-out), visibility 0s linear var(--d-1);
}
.nav-sheet.is-open { visibility: visible; opacity: 1; transition: opacity var(--d-2) var(--ease-out), visibility 0s; }
.nav-sheet-inner {
  display: flex; flex-direction: column; min-block-size: 100%;
  padding-block: 1rem max(1.5rem, calc(env(safe-area-inset-bottom) + .75rem));
}
.nav-sheet-links { display: grid; }
.nav-sheet-links a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-block-size: 72px; padding-block: .5rem;
  border-block-end: 1px solid var(--on-dark-line);
  font-size: clamp(1.625rem, 6.2vw, 2rem); font-weight: 500; letter-spacing: -.03em; line-height: 1.15; color: var(--on-dark);
  -webkit-tap-highlight-color: transparent;
}
html[lang="ar"] .nav-sheet-links a { letter-spacing: 0; }
.nav-sheet-links a > span:first-child { transition: color var(--d-1) var(--ease-out); }
.nav-sheet-links a .arrow { inline-size: 1.25rem; block-size: 1.25rem; color: var(--green-500); transition: transform var(--d-2) var(--ease-out); }
.nav-sheet-links a:active > span:first-child, .nav-sheet-links a[aria-current] > span:first-child { color: var(--green-300); }
.nav-sheet-links a:active .arrow { transform: translateX(4px); transition-duration: var(--nav-d-tap); }
[dir="rtl"] .nav-sheet-links a:active .arrow { transform: scaleX(-1) translateX(4px); }
.nav-sheet-act { margin-block: 2.25rem 2.5rem; }
.nav-sheet-cta { min-height: 56px; font-size: 1rem; }
.nav-sheet-lang { margin-block-start: auto; }   /* rests at the foot of the sheet; the button's margin keeps a clear gap on a short screen */

.nav-sheet-links a, .nav-sheet-act, .nav-sheet-lang {
  opacity: 0; transform: translateY(12px);
  transition: opacity 0s linear var(--d-1), transform 0s linear var(--d-1);
}
.nav-sheet.is-open :is(.nav-sheet-links a, .nav-sheet-act, .nav-sheet-lang) {
  opacity: 1; transform: none;
  transition: opacity var(--d-2) var(--ease-out), transform var(--d-3) var(--ease-out); transition-delay: calc(40ms + var(--i, 0) * 35ms);
}
.is-static :is(.nav, .nav-sheet), .is-static :is(.nav, .nav-sheet)::before,
.is-static :is(.nav, .nav-sheet) *, .is-static :is(.nav, .nav-sheet) *::before, .is-static :is(.nav, .nav-sheet) *::after { transition: none !important; }

/* very small phones (320 px): everything still fits on the bar */
@media (max-width: 359px) {
  .nav-home .logo { font-size: 1.1875rem; }
  .nav-lang a { min-inline-size: 32px; padding-inline: .3rem; }
}

/* ————— desktop (980 px: the logo, four links, the switch and the button fit on one line in French) ————— */
@media (min-width: 980px) {
  .nav-bar { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 1.5rem; }
  .nav-home .logo { font-size: 1.5rem; }
  .nav-links { position: relative; display: flex; align-items: center; justify-content: center; gap: clamp(.25rem, 1.2vw, 1rem); }
  .nav-links a {
    position: relative; display: inline-flex; align-items: center; min-block-size: 44px; padding-inline: .8rem; border-radius: var(--pill);
    font-size: var(--fs-small); font-weight: 500; color: var(--on-dark-2); white-space: nowrap; transition: color var(--d-1) var(--ease-out);
    -webkit-tap-highlight-color: transparent;
  }
  /* under the pointer: a hairline that grows from the start of the word, and leaves by its end */
  .nav-links a::after {
    content: ""; position: absolute; inset-inline: .8rem; inset-block-end: 8px; block-size: 1px; background: currentColor; opacity: .5;
    transform: scaleX(0); transform-origin: 100% 50%; transition: transform var(--nav-d-line) var(--ease-out);
  }
  [dir="rtl"] .nav-links a::after { transform-origin: 0 50%; }
  .nav-links a[aria-current] { color: var(--surface); }
  .nav-links a:active { color: var(--green-300); transition-duration: var(--nav-d-tap); }
  @media (hover: hover) {
    .nav-links a:hover { color: var(--surface); }
    .nav-links a:hover::after { transform: scaleX(1); transform-origin: 0 50%; }
    [dir="rtl"] .nav-links a:hover::after { transform-origin: 100% 50%; }
  }
  /* the section in view: ONE green line, 1 px wide at rest and stretched and moved by nav.js (transform only) */
  .nav-marker {
    position: absolute; left: 0; inset-block-end: 7px; inline-size: 1px; block-size: 2px; background: var(--green-500); pointer-events: none;
    opacity: 0; transform-origin: 0 50%;
    transition: transform var(--d-3) var(--ease-in-out), opacity var(--d-2) var(--ease-out);
  }
  .nav-marker.is-on { opacity: 1; }
  .nav-marker.is-snap { transition: opacity var(--d-2) var(--ease-out); }   /* put in place without a slide (first time, a resize) */
  .is-static .nav-marker { transition: none; }
  .nav-end { gap: .875rem; margin-inline-end: 0; }
  .nav-cta { display: inline-flex; }
  .nav-toggle { display: none; }
  .nav-sheet { display: none; }
  .nav-lang a::after { inset: -7px -1px; }
}
@media (max-width: 979.98px) { .nav-marker { display: none; } }
/* wide enough for the links to sit on the true centre of the page */
@media (min-width: 1120px) {
  .nav-bar { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
  .nav-end { justify-self: end; }
}


/* ===== hero ===== */
/* ===== hero: night, a centred headline, and a dome of light made of voice bars that melts into the light page =====
   Layers: .hero-glow (the light: .hero-light = CSS gradients · .hero-haze + .hero-dome = two canvases drawn by js/hero.js ·
   .hero-melt = the page's light rising through the bottom) · the words · the card.
   data-bg on the section picks the light: "dome" (bars) or "plain" (a soft arc, CSS only).
   Motion: everything is transform / opacity, on the shared curves of base.css (--ease-out, --spring, --d-1…4). */
.hero {
  --hero-top: clamp(2.5rem, 6vw, 3.5rem);        /* the air between the nav and the badge */
  --hero-stage: clamp(19.5rem, 84vw, 23rem);     /* the room under the buttons: the dome and the card live here */
  --hero-melt: clamp(7.5rem, 26vw, 13rem);       /* how far up the page's light reaches */
  --hero-foot: clamp(2.25rem, 7vw, 3.75rem);     /* the light under the card (its shadow is sized to end inside it) */
  background: var(--night);
  display: flex; flex-direction: column;
  min-block-size: 100vh; min-block-size: min(100svh, 60rem);
  padding-block: calc(var(--nav-h) + var(--hero-top)) 0;
  overflow: hidden; overflow: clip;
  isolation: isolate;
}
.hero > .container { flex: 1 1 auto; display: flex; flex-direction: column; }

/* ————— the words ————— */
.hero-copy { display: grid; justify-items: center; text-align: center; inline-size: 100%; max-inline-size: 56rem; margin-inline: auto; }
.hero-copy .eyebrow { justify-self: center; margin-block-end: clamp(1.25rem, 3vw, 1.75rem); }
.hero-copy .display { --hero-fs: var(--fs-display); font-size: var(--hero-fs); color: var(--surface); margin-block-end: clamp(1.1rem, 2.4vw, 1.6rem); }
html[lang="ar"] .hero-copy .display { font-size: min(var(--hero-fs), 10.8vw); }   /* the Arabic claim is wider: on the smallest phones it still holds one line */
/* two lines, always: the claim, then the accent line in the logo green (its padding keeps descenders inside the painted text) */
.hero-line { display: block; }
.hero-copy .display .accent { white-space: nowrap; padding-block: .06em .16em; margin-block: -.06em -.16em; }
.hero-copy .lead { max-inline-size: 34em; text-wrap: balance; margin-block-end: clamp(1.75rem, 4vw, 2.5rem); }
.hero-cta { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .4rem 1.75rem; }

/* the button of the reference: a white pill that carries its arrow in a dark disc.
   It rests a breath under pure white; the hover fades a white overlay and a soft halo in (opacity only). */
.hero .hero-cta .btn {
  --btn-bg: var(--on-dark);
  position: relative; isolation: isolate; gap: .85em; padding-inline-end: .5em;
  transition: transform var(--d-3) var(--spring);
}
.hero .hero-cta .btn:hover { --btn-bg: var(--on-dark); }
.hero-cta .btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  background: var(--surface);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, .07), 0 8px 30px -8px var(--glow-hi);
  opacity: 0; transition: opacity var(--d-2) var(--ease-out);
}
.hero .hero-cta .btn:active { transform: scale(.97); transition-duration: .08s; transition-timing-function: var(--ease-out); }
.hero-cta .btn .arrow {
  inline-size: 2.15em; block-size: 2.15em; transition: transform var(--d-2) var(--ease-out);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Cmask id='m'%3E%3Crect width='28' height='28' fill='%23fff'/%3E%3Cpath d='M9 14h10M14.8 9.8l4.2 4.2-4.2 4.2' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/mask%3E%3Ccircle cx='14' cy='14' r='14' mask='url(%23m)'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Cmask id='m'%3E%3Crect width='28' height='28' fill='%23fff'/%3E%3Cpath d='M9 14h10M14.8 9.8l4.2 4.2-4.2 4.2' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/mask%3E%3Ccircle cx='14' cy='14' r='14' mask='url(%23m)'/%3E%3C/svg%3E");
}
/* the text link: a pill-shaped focus ring, an arrow that nudges */
.hero-cta .link { padding-inline: .7em; margin-inline: -.7em; border-radius: var(--pill); -webkit-tap-highlight-color: transparent; }
.hero-cta .link .arrow { transition: transform var(--d-2) var(--ease-out); }
/* a tap leaves no stuck hover: the arrows only travel under a real pointer, or while pressed */
.hero .hero-cta :is(.btn, .link):hover .arrow { transform: none; }
[dir="rtl"] .hero .hero-cta :is(.btn, .link):hover .arrow { transform: scaleX(-1); }
@media (hover: hover) {
  .hero-cta .btn:hover::before { opacity: 1; }
  .hero .hero-cta .btn:hover .arrow { transform: translateX(2px); }
  [dir="rtl"] .hero .hero-cta .btn:hover .arrow { transform: scaleX(-1) translateX(2px); }
  .hero .hero-cta .link:hover .arrow { transform: translateX(3px); }
  [dir="rtl"] .hero .hero-cta .link:hover .arrow { transform: scaleX(-1) translateX(3px); }
}
.hero .hero-cta .link:active .arrow { transform: translateX(5px); transition-duration: .08s; }
[dir="rtl"] .hero .hero-cta .link:active .arrow { transform: scaleX(-1) translateX(5px); }
.hero-copy :focus-visible { outline: 2px solid var(--glow-hi); outline-offset: 3px; }

/* ————— the entrance (first load, once, about 1.1 s): badge → the two lines → sub → the pill lands → the link →
   the light blooms and the bars rise (js) → the card lifts into the glow. Pure CSS, so the headline never waits for
   a script; "backwards" only holds the first frame during each delay, so every end state is the plain element
   (transform: none, crisp text, free for :active). js/hero.js reads this clock for the bars and the card's words. ————— */
@keyframes hero-rise { from { opacity: 0; transform: translate3d(0, var(--in-y, 12px), 0); } }
@keyframes hero-fade { from { opacity: 0; } }
@keyframes hero-land { from { transform: translate3d(0, 10px, 0) scale(.94); } }
@keyframes hero-bloom { from { opacity: .5; transform: translate3d(0, 6%, 0) scale(1, .66); } }   /* a low ember from the first frame, then it swells */
.js:not(.is-static) .hero:not(.is-settled) .hero-in { animation: hero-rise var(--in-d, .5s) var(--ease-out) var(--in-at, 0s) backwards; }
.hero-in--badge { --in-at: 0s; --in-d: .42s; --in-y: 8px; }
.hero-in--a { --in-at: .07s; --in-d: .55s; --in-y: 16px; }
.hero-in--b { --in-at: .14s; --in-d: .6s; --in-y: 16px; }
.hero-in--sub { --in-at: .23s; --in-d: .55s; --in-y: 12px; }
.js:not(.is-static) .hero:not(.is-settled) .hero-in--pill { animation: hero-fade .3s var(--ease-out) .32s backwards, hero-land .6s var(--spring) .32s backwards; }
.hero-in--link { --in-at: .39s; --in-d: .5s; --in-y: 10px; }
.js:not(.is-static) .hero:not(.is-settled) .hero-light { animation: hero-bloom var(--d-4) var(--ease-out) .34s backwards; }
.hero-in--card { --in-at: .6s; --in-d: .55s; --in-y: 22px; }

/* ————— the light ————— */
.hero-glow { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero-light { position: absolute; inset: 0; transform-origin: 50% 100%; }
/* the page's own light rises through the bottom of the night: the hero has no edge (an eased ramp: no band, no seam) */
.hero-melt {
  position: absolute; inset-inline: 0; inset-block-end: 0; block-size: var(--hero-melt);
  background: linear-gradient(to top, var(--bg) 6%, transparent);
  background: linear-gradient(to top,
    var(--bg) 6%,
    color-mix(in srgb, var(--bg) 97%, transparent) 16%,
    color-mix(in srgb, var(--bg) 88%, transparent) 26%,
    color-mix(in srgb, var(--bg) 76%, transparent) 36%,
    color-mix(in srgb, var(--bg) 59%, transparent) 47%,
    color-mix(in srgb, var(--bg) 42%, transparent) 58%,
    color-mix(in srgb, var(--bg) 27%, transparent) 68%,
    color-mix(in srgb, var(--bg) 14%, transparent) 78%,
    color-mix(in srgb, var(--bg) 4.5%, transparent) 89%,
    transparent);
}

/* "dome": three depths of light on the horizon, each an eased falloff — far (the night lifting), middle (the body of
   the glow), near (a bright band hugging the horizon and its core). The bars are drawn over it by the canvases. */
.hero[data-bg="dome"] .hero-light {
  background: radial-gradient(ellipse 80% 70% at 50% 100%, var(--night-3), transparent);
  background:
    radial-gradient(ellipse 44% 25% at 50% 100%,
      color-mix(in srgb, var(--glow-hi) 72%, transparent),
      color-mix(in srgb, var(--glow-hi) 65%, transparent) 18%,
      color-mix(in srgb, var(--glow-hi) 50%, transparent) 36%,
      color-mix(in srgb, var(--glow-hi) 31%, transparent) 54%,
      color-mix(in srgb, var(--glow-hi) 14%, transparent) 72%,
      color-mix(in srgb, var(--glow-hi) 3%, transparent) 89%,
      transparent),
    linear-gradient(to top,
      color-mix(in srgb, var(--glow-hi) 80%, transparent),
      color-mix(in srgb, var(--glow) 66%, transparent) 9%,
      color-mix(in srgb, var(--glow) 47%, transparent) 15.5%,
      color-mix(in srgb, var(--glow) 30%, transparent) 22%,
      color-mix(in srgb, var(--glow) 17%, transparent) 28.5%,
      color-mix(in srgb, var(--glow) 8%, transparent) 35%,
      color-mix(in srgb, var(--glow) 2.5%, transparent) 41%,
      transparent 47%),
    radial-gradient(ellipse 74% 63% at 50% 100%,
      color-mix(in srgb, var(--glow) 66%, transparent),
      color-mix(in srgb, var(--glow) 59%, transparent) 18%,
      color-mix(in srgb, var(--glow) 46%, transparent) 36%,
      color-mix(in srgb, var(--glow) 29%, transparent) 54%,
      color-mix(in srgb, var(--glow) 13%, transparent) 72%,
      color-mix(in srgb, var(--glow) 3%, transparent) 89%,
      transparent),
    radial-gradient(ellipse 136% 94% at 50% 100%,
      var(--night-3),
      color-mix(in srgb, var(--night-3) 91%, transparent) 18%,
      color-mix(in srgb, var(--night-3) 70%, transparent) 36%,
      color-mix(in srgb, var(--night-3) 44%, transparent) 54%,
      color-mix(in srgb, var(--night-3) 19%, transparent) 72%,
      color-mix(in srgb, var(--night-3) 4%, transparent) 89%,
      transparent);
}
/* the canvases: .hero-dome holds the bars, on whole device pixels · .hero-haze is their glow, tiny and stretched soft
   (js gives it a transform so that its columns sit under the bars). Physical "left": canvas pixels never mirror. */
.hero-dome, .hero-haze { position: absolute; left: 0; inset-block-end: 0; inline-size: 100%; block-size: min(100%, clamp(24rem, 60vw, 31rem)); max-inline-size: none; }
.hero-haze { transform-origin: 0 0; }

/* "plain": the reference's arc, in green — the night is a wide dark disc, the light shows around its lower rim */
.hero[data-bg="plain"] :is(.hero-dome, .hero-haze) { display: none; }
.hero[data-bg="plain"] .hero-light {
  background:
    radial-gradient(ellipse 68% 56% at 50% 27%, var(--night) 74%, transparent),
    linear-gradient(to bottom, var(--night) 30%, var(--glow) 66%, var(--glow-hi) 84%, var(--bg) 95%);
  background:
    radial-gradient(ellipse 68% 56% at 50% 27%, var(--night) 74%, color-mix(in srgb, var(--night) 82%, transparent) 80%, color-mix(in srgb, var(--night) 50%, transparent) 87%, color-mix(in srgb, var(--night) 18%, transparent) 94%, transparent),
    linear-gradient(to bottom, var(--night) 30%, color-mix(in srgb, var(--glow) 38%, var(--night)) 48%, var(--glow) 66%, var(--glow-hi) 84%, var(--bg) 95%);
}

/* ————— the card: a voice becomes text. A light object standing in the glow ————— */
.hero-stage { flex: 1 1 auto; min-block-size: var(--hero-stage); display: flex; align-items: flex-end; justify-content: center; padding-block: 2rem var(--hero-foot); }
.hero-card {
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: 1rem; row-gap: .85rem;
  inline-size: min(100%, 24rem); padding: 1rem 1.15rem 1.2rem; border-radius: var(--r-l);
  background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px -24px var(--night);
  /* lit from behind: a rim of the dome's light around it, and its own soft shadow on the light below
     (the shadow is measured from --hero-foot: it has faded out before the hero ends, so the page shows no seam) */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--glow-hi) 34%, transparent), 0 -12px 46px -12px color-mix(in srgb, var(--glow-hi) 50%, transparent),
    0 calc(var(--hero-foot) * .28) calc(var(--hero-foot) * .56) calc(var(--hero-foot) * -.3) color-mix(in srgb, var(--night) 50%, transparent);
}
.hero-card-top { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: .75rem; min-block-size: 26px; }
/* "Speech to text · Example": the second part steps down a line (and out of sight) when a long tag needs the room */
.hero-card-label { flex: 1 1 0; min-inline-size: 0; display: flex; flex-wrap: wrap; align-items: center; column-gap: .5em; block-size: 1.5em; overflow: hidden; font-size: var(--fs-tiny); line-height: 1.5; font-weight: 600; color: var(--muted); white-space: nowrap; }
.hero-card-ex { display: inline-flex; align-items: center; gap: .5em; font-weight: 500; }
.hero-card-ex::before { content: ""; inline-size: 3px; block-size: 3px; border-radius: 50%; background: currentColor; opacity: .6; }
/* the use case of the example on show: the tags share one place and cross-fade (the incoming one rises a little) */
.hero-tags { flex: none; display: grid; justify-items: end; align-items: center; }
.hero-tag { grid-area: 1 / 1; white-space: nowrap; opacity: 0; transform: translateY(5px); transition: opacity var(--d-1) var(--ease-out), transform 0s linear var(--d-1); }
.hero-tag.is-on { opacity: 1; transform: none; transition: opacity var(--d-2) var(--ease-out) .08s, transform var(--d-2) var(--ease-out) .08s; }
.hero-tag:empty { display: none; }

/* the play button: there only when the example has a recording. Its place is kept, so nothing moves: an example
   without one shows a quiet microphone ring there (the same sign as in the models section) */
.hero-ctl { position: relative; flex: none; display: grid; inline-size: 48px; block-size: 48px; }
.hero-ctl > * { grid-area: 1 / 1; }
.hero-ghost { display: grid; place-items: center; border-radius: 50%; color: var(--green-600); box-shadow: inset 0 0 0 1px var(--line); pointer-events: none;
  opacity: 0; transform: scale(.82); transition: opacity var(--d-1) var(--ease-out), transform var(--d-1) var(--ease-out); }
.hero-ghost .icon { inline-size: 20px; block-size: 20px; }
html:not(.js) .hero-ghost, .hero-card.is-mute .hero-ghost, .hero-play.is-off + .hero-ghost { opacity: 1; transform: none; transition: opacity var(--d-2) var(--ease-out) .06s, transform var(--d-2) var(--ease-out) .06s; }
.hero-card .playbtn { background: var(--green-500); color: var(--surface); box-shadow: 0 6px 18px color-mix(in srgb, var(--green-500) 32%, transparent); }
.hero-card .playbtn:hover { background: var(--green-500); }
@media (hover: hover) { .hero-card .playbtn:hover { background: var(--green-600); } }
html:not(.js) .hero-play, .hero-card.is-mute .hero-play { display: none; }
.hero-card :focus-visible { outline: 2px solid var(--green-700); outline-offset: 3px; }
.hero-play { position: relative; inline-size: 100%; block-size: 100%; -webkit-tap-highlight-color: transparent; touch-action: manipulation; transition: transform var(--d-3) var(--spring), opacity var(--d-2) var(--ease-out), background-color var(--d-1), visibility 0s; }
.hero-card .hero-play:active { transform: scale(.93); background: var(--green-700); transition-duration: .08s, var(--d-2), .08s, 0s; transition-timing-function: var(--ease-out); }
.hero-play.is-off { opacity: 0; visibility: hidden; transform: scale(.82); pointer-events: none; transition: transform var(--d-1) var(--ease-out), opacity var(--d-1) var(--ease-out), visibility 0s linear var(--d-1); }
/* one ring, once, when a recording becomes available (js/hero.js animates it; at rest it is not there) */
.hero-play-ring { position: absolute; inset: 0; border-radius: 50%; box-shadow: 0 0 0 2px var(--green-500); opacity: 0; pointer-events: none; }
.hero-play-i { grid-area: 1 / 1; display: grid; place-items: center; transition: opacity var(--d-1) var(--ease-out), transform var(--d-2) var(--ease-out); }
.hero-play-i--play { transform: translateX(1px); }
.hero-play-i--pause { opacity: 0; transform: scale(.7); }
.hero-card.is-playing .hero-play-i--play { opacity: 0; transform: scale(.7); }
.hero-card.is-playing .hero-play-i--pause { opacity: 1; transform: none; }

/* the examples lie on one another in a single grid cell: the card always has the height of the tallest one */
.hero-samples { display: grid; align-items: center; min-inline-size: 0; }
.hero-sample { grid-area: 1 / 1; display: block; min-inline-size: 0; line-height: 1.45; text-wrap: balance; }
[dir="ltr"] .hero-sample { text-align: left; }
[dir="rtl"] .hero-sample { text-align: right; }
/* on a left-to-right page the Arabic lines still share their right edge, in a block that hugs the start
   (js/hero.js gives it the width of its widest line) */
.hero-said { display: block; }
[dir="ltr"] .hero-said { text-align: right; margin-inline-start: auto; }
html:not(.js)[dir="ltr"] .hero-said { text-align: left; }   /* no script, no measured width: the plain start-aligned sentence */
.hero-card .ha { color: var(--ink); font-size: clamp(1.25rem, .3vw + 1.18rem, 1.4375rem); }   /* calm, also on a wide screen: sentences of any length fit */
.hero-card .gloss { color: var(--muted); margin-block-start: .1rem; text-wrap: balance; }
.hero-w { display: inline-block; max-inline-size: 100%; }
.hero-w--nb { white-space: nowrap; }
/* the example on show has .is-on; it leaves with a quick fade. (.is-armed, below, is set by the script only.) */
.hero-sample:not(.is-on) { opacity: 0; visibility: hidden; transition: opacity var(--d-1) var(--ease-out), visibility 0s linear var(--d-1); }
/* each word waits for its moment (--at), rises into place, then holds still; the translation follows the last word */
.hero-card.is-armed .hero-w { opacity: 0; transform: translateY(.24em); }
.hero-card.is-armed .is-said .hero-w { opacity: 1; transform: none; transition: opacity var(--d-2) var(--ease-out) var(--at, 0s), transform .4s var(--ease-out) var(--at, 0s); }
.hero-card.is-armed .gloss { opacity: 0; transform: translateY(4px); }
.hero-card.is-armed .is-said .gloss { opacity: 1; transform: none; transition: opacity var(--d-3) var(--ease-out) var(--said, 0s), transform var(--d-3) var(--ease-out) var(--said, 0s); }
/* while the recording plays the sentence stays where it is: it dims, and each word lights up as it is heard */
.hero-card.is-armed .is-listen .hero-w { opacity: .3; transform: none; transition: opacity var(--d-1) linear; }
.hero-card.is-armed .is-listen.is-said .hero-w { opacity: 1; transition: opacity var(--d-2) var(--ease-out) var(--at, 0s); }
.hero-card.is-armed .is-listen .gloss { opacity: 1; transform: none; transition: none; }
.hero-card .is-now :is(.hero-w, .gloss) { transition-delay: 0s !important; }

/* on the dome the bars behind the card are its waveform; the plain glow keeps a small one inside the card */
.hero-wave { display: none; block-size: 40px; transition: opacity var(--d-2) var(--ease-out); }
.hero-wave.is-out { opacity: 0; transition-duration: var(--d-1); }
.hero-card .wave > i { background: var(--green-500); }
.hero-card .wave > i.g { background: var(--green-800); }
/* armed: every bar is pale until the voice has passed it (a delay per bar: --k is its place, --bar the length of the pass) */
.hero-card.is-armed .wave > i { background: var(--green-200); transition: background-color var(--d-1) linear; }
.hero-card.is-armed .wave.is-heard > i { background: var(--green-500); transition-delay: calc(var(--k, 0) * var(--bar, 0s)); }
.hero-card.is-armed .wave.is-heard > i.g { background: var(--green-800); }
.hero[data-bg="plain"] .hero-wave { display: flex; }
.hero[data-bg="plain"] .hero-samples { grid-column: 1 / -1; }

/* ————— wider screens: the same picture, with more room ————— */
@media (min-width: 720px) {
  .hero { --hero-stage: 22rem; }
  .hero-card { inline-size: min(100%, 27rem); padding: 1.15rem 1.4rem 1.35rem; column-gap: 1.15rem; }
  .hero-ctl { inline-size: 52px; block-size: 52px; }
}
/* a desktop: the card is wider, so a long sentence takes fewer lines and the card stays low under the dome */
@media (min-width: 960px) { .hero-card { inline-size: min(100%, 30rem); } }
/* a short, wide window (a 768-pixel laptop, a phone on its side): the whole hero still fits — smaller air, a lower dome.
   (Only where the small-viewport unit exists: an older browser keeps the roomy layout above.) */
@media (min-width: 720px) and (max-height: 860px) {
  @supports (height: 1svh) {
    .hero { --hero-top: clamp(1rem, 4.4svh, 3.5rem); --hero-stage: clamp(12.5rem, 46svh - 4rem, 22rem); --hero-foot: clamp(1.5rem, 4.4svh, 3.75rem); }
    .hero-copy .eyebrow { margin-block-end: clamp(.9rem, 2.6svh, 1.75rem); }
    .hero-copy .display { --hero-fs: min(var(--fs-display), 8.5svh); margin-block-end: clamp(.7rem, 2.6svh, 1.6rem); }
    .hero-copy .lead { margin-block-end: clamp(1.25rem, 3.6svh, 2.5rem); }
    .hero-stage { padding-block-start: 1.25rem; }
    .hero-card { padding-block: .95rem 1.1rem; row-gap: .65rem; }
  }
}

/* greetings in Pulaar and Wolof are written left to right (Latin script); Hassaniya stays right to left */
.hero-sample--ltr .hero-said { direction: ltr; unicode-bidi: isolate; letter-spacing: -.005em; }
[dir="ltr"] .hero-sample--ltr .hero-said { text-align: left; margin-inline-start: 0; }
[dir="rtl"] .hero-sample--ltr .hero-said { text-align: right; }
[dir="rtl"] .hero-sample--ltr .gloss { direction: rtl; font-family: var(--font-ar); }


/* ===== models ===== */
/* models — "Our models", the heart of the page: three calm cards, each one = icon, name, the one "first" sentence,
   one small example that changes (several use cases per model, a chip names the one on screen, dots under it).
   Phone: the cards stack. From 720px: the speech card lies across the top (words | example) and translation and the
   LLM share the row under it. From 1100px: three equal columns.

   How the examples change without moving anything: every example of a model is in the page at once, stacked in one
   grid cell (.models-stage > .models-ex), so the cell always has the height of the tallest one; only the one with
   .is-on is visible. Changes are opacity + a few pixels of transform, never a size. State is carried by classes
   (js/models.js sets them on timers): the end of every sequence is plain CSS, whatever happened to the fades.
   Every class here starts with .models-. */

.models { --models-x: 1; }                 /* +1: things grow towards the right; −1 on the Arabic page */
[dir="rtl"] .models { --models-x: -1; }

.models-grid { display: grid; gap: clamp(1.5rem, 2.2vw, 1.75rem); grid-template-columns: minmax(0, 1fr); }
.models-card { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; row-gap: clamp(1.6rem, 2.4vw, 2rem); min-inline-size: 0;
  padding: clamp(1.5rem, 2.5vw, 2.25rem); padding-block-end: clamp(1rem, 1.9vw, 1.6rem); }

/* the cards arrive one after the other (60 ms apart); once a card has arrived (.is-arrived, set by models.js) its
   transition becomes the quick one of the hover lift */
.js:not(.is-static) .models .models-card[data-reveal] { transform: translateY(16px);
  transition: opacity var(--d-3) var(--ease-out), transform var(--d-3) var(--ease-out); transition-delay: calc((var(--i, 1) - 1) * 60ms); }
.js:not(.is-static) .models .models-card[data-reveal].is-in { transform: none; }
.js .models .models-grid .models-card.is-arrived[data-reveal] { transition: transform var(--d-2) var(--ease-out), opacity var(--d-2) var(--ease-out); transition-delay: 0s; }
/* the deeper shadow of a lifted card is a layer that fades in: the shadow itself never animates */
.models-card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: var(--shadow-2); opacity: 0; pointer-events: none;
  transition: opacity var(--d-2) var(--ease-out); }
.models-top .well { transition: transform var(--d-3) var(--spring); }
@media (hover: hover) {
  .js .models .models-grid .models-card.is-arrived[data-reveal]:hover { transform: translateY(-2px); }
  .models-card:hover::after { opacity: 1; }
  .models-card:hover .models-top .well { transform: scale(1.07); }
}

/* ————— the card's words: icon, name, one short grey line ————— */
.models-top { display: grid; justify-items: start; align-content: start; min-inline-size: 0; }
.models-top .well { inline-size: 48px; block-size: 48px; margin-block-end: 1.15rem; }
.models-top .well .icon { inline-size: 24px; block-size: 24px; }
.models-claim { margin-block-start: .5rem; max-inline-size: 26em; font-size: var(--fs-small); line-height: 1.5; color: var(--muted); }
html[lang="ar"] .models-claim { font-size: 1rem; line-height: 1.7; }

/* ————— the example: its surface, then the dots under it ————— */
.models-demo { display: flex; flex-direction: column; min-inline-size: 0; }
.models-mini { position: relative; flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; min-inline-size: 0;
  padding: clamp(1.5rem, 2.2vw, 1.75rem) clamp(1rem, 1.8vw, 1.5rem) clamp(1.25rem, 2vw, 1.6rem); }
.models-mini .gloss { text-wrap: balance; }

/* all the examples of one model lie in the same cell: it is as tall as the tallest, and nothing around it ever moves */
.models-stage { display: grid; grid-template-columns: minmax(0, 1fr); min-inline-size: 0; }
.models-stage > .models-ex { grid-area: 1 / 1; align-self: start; min-inline-size: 0; }
/* an example leaves as one piece: it fades and drifts up 4px. It comes in piece by piece (its words, its bubbles). */
.models-ex { opacity: 0; visibility: hidden; translate: 0 -4px;
  transition: opacity var(--d-1) var(--ease-in-out), translate var(--d-1) var(--ease-in-out), visibility 0s linear var(--d-1); }
.models-ex.is-on { opacity: 1; visibility: visible; translate: none; transition: none; }

/* things that are swapped whole (the chip, the English line): the old one fades up and away, the new one rises into its
   place a moment later. `translate` carries the way out, `transform` the way in (it goes back under, unseen, once the
   old one has faded), so both ways run from wherever the thing is: a tap in the middle never jumps. */
:is(.models-chip, .models-mt-src > .models-ex) { opacity: 0; visibility: hidden; transform: translateY(10px); translate: 0 -4px;
  transition: opacity var(--d-1) var(--ease-in-out), translate var(--d-1) var(--ease-in-out), transform 0s linear var(--d-1), visibility 0s linear var(--d-1); }
:is(.models-chip, .models-mt-src > .models-ex).is-on { opacity: 1; visibility: visible; transform: none; translate: none;
  transition: opacity var(--d-2) var(--ease-out) .14s, transform .32s var(--ease-out) .14s, translate .32s var(--ease-out) .14s, visibility 0s; }

/* the use case of the example on screen: a small pill pinned on the top edge of the surface, at its far corner */
.models-chips { position: absolute; z-index: 2; inset-block-start: -12px; inset-inline-end: 14px; display: grid; justify-items: end; pointer-events: none; }
.models-chip { grid-area: 1 / 1; display: inline-flex; align-items: center; block-size: 24px; padding-inline: 10px; border-radius: var(--pill);
  background: var(--surface); box-shadow: inset 0 0 0 1px var(--line), 0 1px 2px rgba(11, 51, 39, .05);
  font-size: var(--fs-tiny); font-weight: 600; line-height: 1; letter-spacing: .005em; white-space: nowrap; color: var(--green-800); }
html[lang="ar"] .models-chip { letter-spacing: 0; padding-block-end: 1px; }

/* a Hassaniya sentence as a tidy block: it hugs the start edge, its lines stay right-aligned, the gloss sits under it */
.models-say { inline-size: fit-content; max-inline-size: 100%; }
.models .models-say { font-size: clamp(1.25rem, .45vw + 1.15rem, 1.4375rem); }   /* small and calm, also on a wide screen */
.models-say .gloss { margin-block-start: .25rem; }

/* word by word: the words are in the page from the start (so no line ever re-wraps); each one fades up 4px, at its own
   moment (--at, set by models.js). A sentence is said when its example has .is-said (or, following a real recording,
   when the word itself has .is-on). Unsaid words go at once. */
.models-w { display: inline-block; white-space: nowrap; }
.models-nb { white-space: nowrap; }
.models-ex :is(.models-w, [data-models-gloss]) { transition: opacity .22s var(--ease-out) var(--at, 0ms), transform var(--d-2) var(--ease-out) var(--at, 0ms); }
.models-ex :is(.models-w, [data-models-gloss]).is-on { transition-delay: 0ms; }
.models-ex:not(.is-said) :is(.models-w, [data-models-gloss]):not(.is-on) { opacity: 0; transform: translateY(4px); transition: opacity .12s linear, transform 0s linear .12s; }

/* ————— 1 · speech to text ————— */
.models-asr, .models-mt { justify-content: flex-start; }   /* these two read from the top; room kept for a longer example stays under them */
.models-asr-player { display: flex; align-items: center; gap: 14px; direction: ltr; }   /* audio time runs left to right, in every language */
.models-asr .models-stage { margin-block-start: 1rem; }
html:not(.js) .models-asr-player { display: none; }   /* nothing to press, and no waveform, without scripts */
html:not(.js) .models-asr .models-stage { margin-block-start: 0; }

/* the place of the play button is always kept (the waveform never moves): the button when the example has a recording,
   a quiet microphone ring when it has none */
.models-asr-ctl { position: relative; flex: none; inline-size: 48px; block-size: 48px; }
.models-asr-ghost { position: absolute; inset: 0; display: grid; place-items: center; border-radius: 50%; color: var(--green-600);
  box-shadow: inset 0 0 0 1px var(--line); transition: opacity var(--d-2) var(--ease-out), transform var(--d-2) var(--ease-out); }
.models-asr-ghost .icon { inline-size: 20px; block-size: 20px; }
.models .models-play { position: absolute; inset: 0; inline-size: 48px; block-size: 48px; opacity: 0; visibility: hidden; transform: scale(.8);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: opacity var(--d-1) var(--ease-in-out), transform var(--d-1) var(--ease-in-out), visibility 0s linear var(--d-1); }
.models-asr.has-audio .models-play { opacity: 1; visibility: visible; transform: none;
  transition: opacity var(--d-2) var(--ease-out), transform var(--d-3) var(--spring), background-color var(--d-1), visibility 0s; }
.models-asr.has-audio .models-play:active { transform: scale(.96); transition-duration: var(--d-1), .08s, var(--d-1), 0s; }
.models-asr.has-audio .models-asr-ghost { opacity: 0; transform: scale(.8); transition-duration: var(--d-1); }
.models .models-play:focus-visible { outline-offset: 3px; }
.models-play .icon { inline-size: 20px; block-size: 20px; }
.models-play > span { grid-area: 1 / 1; display: grid; place-items: center; transition: opacity var(--d-1) var(--ease-out), transform var(--d-2) var(--ease-out); }
.models-play-a { padding-inline-start: 2px; }   /* the triangle looks centred a little to the right of its box */
.models-play-b, .models-play.is-playing .models-play-a { opacity: 0; transform: scale(.6); }
.models-play.is-playing .models-play-b { opacity: 1; transform: none; }
/* while the recording plays: one soft ring leaves the button, again and again (it stops with the sound) */
.models-play::after { content: ""; position: absolute; inset: 0; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--green-500); opacity: 0; pointer-events: none; }
.models-play.is-playing::after { animation: models-ring 1.4s var(--ease-out) infinite; }
@keyframes models-ring { from { transform: none; opacity: .55; } to { transform: scale(1.55); opacity: 0; } }

/* the waveform: bars of whole pixels (width, gap and height), round caps. A bar not yet heard is the same bar at low
   opacity; "heard" is an opacity cross-fade per bar, each at its own moment (--at). A new example reshapes the bars
   with a transform only (models.js sets the new height and plays the difference back as a scaleY that ends at none). */
.models-wave { position: relative; isolation: isolate; flex: 1 1 0; min-inline-size: 0; display: flex; align-items: center; gap: var(--models-gap, 2px); block-size: 48px; direction: ltr; }
.models-wave > i { flex: none; inline-size: var(--models-bar, 3px); block-size: calc(var(--h, 8) * 1px); border-radius: var(--pill); background: var(--green-500); opacity: .26;
  transition: opacity var(--d-1) var(--ease-in-out), transform .36s var(--ease-in-out) calc(var(--k, 0) * 3ms); }
.models-wave > i.g { background: var(--green-700); }
.models-wave.is-swept > i { opacity: 1; transition: opacity var(--d-1) var(--ease-out) var(--at, 0ms), transform .36s var(--ease-in-out) calc(var(--k, 0) * 3ms); }
.models-wave > i.on { opacity: 1; }
.models-wave.is-setting > i { transition-property: opacity !important; }   /* the new shape is set without a fade; the bar keeps fading to "not heard" */
/* a soft light that travels with the playhead, behind the bars */
.models-glow { position: absolute; z-index: -1; inset-block: 0; left: -18px; inline-size: 36px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(103, 160, 95, .22), rgba(103, 160, 95, 0)); opacity: 0; transform: translateX(0);
  transition: opacity var(--d-2) var(--ease-in-out), transform 0s linear var(--d-2); }
.models-wave.is-sweeping .models-glow { opacity: 1; transform: translateX(var(--models-run, 200px)); transition: opacity var(--d-2) var(--ease-out), transform var(--models-sweep, 1.1s) linear; }
.models-wave.is-live .models-glow { opacity: 1; transition: opacity var(--d-2) var(--ease-out), transform .12s linear; }

/* ————— 2 · translation ————— */
.models-label { display: block; font-size: var(--fs-tiny); line-height: 1.3; font-weight: 600; color: var(--muted); }
html[lang="ar"] .models-label { font-size: .875rem; }
.models-mt-src { margin-block-start: .3rem; }
.models-mt-en { font-size: clamp(1.125rem, .6vw + 1rem, 1.3125rem); line-height: 1.4; font-weight: 500; color: var(--ink); }
.models-mt-en .latin { display: inline-block; letter-spacing: -.015em; }
.models-mt-seam { margin-block: 1.1rem; }
.models-mt-dst { position: relative; margin-block-start: .15rem; }
/* "working": three soft pills on the first line of the answer, one quick light passing over them */
.models-mt-shimmer { position: absolute; inset-block-start: 0; inset-inline: 0; block-size: 1.6em; font-size: clamp(1.25rem, .45vw + 1.15rem, 1.4375rem);
  display: flex; align-items: center; gap: 6px; opacity: 0; pointer-events: none; transition: opacity .12s var(--ease-in-out); }
.models-mt-shimmer > i { position: relative; overflow: hidden; block-size: 12px; border-radius: var(--pill); background: var(--green-200); }
.models-mt-shimmer > i:nth-child(1) { inline-size: 56px; }
.models-mt-shimmer > i:nth-child(2) { inline-size: 36px; }
.models-mt-shimmer > i:nth-child(3) { inline-size: 68px; }
.models-mt-shimmer > i::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .92), transparent); transform: translateX(-110%); }
.models-mt.is-working .models-mt-shimmer { opacity: 1; transition: opacity var(--d-1) var(--ease-out); }
.models-mt.is-working .models-mt-shimmer > i::after { animation: models-sheen .34s var(--ease-in-out) both; }
.models-mt.is-working .models-mt-shimmer > i:nth-child(2)::after { animation-delay: .04s; }
.models-mt.is-working .models-mt-shimmer > i:nth-child(3)::after { animation-delay: .08s; }
[dir="rtl"] .models-mt.is-working .models-mt-shimmer > i::after { animation-direction: reverse; }
@keyframes models-sheen { to { transform: translateX(110%); } }

/* ————— 3 · the language model ————— */
.models-llm { padding-inline: clamp(.8rem, 1.8vw, 1.5rem); }   /* bubbles carry their own padding: a little more room for them on a small phone */
.models-llm .models-stage > .models-ex { align-self: stretch; justify-content: center; gap: .7rem; }   /* a short exchange sits in the middle of the room kept for the longest */
.models-llm .bubble { max-inline-size: 90%; padding-inline: .85rem; }
.models-llm .bubble--user { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); }   /* white on the tinted surface */
/* the model's turn: the MauriAI mark in a small night disc (no face), then its answer; the dots wait where the answer will sit */
.models-llm-turn { align-self: flex-start; display: flex; align-items: flex-end; gap: .4rem; max-inline-size: 100%; min-inline-size: 0; }
.models-llm-ava { inline-size: 28px; block-size: 28px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--night-2); }
.models-llm-ava .logo-mark { inline-size: 15px; }
.models-llm-body { position: relative; display: grid; min-inline-size: 0; }
.models-llm .models-llm-bot { max-inline-size: 100%; transform-origin: 0 100%; }
[dir="rtl"] .models-llm .models-llm-bot { transform-origin: 100% 100%; }
.models-llm .models-llm-typing { position: absolute; inset-block-end: 0; inset-inline-start: 0; max-inline-size: none; display: flex; align-items: center; gap: 5px; padding: 1rem;
  opacity: 0; visibility: hidden; transition: opacity var(--d-1) var(--ease-in-out), visibility 0s linear var(--d-1); }
.models-llm-typing > i { inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--green-700); opacity: .3; }
/* the three steps of an exchange (classes on the example): .is-q the question, .is-typing the dots, .is-said the answer */
.models-llm-user { transition: opacity var(--d-2) var(--ease-out), transform .36s var(--ease-out); }
.models-llm-ava { transition: opacity var(--d-1) var(--ease-out), transform var(--d-3) var(--spring); }
.models-llm-bot { transition: opacity var(--d-1) var(--ease-out), transform var(--d-2) var(--ease-out); }
.models-ex:not(.is-q) .models-llm-user { opacity: 0; transform: translateY(8px); transition: none; }
.models-ex:not(.is-typing):not(.is-said) .models-llm-ava { opacity: 0; transform: scale(.6); transition: none; }
.models-ex:not(.is-said) .models-llm-bot { opacity: 0; transform: scale(.94); transition: none; }
.models-ex.is-typing .models-llm-typing { opacity: 1; visibility: visible; transition: opacity var(--d-1) var(--ease-out), visibility 0s; }
.models-ex.is-typing .models-llm-typing > i { animation: models-dot .34s var(--ease-in-out) both; }
.models-ex.is-typing .models-llm-typing > i:nth-child(2) { animation-delay: .07s; }
.models-ex.is-typing .models-llm-typing > i:nth-child(3) { animation-delay: .14s; }
@keyframes models-dot { 0%, 100% { transform: none; opacity: .3; } 45% { transform: translateY(-3px); opacity: 1; } }

/* ————— the dots: one per example. The one on screen is a short bar that fills while its example stays ————— */
/* Each dot keeps a 24px place. The bar of the active one is 16px longer: the dots after it step aside by 16px (transform),
   and the bar grows from the dot with three pieces (two round caps and a middle that scales), so nothing changes size. */
.models-dots { display: flex; justify-content: center; block-size: 24px; margin-block-start: .6rem; padding-inline-end: 16px; }
html:not(.js) .models-dots { display: none; }
.models-dot { position: relative; flex: none; inline-size: 24px; block-size: 24px; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: transform .32s var(--ease-in-out); }
.models-dot.is-after { transform: translateX(calc(16px * var(--models-x))); }
.models-dot::after { content: ""; position: absolute; inset: -8px 0; }   /* easier to tap: 24 × 40 */
.models-dot.is-active::after { inset-inline-end: -16px; }
/* pressed / focused: a soft halo round the dot (round the whole bar when it is the active one) */
.models-dot::before { content: ""; position: absolute; inset: 2px; border-radius: 10px; background: rgba(10, 20, 16, .07); opacity: 0; transition: opacity var(--d-2) var(--ease-out); }
.models-dot.is-active::before { inset-inline-end: -14px; }
.models-dot:active::before { opacity: 1; transition-duration: .06s; }
.models-dot:focus-visible { outline: 0; }
.models-dot:focus-visible::before { opacity: 1; background: transparent; box-shadow: 0 0 0 2px var(--green-600); }
.models-dot-v { position: absolute; inset-block-start: 8px; inset-inline-start: 8px; inline-size: 8px; block-size: 8px; transition: transform var(--d-3) var(--spring); }
@media (hover: hover) { .models-dot:not(.is-active):hover .models-dot-v { transform: scale(1.3); } }
.models .models-dots .models-dot:active .models-dot-v { transform: scale(.82); transition: transform .08s var(--ease-out); }   /* pressed: at once; released: back with the spring */
.models-dot-v > i { position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 8px; border-radius: 50%; background: var(--sand-300); transition: transform .32s var(--ease-in-out); }
.models-dot-v > i:nth-child(2) { inset-inline-start: 4px; inline-size: 16px; border-radius: 0; transform: scaleX(0); transform-origin: 0 50%; }
[dir="rtl"] .models-dot-v > i:nth-child(2) { transform-origin: 100% 50%; }
.models-dot.is-active .models-dot-v > i:nth-child(2) { transform: none; }
.models-dot.is-active .models-dot-v > i:nth-child(3) { transform: translateX(calc(16px * var(--models-x))); }
/* the fill: a green bar that slides out from under the start of the track (models.js runs it over the time the example stays) */
.models-dot-fill { position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 24px; border-radius: 4px; overflow: hidden; opacity: 0; transition: opacity var(--d-1) var(--ease-in-out); }
.models-dot.is-active .models-dot-fill { opacity: 1; transition: opacity var(--d-2) var(--ease-out) .1s; }
.models-dot-fill > i { position: absolute; inset: 0; border-radius: 4px; background: var(--green-500); transform: translateX(calc(-16px * var(--models-x))); }

/* ————— a static page (?static=1, reduced motion): example 1 at rest; the dots still work, a swap is immediate ————— */
html.is-static .models-grid *, html.is-static .models-grid *::before, html.is-static .models-grid *::after { transition: none !important; animation: none !important; }
html.is-static .models-dot.is-active .models-dot-fill > i { transform: none; }
/* used by models.js to put something at its start without a fade */
.models-rw, .models-rw *, .models-rw *::before, .models-rw *::after { transition: none !important; }
/* …and to finish something at once (every piece together, no stagger) */
.models-now, .models-now * { transition-delay: 0s !important; }

/* ————— under the cards: one quiet line, one button ————— */
.models-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.1rem 2rem; margin-block-start: clamp(2rem, 4vw, 3rem); }
.models-note { font-size: var(--fs-small); line-height: 1.5; color: var(--muted); }
html[lang="ar"] .models-note { font-size: 1rem; }

/* ————— 720px: the speech card across the top, the other two side by side under it ————— */
@media (min-width: 720px) {
  .models-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 720px) and (max-width: 1099.98px) {
  .models-card--asr { grid-column: 1 / -1; grid-template-columns: minmax(0, 5fr) minmax(0, 8fr); grid-template-rows: auto; column-gap: clamp(1.5rem, 4vw, 3rem); align-items: center; }
}
/* ————— 1100px: three equal columns ————— */
@media (min-width: 1100px) {
  .models-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 30px; }   /* 30: three whole-pixel columns in the 1200px container */
}
/* cards that share a row line up part for part: the words on one line of the grid, the examples on the next */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 720px) {
    .models-card:not(.models-card--asr) { grid-row: span 2; grid-template-rows: subgrid; }
  }
  @media (min-width: 1100px) {
    .models-card--asr { grid-row: span 2; grid-template-rows: subgrid; }
  }
}


/* ===== product ===== */
/* ===================================================================================================
   product — "Agents that answer your customers."  One dark rounded panel on the light page: few words,
   a list of use cases, and ONE conversation at a time that changes with the use case (js/product.js
   rotates them), then one quiet line about Wakil and the film button (the only video of the site).

   Phone first: the words · the use cases (pills in a row that scrolls sideways) · the conversation · the
   note · Wakil and the film.   1000px: two columns, the words and the list (rows) | the conversation.

   Motion: only transform and opacity move (plus the stroke of the check mark, drawn once). Every line of
   every conversation waits in its final place, so nothing is ever laid out again: the stage is a stack
   where all the conversations share one cell, which makes it as tall as the tallest one at any width,
   with any font, before and after JavaScript. At rest nothing here is hidden.
   =================================================================================================== */

.product .product-panel {
  --product-px: clamp(1.25rem, 5vw, 4.75rem);                      /* the panel's side padding (the pills and the card reach into it) */
  --product-user: rgba(243, 247, 242, .07); --product-user-line: var(--on-dark-line);
  --product-bot: rgba(103, 160, 95, .17); --product-bot-line: rgba(143, 212, 131, .2);
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: start;
  padding: clamp(2.6rem, 7vw, 5.25rem) var(--product-px);
}
[dir="rtl"] .product .product-panel::before { transform: scaleX(-1); }   /* the corner glow stays behind the conversation */

/* ————— the words ————— */
.product-copy { min-inline-size: 0; }
.product .product-head { margin-block-end: 0; gap: 1.15rem; }
.product .product-head .h2 { font-size: clamp(1.9rem, 2.4vw + 1.15rem, 3rem); }
.product .product-head .lead { font-size: clamp(1.0625rem, .3vw + 1rem, 1.1875rem); max-inline-size: 30em; }

/* ————— the use cases. Phone: pills in one row; the row reaches the panel's edges and scrolls inside itself ————— */
.product-cases { position: relative; display: flex; gap: 8px; min-inline-size: 0;
  margin: clamp(1.6rem, 5vw, 2.25rem) calc(var(--product-px) * -1) 0; padding: 6px var(--product-px);
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity; scroll-padding-inline: var(--product-px); scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--product-px), #000 calc(100% - var(--product-px)), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 var(--product-px), #000 calc(100% - var(--product-px)), transparent); }
.product-cases::-webkit-scrollbar { display: none; }
.product-cases:empty { display: none; }

.product-case { position: relative; z-index: 1; flex: none; display: inline-flex; align-items: center; gap: 8px; min-block-size: 44px; padding-inline: 14px 17px;
  border-radius: var(--pill); box-shadow: inset 0 0 0 1px var(--on-dark-line); color: var(--on-dark);
  font-size: .875rem; font-weight: 500; line-height: 1.25; letter-spacing: -.005em; white-space: nowrap; scroll-snap-align: center;
  transition: transform var(--d-3) var(--spring); -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
html[lang="ar"] .product-case { letter-spacing: 0; font-size: .9375rem; }
.product-case > span { opacity: .62; transition: opacity var(--d-2) var(--ease-out); }
.product-case[aria-selected="true"] > span { opacity: 1; }
@media (hover: hover) { .product-case:hover > span { opacity: 1; } }
.product-case:active { transform: scale(.97); transition-duration: .05s; }   /* pressed at once; the release springs back */
.product-case:focus-visible { outline-offset: 2px; border-radius: var(--pill); }
.product-case-ic { display: grid; color: var(--green-300); }
.product-case-ic > .icon { inline-size: 18px; block-size: 18px; }

/* the highlight: ONE shape that slides from tab to tab (js sets its size and a translate: whole pixels), and inside it
   the progress of the conversation on show (a scaleX that js runs, freezes and resumes) */
.product-hl { position: absolute; top: 0; left: 0; z-index: 0; inline-size: 0; block-size: 0; overflow: hidden; pointer-events: none;
  border-radius: var(--pill); background: rgba(243, 247, 242, .09); box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .2);
  transform-origin: 0 0; opacity: 0; transition: transform var(--d-3) var(--ease-in-out); }
.product-hl.is-set { opacity: 1; }
.product-hl-fill { position: absolute; inset: 0; background: rgba(143, 212, 131, .2); transform: scaleX(0); transform-origin: 0 50%; }
[dir="rtl"] .product-hl-fill { transform-origin: 100% 50%; }
.is-static .product-hl-fill { display: none; }
.is-static .product-hl { transition: none; }

/* ————— the stage: a card of dark glass. On a phone it sits 8px inside the panel (same centre for both corners:
   30 − 8 = 22) and its content lines up with the words above ————— */
.product-scene { min-inline-size: 0; margin-block-start: .5rem; }
.product-card { margin-inline: calc(8px - var(--product-px)); padding: 18px calc(var(--product-px) - 8px) 20px; border-radius: 22px;
  background: linear-gradient(180deg, rgba(243, 247, 242, .055), rgba(243, 247, 242, .02));
  box-shadow: inset 0 0 0 1px var(--on-dark-line), inset 0 1px 0 rgba(243, 247, 242, .08); }
@media (min-width: 600px) {
  .product-scene { max-inline-size: 40rem; }
  .product-card { margin-inline: 0; padding: clamp(1.5rem, 2.6vw, 2rem); border-radius: 26px; }
}

/* all the conversations share one cell: the cell is as tall as the tallest, and a shorter one sits in its middle.
   Only the one on show (and the one fading out) is visible; the others keep their place, unseen. */
.product-stage { display: grid; grid-template-columns: minmax(0, 1fr); }
.product-conv { grid-area: 1 / 1; align-self: center; min-inline-size: 0; gap: 14px; }
.js .product-conv { visibility: hidden; }
.js .product-conv:is(.is-on, .is-leaving) { visibility: visible; }
.product-conv.is-on { z-index: 1; }

/* one line: the agent's mark and its bubble, or the customer's voice note on the other side */
.product-msg { position: relative; display: grid; grid-template-columns: 30px minmax(0, 1fr); column-gap: 9px; align-items: end; }
.product-msg[data-who="u"] { grid-template-columns: minmax(0, 1fr); }
.product-msg > .product-disc, .product-msg > .bubble, .product-msg > .product-typing { grid-row: 1; }
.product-msg > .product-disc { grid-column: 1; }
.product-msg > .bubble, .product-msg > .product-typing { grid-column: 2; justify-self: start; }
.product-msg[data-who="u"] > .bubble { grid-column: 1; justify-self: end; }
.product-msg[data-who="u"] > :is(.product-disc, .product-typing), .product-msg[data-who="b"] .product-voice,
.product-msg[data-who="u"] .product-who > [data-for="b"], .product-msg[data-who="b"] .product-who > [data-for="u"] { display: none; }

/* the agent's mark: the seven voice bars of the logo on a disc of the logo green, drawn with whole pixels
   (2px bars, 1px apart, even heights) so it stays sharp at this size on any screen */
.product-disc { inline-size: 30px; block-size: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; gap: 1px; direction: ltr;
  background: var(--green-500); box-shadow: 0 0 0 4px rgba(103, 160, 95, .16); }
.product-disc > i { inline-size: 2px; block-size: 2px; border-radius: 1px; background: var(--night); }
.product-disc > i:is(:nth-child(2), :nth-child(6)) { block-size: 6px; }
.product-disc > i:is(:nth-child(3), :nth-child(5)) { block-size: 10px; }
.product-disc > i:nth-child(4) { block-size: 16px; }

/* bubbles: one radius (20), one small corner (6) on the speaker's side */
.product .product-stage .bubble { max-inline-size: 100%; min-inline-size: 0; padding: 10px 16px 12px; border-radius: 20px; border-end-start-radius: 6px;
  background: var(--product-bot); box-shadow: inset 0 0 0 1px var(--product-bot-line); transform-origin: 0 100%; }
.product .product-stage .product-msg[data-who="u"] > .bubble { max-inline-size: 92%; background: var(--product-user); box-shadow: inset 0 0 0 1px var(--product-user-line);
  border-end-start-radius: 20px; border-end-end-radius: 6px; transform-origin: 100% 100%; }
[dir="rtl"] .product .product-stage .bubble { transform-origin: 100% 100%; }
[dir="rtl"] .product .product-stage .product-msg[data-who="u"] > .bubble { transform-origin: 0 100%; }
/* line heights are whole pixels, written in rem (30 for 18, 32 for 19, 19 for 13): every conversation is a whole number of pixels tall */
.product .product-stage .ha { display: block; font-size: 1.125rem; font-weight: 500; line-height: 1.875rem; text-wrap: pretty; }
.product .product-stage .gloss { margin-block-start: 1px; font-weight: 400; line-height: 1.1875rem; text-wrap: balance; }
@media (min-width: 480px) { .product .product-stage .ha { font-size: 1.1875rem; line-height: 2rem; } }

/* the customer speaks: a voice note. The waveform always runs left to right; its bars are 2px wide on a 4px step,
   with even heights: whole pixels at any width (the grid shows as many whole bars as fit, the rest wrap out of sight) */
.product-voice { display: flex; align-items: center; gap: 9px; direction: ltr; block-size: 20px; margin-block: 4px 5px; color: var(--green-300); }
.product-voice > .icon { inline-size: 16px; block-size: 16px; }
.product-wave { flex: 1 1 0; min-inline-size: 104px; max-inline-size: 176px; block-size: 20px; overflow: hidden; direction: ltr;
  display: grid; grid-template-columns: repeat(auto-fill, 4px); grid-auto-rows: 20px; row-gap: 20px; align-items: center; justify-items: start; }
.product-wave > i { inline-size: 2px; block-size: 2px; border-radius: 1px; background: var(--green-500); }
.product-wave > i.g { background: var(--green-300); }
html:not(.js) .product-voice { display: none; }

/* "the agent is answering": three dots in the place of the coming reply (same cell: nothing moves) */
.product-typing { display: inline-flex; align-items: center; gap: 5px; block-size: 38px; padding-inline: 16px; border-radius: 20px; border-end-start-radius: 6px;
  background: var(--product-bot); box-shadow: inset 0 0 0 1px var(--product-bot-line); opacity: 0; pointer-events: none; }
.product-typing > i { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--green-300); }

/* what the agent did: a small system confirmation. The glow is a layer of its own (only its opacity ever changes) */
.product-result { position: relative; isolation: isolate; display: grid; grid-template-columns: 32px minmax(0, 1fr); align-items: center; column-gap: 12px;
  margin-block-start: 4px; padding: 12px; padding-inline-end: 16px; border-radius: 16px;
  background: linear-gradient(180deg, rgba(103, 160, 95, .24), rgba(103, 160, 95, .12));
  box-shadow: inset 0 0 0 1px rgba(166, 240, 148, .28), inset 0 1px 0 rgba(243, 247, 242, .1); }
.product-result::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  box-shadow: 0 12px 36px -8px rgba(103, 160, 95, .5), 0 2px 8px -2px rgba(103, 160, 95, .28); }
.product-check { position: relative; inline-size: 32px; block-size: 32px; border-radius: 50%; display: grid; place-items: center; background: var(--green-500); color: var(--night); }
.product-check > .icon { inline-size: 20px; block-size: 20px; stroke-width: 2.4; }
.product-check path { stroke-dasharray: 20; stroke-dashoffset: 0; }   /* the mark is 19.8 long */
.product-check::after { content: ""; position: absolute; inset: 0; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--glow-hi); opacity: 0; pointer-events: none; }
.product-result-text { min-inline-size: 0; }
.product-done { display: block; font-size: var(--fs-small); font-weight: 600; line-height: 1.25rem; letter-spacing: -.01em; color: var(--on-dark); }
.product-detail { display: block; margin-block-start: 2px; font-size: var(--fs-tiny); line-height: 1.1875rem; color: var(--on-dark-2); }
.product-detail:empty { display: none; }
html[lang="ar"] .product-done { letter-spacing: 0; line-height: 1.5rem; }
html[lang="ar"] .product-detail { line-height: 1.3125rem; margin-block-start: 0; }

/* under the stage: the honest note, and the pause button (44px to tap, 36px to see) */
.product-under { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-block-size: 44px; margin-block-start: .5rem; }
.product-note { font-size: var(--fs-tiny); line-height: 1.4; color: var(--on-dark-2); }
.product-toggle { position: relative; inline-size: 44px; block-size: 44px; flex: none; margin-inline-end: -4px; border-radius: 50%; display: grid; place-items: center; color: var(--on-dark);
  transition: transform var(--d-3) var(--spring); -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.product-toggle::before { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: rgba(243, 247, 242, .05); box-shadow: inset 0 0 0 1px var(--on-dark-line);
  transition: opacity var(--d-1) linear; }
.product-toggle::after { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: rgba(243, 247, 242, .08); opacity: 0; transition: opacity var(--d-1) linear; }
@media (hover: hover) { .product-toggle:hover::after { opacity: 1; } }
.product-toggle:active { transform: scale(.94); transition-duration: .05s; }
.product-toggle:focus-visible { border-radius: 50%; outline-offset: -1px; }
.product-toggle-ic { position: relative; z-index: 1; display: grid; }
.product-toggle-ic > .icon { grid-area: 1 / 1; inline-size: 16px; block-size: 16px; transition: opacity var(--d-1) linear, transform var(--d-2) var(--spring); }
.product-toggle-ic > .icon:last-child, .product-toggle.is-paused .product-toggle-ic > .icon:first-child { opacity: 0; transform: scale(.5); }
.product-toggle.is-paused .product-toggle-ic > .icon:last-child { opacity: 1; transform: none; }

/* ————— Wakil, the first agent: one quiet line and the one button ————— */
.product-wakil { display: grid; justify-items: start; gap: 1.1rem; margin-block-start: clamp(1.75rem, 5vw, 2.25rem); }
.product-wakil-line { font-size: var(--fs-small); line-height: 1.55; color: var(--on-dark-2); max-inline-size: 27em; }
.product .product-film-btn { inline-size: 100%; min-height: 52px; }
.product-film-btn .icon { inline-size: 16px; block-size: 16px; }
@media (min-width: 520px) { .product .product-film-btn { inline-size: auto; min-height: 48px; padding-inline: 1.4em 1.6em; } }

/* ————— the sequence. js/product.js arms a conversation (.is-armed: every line waits, unseen, in its final place),
   then gives each line .is-typing / .is-in; the conversation that leaves fades as a whole (.is-leaving). ————— */
.product-conv.is-leaving { opacity: 0; transform: translateY(4px); pointer-events: none;
  transition: opacity .18s var(--ease-in-out), transform .18s var(--ease-in-out); }

/* a bubble arrives: it fades, rises 8px and grows from .98, from the corner of its speaker */
.product-conv.is-armed .product-msg > .bubble { opacity: 0; transform: translateY(8px) scale(.98); }
.product-conv.is-armed .product-msg.is-in > .bubble { opacity: 1; transform: none; transition: opacity .28s var(--ease-out), transform .34s var(--ease-out); }
.product-conv.is-armed .product-msg > .product-disc { opacity: 0; transform: scale(.6); }
.product-conv.is-armed .product-msg:is(.is-typing, .is-in) > .product-disc { opacity: 1; transform: none; transition: opacity var(--d-1) linear, transform var(--d-2) var(--spring); }

.product-conv.is-armed .product-typing { transition: opacity .09s linear; }
.product-conv.is-armed .product-msg.is-typing > .product-typing { opacity: 1; }
.product-conv.is-armed .product-msg.is-typing > .product-typing > i { animation: product-dot .45s var(--ease-in-out) infinite alternate; }
.product-conv.is-armed .product-msg.is-typing > .product-typing > i:nth-child(2) { animation-delay: .12s; }
.product-conv.is-armed .product-msg.is-typing > .product-typing > i:nth-child(3) { animation-delay: .24s; }
@keyframes product-dot { from { opacity: .35; transform: none; } to { opacity: 1; transform: translateY(-2px); } }

/* the agent's sentence, word by word (js sets --product-word from PACE); words only fade, they never move.
   The translation follows. */
.product-w--tied { white-space: nowrap; }   /* a word and the lone mark after it (« ول ؟ ») stay on one line */
.product-conv.is-armed .product-w { opacity: 0; }
.product-conv.is-armed .product-msg.is-in .product-w { opacity: 1; transition: opacity .22s linear; transition-delay: calc(40ms + var(--j, 0) * var(--product-word, 60ms)); }
.product-conv.is-armed .product-msg .gloss { opacity: 0; }
.product-conv.is-armed .product-msg.is-in .gloss { opacity: 1; transition: opacity .28s var(--ease-out) .2s; }

/* the customer's note "plays" once as it lands: the bars light up from left to right, and what was heard appears */
.product-conv.is-armed .product-wave > i { opacity: .3; }
.product-conv.is-armed .product-msg.is-in .product-wave > i { opacity: 1; transition: opacity .16s linear; transition-delay: calc(.1s + var(--k, 0) * 11ms); }
.product-conv.is-armed .product-msg[data-who="u"] .ha { opacity: 0; }
.product-conv.is-armed .product-msg[data-who="u"].is-in .ha { opacity: 1; transition: opacity .28s var(--ease-out) .16s; }

/* the confirmation lifts 6px into place, its glow comes up behind it, the disc pops, the check is drawn, one ring leaves */
.product-conv.is-armed .product-result { opacity: 0; transform: translateY(6px); }
.product-conv.is-armed .product-result.is-in { opacity: 1; transform: none; transition: opacity .26s var(--ease-out), transform .36s var(--ease-out); }
.product-conv.is-armed .product-result::before { opacity: 0; }
.product-conv.is-armed .product-result.is-in::before { opacity: 1; transition: opacity var(--d-3) var(--ease-out) .1s; }
.product-conv.is-armed .product-check { transform: scale(.7); }
.product-conv.is-armed .product-result.is-in .product-check { transform: none; transition: transform var(--d-3) var(--spring) .04s; }
.product-conv.is-armed .product-check path { stroke-dashoffset: 20; opacity: 0; }
.product-conv.is-armed .product-result.is-in .product-check path { stroke-dashoffset: 0; opacity: 1; transition: stroke-dashoffset .3s var(--ease-in-out) .14s, opacity .01s linear .14s; }
.product-conv.is-armed .product-result.is-in .product-check::after { animation: product-ring .6s var(--ease-out) .36s; }
@keyframes product-ring { from { opacity: .55; transform: none; } to { opacity: 0; transform: scale(1.8); } }

/* ?test=mid (screenshots): a middle state that stands still */
.product-scene.is-frozen * , .product-scene.is-frozen *::before, .product-scene.is-frozen *::after { transition: none !important; animation-play-state: paused !important; }

/* ————— 1000px: the words, the list and Wakil | the conversation. The list becomes calm rows; the highlight is a soft
   box that reaches 14px past the text, and the progress is a thin line along its lower edge ————— */
@media (min-width: 1000px) {
  .product .product-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 26.5rem); grid-template-rows: 1fr auto auto auto 1fr; column-gap: clamp(3rem, 6vw, 5.5rem); }
  .product-copy { grid-area: 2 / 1; }
  .product-cases { grid-area: 3 / 1; }
  .product-wakil { grid-area: 4 / 1; }
  .product-scene { grid-area: 1 / 2 / -1 / 3; align-self: center; inline-size: 100%; margin-block-start: 0; }

  .product-cases { flex-direction: column; gap: 2px; max-inline-size: 24rem; margin: 2.25rem 0 0; margin-inline-start: -14px; padding: 0; overflow: visible; scroll-snap-type: none;
    -webkit-mask-image: none; mask-image: none; }
  .product-case { inline-size: 100%; min-block-size: 48px; gap: 14px; padding-inline: 14px; border-radius: 14px; box-shadow: none; font-size: 1rem; scroll-snap-align: none; }
  html[lang="ar"] .product-case { font-size: 1.0625rem; }
  .product-case:focus-visible { border-radius: 14px; }
  .product-case-ic > .icon { inline-size: 20px; block-size: 20px; }
  .product-hl { border-radius: 14px; background: rgba(243, 247, 242, .055); box-shadow: inset 0 0 0 1px var(--on-dark-line), inset 0 1px 0 rgba(243, 247, 242, .05); }
  .product-hl-fill { inset: auto 0 0; block-size: 2px; background: linear-gradient(90deg, var(--green-500), var(--glow-hi)); }
  [dir="rtl"] .product-hl-fill { background: linear-gradient(270deg, var(--green-500), var(--glow-hi)); }

  .product-wakil { margin-block-start: 2rem; padding-block-start: 1.75rem; border-block-start: 1px solid var(--on-dark-line); max-inline-size: 24rem; }
}
@media (min-width: 1240px) { .product .product-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 31rem); } }

/* ————— the film modal (native dialog, top layer) ————— */
html.product-lock { overflow: hidden; }   /* the page behind holds still; product.js pads the body by the scrollbar's width so nothing jumps */
.product-film { position: fixed; inset: 0; z-index: 300; inline-size: 100vw; block-size: 100vh; block-size: 100dvh; max-inline-size: none; max-block-size: none;
  margin: 0; padding: 0; border: 0; background: transparent; color: var(--on-dark); overflow: hidden; overscroll-behavior: contain; }
.product-film[open] { display: grid; place-items: center; animation: product-film-in .3s var(--ease); }
.product-film::backdrop { background: var(--night); opacity: .92; animation: product-film-in .3s var(--ease); }
@keyframes product-film-in { from { opacity: 0; } }
.product-film-frame { position: relative; inline-size: 100vw; }
.product-film-video { display: block; inline-size: 100%; aspect-ratio: 16 / 9; block-size: auto; background: var(--night); object-fit: contain; }
.product-film-close { position: absolute; inset-block-end: calc(100% + 12px); inset-inline-end: 12px; inline-size: 44px; block-size: 44px; border-radius: 50%;
  display: grid; place-items: center; color: var(--on-dark); background: rgba(243, 247, 242, .12); box-shadow: inset 0 0 0 1px var(--on-dark-line);
  transition: transform var(--t-fast) var(--ease); -webkit-tap-highlight-color: transparent; }
.product-film-close:hover { background: rgba(243, 247, 242, .22); }
.product-film-close:active { transform: scale(.94); }
.product-film-close:focus-visible { outline-color: var(--glow-hi); border-radius: 50%; }
@media (min-width: 600px) {
  /* room for the close button above the frame, whatever the window's shape */
  .product-film-frame { inline-size: min(1100px, 100vw - 24px, (100vh - 136px) * 16 / 9); inline-size: min(1100px, 100vw - 24px, (100dvh - 136px) * 16 / 9); }
  .product-film-video { border-radius: var(--r-m); box-shadow: var(--shadow-3), 0 0 0 1px var(--on-dark-line); }
  .product-film-close { inset-inline-end: 0; }
}
/* a phone on its side: the film takes the height, the button sits on its top corner */
@media (orientation: landscape) and (max-height: 520px) {
  .product-film-frame { inline-size: min(100vw - 24px, (100vh - 24px) * 16 / 9); inline-size: min(100vw - 24px, (100dvh - 24px) * 16 / 9); }
  .product-film-video { border-radius: var(--r-s); }
  .product-film-close { inset-block-end: auto; inset-block-start: 8px; inset-inline-end: 8px; background: var(--night-2); }
}
.is-static .product-film[open], .is-static .product-film::backdrop { animation: none; }
@media (prefers-reduced-motion: reduce) { .product-film[open], .product-film::backdrop { animation: none; } }


/* ===== developers ===== */
/* ===================================================================================================
   developers — "Built for your applications."
   Phone first: the words, one button and one link, then the pipeline on a night panel, with clear space.
   From 960 px: the words on the inline-start, the panel on the inline-end.
   The panel sizes its own contents with a container query (it is narrow on a phone AND in the
   desktop column, wide on a tablet), so the nodes switch layout by the panel's width, not the screen's.

   Crisp (v4): every vertical measure inside the panel is a whole pixel (paddings, line heights, the wells),
   so the connectors land on whole device pixels at any width; they are 1 px thick, 1.5 px on dense screens.
   Motion (v4): only opacity and transform, on the shared curves; js/developers.js only switches classes on timers.
   =================================================================================================== */

.developers { --developers-dir: 1; --developers-glow: 103, 160, 95; --developers-tap: calc(var(--d-1) / 2); }   /* the logo green (--glow), as r, g, b for soft washes */
[dir="rtl"] .developers { --developers-dir: -1; }

.developers-grid { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: clamp(2.75rem, 9vw, 4rem); }
.developers-intro { min-inline-size: 0; }
.developers-head { margin-block-end: 0; }
.developers-cta { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1.75rem; margin-block-start: clamp(1.75rem, 3vw, 2.25rem); }

/* the button: the hover tint is a layer that fades in; a press lands at once and lets go on the spring */
.developers-cta .btn { white-space: normal; position: relative; isolation: isolate; transition: transform var(--d-3) var(--spring); }
.developers-cta .btn:hover { --btn-bg: var(--ink); }
.developers-cta .btn::before { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; background: rgba(255, 255, 255, .11); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
.developers-cta .btn:active { transform: scale(.97); transition-duration: var(--developers-tap); }
.developers-cta .link { position: relative; transition: opacity var(--d-1) var(--ease-out); }
.developers-cta .link:active { opacity: .7; transition-duration: var(--developers-tap); }
.developers-cta .arrow { transition: transform var(--d-2) var(--ease-out); }
@media (hover: hover) { .developers-cta .btn:hover::before { opacity: 1; } }
@media (hover: none) {   /* no arrow left pushed aside after a tap */
  .developers-cta :is(.btn, .link):hover .arrow { transform: none; }
  [dir="rtl"] .developers-cta :is(.btn, .link):hover .arrow { transform: scaleX(-1); }
}
.developers :focus-visible { outline-width: 2px; }

/* ————— the night panel (base .panel gives the night, the radius and the soft corner glow) ————— */
.developers-panel { container: developers-panel / inline-size; padding: 0; }
.developers-panel::after { content: ""; position: absolute; inset: 0; z-index: 3; border-radius: inherit; box-shadow: inset 0 0 0 1px var(--on-dark-line); pointer-events: none; }

/* the flows: one grid, every row shares its five columns (node · connector · model · connector · node) */
.developers-flows {
  --developers-conn: 20px;      /* connector column */
  --developers-well: 44px;      /* icon well and model pill height: the connector runs through their middle */
  --developers-line: 1px;       /* connector thickness */
  --developers-padx: .75rem;
  --developers-cols: 3.5;       /* the sum of the three fr columns below */
  --developers-colw: 76px;      /* width of a node column (fallback; measured from the panel just below) */
  --developers-tpl: minmax(0, 1fr) var(--developers-conn) minmax(0, 1.5fr) var(--developers-conn) minmax(0, 1fr);
  display: grid; margin: 0;
  grid-template-columns: var(--developers-tpl);
  padding: .875rem var(--developers-padx);
}
@media (min-resolution: 1.5dppx) { .developers-flows { --developers-line: 1.5px; } }
@supports (width: 1cqi) {
  .developers-flows { --developers-colw: calc((100cqi - 2 * var(--developers-padx) - 2 * var(--developers-conn)) / var(--developers-cols)); }
}
.developers-flow {
  position: relative; grid-column: 1 / -1; display: grid; align-items: start;
  grid-template-columns: var(--developers-tpl);
  grid-template-columns: subgrid;
  padding-block: 1.375rem 1.25rem;
}
/* the row that is running gets a very quiet band of light */
.developers-flow::before { content: ""; position: absolute; z-index: -1; inset-block: 0; inset-inline: calc(var(--developers-padx) * -1 + 6px); border-radius: var(--r-m); background: var(--on-dark); opacity: 0; transition: opacity var(--d-3) var(--ease-out); pointer-events: none; }

.developers-node { position: relative; display: flex; flex-direction: column; align-items: center; gap: .5625rem; min-inline-size: 0; text-align: center; }
.developers-label { font-size: var(--fs-tiny); font-weight: 600; line-height: 1rem; letter-spacing: -.005em; color: var(--on-dark); }
html[lang="ar"] .developers-label { font-size: .9375rem; line-height: 1.3125rem; letter-spacing: 0; }

/* a node's body is drawn by two layers behind its icon or its word: the resting body, and the "lit" one over it
   (a green tint, outline and soft bloom) whose opacity is all that changes. When the pulse reaches the node the two
   layers swell by 4 % and settle; the icon and the word stay exactly where they are, sharp. */
.developers-well { position: relative; isolation: isolate; inline-size: var(--developers-well); block-size: var(--developers-well); flex: none; border-radius: var(--r-m); display: grid; place-items: center; color: var(--on-dark); }
.developers-well .icon { inline-size: 24px; block-size: 24px; }   /* the icons' own grid, one to one */
.developers-well::before, .developers-well::after, .developers-pill::before, .developers-pill::after { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; }
.developers-well::before { background: rgba(243, 247, 242, .06); box-shadow: inset 0 0 0 1px var(--on-dark-line); }
.developers-well::after { background: rgba(var(--developers-glow), .16); box-shadow: inset 0 0 0 1px rgba(var(--developers-glow), .6), 0 0 18px rgba(var(--developers-glow), .22); transition: opacity var(--d-3) var(--ease-out); }

/* the MauriAI model: the one filled node. It always glows a little; lit, the glow comes up */
.developers-node--model { align-self: start; }
.developers-pill { position: relative; isolation: isolate; display: flex; align-items: center; justify-content: center; gap: .5rem; inline-size: 100%; min-block-size: var(--developers-well); padding: .25rem .5rem; border-radius: var(--r-m); }
.developers-pill .developers-label { font-weight: 600; }
.developers-pill::before { background: var(--night-3); box-shadow: inset 0 0 0 1px rgba(var(--developers-glow), .42), 0 0 22px rgba(var(--developers-glow), .16); }
.developers-pill::after { background: rgba(var(--developers-glow), .2); box-shadow: inset 0 0 0 1px var(--glow), 0 0 26px rgba(var(--developers-glow), .5); transition: opacity var(--d-3) var(--ease-out); }

/* connectors: a hairline through the middle of the wells, with an arrowhead that points forward (mirrored on the
   Arabic page). No rotated boxes and no overlapping pieces: the connector is a 2 px box (an even number: it centres
   on a whole pixel), and ONE layer draws the line on its top edge and the arrowhead around it, through a mask whose
   height is 8 px + the line. So the line is a whole-pixel bar, the two share one centre at every pixel density, and
   one opacity lights both. */
.developers-conn { position: relative; align-self: start; block-size: 2px; margin-block-start: calc(var(--developers-well) / 2 - 1px); margin-inline: 6px; color: var(--on-dark); }
/* reach out to the icon well, which sits centred in its (wider) column */
.developers-conn--a { margin-inline-start: calc((var(--developers-well) - var(--developers-colw)) / 2 + 6px); }
.developers-conn--b { margin-inline-end: calc((var(--developers-well) - var(--developers-colw)) / 2 + 6px); }
.developers-conn::before {
  --developers-head: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 10' preserveAspectRatio='none' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4-4 4'/%3E%3C/svg%3E");
  content: ""; position: absolute; inset-inline: 0; inset-block-start: -4px; block-size: calc(8px + var(--developers-line)); background: currentColor; opacity: .66;
  -webkit-mask: var(--developers-head) 100% 50% / 6px 100% no-repeat, linear-gradient(#000, #000) 0 50% / calc(100% - 2px) var(--developers-line) no-repeat;
          mask: var(--developers-head) 100% 50% / 6px 100% no-repeat, linear-gradient(#000, #000) 0 50% / calc(100% - 2px) var(--developers-line) no-repeat;
  transition: opacity var(--d-3) var(--ease-out);
}
[dir="rtl"] .developers-conn::before {
  --developers-head: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 10' preserveAspectRatio='none' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 1L1 5l4 4'/%3E%3C/svg%3E");
  -webkit-mask-position: 0 50%, 100% 50%; mask-position: 0 50%, 100% 50%;
}
/* the trace: the same line at full light, drawn from its start by the pulse (scaleX; it only exists while a pulse travels) */
.developers-trace { position: absolute; inset-block-start: 0; block-size: var(--developers-line); inset-inline: 0 2px; background: currentColor; opacity: 0; transform: scaleX(0); transform-origin: 0 50%; pointer-events: none; }
[dir="rtl"] .developers-trace { transform-origin: 100% 50%; }

/* the pulse: ONE soft dot per row. It rides the first connector, is taken in by the model, and rides the second.
   developers.js measures the four stops (--x0…--x3, from the row's left edge) and the line's height (--py). */
.developers-pulse { position: absolute; z-index: 2; left: 0; top: var(--py, 0px); inline-size: 0; block-size: 0; opacity: 0; pointer-events: none; }   /* above every word: nothing has to be drawn over it */
.developers-pulse::before { content: ""; position: absolute; left: -10px; top: -10px; inline-size: 20px; block-size: 20px; border-radius: 50%; background: radial-gradient(closest-side, rgba(166, 240, 148, .5), rgba(var(--developers-glow), .22) 55%, transparent); }   /* --glow-hi, then --glow, thinned */
.developers-pulse::after { content: ""; position: absolute; left: -3px; top: -3px; inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--glow-hi); }
@keyframes developers-glide-a {
  0% { transform: translateX(var(--x0, 0px)); opacity: 0; }
  14%, 80% { opacity: 1; }
  100% { transform: translateX(var(--x1, 0px)); opacity: 0; }
}
@keyframes developers-glide-b {
  0% { transform: translateX(var(--x2, 0px)); opacity: 0; }
  14%, 80% { opacity: 1; }
  100% { transform: translateX(var(--x3, 0px)); opacity: 0; }
}
/* the body of a node the pulse reaches: up by 4 %, and back on the spring */
@keyframes developers-pop {
  0% { transform: none; animation-timing-function: var(--ease-out); }
  28% { transform: scale(1.04); animation-timing-function: var(--spring); }
  100% { transform: none; }
}

/* ————— live (js adds .is-live when motion is allowed): the rows rest quiet but fully readable, the running row lights up
   step by step and lets go slowly, while the next row is already starting. Every step is a fade or a glide: a state that
   arrives takes .28 s, a state that leaves .48 s. Without .is-live (no JS, ?static=1, reduced motion, a browser that
   draws no frames) every node is lit and nothing moves. ————— */
.developers-panel.is-live .developers-node--io { opacity: .72; transition: opacity var(--d-3) var(--ease-out); }
.developers-panel.is-live .developers-node--io.is-on { opacity: 1; transition-duration: var(--d-2); }
.developers-panel.is-live .developers-well::after { opacity: 0; }
.developers-panel.is-live .is-on > .developers-well::after { opacity: 1; transition-duration: var(--d-2); }
.developers-panel.is-live .developers-pill::after { opacity: 0; }
.developers-panel.is-live .is-on > .developers-pill::after { opacity: 1; transition-duration: var(--d-2); }
.developers-panel.is-live .is-on > :is(.developers-well, .developers-pill)::before,
.developers-panel.is-live .is-on > :is(.developers-well, .developers-pill)::after { animation: developers-pop var(--d-3) 1; }
.developers-panel.is-live .developers-conn::before { opacity: .36; }
.developers-panel.is-live .developers-conn.is-on::before { opacity: .95; transition-duration: var(--d-1); }
.developers-panel.is-live .developers-flow.is-active::before { opacity: .05; transition-duration: var(--d-2); }
/* the pulse sets off: the trace is drawn exactly under it (same time, same curve) */
.developers-panel.is-live .developers-flow.is-a > .developers-pulse { animation: developers-glide-a var(--d-3) var(--ease-in-out) both; }
.developers-panel.is-live .developers-flow.is-b > .developers-pulse { animation: developers-glide-b var(--d-3) var(--ease-in-out) both; }
.developers-panel.is-live .developers-flow.is-a > .developers-conn--a > .developers-trace,
.developers-panel.is-live .developers-flow.is-b > .developers-conn--b > .developers-trace { opacity: .95; transform: scaleX(1); transition: transform var(--d-3) var(--ease-in-out); }
/* it has arrived: the line itself is lit now, and the trace steps back under it */
.developers-panel.is-live .developers-flow > .developers-conn.is-on > .developers-trace { opacity: 0; transition: opacity var(--d-1) linear; }
/* ?test hook: a pulse caught half-way */
.developers-panel .developers-flow.is-mid-a > .developers-pulse { opacity: 1; transform: translateX(calc((var(--x0, 0px) + var(--x1, 0px)) / 2)); }
.developers-panel .developers-flow.is-mid-b > .developers-pulse { opacity: 1; transform: translateX(calc((var(--x2, 0px) + var(--x3, 0px)) / 2)); }
.developers-panel .developers-flow.is-mid-a > .developers-conn--a > .developers-trace,
.developers-panel .developers-flow.is-mid-b > .developers-conn--b > .developers-trace { opacity: .95; transform: scaleX(.5); }

/* ————— entrance: the panel rises in (data-reveal), then its three rows, 60 ms apart; the loop starts after them ————— */
.js:not(.is-static) .developers-panel[data-reveal] .developers-flow {
  opacity: 0; transform: translateY(10px);
  transition: opacity var(--d-2) var(--ease-out), transform var(--d-2) var(--ease-out); transition-delay: calc(200ms + var(--r, 0) * 60ms);
}
.js:not(.is-static) .developers-panel[data-reveal].is-in .developers-flow { opacity: 1; transform: none; }

/* ————— a very narrow panel (320 px phones) ————— */
@container developers-panel (max-width: 299.98px) {
  .developers-flows { --developers-conn: 14px; --developers-padx: .5rem; }
  .developers-pill { padding-inline: .25rem; }
}
/* ————— a medium panel (the desktop column before it is wide enough for the row layout): same stacked nodes, more air ————— */
@container developers-panel (min-width: 440px) and (max-width: 679.98px) {
  .developers-flows { --developers-conn: 40px; --developers-padx: 1.25rem; --developers-cols: 3.2; padding-block: 1.25rem;
    --developers-tpl: minmax(0, 1fr) var(--developers-conn) minmax(0, 1.2fr) var(--developers-conn) minmax(0, 1fr); }
  .developers-flow { padding-block: 1.625rem 1.375rem; }
  .developers-label { font-size: .875rem; line-height: 1.125rem; }
  html[lang="ar"] .developers-label { font-size: 1rem; line-height: 1.375rem; }
}
@container developers-panel (min-width: 540px) and (max-width: 679.98px) {
  .developers-flows { --developers-conn: 48px; --developers-padx: 1.5rem; --developers-well: 48px; padding-block: 1.5rem; }
  .developers-flow { padding-block: 1.75rem 1.5rem; }
  .developers-label { font-size: .9375rem; line-height: 1.25rem; }
  html[lang="ar"] .developers-label { font-size: 1.0625rem; line-height: 1.5rem; }
}

/* ————— a wide panel (a tablet, where it takes the full width): icon and label side by side, the model becomes a true pill ————— */
@container developers-panel (min-width: 680px) {
  .developers-flows { --developers-padx: 1.75rem; padding-block: 1.25rem; }
  .developers-flow { padding-block: 1.625rem; align-items: center; }
  .developers-node { flex-direction: row; gap: .625rem; text-align: start; }
  .developers-label { font-size: .9375rem; line-height: 1.25rem; }
  html[lang="ar"] .developers-label { font-size: 1.0625rem; line-height: 1.5rem; }
  .developers-pill { border-radius: var(--pill); padding: .25rem 1rem; }
  .developers-node--model { align-self: center; }
  .developers-conn { align-self: center; margin-block-start: 0; }
  .developers-conn--a, .developers-conn--b { margin-inline: 10px; }
  .developers-flows { --developers-tpl: minmax(0, 1fr) 44px minmax(0, 1.25fr) 44px minmax(0, 1.15fr); }
  @supports (grid-template-columns: subgrid) {
    /* shared columns sized by the longest label in each: the three rows line up exactly */
    .developers-flows { --developers-tpl: auto minmax(40px, 1fr) auto minmax(40px, 1fr) auto; }
    .developers-node--io .developers-label { white-space: nowrap; }
  }
}

/* ————— desktop: two columns; the words are centred against the panel ————— */
@media (min-width: 960px) {
  .developers-grid { grid-template-columns: minmax(0, .95fr) minmax(0, 1fr); column-gap: clamp(3rem, 7vw, 6rem); align-items: center; }
}


/* ===== company ===== */
/* ===================================================================================================
   company — "Everyone can speak."
   The quietest section: the statement, one voice drawn as a hairline across the whole page (in the
   green of the logo), then the reason, the languages, and where it is made. Mostly air.
   Phone: one column. From 960 px: the reason on the inline-start, the languages on the inline-end.
   js/company.js draws the line in and lets it breathe; without it the line is simply there.
   =================================================================================================== */

.company-head { margin-block-end: 0; }

/* ————— the voice line: full width of the page, always left to right (it is a picture of sound) ————— */
.company-line { position: relative; direction: ltr; margin-block: clamp(2.25rem, 5vw, 4rem) clamp(2.5rem, 5.5vw, 4.5rem); overflow: hidden; }
/* the drawing is 1440 × 96: from 960 px it spans the page; on a phone it keeps its size and shows its middle (slice).
   Its height is always an odd number of whole pixels, so its still middle (the flat ends of the line) sits on a
   pixel row instead of between two: one clean row with a faint edge, at any width. */
.company-line > svg { inline-size: 100%; block-size: clamp(64px, 6.667vw, 280px); block-size: calc(round(down, clamp(64px, 6.667vw, 280px), 2px) + 1px); }
.company-line path { stroke: var(--green-500); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke-linejoin: round; shape-rendering: geometricPrecision; }
@media (min-resolution: 1.5dppx) { .company-line path { stroke-width: 1.25; } }   /* dense screens: 2.5 device pixels, two full rows */

/* drawn once, start to end, in .8 s: a cover in the page colour, with a soft leading edge, glides off (transform only).
   The cover only exists while company.js holds .is-armed; it drops it after the draw, or if the browser gives no sign of life */
.company-line.is-armed::after {
  content: ""; position: absolute; inset-block: 0; left: -140px; inline-size: calc(100% + 140px); pointer-events: none;
  background: linear-gradient(to right, transparent, var(--bg) 140px);
}
.company-line.is-armed.is-drawing::after { transform: translateX(100%); transition: transform var(--d-4) var(--ease-out); }

/* then it breathes, almost imperceptibly: the whole voice between 96 % and 100 % of its height, very slowly, and only
   while it is on screen (.is-seen). The stroke does not scale, so the line keeps its weight.
   The breath is a registered number (company.js registers --company-breath, and gives .is-alive only where that works)
   that moves in 48 small steps per breath: the browser then redraws the line itself, sharp, ten times a second,
   instead of stretching a picture of it (which softens a 1.5 px line for as long as it moves). */
.company-voice { transform-origin: 720px 48px; }
@keyframes company-breathe { from { --company-breath: 1; } to { --company-breath: .96; } }
.company-line.is-alive .company-voice { transform: scaleY(var(--company-breath, 1)); animation: company-breathe calc(var(--d-4) * 6) steps(48, end) infinite alternate; animation-play-state: paused; }
.company-line.is-alive.is-seen .company-voice { animation-play-state: running; }

/* ————— the reason, the languages, the origin ————— */
.company-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2.5rem, 6vw, 4rem); }
.company .company-text { max-inline-size: 31em; }

.company-langs { display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem; align-content: start; }
.company-cap { font-size: var(--fs-tiny); font-weight: 600; line-height: 1.125rem; color: var(--muted); }
html[lang="ar"] .company-cap { font-size: .875rem; line-height: 1.375rem; }
.company-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-block-start: .625rem; }
.company-chip {
  display: inline-flex; align-items: center; gap: .375rem; block-size: 40px; padding-inline: 1rem; border-radius: var(--pill);
  font-size: var(--fs-small); font-weight: 500; line-height: 1.25rem; color: var(--ink-2); box-shadow: inset 0 0 0 1px var(--line); text-transform: capitalize;
  transition: transform var(--d-1) var(--ease-out);
}
html[lang="ar"] .company-chip { font-size: 1rem; line-height: 1.5rem; padding-block-end: 2px; }   /* the Arabic face sits low in its line: lift it to the middle */
.company-chip--on { background: var(--green-100); color: var(--green-800); font-weight: 600; padding-inline-start: .75rem; box-shadow: inset 0 0 0 1px var(--green-500); }
.company-chip--on .icon { inline-size: 18px; block-size: 18px; stroke-width: 2.2; color: var(--green-700); }
@media (hover: hover) { .company-chip:hover { transform: translateY(-1px); } }

/* the block is revealed as one moment (core.js gives .is-in) but holds still itself: its pieces arrive, 40 ms apart,
   and the check of today's language is drawn. Animations that fill backwards only: once in, a chip is plain again. */
.js:not(.is-static) .company .company-langs[data-reveal] { opacity: 1; transform: none; transition: none; will-change: auto; }
.js:not(.is-static) .company-langs[data-reveal]:not(.is-in) :is(.company-cap, .company-chip) { opacity: 0; }
.js:not(.is-static) .company-langs.is-in .company-cap { animation: company-fade var(--d-2) var(--ease-out) backwards; animation-delay: calc(45ms + var(--c, 0) * 120ms); }
.js:not(.is-static) .company-langs.is-in .company-chip {
  animation: company-fade var(--d-2) var(--ease-out) backwards, company-chip-in var(--d-3) var(--spring) backwards;
  animation-delay: calc(90ms + var(--c, 0) * 40ms);
}
@keyframes company-fade { from { opacity: 0; } }
@keyframes company-chip-in { from { transform: translateY(8px) scale(.94); } }
.js:not(.is-static) .company-langs[data-reveal] .company-chip--on .icon path { stroke-dasharray: 20; stroke-dashoffset: 20; transition: stroke-dashoffset var(--d-2) var(--ease-out) 300ms; }
.js:not(.is-static) .company-langs[data-reveal].is-in .company-chip--on .icon path { stroke-dashoffset: 0; }

.company-origin { display: flex; align-items: start; gap: .625rem; font-size: var(--fs-small); line-height: 1.5rem; color: var(--muted); }
.company-origin::before { content: ""; flex: none; inline-size: 6px; block-size: 6px; margin-block-start: .5625rem; border-radius: 50%; background: var(--green-500); }
html[lang="ar"] .company-origin { font-size: 1rem; line-height: 1.75rem; }
html[lang="ar"] .company-origin::before { margin-block-start: .75rem; }

@media (min-width: 960px) {
  .company-body { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); column-gap: clamp(3rem, 8vw, 7rem); row-gap: clamp(3rem, 5vw, 4.5rem); }
  .company-langs { padding-block-start: .25rem; }
  .company-origin { grid-column: 1 / -1; }
}


/* ===== contact ===== */
/* contact — one night panel with a soft green glow on the light page: the title, one line, three glass fields and a
   white button, two quiet direct lines. No card inside the panel, no rules: the space does the work.
   Motion (v4): every state is a layer that fades or a small move (opacity / transform only, on the shared curves).
   Nothing changes size: the note floats under the button, the confirmation takes the form's own place. */

.contact { --contact-glow: 103, 160, 95; --contact-tap: calc(var(--d-1) / 2); --contact-ring: 2px; }
@media (min-resolution: 1.5dppx) { .contact { --contact-ring: 1.5px; } }   /* three device pixels on a dense screen, two on a plain one */

.contact-panel {
  display: grid; gap: clamp(2.25rem, 8vw, 3.25rem);
  padding: clamp(2.5rem, 8vw, 5.5rem) clamp(1.375rem, 6vw, 5.5rem);
  background: var(--night);
  box-shadow: 0 44px 80px -48px rgba(var(--contact-glow), .7);   /* the light spills a little under the panel, onto the page */
}
/* its own light: a wide dawn of the logo green rising from the foot of the panel, the title left on clear night */
.contact-panel::before {
  background:
    radial-gradient(150% 46% at 50% 108%, rgba(var(--contact-glow), .66), transparent 68%),
    radial-gradient(90% 30% at 100% 0%, rgba(var(--contact-glow), .16), transparent 70%);
}

.contact :focus-visible { outline: 2px solid var(--green-300); outline-offset: 3px; }
.contact-intro { display: grid; gap: 1.1rem; }
.contact-intro .h2 { max-inline-size: 11em; }
.contact-intro .lead { max-inline-size: 23em; }

/* ————— the form: three glass fields, one white pill ————— */
html:not(.js) .contact-box { display: none; }   /* the form needs JavaScript to send: without it the two direct lines remain */
.contact-box { display: grid; inline-size: 100%; }
.contact-box > * { grid-area: 1 / 1; min-inline-size: 0; }   /* the form and the confirmation share one place: its height never changes */
.contact-form {
  display: grid; gap: 1.25rem; color-scheme: dark;
  transition: opacity var(--d-1) var(--ease-out), transform var(--d-1) var(--ease-out), visibility 0s linear var(--d-1);
}
.contact .field { gap: .5rem; scroll-margin-block: 1rem; }   /* a field brought into view keeps its label clear of the bar */
.contact .field > label { font-size: .875rem; font-weight: 500; line-height: 1.25rem; color: var(--on-dark-2); transition: color var(--d-2) var(--ease-out); }
.contact .field:focus-within > label { color: var(--on-dark); }
.contact-control { position: relative; display: grid; border-radius: var(--r-m); }
.contact .input {
  min-height: 54px; padding-inline: 1.1em; border-radius: var(--r-m);
  background: rgba(243, 247, 242, .06); color: var(--on-dark); caret-color: var(--green-300);   /* --on-dark, thinned */
  box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .16); transition: none;   /* the hairline never changes: the states are the layers below */
}
.contact .input:hover, .contact .input:focus { outline: 0; box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .16); }
.contact textarea.input { min-height: 88px; max-block-size: 14rem; resize: none; field-sizing: content; }   /* short; grows with the text where the browser can */
html[dir="rtl"] .contact .input[dir="ltr"] { text-align: right; }   /* Latin values line up under the Arabic labels */
/* a value filled in by the browser keeps the panel's colours (two rules: a browser that lacks one selector keeps the other) */
.contact .input:-webkit-autofill { -webkit-text-fill-color: var(--on-dark); caret-color: var(--green-300); box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .16), inset 0 0 0 100px var(--night-3); }
.contact .input:autofill { -webkit-text-fill-color: var(--on-dark); caret-color: var(--green-300); box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .16), inset 0 0 0 100px var(--night-3); }

/* the states of a field, each a layer over it whose opacity is all that moves:
   under the pointer (a brighter hairline) · in focus (a green ring, a faint inner glow, a little more glass) · still missing (a white ring) */
.contact-control::before, .contact-ring, .contact-ring::before, .contact-ring::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
.contact-control::before { box-shadow: inset 0 0 0 1px rgba(243, 247, 242, .2); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
@media (hover: hover) { .contact-control:hover::before { opacity: 1; } }
.contact-ring::before, .contact-ring::after { opacity: 0; transition: opacity var(--d-2) var(--ease-out); }
.contact-ring::before { background: rgba(243, 247, 242, .03); box-shadow: inset 0 0 0 var(--contact-ring) var(--green-300), inset 0 0 22px rgba(var(--contact-glow), .26); }
.contact-ring::after { box-shadow: inset 0 0 0 var(--contact-ring) var(--on-dark); }
.contact .input:focus ~ .contact-ring::before { opacity: 1; }
.contact .input[aria-invalid="true"] ~ .contact-ring::after { opacity: 1; }
/* the first time a field is found missing it shakes its head, once (contact.js; never with reduced motion) */
@keyframes contact-shake { 0%, 100% { transform: none; } 18% { transform: translateX(-5px); } 40% { transform: translateX(4px); } 62% { transform: translateX(-3px); } 82% { transform: translateX(2px); } }
.js:not(.is-static) .contact-control.is-shake { animation: contact-shake calc(var(--d-1) * 2) var(--ease-in-out) 1; }

/* the honeypot: out of sight, out of reach */
.contact-hp { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); opacity: 0; pointer-events: none; }

/* ————— the button, and the note that floats under it ————— */
.contact-foot { position: relative; display: grid; margin-block-start: .375rem; }
.contact-send {
  position: relative; isolation: isolate; display: grid; place-items: center; min-height: 54px; font-size: 1rem;
  transition: transform var(--d-3) var(--spring), opacity var(--d-2) var(--ease-out);
}
.contact-panel .contact-send.btn:hover { --btn-bg: #fff; }   /* the hover tint is the layer below: the fill itself never changes */
.contact-send::before { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit; background: var(--green-100); opacity: 0; transition: opacity var(--d-1) var(--ease-out); }
@media (hover: hover) { .contact-send:not([disabled]):hover::before { opacity: 1; } }
.contact-send:not([disabled]):active { transform: scale(.97); transition-duration: var(--contact-tap), var(--d-2); }
.contact-send:not([disabled]):active::before { opacity: 1; transition-duration: var(--contact-tap); }
.contact-send[disabled] { opacity: .8; cursor: progress; }
/* two faces in one place: "Send →" and "Sending" with its three dots. One leaves upwards (.16 s) as the other comes up (.28 s) */
.contact-send > span { grid-area: 1 / 1; display: inline-flex; align-items: center; justify-content: center; gap: .6em; }
.contact-send-idle { transition: opacity var(--d-2) var(--ease-out) 60ms, transform var(--d-2) var(--ease-out) 60ms; }
.contact-send-busy { opacity: 0; transform: translateY(6px); transition: opacity var(--d-1) var(--ease-out), transform var(--d-1) var(--ease-out); }
.contact-send.is-busy .contact-send-idle { opacity: 0; transform: translateY(-6px); transition: opacity var(--d-1) var(--ease-out), transform var(--d-1) var(--ease-out); }
.contact-send.is-busy .contact-send-busy { opacity: 1; transform: none; transition: opacity var(--d-2) var(--ease-out) 60ms, transform var(--d-2) var(--ease-out) 60ms; }
.contact-send .arrow { transition: transform var(--d-2) var(--ease-out); }
@media (hover: none) {   /* no arrow left pushed aside after a tap */
  .contact-send:hover .arrow { transform: none; }
  [dir="rtl"] .contact-send:hover .arrow { transform: scaleX(-1); }
}
.contact-dots { display: inline-flex; gap: 4px; margin-inline-start: -.15em; }
.contact-dots i { inline-size: 4px; block-size: 4px; border-radius: 50%; background: currentColor; opacity: .3; }
@keyframes contact-dot { 0%, 60%, 100% { opacity: .3; transform: none; } 30% { opacity: 1; transform: translateY(-2px); } }
.js:not(.is-static) .contact-send.is-busy .contact-dots i { animation: contact-dot calc(var(--d-4) * 1.4) var(--ease-in-out) infinite; }
.js:not(.is-static) .contact-send.is-busy .contact-dots i:nth-child(2) { animation-delay: var(--d-1); }
.js:not(.is-static) .contact-send.is-busy .contact-dots i:nth-child(3) { animation-delay: calc(var(--d-1) * 2); }
.is-static .contact-dots, html:not(.js) .contact-dots { display: none; }   /* at rest the word keeps its own "…" */

/* what is missing, or that sending failed: it comes down 6 px from under the button, into the space below it
   (on a phone the small "or directly" caption steps back for it; see .is-noting) */
.contact-note {
  position: absolute; inset-inline: 0; inset-block-start: calc(100% + .625rem);
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .625rem; align-items: start;
  color: var(--on-dark); font-size: .875rem; font-weight: 500; line-height: 1.25rem; overflow-wrap: anywhere;
  opacity: 0; transform: translateY(-6px); transition: opacity var(--d-1) var(--ease-out), transform var(--d-1) var(--ease-out);
}
.contact-note.is-on { opacity: 1; transform: none; transition-duration: var(--d-2); }
.contact-note::before {
  content: "!"; inline-size: 18px; block-size: 18px; margin-block-start: 1px; border-radius: 50%; background: var(--on-dark); color: var(--night);
  display: grid; place-items: center; font-family: var(--font); font-size: .75rem; font-weight: 800; line-height: 1;
}

/* ————— sent: the form steps back (.16 s) and a calm confirmation comes up in its place: the disc blooms, the check is drawn ————— */
.contact-box.is-sent .contact-form { opacity: 0; transform: translateY(-8px); visibility: hidden; pointer-events: none; }
.contact-done { align-self: center; display: grid; justify-items: start; gap: .5rem; outline: 0; }
.contact-done-mark {
  position: relative; isolation: isolate; inline-size: 56px; block-size: 56px; margin-block-end: .875rem; border-radius: 50%; display: grid; place-items: center;
  background: rgba(var(--contact-glow), .18); box-shadow: inset 0 0 0 1px rgba(var(--contact-glow), .5); color: var(--green-300);   /* --glow, thinned */
}
.contact-done-mark::before { content: ""; position: absolute; z-index: -1; inset: -20px; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--contact-glow), .38), transparent); pointer-events: none; }
.contact-done-mark .icon { inline-size: 24px; block-size: 24px; stroke-width: 2; }
.contact-done-title { font-size: clamp(1.5rem, 1.2vw + 1.2rem, 1.875rem); font-weight: 500; --k: 1; }
.contact-done-text { color: var(--on-dark-2); max-inline-size: 22em; font-size: var(--fs-lead); line-height: 1.5; text-wrap: balance; --k: 2; }
/* before it is sent (and only where motion is allowed) the pieces wait just below their place */
.js:not(.is-static) .contact-box:not(.is-sent) .contact-done > * { opacity: 0; transform: translateY(10px); }
.js:not(.is-static) .contact-box:not(.is-sent) .contact-done-mark { transform: scale(.7); }
.js:not(.is-static) .contact-box:not(.is-sent) .contact-done-mark::before { opacity: 0; transform: scale(.55); }
.js:not(.is-static) .contact-box:not(.is-sent) .contact-done-mark .icon path { stroke-dasharray: 20; stroke-dashoffset: 20; }
.js:not(.is-static) .contact-box.is-sent .contact-done > * { transition: opacity var(--d-2) var(--ease-out), transform var(--d-3) var(--ease-out); transition-delay: calc(110ms + var(--k, 0) * 50ms); }
.js:not(.is-static) .contact-box.is-sent .contact-done-mark { transition: opacity var(--d-2) var(--ease-out) 110ms, transform var(--d-3) var(--spring) 110ms; }
.js:not(.is-static) .contact-box.is-sent .contact-done-mark::before { transition: opacity var(--d-3) var(--ease-out) 170ms, transform var(--d-4) var(--ease-out) 170ms; }
.js:not(.is-static) .contact-box.is-sent .contact-done-mark .icon path { stroke-dasharray: 20; stroke-dashoffset: 0; transition: stroke-dashoffset calc(var(--d-2) * 1.25) var(--ease-out) 320ms; }

/* ————— the two direct lines: an icon and the value, nothing around them ————— */
.contact-direct { display: grid; justify-items: start; }
.contact-or { font-size: .875rem; font-weight: 500; line-height: 1.25rem; color: var(--on-dark-2); margin-block-end: .375rem; transition: opacity var(--d-2) var(--ease-out); }
.contact-line {
  display: inline-flex; align-items: center; gap: .75rem; min-block-size: 48px; max-inline-size: calc(100% + 1rem);
  padding-inline: .5rem; margin-inline: -.5rem; border-radius: var(--r-s);   /* room for the focus ring, nothing moves */
  font-size: 1.0625rem; font-weight: 500; line-height: 1.5rem; color: var(--on-dark); transition: opacity var(--d-1) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.contact-line .icon { color: var(--green-500); }
.contact-line .latin { letter-spacing: 0; white-space: nowrap; }
.contact-line-label { color: var(--on-dark-2); margin-inline-end: -.25rem; transition: color var(--d-1) var(--ease-out); }
.contact-line-value { position: relative; transition: color var(--d-1) var(--ease-out); }
/* under the pointer: the value turns to the light green, a hairline grows under it from its start, an arrow steps in */
.contact-line-value::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: -2px; block-size: 1px; background: currentColor; opacity: .55;
  transform: scaleX(0); transform-origin: 100% 50%; transition: transform calc(var(--d-1) * 1.25) var(--ease-out);
}
.contact-line .arrow { margin-inline-start: -.25rem; color: var(--green-300); opacity: 0; transform: translateX(-6px); transition: opacity var(--d-1) var(--ease-out), transform var(--d-2) var(--ease-out); }
[dir="rtl"] .contact-line .arrow { transform: scaleX(-1) translateX(-6px); }
@media (hover: hover) {
  .contact-line:hover .contact-line-label, .contact-line:hover .contact-line-value { color: var(--green-300); }
  .contact-line:hover .contact-line-value::after { transform: scaleX(1); transform-origin: 0 50%; }
  .contact-line:hover .arrow { opacity: 1; transform: none; }
  [dir="rtl"] .contact-line:hover .arrow { transform: scaleX(-1); }
}
/* reached with the keyboard: the same answer, inside the ring */
.contact-line:focus-visible .contact-line-value::after { transform: scaleX(1); transform-origin: 0 50%; }
.contact-line:focus-visible .arrow { opacity: 1; transform: none; }
[dir="rtl"] .contact-line:focus-visible .arrow { transform: scaleX(-1); }
.contact-line:active { opacity: .7; transition-duration: var(--contact-tap); }

/* very small phones (320 px): the WhatsApp line still fits on one line */
@media (max-width: 359px) {
  .contact-panel { padding-inline: 1.125rem; }
  .contact-line { font-size: 1rem; gap: .6rem; }
  .contact-box { margin-block-end: .75rem; }   /* the note can take three lines here: a little more room under the button, always */
}
/* one column: the note lies in the space between the button and the direct lines, and their small caption makes room */
@media (max-width: 899.98px) {
  .contact-panel.is-noting .contact-or { opacity: 0; transition-duration: var(--d-1); }
}

/* ————— wider: the words on one side, the form on the other; the direct lines rest on the form's last line ————— */
@media (min-width: 900px) {
  .contact-panel {
    grid-template-columns: minmax(0, 1fr) clamp(22rem, 30vw, 26rem); grid-template-rows: auto 1fr; grid-template-areas: "intro box" "direct box";
    column-gap: clamp(3rem, 6vw, 7rem); row-gap: 3rem; align-items: start;
  }
  .contact-panel::before {
    background:
      radial-gradient(70% 115% at 76% 128%, rgba(var(--contact-glow), .72), transparent 64%),
      radial-gradient(45% 60% at 0% 0%, rgba(var(--contact-glow), .10), transparent 70%);
  }
  [dir="rtl"] .contact-panel::before {   /* the light stays under the form */
    background:
      radial-gradient(70% 115% at 24% 128%, rgba(var(--contact-glow), .72), transparent 64%),
      radial-gradient(45% 60% at 100% 0%, rgba(var(--contact-glow), .10), transparent 70%);
  }
  .contact-intro { grid-area: intro; }
  .contact-intro .h2 { font-size: clamp(2.125rem, 3.48vw + .17rem, 3.3rem); }   /* fits the narrower column at 900 px, the full size at 1440 */
  .contact-box { grid-area: box; }
  .contact-direct { grid-area: direct; align-self: end; }
  /* the form is the taller column in every language, so the direct lines end on the button's line */
  .contact-form { gap: 1.5rem; }
  .contact textarea.input { min-height: 112px; }
}


/* ===== footer ===== */
/* footer — night: the logo, one line, the section links, the language, the legal line. Nothing else.
   (The language switch and the --nav-d-* times come from nav.css.) */

.footer { background: var(--night); color: var(--on-dark); position: relative; padding-block: clamp(3.5rem, 7vw, 5rem) max(2.25rem, calc(env(safe-area-inset-bottom) + 1.25rem)); }
@supports (width: round(1.5px, 1px)) { .footer { padding-block-start: round(clamp(3.5rem, 7vw, 5rem), 1px); } }   /* everything below starts on a whole pixel */
.footer :focus-visible { outline: 2px solid var(--green-300); outline-offset: 3px; }
.footer-grid { display: grid; gap: 2.25rem; justify-items: start; }

.footer-brand { display: grid; gap: .5rem; justify-items: start; }
.footer-home { display: inline-flex; align-items: center; min-block-size: 44px; border-radius: var(--r-s); -webkit-tap-highlight-color: transparent; transition: opacity var(--d-1) var(--ease-out); }
.footer-home:active { opacity: .72; transition-duration: var(--nav-d-tap); }
/* the same lockup as the bar: the mark 1.48 × the type size wide, the gap .36, centred on the capitals */
.footer-home .logo { font-size: 1.5rem; gap: .36em; }
.footer-home .logo-mark { inline-size: 1.48em; position: relative; inset-block-start: .05em; }
.footer-tagline { color: var(--on-dark-2); font-size: var(--fs-small); line-height: 1.5rem; }

/* section links: two tidy columns on a phone */
.footer-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1.5rem; inline-size: 100%; max-inline-size: 22rem; }
.footer-links a { display: inline-flex; align-items: center; justify-self: start; min-block-size: 46px; padding-inline: .5rem; margin-inline: -.5rem; border-radius: var(--r-s); font-size: var(--fs-small); font-weight: 500; line-height: 1.25rem; color: var(--on-dark); transition: color var(--d-1) var(--ease-out); -webkit-tap-highlight-color: transparent; }
/* under the pointer: the same hairline as in the bar, growing from the start of the word and leaving by its end */
.footer-links a > span { position: relative; }
.footer-links a > span::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: -4px; block-size: 1px; background: currentColor; opacity: .5;
  transform: scaleX(0); transform-origin: 100% 50%; transition: transform var(--nav-d-line) var(--ease-out);
}
[dir="rtl"] .footer-links a > span::after { transform-origin: 0 50%; }
.footer-links a:active { color: var(--green-300); transition-duration: var(--nav-d-tap); }
@media (hover: hover) {
  .footer-links a:hover { color: var(--surface); }
  .footer-links a:hover > span::after { transform: scaleX(1); transform-origin: 0 50%; }
  [dir="rtl"] .footer-links a:hover > span::after { transform-origin: 100% 50%; }
}

.footer-lang a { min-inline-size: 44px; block-size: 34px; }
.footer-legal { font-size: var(--fs-tiny); line-height: 1.25rem; color: var(--on-dark-2); margin-block-start: -.75rem; }

/* tablet: the links become one row */
@media (min-width: 600px) {
  .footer-links { display: flex; flex-wrap: wrap; column-gap: 2.25rem; max-inline-size: none; }
}
/* wide: two calm rows. The logo and the links; then the legal line and the language. */
@media (min-width: 900px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "brand links" "legal lang"; column-gap: 3rem; row-gap: clamp(3rem, 5vw, 4.5rem); align-items: start; justify-items: stretch; }
  @supports (width: round(1.5px, 1px)) { .footer-grid { row-gap: round(clamp(3rem, 5vw, 4.5rem), 1px); } }
  .footer-brand { grid-area: brand; }
  .footer-links { grid-area: links; justify-content: flex-end; inline-size: auto; }
  .footer-links a { min-block-size: 44px; color: var(--on-dark-2); }
  .footer-lang { grid-area: lang; justify-self: end; align-self: center; }
  .footer-legal { grid-area: legal; align-self: center; margin: 0; }
}
