/* ==========================================================================
   iHotel — reference site stylesheet
   Tokens first. Logical properties throughout. Three theme states.

   THEME CONTRACT (do not break):
     :root                                   -> complete LIGHT palette
     @media (prefers-color-scheme: dark)
       :root:not([data-theme="light"])       -> dark, unless user forced light
     :root[data-theme="dark"]                -> dark, forced by the toggle
   Never give a colour its only definition inside a media query.
   ========================================================================== */

/* ----------------------------------------------------------------- faces --
   SELF-HOSTED. Every family here is served from this repo, never from a font
   CDN: the audience is Saudi and a runtime request to a third party is a PDPL
   exposure, not a performance note. It is also the only way the offline copy
   an installer carries onto a property renders correctly.

   The WOFF2 files are Google's own and the unicode-range values are copied
   verbatim from the css2 stylesheets they were served with — those ranges are
   what stops a Latin page fetching the Arabic subset and the reverse.

   THE HOUSE STYLE PAIRING
     Cormorant Garamond   display — a light, high-contrast serif. It carries
                          the whole personality, so it is only ever used large.
     Archivo              body and UI. A plain grotesque that stays out of the
                          serif's way and holds up in the dense reference
                          pages, where a Garamond would not.
     Amiri                Arabic display. The Arabic half gets a real naskh
                          serif rather than the body sans at heading size —
                          otherwise the Arabic is a translation of the design
                          instead of the design. One weight: the display sizes
                          are light, so there is no 700, and Latin inside an
                          Arabic heading falls through the stack to Tajawal,
                          which already ships its Latin.
     Tajawal              Arabic body.
     JetBrains Mono       code, and nothing else.

   Archivo, Cormorant Garamond and JetBrains Mono ship from Google as VARIABLE
   fonts — one file per subset covers the whole weight range, which is why
   there is one @font-face per family rather than one per weight. Tajawal and
   Amiri are static, so they need a file per weight.

   Paths are relative to THIS stylesheet, so they resolve from /, from /ar/
   and from file:// alike. Never make them root-relative.

   All five families are SIL Open Font License 1.1. assets/fonts/OFL.txt
   carries the copyright notices and the licence text, and it SHIPS — the OFL
   requires it to travel with the files. Do not delete it to save 15 KB.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/archivo-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url("../fonts/cormorant-garamond-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Amiri';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/amiri-400-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/tajawal-400-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/tajawal-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/tajawal-500-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/tajawal-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/tajawal-700-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}
@font-face {
  font-family: 'Tajawal';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/tajawal-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------- tokens -- */
:root {
  /* ground + ink — stone and a warm near-black. The neutral is warm on
     purpose: a cool grey under a Garamond reads as a document, not a house. */
  --bg:          #F1EFEA;
  --surface:     #FBFAF7;
  --surface-2:   #E7E3DA;
  --surface-3:   #DDD8CD;
  --ink:         #211F1C;
  --ink-2:       #57524A;
  --ink-3:       #6A6459;   /* measured: 4.58:1 on --surface-2, the tightest ground */
  --rule:        #D5CFC3;
  --rule-soft:   #E4DFD5;

  /* brand — in this direction the brand IS the ink. There is no corporate
     blue: the house speaks in paper, ink and one restrained brass. */
  --brand:       #211F1C;
  --brand-hover: #3B372F;
  --brand-link:  #6B5A33;   /* measured: 5.83:1 on --bg */
  --brand-soft:  #E9E3D5;
  --brand-line:  #C6BCA4;

  /* the one warm accent, held back to hairlines and small labels */
  --gold:        #6F5C30;   /* measured: 5.34:1 on --gold-soft, the tightest ground */
  --gold-fill:   #8A7448;   /* fills, rules, markers */
  --gold-soft:   #EFE9DB;

  /* the two semantic colours: a form that refuses input has to say so, and
     one that accepted it should say that too */
  --warn:        #8E3620;
  --ok:          #4B6B3C;   /* measured: 5.27:1 on --bg */

  /* The focus ring is its own token because it is the one colour with a
     contrast floor of its own (WCAG 1.4.11, 3:1 against the adjacent ground).
     This brass measures 5.62:1 on --bg and 6.19:1 on --surface. */
  --focus:       #6F5C30;

  /* Type — a serif for display, a grotesque for everything that has to work.
     The split is the design: Cormorant carries the voice at large sizes and
     is never asked to set a dense list, which is where it would fall apart. */
  --f-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --f-body:    Archivo, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --f-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Arabic gets the same two-face structure rather than one face doing both:
     Amiri is the naskh answer to Cormorant, Tajawal the answer to Archivo. */
  --f-arabic:         Tajawal, Cairo, "Noto Sans Arabic", "Geeza Pro", "Segoe UI", Tahoma, sans-serif;
  --f-arabic-display: Amiri, Tajawal, "Noto Naskh Arabic", "Geeza Pro", Georgia, serif;

  /* One scale. Every size on the site comes from this list — nothing ad hoc.
     The display steps are larger than they were: Cormorant sits small on the
     em and is set light, so it needs the size to hold the page. */
  --fs-xs:   11.5px;  /* wide-tracked capitals: labels, eyebrows, captions */
  --fs-sm:   14.5px;  /* secondary text, card briefs */
  --fs-base: 16.5px;  /* body */
  --fs-md:   19px;    /* lead paragraph */
  --fs-lg:   26px;    /* h3 / card headline */
  --fs-xl:   40px;    /* h2 / section */
  --fs-2xl:  62px;    /* h1 */
  --lh-tight: 1.1;
  --lh-body:  1.68;

  /* measure + rhythm */
  --measure: 68ch;
  --page:    1180px;

  /* Corners are square. A Garamond over a 10px radius reads as a template;
     the one place a curve survives is the round count badge, which is a
     different object. Kept as a token so it is one decision, not forty. */
  --radius:    0px;
  --radius-sm: 0px;

  /* The hero scrim's opaque floor. Fixed dark in both themes, like the copy
     that sits on it — see the note at .hero--img::after for the measurement
     this number comes from. */
  --scrim-floor: rgba(19, 17, 16, .74);

  --shadow-1: 0 1px 2px rgba(33,31,28,.04), 0 8px 24px rgba(33,31,28,.05);
  --shadow-2: 0 2px 6px rgba(33,31,28,.06), 0 18px 44px rgba(33,31,28,.07);

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:          #14120F;
    --surface:     #1D1A16;
    --surface-2:   #232019;
    --surface-3:   #2C2820;
    --ink:         #EFEBE3;
    --ink-2:       #B0A99C;
    --ink-3:       #948D80;   /* measured: 4.94:1 on --surface-2 */
    --rule:        #302B23;
    --rule-soft:   #26221B;

    /* On a dark ground the ink cannot also be the brand — a primary button has
       to be visible. The brass takes over, and the button inverts. */
    --brand:       #E4C98F;
    --brand-hover: #F0DBAC;
    --brand-link:  #DCC08A;
    --brand-soft:  #2A2418;
    --brand-line:  #4A4130;

    --gold:        #DCC08A;
    --gold-fill:   #A98F55;
    --gold-soft:   #241F16;
    --warn:        #DE9075;
    --ok:          #9DC48A;   /* measured: 8.83:1 on --surface */
    --focus:       #C9A959;   /* measured: 8.28:1 on --bg */

    --shadow-1: 0 1px 2px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.28);
    --shadow-2: 0 2px 6px rgba(0,0,0,.4), 0 18px 44px rgba(0,0,0,.35);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg:          #14120F;
  --surface:     #1D1A16;
  --surface-2:   #232019;
  --surface-3:   #2C2820;
  --ink:         #EFEBE3;
  --ink-2:       #B0A99C;
  --ink-3:       #948D80;   /* measured: 4.94:1 on --surface-2 */
  --rule:        #302B23;
  --rule-soft:   #26221B;

  /* On a dark ground the ink cannot also be the brand — a primary button has
     to be visible. The brass takes over, and the button inverts. */
  --brand:       #E4C98F;
  --brand-hover: #F0DBAC;
  --brand-link:  #DCC08A;
  --brand-soft:  #2A2418;
  --brand-line:  #4A4130;

  --gold:        #DCC08A;
  --gold-fill:   #A98F55;
  --gold-soft:   #241F16;
  --warn:        #DE9075;
  --ok:          #9DC48A;   /* measured: 8.83:1 on --surface */
  --focus:       #C9A959;   /* measured: 8.28:1 on --bg */

  --shadow-1: 0 1px 2px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.28);
  --shadow-2: 0 2px 6px rgba(0,0,0,.4), 0 18px 44px rgba(0,0,0,.35);

  color-scheme: dark;
}

/* ----------------------------------------------------------------- base -- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Reserve the scrollbar's width at all times, so locking the scroll while
     the search dialog is open does not shift the page sideways underneath it.
     Ignored where scrollbars overlay the content, which is every phone. */
  scrollbar-gutter: stable;
}
/* The search dialog is modal: the page behind it must not scroll away. */
html.is-search-open { overflow: hidden; }

body {
  margin: 0;
  background: var(--bg);          /* explicit: the host paints its own ground */
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;             /* body must never scroll sideways */
}

/* Arabic glyphs sit smaller on the same em, so the whole page steps up one
   notch and gains leading. Done once here rather than per component. */
/* AR — and the Arabic half of /404.html, which is an Arabic run inside an English
   document. The asset handler serves the nearest 404.html, and there is no
   ar/404.html, so that one page answers unknown URLs under /ar/ as well as at the
   root and has to speak both languages with <html lang> stuck at "en".

   It is added as a second selector on each Arabic rule rather than given a block of
   its own, because a block of its own would mean a second copy of the type scale
   below — and this stylesheet already carries one policy written twice (the CSP,
   see _headers) which the README flags as a hazard. One source, two selectors.

   Scoped to that page, not to [lang="ar"] generally: the header's language toggle
   carries lang="ar" on every English page, and it keeps the face it has there. */
html[lang="ar"],
[data-page="404.html"] [lang="ar"] {
  --fs-xs:   14px;
  --fs-sm:   16px;
  --fs-base: 17.5px;
  --fs-md:   20px;
  --fs-lg:   21px;
  --fs-xl:   31px;
  --fs-2xl:  44px;
  --lh-tight: 1.45;
  --lh-body:  1.9;
}
html[lang="ar"] body,
[data-page="404.html"] [lang="ar"] { font-family: var(--f-arabic); }

/* JetBrains Mono has no Arabic glyphs, so any label styled with it falls back
   to whatever the system offers — which is not Tajawal and looks foreign.
   In Arabic every label takes the Arabic face; only real code stays mono. */
html[lang="ar"] code,
html[lang="ar"] kbd,
html[lang="ar"] .dr-cr,
html[lang="ar"] .domain__ref { font-family: var(--f-mono); }

html[lang="ar"] .eyebrow,
html[lang="ar"] .brand__tag,
html[lang="ar"] .tool-btn,
html[lang="ar"] .tier,
html[lang="ar"] .chip,
html[lang="ar"] .stat__l,
html[lang="ar"] .group__count,
html[lang="ar"] .groups-toolbar__n,
html[lang="ar"] .plan__name,
html[lang="ar"] figcaption,
html[lang="ar"] caption,
html[lang="ar"] thead th,
html[lang="ar"] .search-foot,
html[lang="ar"] .search-result__c,
html[lang="ar"] .site-footer .foot__col,
html[lang="ar"] .site-footer__bar,
html[lang="ar"] .dg-text-sm {
  font-family: var(--f-arabic);
  letter-spacing: 0;
  text-transform: none;
}

img, svg, video { max-width: 100%; height: auto; }

:where(a):focus-visible,
:where(button):focus-visible,
:where(summary):focus-visible,
:where(input):focus-visible,
:where(select):focus-visible,
:where(textarea):focus-visible,
:where([tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip {
  position: absolute;
  inset-inline-start: 8px;
  inset-block-start: -60px;
  z-index: 200;
  background: var(--brand);
  color: #fff;
  padding: 10px 16px;
  border-radius: 0;
  font-weight: 600;
  text-decoration: none;
  transition: inset-block-start .15s ease;
}
:root[data-theme="dark"] .skip,
:root:not([data-theme="light"]) .skip { color: #14120F; }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .skip { color: #fff; } }
.skip:focus { inset-block-start: 0; }

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

/* The no-JS floor. Rendered only when scripting is off, where it stands in
   for the header and footer the renderer would have built. */
.noscript {
  max-width: var(--page); margin-inline: auto;
  padding: 16px clamp(16px, 4vw, 40px);
  background: var(--surface-2);
  border-block-end: 1px solid var(--rule);
}
.noscript p { font-size: var(--fs-sm); color: var(--ink-2); margin: 0 0 10px; }
.noscript ul {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  list-style: none; padding: 0; margin: 0; max-width: none;
}
.noscript li { margin: 0; }
.noscript a { font-size: 14px; font-weight: 600; }

/* ------------------------------------------------------------- headings -- */
h1, h2, h3, h4 { font-family: var(--f-display); text-wrap: balance; margin: 0; line-height: var(--lh-tight); }
html[lang="ar"] h1, html[lang="ar"] h2,
html[lang="ar"] h3, html[lang="ar"] h4,
[data-page="404.html"] [lang="ar"] :is(h1, h2, h3, h4) { font-family: var(--f-arabic-display); letter-spacing: 0; font-weight: 400; }

/* Light weights and almost no negative tracking: a Garamond is already
   narrow, and tightening it at 62px closes the counters. */
h1 { font-size: var(--fs-2xl); letter-spacing: -.012em; font-weight: 300; }
h2 { font-size: var(--fs-xl);  letter-spacing: -.008em; font-weight: 400; }
h3 { font-size: var(--fs-lg);  letter-spacing: 0;       font-weight: 400; }
@media (max-width: 640px) {
  :root { --fs-2xl: 40px; --fs-xl: 30px; --fs-lg: 22px; }
  html[lang="ar"] { --fs-2xl: 34px; --fs-xl: 27px; --fs-lg: 21px; }
}

.eyebrow {
  font-family: var(--f-body);
  font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--gold); margin: 0 0 22px;
}
html[lang="ar"] .eyebrow,
[data-page="404.html"] [lang="ar"] .eyebrow { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: var(--fs-sm); }

p { margin: 0 0 14px; max-width: var(--measure); }
.lead { font-size: var(--fs-md); line-height: 1.66; color: var(--ink-2); max-width: 56ch; font-weight: 400; }

a { color: var(--brand-link); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--brand-hover); }

strong { font-weight: 600; color: var(--ink); }

ul, ol { margin: 0 0 14px; padding-inline-start: 22px; max-width: var(--measure); }
li { margin-block-end: 6px; }
li::marker { color: var(--ink-3); }

code, .u-mono { font-family: var(--f-mono); font-size: .88em; }
/* Latin identifiers inside Arabic prose must not be reordered by the bidi
   algorithm — isolate them so "409 DOUBLE_BOOKING" stays in that order. */
code, .u-mono, .dr-cr, .domain__ref { unicode-bidi: isolate; }
code {
  background: var(--surface-2);
  border: 1px solid var(--rule-soft);
  border-radius: 3px;
  padding: 1px 5px;
  color: var(--brand);
}
kbd {
  font-family: var(--f-mono); font-size: .82em;
  background: var(--surface-2);
  border: 1px solid var(--rule); border-block-end-width: 2px;
  border-radius: 4px; padding: 1px 5px; color: var(--ink-2);
}

/* --------------------------------------------------------------- layout -- */
.wrap { max-width: var(--page); margin-inline: auto; padding-inline: clamp(16px, 4vw, 40px); }

main { display: block; padding-block-end: 72px; }

.band { padding-block: clamp(38px, 5vw, 60px); border-block-end: 1px solid var(--rule); }
.band:last-child { border-block-end: 0; }
.band--tint { background: var(--surface-2); }

.stack > * + * { margin-block-start: 14px; }

.grid { display: grid; gap: 16px; }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr)); }
.grid p { max-width: none; }

/* --------------------------------------------------------------- header --
   RESERVING THE HEADER'S HEIGHT

   #site-header ships empty and render.js fills it, so until the script ran,
   every page pushed its own content down by the whole height of the header —
   a layout shift on every load, on every page.

   The reservation is scoped to :empty on purpose. It applies only while the
   div has no children, which is exactly the window the shift happens in, and
   stops applying the instant the header is injected. So a number that is a
   little off costs a little residual shift and can never leave a strip of
   bare page under a sticky header — which a plain min-height would, the first
   time a font or a nav label changed the wrap point.

   The numbers are measured, per band and per language, because the English
   nav labels are wider than the Arabic ones and the two therefore wrap onto
   an extra row at different widths. They are measured with the SELF-HOSTED
   faces loaded: a nav label's width is a property of Archivo and Tajawal at
   the tracking set on .nav a, not of the fallback stack, so re-measure if a
   label changes length OR if the type changes. Every edge below is the exact
   width at which a row is added, found by stepping the viewport one pixel at
   a time. Each value is the measured height, so the reservation is never
   taller than the header that replaces it -- the page only ever settles down,
   never up. With scripting off there is nothing to inject and nothing to
   reserve.

   The navy design took the MAXIMUM across seven pages here, because its
   current-page nav link was bold and so moved the wrap point a few pixels per
   page. This design underlines the current page instead of bolding it -- the
   weight is 500 either way -- so the wrap point no longer varies. Verified,
   not assumed: the reservation was checked against the real header on eight
   pages in both languages before this note was written. If a heavier
   current-page state ever comes back, take the maximum again.

   RE-MEASURED 2026-09-01, and the previous numbers had been WRONG since the
   day the "Live demo" button landed in the header. They described a header
   that fitted on one row above 1127px, and after that button there was no
   width at which it fitted at all: the row needed 1163px and --page caps the
   usable width at 1100px, so every English viewport got the two-row header
   and the 61px band was never once correct. Both facts are why the numbers
   below are measured again rather than adjusted.

   What changed with them: "Live demo" moved to the hero row on index.html,
   the last three nav items fold under "More" (see PAGES in render.js), the
   wordmark went 26px -> 32px and the labels 10px -> 11px on tighter tracking.

   Measured ranges, English then Arabic:

     EN   889+ 66 | 862-888 115 | 362-860 104 | 320-361 140
     AR   868+ 66 | 861-867 119 | 372-860 113 | 320-371 149

   Both languages now hold one row down to the same place, near enough, which
   they never did before -- the English labels no longer set the width, the
   folded six do. Each edge is the exact width at which a row is added, found
   by stepping one pixel at a time, and each value is floored to the integer
   BELOW the measured height so the reservation is never taller than the
   header that replaces it: the page only ever settles down, never up.

   The bare rules below also match an Arabic page, but every Arabic value is
   set by an html[lang="ar"] selector, which outranks them -- so the order of
   the two languages within a band does not matter, only the order of the
   bands, which run widest first. */
#site-header:empty { min-height: 66px; }
html[lang="ar"] #site-header:empty { min-height: 66px; }

@media (max-width: 888px) { #site-header:empty { min-height: 115px; } }
@media (max-width: 867px) { html[lang="ar"] #site-header:empty { min-height: 119px; } }

@media (max-width: 860px) {
  #site-header:empty { min-height: 104px; }
  html[lang="ar"] #site-header:empty { min-height: 113px; }
}
@media (max-width: 371px) { html[lang="ar"] #site-header:empty { min-height: 149px; } }
@media (max-width: 361px) { #site-header:empty { min-height: 140px; } }

/* Both selectors: the Arabic rule above is more specific, so overriding the
   bare one alone would leave an Arabic page reserving space for a header that
   is never coming. */
@media (scripting: none) {
  #site-header:empty,
  html[lang="ar"] #site-header:empty { min-height: 0; }
}

.site-header {
  position: sticky; inset-block-start: 0; z-index: 100;
  /* Plain colour first: color-mix() is Safari 16.2 / Chrome 111, and where it
     is unsupported the whole declaration is dropped — which left a sticky
     header with no background at all and page text scrolling through it. */
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(10px);
  border-block-end: 1px solid var(--rule);
}
.site-header__inner {
  max-width: var(--page); margin-inline: auto;
  padding: 10px clamp(16px, 4vw, 40px);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.brand {
  display: inline-flex;
  flex-direction: column; align-items: center; gap: 5px;
  font-family: var(--f-display); font-weight: 400; font-size: 27px;
  letter-spacing: .005em; line-height: 1;
  color: var(--ink); text-decoration: none;
  margin-inline-end: auto;
}
html[lang="ar"] .brand { font-family: var(--f-arabic-display); }
.brand__i { color: var(--gold-fill); }
.brand__tag {
  font-family: var(--f-body); font-size: 8.5px; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3);
  margin-inline-start: 0; white-space: nowrap;
}

.nav { display: flex; flex-wrap: wrap; gap: 0; align-items: center; }
/* Tracked capitals, one size UP from where they were and on tighter tracking, which
   nets out narrower: folding three items under "More" (see PAGES in render.js) freed
   about 240px of row, and it was spent on legibility rather than banked. */
.nav a, .nav__more > summary {
  font-size: 11px; font-weight: 500; letter-spacing: .02em; text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: none; padding: 7px 5px; border-radius: var(--radius-sm); white-space: nowrap;
  display: inline-flex; align-items: center; min-height: 34px;
}
html[lang="ar"] .nav a,
html[lang="ar"] .nav__more > summary { letter-spacing: 0; text-transform: none; font-size: 14.5px; }
.nav a:hover, .nav__more > summary:hover { background: var(--surface-2); color: var(--ink); }
.nav a[aria-current="page"],
.nav__more > summary[aria-current] { color: var(--ink); background: transparent; box-shadow: inset 0 -1px 0 var(--gold-fill); }

/* ---------------------------------------------------------- the "More" menu -- */
/* A <details>, so the open/closed state, the keyboard and the accessible name are the
   browser's job. Only the marker and the panel are ours. */
/* The bare `details` rule further down this file (see "disclosures") gives every
   disclosure a card: border, surface, radius, and 12px of block margin. That is right
   for the ones in the page body and wrong for a nav item -- unreset, the margins alone
   made the nav 60px tall instead of 34 and pushed the whole header down with it. The
   same applies to the open-state summary border. */
.nav__more {
  position: relative;
  margin: 0; border: 0; border-radius: 0; background: none;
}
.nav__more[open] > summary { border-block-end: 0; }
.nav__more > summary { cursor: pointer; list-style: none; gap: 5px; }
.nav__more > summary::-webkit-details-marker { display: none; }
/* The caret is drawn, not typed: ▾ renders as an emoji on some Android builds and as
   tofu where the fallback face has no glyph for it. */
.nav__more > summary::after {
  content: ''; width: 6px; height: 6px; margin-block-start: -3px;
  /* PHYSICAL right/bottom, not inline-end/block-end. A caret points DOWN in both
     directions -- it is a disclosure, not a direction. With border-inline-end the
     border moves to the left edge under RTL and the same 45deg turn aims the arrow
     sideways, which is what the Arabic header did until this was pinned down. */
  border-right: 1.3px solid currentColor; border-bottom: 1.3px solid currentColor;
  transform: rotate(45deg); transition: transform .15s ease;
}
.nav__more[open] > summary::after { transform: rotate(-135deg); margin-block-start: 2px; }
/* `display` is set on the OPEN state only. Setting it on .nav__menu itself overrides
   the UA rule that hides a closed <details>'s content, and the panel then sits open on
   the page permanently -- which is exactly what happened the first time. */
.nav__menu { display: none; }
.nav__more[open] > .nav__menu {
  position: absolute; inset-block-start: calc(100% + 6px); inset-inline-start: 0;
  z-index: 110; min-width: max-content;
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px;
  background: var(--bg); border: 1px solid var(--rule); border-radius: var(--radius-sm);
  box-shadow: 0 10px 28px rgb(0 0 0 / .22);
}
.nav__menu a { width: 100%; }
@media (prefers-reduced-motion: reduce) { .nav__more > summary::after { transition: none; } }

.tools { display: flex; align-items: center; gap: 4px; }
/* Grown by padding, not by type size: at 11px mono these were 25px tall,
   which is a hard target for a thumb. The box is now 34px; the letters are
   the same size they always were. */
.tool-btn {
  font-family: var(--f-body); font-size: 10px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  background: transparent; color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--radius-sm);
  padding: 10px 7px; cursor: pointer; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px;
}
.tool-btn:hover { background: var(--surface-2); color: var(--ink); border-color: var(--brand-line); }
.tool-btn--icon { min-width: 34px; padding-inline: 8px; }
.tools .btn { padding: 12px 14px; letter-spacing: .08em; }
html[lang="ar"] .tools .btn { padding: 11px 16px; }
.tool-btn--icon svg { display: block; }

.btn {
  display: inline-block;
  font-family: var(--f-body); font-size: 11px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  padding: 15px 30px; border-radius: var(--radius-sm);
  text-decoration: none; cursor: pointer;
  border: 1px solid transparent; line-height: 1.2;
}
/* Arabic has no case, so the tracked-capitals device does not translate.
   The Arabic button keeps its own size and weight instead of a letter-spaced
   run of glyphs that would simply be wrong. */
html[lang="ar"] .btn,
[data-page="404.html"] [lang="ar"] .btn {
  font-family: var(--f-arabic); font-size: var(--fs-sm); font-weight: 500;
  letter-spacing: 0; text-transform: none; padding: 14px 28px;
}
.btn--primary { background: var(--brand); color: var(--bg); }
.btn--primary:hover { background: var(--brand-hover); color: var(--bg); }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }

/* ------------------------------------------------------------ tier tags -- */
/* status badges removed from the public site — see content.js */

/* --------------------------------------------------------------- panels -- */
.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 24px 26px;
  box-shadow: none;
}
.panel > :first-child { margin-block-start: 0; }
.panel > :last-child { margin-block-end: 0; }

.note {
  border-inline-start: 2px solid var(--gold-fill);
  background: var(--gold-soft);
  border-radius: 0;
  padding: 18px 22px;
  margin-block: 24px;
}
.note > :last-child { margin-block-end: 0; }
.note h3 {
  font-family: var(--f-body); font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  margin-block-end: 8px; color: var(--gold);
}
html[lang="ar"] .note h3 { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: var(--fs-sm); }

/* ------------------------------------------------------- feature blocks -- */
.domain { margin-block-start: 40px; }
.domain__head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  border-block-end: 2px solid var(--ink);
  padding-block-end: 8px; margin-block-end: 6px;
}
.domain__ref {
  font-family: var(--f-mono); font-size: 11px; font-weight: 700;
  letter-spacing: .08em; color: var(--gold); margin-inline-start: auto;
}
html[dir="rtl"] .domain__ref { margin-inline-start: auto; }
.domain__intro { color: var(--ink-2); margin-block: 10px 0; }

/* ---- groups: headline + brief, details on click ---- */
.groups-toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-block-end: 26px; padding-block-end: 14px;
  border-block-end: 1px solid var(--rule);
}
.groups-toolbar__n {
  font-family: var(--f-mono); font-size: 11.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
html[lang="ar"] .groups-toolbar__n { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: 13px; }

/* ---- curated product-page sections ---- */
.psections { display: grid; gap: 44px; }
.psection__head { max-width: 66ch; }
.psection__head h2 { margin-block-end: 8px; }
.psection__brief { color: var(--ink-2); font-size: var(--fs-md); margin: 0; }
.seeall {
  margin: 8px 0 0; padding-block-start: 20px;
  border-block-start: 1px solid var(--rule);
}
.seeall a { font-size: 14.5px; font-weight: 600; text-decoration: none; }
.seeall a:hover { text-decoration: underline; }

/* Marketing density: headlines are the page. Details open in place. */
.groups {
  display: grid;
  /* min() so the track can never be wider than the container — a bare
     minmax(310px,…) overflows a 320px viewport. */
  grid-template-columns: repeat(auto-fit, minmax(min(310px, 100%), 1fr));
  gap: 14px;
  margin-block-start: 18px;
  /* Stretch, not start: every card in a row ends at the same depth, which is
     what makes a row read as a set. .card__more already sits at the bottom of
     the card via margin-block-start:auto, so the count lines line up too. */
  align-items: stretch;
}
/* A group that has been opened spans the full width so its detail list is
   readable at a sane measure instead of squeezed into one column. */
details.group[open] { grid-column: 1 / -1; }

details.group {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  margin: 0;
  overflow: hidden;
  /* the header is sticky — a deep link must not land underneath it */
  scroll-margin-block-start: 92px;
}
details.group[open] { box-shadow: var(--shadow-1); border-color: var(--brand-line); }

.group__summary {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 18px 20px;
  cursor: pointer;
  list-style: none;
  border-block-end: 0;
  min-height: 104px;
}
details.group[open] > .group__summary { min-height: 0; }
details.group:not([open]) > .group__summary { min-height: 100%; }
.group__summary::-webkit-details-marker { display: none; }
.group__summary::marker { content: ""; }
.group__summary:hover { background: var(--surface-2); }
details.group[open] > .group__summary { border-block-end: 1px solid var(--rule-soft); }

.group__head { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
/* NOT the display face. Cormorant is the voice of the marketing pages; a
   capability list is four hundred short headlines in a scannable grid, and a
   light serif at that density is unreadable. The grotesque does the work. */
.group__title {
  font-family: var(--f-body); font-weight: 600; font-size: 18px;
  line-height: 1.3; letter-spacing: -.005em; color: var(--ink);
}
html[lang="ar"] .group__title { font-family: var(--f-arabic); font-size: var(--fs-md); }
.group__brief { font-size: var(--fs-sm); line-height: 1.5; color: var(--ink-2); max-width: 68ch; }

.group__meta { display: flex; align-items: center; gap: 10px; flex: none; padding-block-start: 3px; }
.group__count {
  font-family: var(--f-mono); font-size: 10.5px; font-weight: 700;
  min-width: 22px; text-align: center;
  padding: 3px 6px; border-radius: 20px;
  background: var(--surface-2); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
details.group[open] .group__count { background: var(--brand-soft); color: var(--brand); }
.group__chev {
  width: 9px; height: 9px; flex: none;
  border-inline-end: 2px solid var(--ink-3);
  border-block-end: 2px solid var(--ink-3);
  transform: rotate(45deg);
  margin-block-start: -4px;
  transition: transform .15s ease;
}
details.group[open] .group__chev { transform: rotate(-135deg); margin-block-start: 2px; }
@media (prefers-reduced-motion: reduce) { .group__chev { transition: none; } }
html[dir="rtl"] .group__chev {
  border-inline-end: 0; border-block-end: 2px solid var(--ink-3);
  border-inline-start: 2px solid var(--ink-3);
  transform: rotate(-45deg);
}
html[dir="rtl"] details.group[open] .group__chev { transform: rotate(135deg); }

.group__body { padding: 4px 18px 8px; }

.features { list-style: none; padding: 0; margin: 0; max-width: none; display: grid; gap: 0; }
.feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 6px 16px;
  padding: 13px 0;
  border-block-end: 1px solid var(--rule-soft);
  margin: 0;
  align-items: start;
  scroll-margin-block-start: 92px;
}
.feature:last-child { border-block-end: 0; }
.feature__title { font-family: var(--f-body); font-weight: 600; font-size: var(--fs-base); line-height: 1.35; }
html[lang="ar"] .feature__title { font-family: var(--f-arabic); }
.feature__detail { grid-column: 1 / -1; color: var(--ink-2); font-size: var(--fs-sm); margin: 0; max-width: var(--measure); }
.feature__detail code { font-size: .85em; }
.feature[hidden] { display: none; }
.feature--hit { background: var(--gold-soft); border-radius: 6px; padding-inline: 10px; }
.feature--sig .feature__title { color: var(--brand); }
.feature--sig .feature__title::after {
  content: "";
  display: inline-block; vertical-align: middle;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--gold-fill);
  margin-inline-start: 7px;
}

/* ---------------------------------------------------------------- table -- */
.scroller {
  overflow-x: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  margin-block: 20px;
  -webkit-overflow-scrolling: touch;
}
table { border-collapse: collapse; width: 100%; font-size: 14px; min-width: 560px; }
caption {
  caption-side: top; text-align: start;
  font-family: var(--f-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3);
  padding: 12px 16px 10px; border-block-end: 1px solid var(--rule-soft);
}
th, td { text-align: start; padding: 10px 14px; border-block-end: 1px solid var(--rule-soft); vertical-align: top; }
thead th {
  font-family: var(--f-body); font-size: 10.5px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-3); background: var(--surface-2); white-space: nowrap;
}
tbody tr:last-child td { border-block-end: 0; }
.num { font-variant-numeric: tabular-nums; text-align: end; white-space: nowrap; }
.dr-cr { font-family: var(--f-mono); font-size: 12.5px; white-space: nowrap; }

/* ----------------------------------------------------------- stat strip -- */
.stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(148px, 100%), 1fr));
  gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
  margin-block: 24px;
}
.stat { background: var(--surface); padding: 16px 18px; }
.stat__v {
  font-family: var(--f-display); font-size: 36px; font-weight: 300;
  letter-spacing: -.015em; color: var(--ink); line-height: 1.05;
  font-variant-numeric: lining-nums tabular-nums;   /* see .claim b */
}
html[lang="ar"] .stat__v { font-family: var(--f-arabic-display); }
.stat__l {
  font-family: var(--f-body); font-size: 10px; font-weight: 500; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3); margin-block-start: 8px; line-height: 1.4;
}
html[lang="ar"] .stat__l { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: 11.5px; }

/* -------------------------------------------------------------- pillars -- */
.pillar { display: flex; flex-direction: column; gap: 10px; }
.pillar h3 { font-size: 17px; }
.pillar ul { margin: 0; padding-inline-start: 18px; font-size: 14.5px; color: var(--ink-2); }
.pillar__more { margin-block-start: auto; padding-block-start: 8px; font-size: 14px; font-weight: 600; }

/* ------------------------------------------------------------- diagrams -- */
figure { margin: 22px 0; }
figure svg { display: block; width: 100%; height: auto; }
figcaption {
  font-size: 13px; color: var(--ink-3); margin-block-start: 10px;
  font-family: var(--f-mono); letter-spacing: .02em; max-width: var(--measure);
}
html[lang="ar"] figcaption { font-family: var(--f-arabic); }
.dg-fill    { fill: var(--surface); }
.dg-fill-2  { fill: var(--surface-2); }
.dg-stroke  { stroke: var(--rule); fill: none; }
.dg-line    { stroke: var(--ink-3); fill: none; }
.dg-accent  { fill: var(--gold-fill); }
.dg-brand   { fill: var(--brand-soft); stroke: var(--brand-line); }
.dg-text    { fill: var(--ink); font-family: var(--f-body); font-size: 13px; }
.dg-text-sm { fill: var(--ink-2); font-family: var(--f-mono); font-size: 11px; }
html[lang="ar"] .dg-text,
html[lang="ar"] text.dg-text-sm { font-family: var(--f-arabic); }

/* --------------------------------------------------------- disclosures -- */
details {
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--surface); margin-block: 12px;
}
summary {
  cursor: pointer; padding: 13px 18px; list-style-position: inside;
  font-family: var(--f-display); font-weight: 600; font-size: 15px;
}
html[lang="ar"] summary { font-family: var(--f-arabic); }
details[open] > summary { border-block-end: 1px solid var(--rule-soft); }
.details__body { padding: 16px 18px; }
.details__body > :last-child { margin-block-end: 0; }

/* ------------------------------------------------------------- filters -- */
.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-block: 16px; }
.chip {
  font-family: var(--f-body); font-size: 10.5px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  background: transparent; color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--radius-sm);
  padding: 10px 14px; cursor: pointer; line-height: 1;
  display: inline-flex; align-items: center;
  min-height: 34px; text-decoration: none;
}
html[lang="ar"] .chip { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: 12.5px; }
.chip:hover { border-color: var(--brand-line); color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--brand); color: var(--bg); border-color: var(--brand); }

/* -------------------------------------------------------------- search -- */
.search-overlay {
  position: fixed; inset: 0; z-index: 300;
  /* Same reason as the header: without a fallback, an older engine drops the
     declaration and the scrim disappears entirely. A fixed dark rgba() reads
     correctly on both themes. */
  background: rgba(8, 18, 24, .55);
  background: color-mix(in srgb, var(--ink) 45%, transparent);
  display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(16px, 8vh, 90px) 16px 16px;
}
.search-overlay[hidden] { display: none; }
.search-box {
  width: min(660px, 100%);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  overflow: hidden;
  display: flex; flex-direction: column;
  max-height: min(70vh, 640px);
}
.search-head {
  display: flex; align-items: stretch;
  border-block-end: 1px solid var(--rule);
}
.search-input {
  flex: 1; min-width: 0; border: 0;
  background: var(--surface); color: var(--ink);
  font-family: var(--f-body); font-size: 17px;
  padding: 16px 18px; outline: none;
}
/* A dismissal a mouse or a touch can find — Escape is not discoverable, and
   on a phone there is no Escape key at all. */
.search-close {
  flex: none; min-width: 46px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-3); font-size: 15px; line-height: 1;
  padding-inline: 14px;
}
.search-close:hover { color: var(--ink); background: var(--surface-2); }
html[lang="ar"] .search-input { font-family: var(--f-arabic); }
.search-input::placeholder { color: var(--ink-3); }
/* Chromium draws its own ✕ inside a type="search" field, which would sit
   next to ours meaning something else entirely. */
.search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.search-results { overflow-y: auto; margin: 0; padding: 6px; list-style: none; max-width: none; }
.search-results li { margin: 0; }
.search-result {
  display: block; padding: 10px 12px; border-radius: var(--radius-sm);
  text-decoration: none; color: inherit;
}
.search-result:hover, .search-result:focus-visible { background: var(--surface-2); }
.search-result__t { font-weight: 600; font-size: 14.5px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.search-result__c { font-size: 12.5px; color: var(--ink-3); font-family: var(--f-mono); margin-block-start: 2px; }
html[lang="ar"] .search-result__c { font-family: var(--f-arabic); }
.search-foot {
  border-block-start: 1px solid var(--rule); padding: 9px 14px;
  font-family: var(--f-mono); font-size: 11px; color: var(--ink-3);
  display: flex; gap: 14px; flex-wrap: wrap;
}
html[lang="ar"] .search-foot { font-family: var(--f-arabic); }
.search-empty { padding: 26px 18px; color: var(--ink-3); text-align: center; font-size: 14.5px; }

/* ---------------------------------------------------------------- forms -- */
.field { display: flex; flex-direction: column; gap: 6px; margin-block-end: 16px; }
.field label {
  font-family: var(--f-body); font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-2);
}
html[lang="ar"] .field label { font-family: var(--f-arabic); letter-spacing: 0; text-transform: none; font-size: var(--fs-sm); }
.field input, .field select, .field textarea {
  font-family: var(--f-body); font-size: 15px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius-sm); padding: 12px 14px;
  width: 100%;
}
html[lang="ar"] .field input, html[lang="ar"] .field select, html[lang="ar"] .field textarea { font-family: var(--f-arabic); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--brand-line); }
.field textarea { min-height: 120px; resize: vertical; }
.field__hint { font-size: 12.5px; color: var(--ink-3); }
/* A field that was refused says so beside itself, not only in a summary
   somewhere below the button. */
.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: var(--warn); }
.field__err { font-size: 12.5px; color: var(--warn); margin: 0; }
.field__ok  { color: var(--ok); }

/* -------------------------------------------------------------- pricing -- */
.plan { display: flex; flex-direction: column; gap: 12px; height: 100%; }
.plan__name {
  margin: 0; font-family: var(--f-display); font-weight: 400;
  font-size: var(--fs-lg); line-height: var(--lh-tight);
  letter-spacing: 0; text-transform: none; color: var(--ink);
}
html[lang="ar"] .plan__name { font-family: var(--f-arabic-display); letter-spacing: 0; }
/* The differentiating sentence sits UNDER the name rather than instead of it.
   It used to be the heaviest thing on the card, which is why the plan's own
   name read as a label above it. */
.plan__what { font-family: var(--f-body); font-size: 15px; font-weight: 500; line-height: 1.45; color: var(--ink-2); }
html[lang="ar"] .plan__what { font-family: var(--f-arabic); }
.plan ul { margin: 0; padding-inline-start: 18px; font-size: 14px; color: var(--ink-2); }
.plan--feature { border-color: var(--brand-line); box-shadow: var(--shadow-2); }

/* --------------------------------------------------------------- footer -- */
.site-footer {
  border-block-start: 2px solid var(--ink);
  background: var(--surface-2);
  padding-block: 34px 28px;
}
.site-footer__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr)); gap: 24px; }
.site-footer .foot__col {
  font-family: var(--f-body); font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--ink-3); margin-block-end: 14px;
}
html[lang="ar"] .site-footer .foot__col { font-family: var(--f-arabic); letter-spacing: 0; }
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer li { margin-block-end: 6px; }
.site-footer a { font-size: 14px; color: var(--ink-2); text-decoration: none; }
.site-footer a:hover { color: var(--brand); text-decoration: underline; }
.site-footer__bar {
  margin-block-start: 26px; padding-block-start: 16px;
  border-block-start: 1px solid var(--rule);
  font-family: var(--f-mono); font-size: 11px; color: var(--ink-3);
  display: flex; gap: 10px 26px; flex-wrap: wrap; justify-content: space-between;
}
html[lang="ar"] .site-footer__bar { font-family: var(--f-arabic); }

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

/* ------------------------------------------------------------ responsive -- */
@media (max-width: 860px) {
  .site-header__inner { padding-block: 8px; }
  .brand__tag { display: none; }
  /* Nine links in a strip that shows about four. A hard clip at the edge
     reads as the end of the list, so the last visible item is faded out
     instead: half a word cut mid-fade is the affordance. The scrollbar is
     hidden because its height varies by platform, which would make the
     reserved header height above wrong on some of them — the fade replaces
     it. Focus inside the strip drops the mask so a focused link at the far
     end is never half-invisible. */
  .nav {
    order: 3; width: 100%; overflow-x: auto; padding-block-end: 2px;
    flex-wrap: nowrap; scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
  }
  .nav::-webkit-scrollbar { display: none; }
  html[dir="rtl"] .nav {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent);
            mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent);
  }
  .nav:focus-within,
  html[dir="rtl"] .nav:focus-within { -webkit-mask-image: none; mask-image: none; }
  .nav a { font-size: 13px; padding: 7px 10px; min-height: 32px; }
}
@media (max-width: 560px) {
  body { font-size: 15.5px; }
  .feature { grid-template-columns: 1fr; }
  .feature__tier { justify-self: start; }
  .stat__v { font-size: 30px; }
  /* Stacked, the hairline would sit to the left of every figure instead of
     between them, which is not what a rule between columns means. */
  .claim { padding-inline-start: 0; border-inline-start: 0; }
  .claims { gap: 26px 0; }
}


/* ==========================================================================
   Advertising-page components
   Short headline, one claim strip, a grid of short cards, one call to action.
   Detail lives in the wiki, not here.
   ========================================================================== */

.band--hero { padding-block: clamp(56px, 9vw, 108px) clamp(36px, 6vw, 64px); }
.band--hero .lead { margin-block-start: 20px; }
/* A photographic hero is given real height and the copy sits at the bottom of
   it, the way a property's own site would open. */
.band--hero.hero--img { padding-block: clamp(112px, 17vw, 208px) clamp(56px, 8vw, 96px); }
.band--cta { text-align: center; }
.band--cta .lead { margin-inline: auto; }

.cta-row {
  display: flex; gap: 12px; flex-wrap: wrap;
  margin-block-start: 26px; max-width: none;
}
.band--cta .cta-row { justify-content: center; }

/* image slots ------------------------------------------------------------
   Real photography. Every <img> carries width/height so the box is reserved
   before the bytes land and nothing below it jumps. Sources are WebP at
   several widths; the browser picks from srcset. */
.shot { margin-block: clamp(28px, 5vw, 48px) 0; }
.shot img {
  width: 100%; height: auto; display: block;
  border-radius: var(--radius);
  background: var(--surface-2);            /* holds the space while loading */
  filter: saturate(.82) contrast(1.02);    /* one grade, so the set reads as one shoot */
}
.shot figcaption {
  margin-block-start: 10px;
  font-size: var(--fs-xs); color: var(--ink-3);
}

/* Inside a card grid every plate takes the SAME crop. The source photographs
   are a mix of 16:9 and 2:1, so at their natural aspect the three pillars on
   the home page ended at three different heights and the row of headings under
   them stepped down like a staircase. object-fit crops rather than distorts.
   Only the grid is affected -- a full-width shot keeps its own proportions. */
.grid .shot img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Crops taken from a contact sheet top out around 500-650px wide. Capping
   them keeps the browser from upscaling one into a soft full-width band. */
.shot--sm { max-width: 640px; }

/* a portrait plate (the door panel) sits narrower than the text column */
.shot--tall { max-width: 420px; }
.shot--tall img { border-radius: var(--radius); }

/* two shots side by side, collapsing to one on narrow screens */
.shots {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  margin-block: clamp(28px, 5vw, 48px) 0;
}
.shots .shot { margin-block: 0; }

/* full-bleed hero image: a real <img> so it can be prioritised and
   responsive, with the copy laid over a scrim that keeps text legible
   against whatever the photograph is doing underneath. */
.hero--img { position: relative; isolation: isolate; overflow: clip; }
.hero--img > .hero__bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  border-radius: 0;
}
/* THE SCRIM HAS A FLOOR, AND THE FLOOR IS A CONTRAST GUARANTEE.

   Carried over from the navy design, where it was found by measurement, and
   re-measured for this one. Gradients alone are not safe: the eyebrow sits
   about a third of the way down, which is exactly where a top-and-bottom
   scrim is weakest, and this one bottomed out at .38 there. Against a white
   photograph that is 2.2:1 for the eyebrow — nowhere near the 4.5:1 its size
   requires.

   The flat layer underneath is the floor. At .74 the weakest point of the
   gradients still composites to .74, where the eyebrow measures 4.65:1 and
   the stone copy 7.25:1 against a white photograph — the worst case there is.
   The eyebrow is #DCC08A rather than the page's darker brass because at that
   colour the floor would have had to reach .80 to clear the same bar, and
   that much flat black buries the photograph this direction is built on.
   Raise the gradients freely; never lower the floor, and re-measure if the
   eyebrow colour changes.

   Being vertical, the gradient needs no RTL variant. */
.hero--img::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to bottom,
      rgba(19,17,16,.30) 0%,  rgba(19,17,16,0)   30%,
      rgba(19,17,16,.22) 62%, rgba(19,17,16,.55) 100%),
    var(--scrim-floor);
}
/* the scrim is fixed dark in both themes, so the copy on it is too */
.hero--img,
.hero--img h1,
.hero--img .lead,
.hero--img .eyebrow { color: #F4F1EA; }
.hero--img .eyebrow { color: #DCC08A; }   /* measured on the scrim floor above */
.hero--img .btn--ghost {
  color: #F4F1EA; border-color: rgba(244,241,234,.7);
}
.hero--img .btn--ghost:hover { border-color: #F4F1EA; background: #F4F1EA; color: #131110; }
.hero--img .btn--primary { background: #F4F1EA; color: #131110; }
.hero--img .btn--primary:hover { background: #FFFFFF; color: #131110; }

/* placeholder — a slot whose photograph has not been shot yet */
.shot__ph {
  aspect-ratio: 16 / 7;
  display: grid; place-items: center;
  padding: 24px;
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--ink-3);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  text-align: center;
}
html[lang="ar"] .shot__ph { font-family: var(--f-arabic); }

/* claim strip — four short numbers, no prose */
.claims {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
  gap: 32px 0;
}
/* Ranged left against a hairline rather than centred in a box. Centred
   numbers are a dashboard; a rule and a ranged figure is a page. */
.claim {
  text-align: start;
  padding-inline-start: 28px;
  border-inline-start: 1px solid var(--rule);
}
.claim:first-child { padding-inline-start: 0; border-inline-start: 0; }
.claim b {
  display: block;
  font-family: var(--f-display);
  font-size: clamp(42px, 5vw, 56px); font-weight: 300;
  letter-spacing: -.015em; color: var(--ink);
  /* Cormorant defaults to OLD-STYLE figures, where 3 4 7 9 drop below the
     baseline. Beautiful in running prose, wrong in a row of four numbers that
     are meant to line up with each other -- lnum puts them back on one line. */
  font-variant-numeric: lining-nums tabular-nums; line-height: 1;
}
html[lang="ar"] .claim b { font-family: var(--f-arabic-display); }
.claim span {
  display: block; margin-block-start: 14px;
  font-family: var(--f-body); font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-2);
}
html[lang="ar"] .claim span {
  font-family: var(--f-arabic); letter-spacing: 0; text-transform: none;
  font-size: var(--fs-sm);
}

/* On an advertising page the sections breathe more and the cards say less. */
.psections { gap: clamp(36px, 6vw, 56px); }
.psection__head { margin-block-end: 4px; }

/* ------------------------------------------------------------------ wiki --
   The reference half of the site. The product pages are an advertisement;
   this is the manual, and it is allowed to be dense. Two columns on desktop
   with a sticky contents rail, one column below 900px where a sticky rail
   would eat the screen. */
.wiki__grid {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: clamp(24px, 4vw, 52px);
  align-items: start;
}
.wiki__nav { position: sticky; top: 88px; max-height: calc(100vh - 110px); overflow-y: auto; }
.wiki__nav h2 {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); font-family: var(--f-mono); margin-block-end: 12px;
}
html[lang="ar"] .wiki__nav h2 {
  font-family: var(--f-arabic); letter-spacing: 0; text-transform: none;
}
.wiki__nav ol { list-style: none; margin: 0; padding: 0; }
.wiki__nav li { margin-block-end: 2px; }
.wiki__nav a {
  display: block; padding: 7px 12px; border-radius: var(--radius-sm);
  color: var(--ink-2); text-decoration: none;
  font-size: var(--fs-sm); line-height: 1.35;
  border-inline-start: 2px solid transparent;
}
.wiki__nav a:hover { background: var(--surface-2); color: var(--ink); }
.wiki__nav a[aria-current="true"] {
  background: var(--surface-2); color: var(--ink);
  border-inline-start-color: var(--brand); font-weight: 600;
}

/* A grid item's automatic minimum size is its min-content, and the reference
   tables in here are 560px wide before they start scrolling. Without this the
   whole column refuses to shrink and the page scrolls sideways on a phone. */
.wiki__body { min-width: 0; }
.wiki__body > section { scroll-margin-block-start: 92px; }
.wiki__body > section + section {
  margin-block-start: clamp(44px, 6vw, 72px);
  padding-block-start: clamp(32px, 4vw, 48px);
  border-block-start: 1px solid var(--rule);
}
.wiki__body h2 { font-size: var(--fs-xl); }
.wiki__lede { color: var(--ink-2); margin-block: 10px 22px; }

@media (max-width: 900px) {
  .wiki__grid { grid-template-columns: minmax(0, 1fr); }
  .wiki__nav {
    position: static; max-height: none;
    padding-block-end: 20px; border-block-end: 1px solid var(--rule);
  }
  .wiki__nav ol { display: flex; flex-wrap: wrap; gap: 4px; }
  .wiki__nav a { padding: 6px 10px; border-inline-start: 0; }
}

/* the official wordmark, once the asset is in place ------------------------
   Height-constrained so whatever aspect the file has, it sits on the same
   baseline as the text wordmark it replaces. */
.brand__logo {
  height: 32px; width: auto; display: block;
  /* the mark is a gold gradient — it carries itself on both themes */
}
@media (max-width: 560px) { .brand__logo { height: 26px; } }

/* product-page cards --------------------------------------------------------
   Flat on purpose. These are read by someone deciding whether to book a demo,
   so a card says what they get in one line and stops. The capability detail
   behind it is on the wiki, where the reader came looking for it — and the
   whole card is the link that takes them there, so the hover and focus states
   belong to the card rather than to a small link inside it. */
.card {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 18px 20px;
  color: inherit; text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.card:hover {
  color: inherit;
  border-color: var(--brand-line);
  box-shadow: var(--shadow-1);
}
.card__t {
  font-size: var(--fs-md); line-height: 1.3; margin: 0 0 7px;
  letter-spacing: -.01em;
}
.card__b { margin: 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6; }
.card__more {
  display: block;
  margin-block-start: auto; padding-block-start: 12px;
  font-size: 13.5px; font-weight: 600; color: var(--brand-link);
}
.card:hover .card__more { text-decoration: underline; }
