/* ═══════════════════════════════════════════════════════════════
   DHARA — ذرى · brand implementation
   Palette from the DHARA brand guideline:
     Teal      #166487  fonts · logo icon
     Green     #1f6047  backgrounds · fonts
     Navy      #1e2735  logo icon · deep backgrounds
     Forest    #0f2718  deep green (dark lockup ink)
     Ice       #d6eef4 / #bbdbe2  light backgrounds · logo on dark
     Sand      #edd9b8  warm background accent
   Typeface: Rubik (all weights, Latin + Arabic).
   Single light theme. One stylesheet serves every page in both the
   LTR (EN) and RTL (AR) trees — physical left/right is avoided in
   favour of logical properties; [dir="rtl"] overrides live in §7.

   Sections:
     §1 · TOKENS          design primitives and semantic variables
     §2 · BASE            reset, typography, small utilities
     §3 · LAYOUT          site chrome (header/nav/footer), chapters, bands
     §4 · COMPONENTS      shared UI used across pages
     §5 · PAGE-SPECIFIC   home hero · compliance-guide components
     §6 · RESPONSIVE      cross-component breakpoint adjustments
     §7 · RTL OVERRIDES   the only physical-direction exceptions
   ═══════════════════════════════════════════════════════════════ */


/* ═══ §1 · TOKENS ═══════════════════════════════════════════════ */

:root {
  color-scheme: light;

  /* Brand primitives */
  --brand-teal:   #166487;
  --brand-green:  #1f6047;
  --brand-navy:   #1e2735;
  --brand-forest: #0f2718;
  --brand-ice:    #d6eef4;
  --brand-ice-2:  #bbdbe2;
  --brand-sand:   #edd9b8;

  /* ── 60 · 30 · 10 ─────────────────────────────────────────────
     60  light ice ground        --bg, --surface-1/2
     30  brand green + navy deep sections, ice/sand tinted bands
     10  teal accent — CTAs, links, active states, numerals
     Contrast is checked against the ground each pair sits on; every
     text/background pair below clears WCAG AA (4.5:1), headings and
     large type clear AAA. Notes are inline where a value is tight. */

  /* Text scale — navy/forest ink on the ice ground */
  --ink-50:  #fff;
  --ink-100: #1e2735;   /* body text — brand navy      12.6:1 on --bg */
  --ink-200: #2e3d4c;   /* secondary copy              10.0:1 on --bg */
  --ink-300: #10556f;   /* labels — deepened teal       7.1:1 on --bg */
  --ink-600: #24313f;
  --ink-700: #1e2735;
  --ink-800: #16202b;
  --ink-900: #0f2718;

  /* Surfaces — ice-tinted light ground */
  --bg:        #edf4f6;
  --surface-1: #ffffff;
  --surface-2: #dfedf1;
  --surface-3: #d6eef4;
  --surface-sand: #f5ead8;

  /* Deep grounds — the 30%. Used by .is-deep sections and the footer. */
  --deep-green:  #1f6047;
  --deep-green-2:#154c37;
  --deep-navy:   #1e2735;

  /* Headings — deep forest green (the dark lockup ink) */
  --cream-50:  #0f2718;
  --cream-100: #0f2718;
  --cream-200: #1e5f47;

  /* Accents (legacy var names kept; values are the DHARA palette) */
  --accent:     #166487;  /* the 10% — teal */
  --accent-2:   #1f6047;  /* green, for outline numerals and rules */
  --peach-200: #bbdbe2;
  --peach-300: #166487;   /* primary accent — teal */
  --peach-400: #1f6047;   /* secondary accent — green */
  --peach-500: #0f2718;

  /* Hairlines — teal-cast, a shade stronger than before so structure reads */
  --line:        rgba(22, 100, 135, .20);
  --line-strong: rgba(22, 100, 135, .38);

  /* Paper cards — white with an ice cast */
  --paper-bg: radial-gradient(140% 90% at 50% 0%, #ffffff 0%, #f4fafb 58%, #e6f2f5 100%);
  --paper-border: rgba(22, 100, 135, .22);
  --paper-shadow: 0 1px 0 #fffc inset, 0 18px 40px -26px rgba(15, 39, 24, .34);

  --hero-video-filter: brightness(.96) saturate(.95);
  /* ice fade at the BOTTOM (into the page) mirrored at the TOP */
  --hero-scrim:
    linear-gradient(180deg, #f2f6f7c2 0%, #f2f6f76b 12%, #f2f6f71f 25%, transparent 38%),
    linear-gradient(0deg, #f2f6f7c2 0%, #f2f6f76b 24%, #f2f6f71f 50%, transparent 76%);

  /* Type — Rubik carries every register per the brand fonts sheet */
  --font-display: "Rubik", ui-sans-serif, system-ui, sans-serif;
  --font-mono:    "Rubik", ui-sans-serif, system-ui, sans-serif;
  --font-serif:   "Rubik", ui-sans-serif, system-ui, sans-serif;

  --chrome-gutter-edge: clamp(12px, 1.4vw, 22px);

  /* TOC rail item count — keep in sync with the nav markup */
  --toc-count: 6;
}


/* ═══ §2 · BASE ═════════════════════════════════════════════════ */

body { background: radial-gradient(ellipse at 50% 18%, #ffffffa8 0%, transparent 58%), linear-gradient(180deg, #f1f7f8 0%, #dfedf1 100%) fixed, var(--bg); }

*,*::before,*::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  color: var(--ink-100);
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* clip, NOT hidden. `overflow-x: hidden` forces the other axis to compute
     to `auto`, which makes <body> a scroll container — and position:sticky
     resolves against its nearest scroll container, so every sticky element
     on the site silently stopped sticking and just scrolled with the page.
     `clip` fences the same horizontal overflow without creating one.
     The `hidden` line is the fallback for browsers without `clip`
     (Safari < 16): they keep the guard, and sticky stays as it was. */
  overflow-x: hidden;
  overflow-x: clip;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1,h2,h3 { font-family: var(--font-display); color: var(--cream-100); font-weight: 600; }
h2 { font-size: clamp(2rem, 4.6vw, 4.4rem); letter-spacing: -.02em; line-height: 1.02; max-width: 24ch; }
h3 { font-size: clamp(1.2rem, 2vw, 1.75rem); letter-spacing: -.01em; }

/* ── Small uppercase metadata label ─────────────────────────── */
.label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-300);
  font-weight: 500;
}
.accent { color: var(--peach-300); }
.dim { color: color-mix(in srgb, var(--ink-100) 55%, transparent); }
.serif { font-family: var(--font-serif); }
.serif em { font-style: italic; color: var(--ink-200); }

/* anchors on subpages land below the fixed chrome */
.subpage [id] { scroll-margin-top: 140px; }

/* mobile-only / desktop-only helpers */
@media (min-width: 1024px) { .hide-desktop { display: none; } }

/* skip link — visually hidden until focused */
.skip-link {
  position: fixed; top: -64px; inset-inline-start: 16px; z-index: 100;
  background: var(--cream-100); color: var(--bg);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  padding: 12px 18px; border-radius: 0 0 12px 12px;
  transition: top .25s ease;
}
.skip-link:focus { top: 0; }


/* ═══ §3 · LAYOUT ═══════════════════════════════════════════════ */

/* ── Pills / buttons ────────────────────────────────────────── */
/* The accent's main job: every primary action is brand teal on light
   (6.5:1 against white text), and deepens to brand green on hover. */
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: #fff; background: var(--accent);
  border: 1px solid var(--accent); border-radius: 999px;
  padding: 12px 22px; cursor: pointer;
  box-shadow: 0 10px 22px -16px rgba(15, 39, 24, .8);
  transition: background .3s, color .3s, border-color .3s, transform .3s;
}
/* the hover travel lives in §14 with the rest of the push-button behaviour */
.pill:hover { background: var(--brand-green); border-color: var(--brand-green); color: #fff; }
.pill:focus-visible { outline: 2px solid var(--brand-forest); outline-offset: 3px; }
.pill-ghost { background: transparent; color: var(--brand-forest); border-color: color-mix(in srgb, var(--accent) 50%, transparent); box-shadow: none; }
.pill-ghost:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: var(--accent); color: var(--brand-teal); }
.pill-small { padding: 8px 16px; font-size: 10px; }

/* ── Site chrome (multipage): utility strip + header in one fixed block ── */
.site-chrome { position: fixed; inset: 0 0 auto 0; z-index: 50; }
.site-chrome .site-header { position: static; }
/* Opaque, not translucent: the nav sits over photography on the home hero the
   moment the page moves, and a 90%-alpha wash was not enough to stop the image
   showing through the type. */
body.header-solid .site-chrome {
  background: color-mix(in srgb, var(--bg) 97%, transparent);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 14px 30px -26px rgba(15, 39, 24, .65);
}
body.header-solid .site-chrome .site-header { background: transparent; backdrop-filter: none; border-bottom-color: transparent; }

/* utility strip (desktop only) — UTIL-01..UTIL-04
   A permanent band of brand green across the top of every page: the first
   thing the palette says, and it holds even while the header is transparent. */
.utility-strip { display: none; }
@media (min-width: 1024px) {
  .utility-strip {
    display: flex; align-items: center; gap: 26px; padding: 8px 28px;
    background: linear-gradient(90deg, var(--deep-green) 0%, var(--deep-green-2) 100%);
    border-bottom: 1px solid rgba(15, 39, 24, .3);
    font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .08em;
    color: var(--brand-ice);   /* 6.2:1 on the green */
  }
  .utility-strip a { transition: color .3s; }
  .utility-strip a:hover { color: var(--brand-sand); }
  .utility-strip .lang-switch { color: var(--brand-ice); }
  .utility-strip .lang-switch:hover { background: transparent; color: var(--brand-sand); }
  .util-spacer { flex: 1; }
}

/* ── Fixed header ───────────────────────────────────────────── */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px;
  padding: 16px 28px; height: 90px;
  background: transparent; border-bottom: 1px solid transparent;
  transition: background-color .5s ease, border-color .5s ease, backdrop-filter .5s ease;
}
body.header-solid .site-header {
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}
.header-logo { display: flex; align-items: center; height: 56px; flex-shrink: 0; }
.header-logo img { height: 56px; width: auto; max-width: 300px; object-fit: contain; }
.header-right { display: flex; align-items: center; gap: 12px; }

/* language switch — a quiet ghost pill */
.lang-switch {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .08em;
  color: var(--ink-300); border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 7px 14px; transition: background .3s, color .3s;
}
.lang-switch:hover { background: var(--brand-ice); color: var(--brand-forest); }
.utility-strip .lang-switch { border: none; padding: 0; }

/* ── Primary nav — NAV-01..NAV-05 ───────────────────────────── */
.site-nav { display: flex; align-items: center; gap: clamp(16px, 2.2vw, 30px); }
.site-nav a {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-600); padding: 6px 2px; border-bottom: 1px solid transparent;
  transition: color .3s, border-color .3s;
}
.site-nav a:hover { color: var(--peach-300); }
.site-nav a[aria-current="page"] { color: var(--peach-300); border-bottom-color: var(--peach-300); }

/* mobile nav — disclosure button + dropdown panel */
.nav-toggle { display: none; }
@media (max-width: 1023px) {
  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; flex-shrink: 0;
    border: 1px solid var(--line-strong); border-radius: 999px;
    background: color-mix(in srgb, var(--surface-1) 60%, transparent); cursor: pointer;
  }
  .nav-toggle-bars { display: flex; flex-direction: column; gap: 4px; }
  .nav-toggle-bars span { display: block; width: 16px; height: 1.5px; background: var(--ink-100); transition: transform .3s, opacity .3s; }
  body.nav-open .nav-toggle-bars span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  body.nav-open .nav-toggle-bars span:nth-child(2) { opacity: 0; }
  body.nav-open .nav-toggle-bars span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

  html.js .site-nav {
    display: none; position: absolute; top: calc(100% + 8px); inset-inline: 12px;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--paper-bg); border: 1px solid var(--paper-border); border-radius: 18px;
    box-shadow: var(--paper-shadow); padding: 10px;
  }
  html.js body.nav-open .site-nav { display: flex; }
  html.js .site-nav a { padding: 13px 14px; font-size: 12px; border-bottom: 1px solid var(--line); }
  html.js .site-nav a:last-child { border-bottom: none; }
  html.js .site-nav a[aria-current="page"] { border-bottom-color: var(--line); }
  /* no-JS fallback: nav stays inline and the header wraps */
  html:not(.js) .site-header { height: auto; flex-wrap: wrap; padding-block: 12px; }
  html:not(.js) .site-nav { order: 3; width: 100%; flex-wrap: wrap; gap: 4px 14px; }
  html:not(.js) .nav-toggle { display: none; }
}

/* ── TOC rail (home one-pager: bottom pill on mobile, side rail on desktop) ── */
.toc-rail {
  position: fixed; z-index: 40; pointer-events: none;
  left: 50%; bottom: max(16px, env(safe-area-inset-bottom)); transform: translateX(-50%);
  display: flex;
}
.toc-rail-inner {
  --row-h: 44px; --row-gap: 4px;
  pointer-events: auto; position: relative; overflow: hidden;
  display: flex; gap: var(--row-gap); padding: 6px;
  width: min(calc(100vw - 32px), 396px);
  background: color-mix(in srgb, var(--surface-1) 78%, transparent);
  border: 1px solid var(--line-strong); border-radius: 999px;
  backdrop-filter: blur(12px);
  box-shadow: 0 18px 38px -22px rgba(22,100,135,.35);
  transition: width .36s cubic-bezier(.16,1,.3,1), border-radius .4s cubic-bezier(.16,1,.3,1), padding .4s cubic-bezier(.16,1,.3,1);
}
.toc-rail-spotlight {
  position: absolute; z-index: 0; top: 6px; inset-inline-start: 6px;
  width: calc((100% - 12px - ((var(--toc-count) - 1) * var(--row-gap))) / var(--toc-count));
  height: var(--row-h);
  background: color-mix(in srgb, var(--peach-300) 20%, transparent);
  border-radius: 999px;
  transform: translateX(calc(var(--toc-active-index) * (100% + var(--row-gap))));
  transition: transform .55s cubic-bezier(.16,1,.3,1), width .36s cubic-bezier(.16,1,.3,1), border-radius .28s;
}
.toc-rail-item {
  position: relative; z-index: 2; overflow: hidden;
  display: inline-flex; justify-content: center; align-items: center;
  width: 100%; height: var(--row-h);
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-300); white-space: nowrap;
  transition: color .3s, transform .24s cubic-bezier(.34,1.56,.64,1);
}
.toc-rail-item .tick, .toc-rail-item .label { display: none; }
.toc-rail-item .num { font-weight: 400; transition: color .3s; text-align: center; }
.toc-rail-item.active .num, .toc-rail-item:hover .num { color: var(--peach-300); }

@media (min-width: 1024px) {
  .toc-rail { top: 50%; bottom: auto; left: auto; inset-inline-start: var(--chrome-gutter-edge); transform: translateY(-50%); }
  .toc-rail-inner {
    --row-h: 16px; --row-gap: 13px;
    display: grid; width: 46px; padding: 18px 11px; border-radius: 999px;
  }
  .toc-rail-spotlight {
    top: 18px; inset-inline-start: 8px; width: 28px;
    transform: translateY(calc(var(--toc-active-index) * (var(--row-h) + var(--row-gap))));
    transition: transform .55s cubic-bezier(.16,1,.3,1), width .36s cubic-bezier(.16,1,.3,1), border-radius .32s, inset-inline-start .4s, top .4s;
  }
  .toc-rail-item { display: grid; grid-template-columns: 22px 28px 130px; gap: 8px; width: 22px; justify-content: normal; letter-spacing: .22em; }
  .toc-rail-item .tick { display: block; width: 100%; height: 1px; background: var(--ink-300); opacity: 0; transition: opacity .16s, background .3s; }
  .toc-rail-item .label { display: block; opacity: 0; overflow: hidden; transition: opacity .18s; }
  .toc-rail-item.active .tick, .toc-rail-item:hover .tick { background: var(--peach-400); }
  .toc-rail-inner:hover, .toc-rail-inner:focus-within { width: 256px; border-radius: 30px; padding: 20px 24px; }
  .toc-rail-inner:hover .toc-rail-item, .toc-rail-inner:focus-within .toc-rail-item { width: 196px; color: var(--ink-200); }
  .toc-rail-inner:hover .toc-rail-item .tick, .toc-rail-inner:hover .toc-rail-item .label,
  .toc-rail-inner:focus-within .toc-rail-item .tick, .toc-rail-inner:focus-within .toc-rail-item .label { opacity: 1; }
  .toc-rail-inner:hover .toc-rail-spotlight { width: 216px; border-radius: 14px; inset-inline-start: 16px; top: 20px; }
  .toc-rail-inner:hover .toc-rail-item:hover { transform: translateX(3px) scale(1.035); }
}

/* ── Bands (full-width hairline-framed strips) ─────────────── */
.band { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 34px 6vw; position: relative; }
.band + .band { border-top: none; }
.band-label { margin-bottom: 22px; }

/* ── Chapters ───────────────────────────────────────────────── */
.chapter { padding: clamp(70px, 11vh, 130px) 6vw; position: relative; }
/* Number and title share a line, always. The label is pulled to the front of
   the grid flow and spans both columns, so it sits ABOVE the pair rather than
   beside the number — which is what pushed the heading onto its own row and
   left the numeral stranded next to a 10px label. Auto-placement then puts
   the numeral and the heading side by side on the next row, baseline-aligned;
   heads with no label (about half of them) place exactly as they did. */
.chapter-head { display: grid; grid-template-columns: auto 1fr; gap: 6px clamp(16px, 1.8vw, 26px); align-items: baseline; margin-bottom: clamp(30px, 5vh, 56px); }
.chapter-head > .label { order: -1; grid-column: 1 / -1; }
.chapter-num {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.6rem, 6vw, 5rem); color: transparent;
  -webkit-text-stroke: 1px var(--peach-400); line-height: .9;
}
.chapter-rule { grid-column: 1 / -1; height: 1px; background: var(--line); margin-top: 26px; transform-origin: 0 50%; animation: chapter-rule-settle 1s cubic-bezier(.16,1,.3,1) both; }
@keyframes chapter-rule-settle { 0% { opacity: 0; transform: scaleX(0); } 56% { opacity: .9; transform: scaleX(1); } 100% { opacity: 1; } }
.chapter-intro { max-width: 62ch; color: var(--ink-200); margin-bottom: clamp(24px, 4vh, 44px); }
.chapter-close { max-width: 62ch; color: var(--ink-200); margin-top: clamp(24px, 4vh, 44px); }
.chapter-cta { margin-top: clamp(24px, 4vh, 40px); display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* prose column (About) */
.prose { max-width: 66ch; }
.prose p { color: var(--ink-200); margin-bottom: 1.4em; font-size: 1.08rem; }
.drop-cap::first-letter {
  float: inline-start; font-family: var(--font-display); font-weight: 600; font-style: normal;
  font-size: 5.2em; line-height: .82; padding-block: .08em 0; padding-inline: 0 .1em; color: var(--peach-400); letter-spacing: -.04em;
}

/* ── Footer — brand green band, ice lockup ──────────────────── */
.site-footer {
  overflow: hidden; margin-top: 40px;
  background: linear-gradient(170deg, #1f6047 0%, #16503a 100%);
  padding: clamp(48px, 8vh, 96px) 6vw 0;
  color: var(--brand-ice);
}
.footer-lockup {
  display: block; margin: 0 auto clamp(28px, 5vh, 56px);
  width: clamp(180px, 26vw, 340px); height: auto;
}

/* six columns — FOOT-01..FOOT-24 */
.footer-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 30px 22px; max-width: 1160px; margin: 0 auto clamp(38px, 6vh, 70px); }
.footer-col .label { color: var(--brand-ice-2); margin-bottom: 12px; }
.footer-col ul { list-style: none; display: flex; flex-direction: column; gap: 9px; }
.footer-col a { color: var(--brand-ice); font-size: .95rem; }
.footer-col a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.footer-col address { font-style: normal; display: flex; flex-direction: column; gap: 9px; color: var(--brand-ice); font-size: .95rem; }

.footer-meta {
  max-width: 900px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 14px; align-items: center;
  text-align: center;
}
.footer-meta .label { color: var(--brand-ice-2); }
.footer-meta a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 10px 22px; justify-content: center; color: var(--brand-ice); }
.footer-disclaimer {
  color: color-mix(in srgb, var(--brand-ice) 72%, transparent);
  font-size: .88rem; max-width: 66ch; margin-top: 8px;
}
.footer-wordmark {
  font-family: var(--font-display); font-weight: 600; text-align: center;
  font-size: clamp(4rem, 16vw, 15rem); line-height: 1.05; letter-spacing: -.03em;
  color: transparent; -webkit-text-stroke: 1px rgba(214, 238, 244, .5); opacity: .5;
  transform: translateY(18%);
  margin-top: clamp(20px, 4vh, 40px);
}


/* ═══ §4 · COMPONENTS ═══════════════════════════════════════════ */

/* ── Marquees ───────────────────────────────────────────────── */
/* The rail holds N identical .mq-group copies and slides by exactly one of
   them (-100/N%) before snapping back; identical groups mean no seam at the
   wrap. N is measured in JS rather than fixed at two, because after that slide
   only groups 2..N are still covering the track — two groups leave a bare
   stretch of band on any screen wider than the copy. See js/main.js §2. */
.marquee-track {
  --mq-speed: 60s; --mq-gap: 32px;
  overflow: hidden;
  /* ltr on the SCROLL BOX, not just the rail. An overflowing child anchors to
     the inline start of its scroll box, so under dir=rtl the rail hung off the
     LEFT edge of the track instead of starting at x=0 — which is what the
     keyframe below assumes — and each cycle walked it further off screen.
     Forcing ltr here anchors the rail at x=0 in both trees; RTL then differs
     only in which way it travels. Same fix as .supporters-marquee, §8. */
  direction: ltr;
  /* full-bleed, like .supporters-marquee. overflow clips at the BORDER box, so
     .band's 6vw inline padding only held the rail off the LEFT edge at the top
     of the cycle while letting it run freely past the right one — that strip
     sat blank until the rail had travelled 6vw. The band's own background is
     edge-to-edge; the copy riding on it should be too. Block padding stands. */
  padding-inline: 0;
}
.mq-rail { display: flex; width: max-content; animation: mq-scroll var(--mq-speed) linear infinite; }
.marquee-track.pausable:hover .mq-rail { animation-play-state: paused; }
/* padding-RIGHT, not -inline-end: the rail flows ltr in both trees now, so the
   gap that separates one group from the next is always on the physical right */
.mq-group { display: flex; align-items: center; gap: var(--mq-gap); padding-right: var(--mq-gap); flex-shrink: 0; }
.mq-group span { font-family: var(--font-mono); font-size: 12px; letter-spacing: .26em; text-transform: uppercase; color: var(--ink-600); white-space: nowrap; }
.mq-group i { font-style: normal; color: var(--peach-400); }
/* --mq-shift is set per-rail by js/main.js to -100/N%; the -50% fallback is the
   two-group rail you get before the script runs (or with it disabled) */
@keyframes mq-scroll { 0% { transform: translateX(0); } 100% { transform: translateX(var(--mq-shift, -50%)); } }
@media (prefers-reduced-motion: reduce) { .mq-rail { animation: none; } }

/* ── Paper cards ────────────────────────────────────────────── */
.paper { background: var(--paper-bg); border: 1px solid var(--paper-border); border-radius: 18px; box-shadow: var(--paper-shadow); position: relative; }
.paper-stack::before, .paper-stack::after {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: 18px;
  background: var(--surface-2); border: 1px solid var(--paper-border);
}
.paper-stack::before { transform: translate(6px, 8px) rotate(.6deg); }
.paper-stack::after  { transform: translate(12px, 16px) rotate(1.4deg); opacity: .6; }

/* ── Card grids (phase cards, facts, steps) ─────────────────── */
.card-grid { display: grid; gap: 18px; }
.card-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.card-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.card-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.info-card {
  border: 1px solid var(--line); border-radius: 12px; padding: 22px;
  display: flex; flex-direction: column; gap: 10px;
  background: var(--surface-1);
  box-shadow: 0 14px 30px -26px rgba(15, 39, 24, .45);
}
.info-card h3 { font-size: 1.18rem; }
.info-card .serif { color: var(--ink-200); font-size: .98rem; }
.info-card .when {
  font-family: var(--font-display); font-weight: 600; font-size: 1.35rem;
  color: var(--peach-300); line-height: 1.15;
}
.info-card .card-num {
  font-family: var(--font-display); font-weight: 600; font-size: 2rem;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1;
}

/* ── Rollout table (legacy timeline rows) ───────────────────── */
.rollout { border-top: 1px solid var(--line); }
.rollout li {
  display: grid; grid-template-columns: 64px 220px 1fr; gap: 18px;
  padding: 18px 4px; border-bottom: 1px solid var(--line); align-items: baseline;
  list-style: none;
}
.rollout .ph {
  font-family: var(--font-display); font-weight: 600; font-size: 1.9rem;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1;
}
.rollout .when { font-family: var(--font-display); font-weight: 600; color: var(--peach-300); }
.rollout .when b { color: var(--cream-100); font-weight: 600; }
.rollout .who { color: var(--ink-200); }

/* ── Numbered lists ─────────────────────────────────────────── */
.num-list { list-style: none; counter-reset: nl; border-top: 1px solid var(--line); max-width: 76ch; }
.num-list li {
  counter-increment: nl;
  display: grid; grid-template-columns: 56px 1fr; gap: 18px;
  padding: 18px 4px; border-bottom: 1px solid var(--line);
}
.num-list li::before {
  content: counter(nl, decimal-leading-zero);
  font-family: var(--font-display); font-weight: 600; font-size: 1.6rem;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1.2;
}
.num-list b { color: var(--cream-100); font-weight: 600; }
.num-list p { color: var(--ink-200); }

/* ── Service lines (repurposed role pattern) ────────────────── */
.role { display: grid; grid-template-columns: 130px 1fr; gap: clamp(22px, 4vw, 60px); padding: clamp(36px, 6vh, 70px) 0; border-top: 1px solid var(--line); }
.role-side { display: flex; flex-direction: column; gap: 16px; }
@media (min-width: 1024px) { .role-side { position: sticky; top: 7rem; align-self: start; } }
.role-side .rn { font-family: var(--font-display); font-weight: 600; font-size: 3.4rem; color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1; }
.role-body h3 { font-size: clamp(1.5rem, 2.4vw, 2.1rem); margin: 6px 0 4px; }
.role-body > .serif { color: var(--ink-200); max-width: 66ch; margin: 18px 0 8px; }
.service-list { list-style: none; margin-top: 14px; max-width: 66ch; }
.service-list li {
  padding: 10px 0; padding-inline-start: 26px; border-bottom: 1px solid var(--line);
  color: var(--ink-200); position: relative;
}
.service-list li::before {
  content: "";
  position: absolute; inset-inline-start: 2px; top: 1.05em;
  width: 12px; height: 2px; background: var(--peach-400);
}

/* ── Scroll-revealed service panels (home §02) ───────────────
   Two services revealed by a curtain. Both panels are stacked in the same
   place — each carries its own copy of the section heading — and the
   second sits on top, on its own green ground, clipped to a horizontal
   edge that sets off from the fixed header's bottom border and sweeps to
   the foot of the screen as you scroll. Above the edge is the second
   service, heading and all; below it the first is still there, untouched.
   Scroll back and the edge returns, so the reveal is fully reversible.

   Everything is driven by one number, --svc-p (0 → 1), set on the section
   by js/main.js §3b straight from scroll position — no animation, so the
   edge tracks the wheel exactly and reverses with it.

   The two grounds are read straight off the artwork — ice #badae1 for
   Dhara Tax, green #1a5f47 for Dhara ACCT — so panel and plate are the
   same colour, not an approximation. The green panel carries .is-deep,
   whose token block (§11.2) re-skins the type inside it; only its gradient
   is overridden, because the ground has to match the plate exactly.

   Sides come from the grid, not from left/right: the words sit in the
   inline-start column and the picture in the inline-end one, which is
   text-left / picture-right in English and mirrors itself in Arabic with
   no RTL override. */
.svc-chapter {
  --svc-bg: #badae1;
  --svc-deep: #1a5f47;
  background-color: var(--svc-bg);
  /* no hairline top or bottom — the colour itself is the edge */
  border-block: none;
}

/* Stacked by default (and whenever JS is off): heading, then each service
   as one block, plate above its own words, read top to bottom. No curtain,
   no pinning — the honest layout when there is no screenful to pin. */
.svc-scroll { display: grid; gap: clamp(26px, 4vh, 48px); }
.svc-panel { display: block; }
.svc-cols { display: grid; gap: clamp(14px, 2vh, 22px); }
.svc-cols .svc-shot { margin: 0; order: -1; }
.svc-panel img { display: block; width: 100%; height: auto; border-radius: 16px; }
/* the second service brings its ground with it even here, so the green
   plate sits on green rather than on a stray ice rectangle */
.svc-panel.is-deep {
  background: var(--svc-deep);
  border-radius: 18px; padding: clamp(20px, 3vh, 32px);
}
/* the second panel's copy of the section heading is a prop for the curtain
   sweep — in any other layout the real heading is already on screen once */
.svc-dup { display: none; }
/* both only exist for the pinned curtain — in the stacked layout the
   runway is a screenful of empty band and the edge has nothing to sweep */
.svc-runway, .svc-wipe { display: none; }
.svc-copy h3 { font-size: clamp(1.5rem, 2.4vw, 2.1rem); margin: 6px 0 4px; }
.svc-copy > .serif { color: var(--ink-200); max-width: 60ch; margin: 18px 0 8px; }
.svc-rn {
  font-family: var(--font-display); font-weight: 600; font-size: 2.6rem; line-height: 1;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400);
  display: block; margin-bottom: 10px;
}

/* The pinned curtain — only with JS, only where a screenful is actually
   available to pin, and only where motion is welcome. The stage (section
   heading, intro and the reveal area) is what sticks, so "Two services,
   one team" and the section heading never leave while the reveal runs. */
@media (min-width: 900px) and (min-height: 760px) and (prefers-reduced-motion: no-preference) {
  html.js .svc-chapter {
    /* flush with the fixed header, so the curtain edge sets off exactly on
       its bottom border — above the section heading, not below it. The
       fixed chrome is 90px of header plus, on wide screens, the utility
       strip; js/main.js §3b measures the real thing and overrides this. */
    --svc-top: 90px;
    /* dwell, sweep, dwell — see js/main.js §3b for the split */
    --svc-runway: 170vh;
    /* the plate takes what the stage has left after the heading block */
    --svc-plate: min(calc(100vh - 30rem), 460px);
  }
  html.js .svc-stage {
    position: sticky; top: var(--svc-top);
    /* exactly one screen, so the reveal area reaches the fold and the
       curtain has no strip of band left over beneath it */
    min-height: calc(100vh - var(--svc-top));
    display: flex; flex-direction: column;
  }
  html.js .svc-runway { display: block; height: var(--svc-runway); }
  /* the heading is on screen the whole time now, so it needs less room */
  html.js .svc-chapter .chapter-head { margin-bottom: 6px; }
  html.js .svc-chapter .chapter-intro { margin-bottom: clamp(12px, 2vh, 26px); }

  /* the reveal area: both panels in one cell, so the edge that sweeps it
     is the same edge for both. Full-bleed, so the curtain and its line run
     to the band's edges rather than stopping at the text margin. */
  html.js .svc-scroll {
    position: relative;
    flex: 1 1 auto;
    display: grid; gap: 0;
    margin-inline: -6vw;
  }
  html.js .svc-panel {
    grid-area: 1 / 1;
    display: flex; flex-direction: column;
    /* back in line with the rest of the section; the top padding is the
       heading's breathing room under the header border the edge rides */
    padding: clamp(18px, 3vh, 30px) 6vw 0; border-radius: 0;
  }
  /* panel two's own copy of the heading — the curtain sweeps it too, so
     the title above the line is service two's and below it service one's */
  html.js .svc-dup { display: block; }
  html.js .svc-cols {
    flex: 1 1 auto; min-height: 0;
    display: grid; gap: 0;
    grid-template-columns: minmax(0, 1fr) minmax(0, 40%);
    column-gap: clamp(36px, 5vw, 90px);
    align-items: center;
  }
  html.js .svc-panel .svc-shot {
    order: 0; margin: 0; width: 100%; height: var(--svc-plate); align-self: center;
  }
  html.js .svc-panel img {
    width: 100%; height: 100%;
    /* contain, not cover: the plate is a logo, and cropping it to fill a
       landscape box cut the mark off at the bottom. The artwork's own
       ground IS the panel colour, so the space either side cannot be seen. */
    object-fit: contain; border-radius: 0;
  }

  /* the curtain. inset() measures its bottom edge from the bottom, so
     (1 - p) of the height clipped away leaves exactly the top p showing —
     the panel is revealed downwards from the heading. */
  html.js .svc-panel[data-svc="2"] {
    z-index: 2;
    clip-path: inset(0 0 calc((1 - var(--svc-p, 0)) * 100%) 0);
  }

  /* the edge itself: a hairline that sets off from the header's border and
     draws the reveal down with it. Fades out at both ends so it reads as a
     drawn line rather than a full-width rule — and it only exists while
     the hand-over is actually running (.is-sweeping, js/main.js §3b): it
     fades in as the shift begins and dissolves once either service holds
     the whole screen, so its presence itself says "you are between the
     two". */
  html.js .svc-wipe {
    display: block; position: absolute; z-index: 3;
    left: 0; right: 0; top: calc(var(--svc-p, 0) * 100%);
    height: 1px; pointer-events: none;
    background: linear-gradient(90deg,
      transparent 0%,
      color-mix(in srgb, var(--brand-sand) 30%, transparent) 12%,
      var(--brand-sand) 50%,
      color-mix(in srgb, var(--brand-sand) 30%, transparent) 88%,
      transparent 100%);
    box-shadow: 0 0 16px 1px color-mix(in srgb, var(--brand-sand) 28%, transparent);
    opacity: 0;
    transition: opacity .5s ease;
  }
  html.js .svc-chapter.is-sweeping .svc-wipe { opacity: 1; }
  /* the shift cue: the curtain casts a soft shadow AHEAD of itself onto
     the service it is covering, and trails a faint sand sheen on the one
     it has revealed — the outgoing content visibly falls into shade while
     the incoming one arrives lit, so the hand-over reads as one page being
     drawn down over another rather than a line crossing a picture. */
  html.js .svc-wipe::after {
    content: ""; position: absolute;
    left: 0; right: 0; top: 1px; height: 130px;
    background: linear-gradient(180deg,
      rgba(13, 46, 35, .32) 0%,
      rgba(13, 46, 35, .12) 46%,
      transparent 100%);
  }
  html.js .svc-wipe::before {
    content: ""; position: absolute;
    left: 0; right: 0; bottom: 1px; height: 64px;
    background: linear-gradient(0deg,
      color-mix(in srgb, var(--brand-sand) 18%, transparent) 0%,
      transparent 100%);
  }

  /* keyboard: tabbing into the second service completes the reveal rather
     than sending focus to something clipped out of sight. --svc-p is set
     on the SECTION, so this override on the reveal area still wins over
     the inline value it inherits. */
  html.js .svc-scroll:has(.svc-panel[data-svc="2"] :focus-visible) { --svc-p: 1; }

  /* The tail. Once the curtain has landed the rest of the section belongs
     to the second service, so the closing line rides the same green out of
     the section instead of the band reverting to the FIRST service's ice —
     which left a blue strip between the green and whatever followed.

     z-index also rescues the line itself: as the section ends, sticky
     clamps the stage to the content box and the stage (positioned) painted
     straight over this paragraph (static), hiding most of it. Lifting it
     one layer puts it back in front. */
  html.js .svc-chapter { padding-bottom: 0; }
  html.js .svc-chapter > .chapter-close {
    position: relative; z-index: 1;
    color: #dbeae4;
    padding-block: clamp(20px, 3vh, 40px) clamp(70px, 11vh, 130px);
  }
  /* a pseudo-element, not a background on the paragraph: the ground has to
     reach the band's edges while the sentence keeps its 62ch measure */
  html.js .svc-chapter > .chapter-close::before {
    content: ""; position: absolute; z-index: -1;
    inset: 0 -6vw;
    background: var(--svc-deep);
  }
}

/* status / caveat note boxes */
.note-box {
  border: 1px solid color-mix(in srgb, var(--brand-teal) 40%, transparent);
  background: color-mix(in srgb, var(--brand-ice) 45%, transparent);
  border-inline-start: 3px solid var(--brand-teal);
  border-radius: 10px; padding: 16px 18px; max-width: 76ch;
  color: var(--ink-200); font-size: .98rem;
}
.note-box b { color: var(--cream-100); }
.note-plain { color: var(--ink-300); font-size: .92rem; max-width: 76ch; }

/* stamps / badges */
.stamp {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .3em; text-transform: uppercase;
  color: var(--peach-300); background: color-mix(in srgb, var(--peach-300) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--peach-300) 42%, transparent);
  border-radius: 999px; padding: 4px 10px;
  white-space: nowrap;
}

/* ── Key/value rows (security page · obligations table) ─────── */
.security-rows, .kv-rows { border-top: 1px solid var(--line); max-width: 82ch; }
.security-rows > div, .kv-rows > div {
  display: grid; grid-template-columns: 240px 1fr; gap: 8px 24px;
  padding: 18px 4px; border-bottom: 1px solid var(--line); align-items: start;
}
.security-rows dt, .kv-rows dt { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.security-rows dt b, .kv-rows dt b { font-family: var(--font-display); color: var(--cream-100); font-weight: 600; }
.security-rows dd, .kv-rows dd { color: var(--ink-200); }

/* ── Chips (software names — text only, no logos) ───────────── */
.chips { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.chips li {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand-teal); border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent); border-radius: 999px; padding: 8px 16px;
  background: var(--surface-1);
}

/* ── FAQ / accordion (native details) ───────────────────────── */
.faq-list { max-width: 78ch; border-top: 1px solid var(--line); }
.faq-list details { border-bottom: 1px solid var(--line); }
.faq-list summary {
  cursor: pointer; list-style: none;
  display: grid; grid-template-columns: 1fr 28px; gap: 16px; align-items: center;
  padding: 18px 4px;
  font-family: var(--font-display); font-weight: 500; font-size: 1.08rem; color: var(--cream-100);
  transition: color .3s;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+";
  font-family: var(--font-display); font-weight: 400; font-size: 1.5rem; line-height: 1;
  color: var(--peach-300); text-align: center;
  transition: transform .3s cubic-bezier(.16,1,.3,1);
}
.faq-list details[open] summary::after { transform: rotate(45deg); }
.faq-list summary:hover { color: var(--peach-300); }
.faq-list details p { padding: 0 4px 20px; color: var(--ink-200); max-width: 70ch; }

/* ── Forms ──────────────────────────────────────────────────── */
.form-cols { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(26px, 4vw, 60px); align-items: start; }
.lead-form { padding: clamp(22px, 3vw, 36px); display: flex; flex-direction: column; gap: 4px; }
.form-body { display: flex; flex-direction: column; gap: 16px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field > .label .req { color: var(--peach-300); }
.field input[type="text"], .field input[type="email"], .field input[type="tel"],
.field select, .field textarea {
  background: transparent; border: none; border-bottom: 1px solid var(--line-strong);
  color: var(--cream-100); font-family: var(--font-serif); font-size: 1.02rem; padding: 8px 2px;
  outline: none; transition: border-color .3s; border-radius: 0;
  width: 100%;
}
.field select { cursor: pointer; }
.field select option { color: var(--brand-navy); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--peach-300); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { outline: 2px solid color-mix(in srgb, var(--peach-300) 45%, transparent); outline-offset: 2px; }

/* radio / checkbox groups */
.opt-group { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.opt {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  color: var(--ink-200); font-size: .98rem;
}
.opt input { accent-color: var(--brand-teal); width: 16px; height: 16px; cursor: pointer; flex-shrink: 0; }
.opt-stack { display: flex; flex-direction: column; gap: 10px; }
.consent { align-items: flex-start; max-width: 62ch; }
.consent input { margin-top: 4px; }
.form-fineprint { color: var(--ink-300); font-size: .88rem; max-width: 62ch; }
.form-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; align-items: center; }
.form-aside { display: flex; flex-direction: column; gap: 18px; }
.form-aside .serif { color: var(--ink-200); }

.form-success {
  display: flex; flex-direction: column; gap: 12px;
  padding: 8px 0;
  color: var(--ink-200); font-size: 1.05rem;
}
.form-success b { color: var(--cream-100); }
.form-success::before {
  content: "✓";
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 999px;
  background: color-mix(in srgb, var(--brand-green) 14%, transparent);
  color: var(--brand-green); font-size: 1.4rem; font-weight: 600;
}

/* ── Media placeholder (auto-applied by js when a file is missing) ── */
.media-placeholder {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  background:
    repeating-linear-gradient(45deg, transparent 0 14px, color-mix(in srgb, var(--peach-300) 6%, transparent) 14px 28px),
    var(--surface-1);
  border: 1px dashed var(--line-strong); border-radius: 12px;
  color: var(--ink-300); text-align: center; padding: 18px; width: 100%;
}
.media-placeholder .ph-icon { font-size: 26px; color: var(--peach-300); }
.media-placeholder .ph-name { font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--peach-300); direction: ltr; }
.media-placeholder .ph-hint { font-family: var(--font-serif); font-style: italic; font-size: .85rem; }

/* diagram slot (plain image figures) */
.diagram-slot { margin-top: clamp(24px, 4vh, 40px); }
.diagram-slot img { border: 1px solid var(--line-strong); border-radius: 16px; width: 100%; }
.diagram-slot figcaption { margin-top: 10px; }

/* ── Scroll reveals ─────────────────────────────────────────── */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity .8s cubic-bezier(.16,1,.3,1) var(--d, 0s), transform .8s cubic-bezier(.16,1,.3,1) var(--d, 0s); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }

/* ── Fluidity screen effect — subtle DHARA teal/green wash ──── */
#fluid-wrap {
  position: fixed; inset: 0; z-index: 6;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: .3;
}
#fluid-wrap canvas { width: 100%; height: 100%; display: block; }


/* ═══ §5 · PAGE-SPECIFIC ════════════════════════════════════════ */

/* ── Home hero (video/media hero) ─────────────────────────────
   The photography is 16:9. A full-height hero is only 16:9 on a window
   that happens to be, and on anything squarer `object-fit: cover` keeps
   the height and cuts the SIDES — 10% on a typical laptop, 30% on a 5:4
   monitor. Nothing is distorted, but the frame reads as zoomed into the
   middle of the picture. So above the phone breakpoint the hero is capped
   at the photograph's own ratio and the whole frame stays visible; the
   620px floor keeps the copy comfortable on short windows, and on phones
   it goes back to filling the screen (portrait always crops). */
:root { --hero-h: 100dvh; }
@media (min-width: 900px) {
  :root { --hero-h: max(620px, min(100dvh, 56.25vw)); }
}
.hero { position: relative; min-height: var(--hero-h); }
.hero-media { position: absolute; inset: 0; overflow: hidden; }
.hero-layer {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transition: opacity .9s cubic-bezier(.76,0,.24,1), filter .4s ease, transform .7s cubic-bezier(.16,1,.3,1);
  will-change: opacity, filter, transform;
}
.hero-video { object-fit: cover; background: linear-gradient(160deg, #dceaf0 0%, #f2f6f7 70%); filter: var(--hero-video-filter, none); }
.hero-media .media-placeholder.hero-layer { border-radius: 0; }
.hero-scrim {
  position: absolute; inset: 0;
  background: var(--hero-scrim);
  transition: background .9s;
}
.hero-content {
  position: relative; z-index: 2; min-height: var(--hero-h);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 6vw 16vh;
}
.eyebrow { font-family: var(--font-mono); font-size: 11px; letter-spacing: .34em; text-transform: uppercase; color: var(--peach-300); margin-bottom: 18px; }
.hero-title {
  font-size: clamp(2.4rem, 6.4vw, 5.6rem);
  line-height: 1.02; letter-spacing: -.02em; color: var(--cream-100);
  max-width: 18ch;
  margin-bottom: 26px;
}
.hero-tag { max-width: 62ch; font-size: clamp(1.02rem, 1.4vw, 1.25rem); color: var(--ink-700); margin-bottom: 28px; }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 20px; }
.hero-trust { color: var(--ink-300); }
.hero-scrollcue {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(max(16px, env(safe-area-inset-bottom)) + 68px);
  z-index: 30; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  color: var(--ink-300);
  transition: opacity .5s ease;
}
body.header-solid .hero-scrollcue { opacity: 0; }
@media (min-width: 1024px) {
  .hero-scrollcue { bottom: 22px; }
}
@keyframes pulse-soft { 0%,100% { opacity: .45; } 50% { opacity: .85; } }
.icon-scroll {
  width: 22px; height: 36px;
  border: 1.5px solid var(--peach-400);
  border-radius: 12px;
  position: relative;
  animation: pulse-soft 2.4s ease-in-out infinite;
}
.icon-scroll-screen {
  position: absolute; left: 50%; top: 7px;
  width: 3px; height: 7px; margin-left: -1.5px;
  border-radius: 2px;
  background: var(--peach-300);
  animation: icon-scroll-wheel 1.8s cubic-bezier(.4, 0, .4, 1) infinite;
}
@keyframes icon-scroll-wheel {
  0%       { transform: translateY(0);    opacity: 0; }
  20%      { opacity: 1; }
  70%,100% { transform: translateY(12px); opacity: 0; }
}

/* ── Page hero (subpages: breadcrumb + title, no media) ─────── */
.page-hero { padding: clamp(140px, 18vh, 200px) 6vw clamp(26px, 5vh, 54px); }
.breadcrumb {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-300); margin-bottom: 20px;
}
.breadcrumb a { transition: color .3s; }
.breadcrumb a:hover { color: var(--peach-300); }
.breadcrumb [aria-current="page"] { color: var(--peach-300); }
.page-title {
  font-size: clamp(2.2rem, 5vw, 4.4rem); line-height: 1.02; letter-spacing: -.02em;
  color: var(--cream-100); max-width: 22ch; margin: 16px 0 22px;
}
.page-lead { max-width: 62ch; font-size: clamp(1.02rem, 1.35vw, 1.2rem); color: var(--ink-700); margin-bottom: 14px; }

/* ── Guide layout (compliance): sticky sidebar + content ────── */
.guide-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 clamp(30px, 4vw, 70px); padding: 0 6vw; align-items: start; }
.guide-main { min-width: 0; }
.guide-main .chapter { padding-inline: 0; }
.guide-toc { margin-top: 10px; }
.guide-toc summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 2px;
}
.guide-toc summary::-webkit-details-marker { display: none; }
.guide-toc summary::after { content: "+"; color: var(--peach-300); font-size: 1.2rem; line-height: 1; transition: transform .3s; }
.guide-toc[open] summary::after { transform: rotate(45deg); }
.guide-toc ol { list-style: none; border-top: 1px solid var(--line); }
.guide-toc li { border-bottom: 1px solid var(--line); }
.guide-toc a {
  display: block; padding: 11px 2px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-300); transition: color .3s;
}
.guide-toc a:hover, .guide-toc a.active { color: var(--peach-300); }
@media (min-width: 1024px) {
  .guide-layout { grid-template-columns: 230px minmax(0, 1fr); }
  .guide-aside { position: sticky; top: 150px; align-self: start; }
  .guide-toc summary { display: none; }
}

/* ── Comparator — two labelled columns, no icon-only meaning ── */
.comparator { display: grid; gap: 18px; }
@media (min-width: 760px) { .comparator { grid-template-columns: 1fr 1fr; } }
.comparator-col { border: 1px solid var(--line); border-radius: 12px; padding: 22px; background: var(--surface-1); }
.comparator-col h3 { font-size: 1.12rem; }
.comparator-col .service-list { margin-top: 10px; max-width: none; }
.comparator-col.is-einvoice { border-color: color-mix(in srgb, var(--brand-teal) 40%, transparent); background: color-mix(in srgb, var(--brand-ice) 38%, transparent); }

/* ── Peppol network — five expandable nodes (native details) ── */
.peppol-figure { margin-bottom: 22px; color: var(--peach-400); }
.peppol-figure svg { width: min(560px, 100%); height: auto; display: block; }
.peppol-flow { display: grid; gap: 14px; }
.peppol-node { border: 1px solid var(--line); border-radius: 12px; background: var(--surface-1); }
.peppol-node summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 12px; padding: 16px 18px;
  font-family: var(--font-display); font-weight: 500; color: var(--cream-100);
  transition: color .3s;
}
.peppol-node summary::-webkit-details-marker { display: none; }
.peppol-node summary:hover { color: var(--peach-300); }
.peppol-node .node-num {
  font-family: var(--font-display); font-weight: 600; font-size: 1.5rem;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1; flex-shrink: 0;
}
.peppol-node summary::after {
  content: "+"; margin-inline-start: auto; color: var(--peach-300);
  font-size: 1.3rem; line-height: 1;
  transition: transform .3s cubic-bezier(.16,1,.3,1);
}
.peppol-node[open] summary::after { transform: rotate(45deg); }
.peppol-node p { padding: 0 18px 18px; color: var(--ink-200); }
.peppol-node--authority { border-inline-start: 3px solid var(--brand-teal); }
@media (min-width: 1024px) {
  .peppol-flow { grid-template-columns: repeat(4, 1fr); }
  .peppol-node--authority { grid-column: 1 / -1; width: 100%; max-width: 560px; justify-self: center; }
}

/* ── Scored readiness checklist ─────────────────────────────── */
.check-items { list-style: none; border-top: 1px solid var(--line); max-width: 76ch; }
.check-items li { border-bottom: 1px solid var(--line); }
.check-item { display: grid; grid-template-columns: 24px 1fr; gap: 14px; padding: 15px 4px; cursor: pointer; align-items: start; }
.check-item input { width: 18px; height: 18px; margin-top: 4px; accent-color: var(--brand-teal); cursor: pointer; }
.check-item input:focus-visible { outline: 2px solid color-mix(in srgb, var(--peach-300) 45%, transparent); outline-offset: 2px; }
.check-item .serif { color: var(--ink-200); }
.check-item b { color: var(--cream-100); font-weight: 600; }
.check-score { margin-top: 22px; font-family: var(--font-display); font-weight: 600; font-size: 1.1rem; color: var(--ink-300); }
.check-score output { font-size: 2.2rem; color: var(--peach-300); }
.score-bands { display: grid; gap: 14px; margin-top: 22px; max-width: 76ch; }
.score-band { border: 1px solid var(--line); border-radius: 12px; padding: 20px 22px; background: var(--surface-1); }
.score-band .band-range { margin-bottom: 8px; }
.score-band h3 { font-size: 1.15rem; margin-bottom: 6px; }
.score-band .serif { color: var(--ink-200); }
/* with JS the checklist scores live and only the active band shows;
   without JS all three bands stay visible (static fallback) */
html.js .check-list.is-scored .score-band { display: none; }
html.js .check-list.is-scored .score-band.active {
  display: block;
  border-color: color-mix(in srgb, var(--brand-teal) 45%, transparent);
  background: color-mix(in srgb, var(--brand-ice) 40%, transparent);
}

/* ── Supported-by strip (home/about) — HOME-08..HOME-14 ─────── */
/* The five marks ride an endless marquee rather than sitting in a five-up
   grid, so the strip reads as a continuous band and never breaks into a
   ragged row on a narrow screen.

   How the loop is seamless: .supporters-track holds two identical
   .supporters-run groups (the second is aria-hidden and carries no copy
   codes) and slides by exactly -50% — one full run — before snapping back.
   Because the two runs are identical there is no visible seam at the wrap.
   The catch two runs alone do not solve: if a run is NARROWER than the
   viewport, the far edge runs out of logos before the wrap and a bare gap
   crosses the band. Hence `min-width: 100vw` on the run — it can never be
   shorter than what is on screen — with space-around spreading the five
   marks across whatever width that turns out to be.

   Direction follows the language, as asked: English travels right→left,
   Arabic left→right. The track lays out in LTR flow in both trees so the
   distance is identical, and the RTL rule only reverses the animation. */
.supporters { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: clamp(28px, 5vh, 48px) 6vw; }
.supporters-head { display: flex; flex-direction: column; gap: 6px; margin-bottom: 22px; }
.supporters-head .serif { color: var(--ink-200); font-size: .95rem; }

/* full-bleed: the logos should enter and leave at the true section edges,
   not at the 6vw text margin, so the viewport pulls back out of the padding */
.supporters-marquee {
  margin-inline: -6vw;
  overflow: hidden;
  /* LTR on the VIEWPORT, not just the track. An overflowing child anchors to
     the inline start of its scroll box, so under dir=rtl the 2-run track hung
     off the LEFT edge and the -50% slide walked it clean off screen — the band
     went blank for half of every cycle. Forcing ltr here anchors the track at
     x=0 in both trees, which is what the -50% keyframe assumes. RTL then
     differs only in which way it travels (animation-direction below). */
  direction: ltr;
  /* fade both ends so marks dissolve rather than being sliced by the edge */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}
.supporters-track {
  display: flex;
  width: max-content;
  animation: supporters-scroll var(--marquee-dur, 36s) linear infinite;
  will-change: transform;
}
.supporters-run {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-around;
  min-width: 100vw;          /* never shorter than the screen — see note above */
}
html[dir="rtl"] .supporters-track { animation-direction: reverse; }
@keyframes supporters-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* let a visitor stop the band to read a mark */
.supporters-marquee:hover .supporters-track,
.supporters-marquee:focus-within .supporters-track { animation-play-state: paused; }

.supporter {
  margin: 0;
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  /* space-around does the spreading; this is only the minimum gutter, and it
     is padding rather than gap so it survives the run boundary */
  padding-inline: clamp(20px, 3vw, 46px);
  min-height: 68px;
}
.supporter img {
  display: block; width: auto;
  height: var(--logo-h, 40px);
  /* the marks differ wildly in proportion (a tall monogram beside a 5:1
     wordmark), so each is sized optically below rather than to one height */
  max-width: none;
  opacity: .82;
  transition: opacity .3s ease;
}
.supporters-marquee:hover .supporter img { opacity: 1; }
.supporter--rd     { --logo-h: 50px; }
.supporter--bloom  { --logo-h: 40px; }
.supporter--chroma { --logo-h: 22px; }
.supporter--riyada { --logo-h: 42px; }
.supporter--fund   { --logo-h: 40px; }
/* the organisation name stays in the accessibility tree — the images are
   decorative (alt="") so the name is announced once, from the caption */
.supporter figcaption {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* Reduced motion: no travel at all. The duplicate run is hidden and the
   single run centres itself as a plain static row. */
@media (prefers-reduced-motion: reduce) {
  .supporters-marquee { -webkit-mask-image: none; mask-image: none; margin-inline: 0; }
  .supporters-track { animation: none; width: 100%; }
  /* flex-basis 100%, not auto — as a max-content-sized flex item the run
     would never wrap, and the five marks would run off a phone screen */
  .supporters-run { flex: 1 1 100%; min-width: 0; flex-wrap: wrap; justify-content: center; row-gap: 6px; }
  /* the whole clone run goes, not its figures — an empty run is still a flex
     item and would take half the width from the run that is still showing */
  .supporters-run[data-marquee-clone] { display: none; }
}

/* ── Phase finder (home) — HOME-15..HOME-44 ─────────────────── */
/* Without JS the wizard stays hidden and the result articles render as a
   static list (the fallback). With JS (.is-app) the three-step wizard runs
   and only the routed result shows. */
.finder { max-width: 860px; }
.finder-app { display: none; }
html.js .finder.is-app .finder-app { display: block; padding: clamp(22px, 3vw, 36px); }
.finder-top { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; min-height: 40px; }
.finder-dots { list-style: none; display: flex; gap: 8px; }
.finder-dots li { width: 10px; height: 10px; border-radius: 999px; border: 1px solid var(--line-strong); transition: background .3s, border-color .3s; }
.finder-dots li.on { background: var(--peach-300); border-color: var(--peach-300); }
.finder-back {
  margin-inline-start: auto; width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: transparent; color: var(--ink-300); font-size: 1.1rem; cursor: pointer;
  transition: background .3s, color .3s;
}
.finder-back::before { content: "←"; }
.finder-back:hover { background: var(--brand-ice); color: var(--brand-forest); }
.finder-back[hidden] { display: none; }
.finder-q { font-family: var(--font-display); font-weight: 600; font-size: 1.25rem; color: var(--cream-100); margin-bottom: 16px; outline: none; }
.finder-opts { display: flex; flex-direction: column; gap: 10px; }
.finder-opts button {
  text-align: start; width: 100%;
  font-family: var(--font-serif); font-size: 1rem; color: var(--ink-200);
  background: var(--surface-1);
  border: 1px solid var(--line-strong); border-radius: 12px;
  padding: 13px 16px; cursor: pointer;
  transition: border-color .3s, background .3s, color .3s;
}
.finder-opts button:hover { border-color: var(--peach-300); color: var(--cream-100); background: color-mix(in srgb, var(--brand-ice) 40%, transparent); }
.finder-opts button:focus-visible { outline: 2px solid color-mix(in srgb, var(--peach-300) 45%, transparent); outline-offset: 2px; }
.finder-results { display: grid; gap: 14px; margin-top: 18px; }
.finder-results > article { border: 1px solid var(--line); border-radius: 12px; padding: 20px 22px; background: var(--surface-1); outline: none; }
.finder-results > article h3 { font-size: 1.2rem; margin-bottom: 6px; }
.finder-results > article .serif { color: var(--ink-200); }
html.js .finder.is-app .finder-results { margin-top: 14px; }
html.js .finder.is-app .finder-results > article { display: none; }
html.js .finder.is-app .finder-results > article.active {
  display: block;
  border-color: color-mix(in srgb, var(--brand-teal) 45%, transparent);
  background: color-mix(in srgb, var(--brand-ice) 40%, transparent);
}
.finder-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 18px; }
html.js .finder.is-app .finder-ctas { display: none; }
html.js .finder.is-app.has-result .finder-ctas { display: flex; }
.finder-note { margin-top: 18px; }

/* ── VAT category rows ──────────────────────────────────────── */
.vat-rows { border-top: 1px solid var(--line); }
.vat-rows > div {
  display: grid; grid-template-columns: 200px 110px 1fr; gap: 12px 24px;
  padding: 20px 4px; border-bottom: 1px solid var(--line); align-items: baseline;
}
.vat-name { font-family: var(--font-display); font-weight: 600; color: var(--cream-100); font-size: 1.15rem; }
.vat-rate {
  font-family: var(--font-display); font-weight: 600; font-size: 1.9rem;
  color: transparent; -webkit-text-stroke: 1px var(--peach-400); line-height: 1;
}
.vat-text { color: var(--ink-200); max-width: 66ch; }


/* ═══ §6 · RESPONSIVE ═══════════════════════════════════════════ */

@media (max-width: 1023px) {
  .card-grid.cols-3, .card-grid.cols-4 { grid-template-columns: 1fr 1fr; }
  .role { grid-template-columns: 1fr; }
  .role-side { flex-direction: row; align-items: baseline; }
  .form-cols { grid-template-columns: 1fr; }
  .rollout li { grid-template-columns: 48px 1fr; }
  .rollout .who { grid-column: 2; }
  .security-rows > div, .kv-rows > div { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 760px) {
  .vat-rows > div { grid-template-columns: 1fr auto; }
  .vat-text { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .card-grid.cols-3, .card-grid.cols-2, .card-grid.cols-4 { grid-template-columns: 1fr; }
  /* one cycle covers one run, and the run is far shorter here, so the
     duration comes down with it to hold roughly the same speed on screen */
  .supporters-marquee { --marquee-dur: 14s; }   /* ≈36px/s, same glide as desktop */
  .supporter { padding-inline: 18px; min-height: 58px; }
  .supporter img { height: calc(var(--logo-h, 40px) * .82); }
  .form-row { grid-template-columns: 1fr; }
  .hero-content { padding-bottom: 22vh; }
  .site-header { padding: 12px 16px; height: 76px; }
  .header-logo, .header-logo img { height: 44px; }
  .header-right .pill-small.hide-mobile { display: none; }
  .footer-grid { grid-template-columns: repeat(2, 1fr); }
}


/* ═══ §7 · RTL OVERRIDES ════════════════════════════════════════
   Arabic: Rubik's Arabic set needs a touch more line-height and no
   negative tracking — negative letter-spacing breaks joined script.
   Everything else flows through logical properties automatically. */

[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3 { letter-spacing: 0; line-height: 1.25; }
[dir="rtl"] .label { letter-spacing: 0; font-size: 12px; }
[dir="rtl"] .pill { letter-spacing: 0; font-size: 13px; }
[dir="rtl"] .pill-small { font-size: 12px; }
[dir="rtl"] .eyebrow { letter-spacing: 0; font-size: 13px; }
[dir="rtl"] .hero-title { letter-spacing: 0; line-height: 1.22; }
[dir="rtl"] .mq-group span { letter-spacing: 0; font-size: 13px; }
/* the track forces ltr so the rail anchors at x=0 (see §4), but the copy inside
   a group is Arabic — give the group back its own base direction so the terms
   still read right-to-left even though the rail no longer does */
[dir="rtl"] .mq-group { direction: rtl; }
[dir="rtl"] .mq-rail { animation-direction: reverse; }
[dir="rtl"] .chapter-rule { transform-origin: 100% 50%; }
[dir="rtl"] .drop-cap::first-letter { letter-spacing: 0; }
[dir="rtl"] .stamp { letter-spacing: 0; font-size: 11px; }
[dir="rtl"] .chips li { letter-spacing: 0; font-size: 12.5px; }
[dir="rtl"] .site-nav a { letter-spacing: 0; font-size: 12.5px; }
[dir="rtl"] .breadcrumb { letter-spacing: 0; font-size: 12px; }
[dir="rtl"] .guide-toc a { letter-spacing: 0; font-size: 12px; }
[dir="rtl"] .utility-strip { letter-spacing: 0; }
[dir="rtl"] .skip-link { letter-spacing: 0; }
/* decorative flow diagram carries no text — safe to mirror */
[dir="rtl"] .peppol-figure svg { transform: scaleX(-1); }
/* back arrow points forward-in-reading-direction */
[dir="rtl"] .finder-back::before { content: "→"; }

/* TOC rail (home): horizontal spotlight travel is physical — mirror it */
[dir="rtl"] .toc-rail-spotlight { transform: translateX(calc(var(--toc-active-index) * -1 * (100% + var(--row-gap)))); }
[dir="rtl"] .toc-rail-item { letter-spacing: 0; }
@media (min-width: 1024px) {
  /* vertical travel needs no RTL mirroring */
  [dir="rtl"] .toc-rail-spotlight { transform: translateY(calc(var(--toc-active-index) * (var(--row-h) + var(--row-gap)))); }
  [dir="rtl"] .toc-rail-inner:hover .toc-rail-item:hover { transform: translateX(-3px) scale(1.035); }
}


/* ═══ §8 · HERO SLIDER · TEAM · CONTACT ═════════════════════════
   Added 2026-08-05. Four things live here:
     8.1  the seamless hero edge (replaces the colour-matched scrim)
     8.2  the home hero slider
     8.3  the "Meet our team" cards
     8.4  contact-page layout
   RTL notes are inline; everything uses logical properties.        */

/* ── 8.1 · Seamless hero edge ─────────────────────────────────
   The old scrim covered the photo with #f2f6f7 at 76% alpha and stopped
   there, while the page behind it is a *fixed* #f2f6f7 → #e3eef2 gradient.
   Two mismatches — never fully opaque, never the right colour — and the
   result was a visible line where the hero ended.

   Rather than chase the page colour (which cannot work: a fixed background
   changes hue under the hero as you scroll), the media now dissolves.
   Masking its alpha to 0 leaves nothing to form an edge, so the photo blends
   into whatever is behind it at any scroll position, in either language
   tree, with no colour to keep in sync. */
:root {
  --hero-mask: linear-gradient(180deg,
      rgba(0,0,0,.32)   0%,
      rgba(0,0,0,.80)   9%,
      #000             23%,
      #000             55%,
      rgba(0,0,0,.74)  75%,
      rgba(0,0,0,.34)  88%,
      rgba(0,0,0,.10)  96%,
      transparent     100%);

  /* Legibility wash only — no longer doing edge duty, so it can stay light:
     a soft ice veil under the copy, and a touch at the top for the header. */
  --hero-scrim:
    linear-gradient(180deg, #f2f6f799 0%, #f2f6f73d 14%, transparent 32%),
    linear-gradient(0deg,   #f2f6f7a6 0%, #f2f6f752 22%, transparent 46%);
}

.hero-media {
  -webkit-mask-image: var(--hero-mask);
          mask-image: var(--hero-mask);
  -webkit-mask-mode: alpha;
          mask-mode: alpha;
}

/* The mask leaves the last tenth of the hero fully transparent, which would
   otherwise read as dead space. Pull the next section up to reclaim it —
   kept modest so it never reaches the slider controls below. */
/* …and no hairline across it. The whole point of the mask is that the hero has
   no edge; a section border drawn through the fade puts one back. (The border
   stays on .supporters elsewhere — on /about it divides two ordinary sections.) */
.hero + .supporters { margin-top: clamp(-80px, -6vh, -44px); position: relative; z-index: 1; border-top: none; }


/* ── 8.2 · Home hero slider ───────────────────────────────────
   Slides carry copy that already exists further down the page (HOME-02/03,
   HOME-16/17, HOME-66/67), so the hero reads as a table of contents for what
   follows and every CTA deep-links to the matching section.
   Without JS the first slide renders alone — i.e. exactly the previous hero
   — and the controls are hidden. */
.hero-slides { position: relative; min-height: var(--hero-h); }

html:not(.js) .hero-slide + .hero-slide { display: none; }
html:not(.js) .hero-controls { display: none; }

html.js .hero-slide {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transition: opacity .85s cubic-bezier(.4,0,.2,1), visibility 0s linear .85s;
}
html.js .hero-slide.is-active {
  opacity: 1; visibility: visible;
  transition: opacity .85s cubic-bezier(.4,0,.2,1), visibility 0s;
}
/* the art drifts very slightly while its slide holds */
html.js .hero-slide .hero-layer, html.js .hero-slide .hero-art { transform: scale(1.035); }
html.js .hero-slide.is-active .hero-layer,
html.js .hero-slide.is-active .hero-art { transform: scale(1); transition: transform 7s linear; }

/* Slides without photography: a brand ground carrying the origami mark.
   Deliberate art rather than an empty frame — swap in an <img class="hero-video
   hero-layer"> the moment real photography exists. */
.hero-art {
  position: absolute; inset: 0;
  background: var(--hero-art-bg, linear-gradient(150deg, #e8f3f6 0%, #d6eef4 46%, #bbdbe2 100%));
}
.hero-art::after {
  content: ""; position: absolute; inset: 0;
  /* inlined so the mark also resolves in the file:// copy, where a
     root-relative url() in a shared stylesheet cannot work */
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSI4OS41IDczLjAgMjMxLjUgMzI2LjUiPgo8ZyBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSI+Cgo8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwtMSwzMTkuMzcyOSwyNTIuMzEwNzkpIiBkPSJNMCAwLTk3Ljk3LTE0NS41ODctMTM0LjU0MS03OS43MzctNzEuMTUyIDE0LjQ1Ny00OS43MjEgNDYuMzM5LTEyLjI1MiAxMDIuMDQtNS4xMTEgMTEyLjYzMi00LjYxOCAxMTIuODM2LTMuOTUxIDk2LjY1OS0xLjcxMyA0MS44NDEtLjU5OCAxNC41NTFaIiBmaWxsPSIjMWU2MDQ4Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDMxNC4yNjIxLDEzOS42Nzg5OSkiIGQ9Ik0wIDAtNy4xNDEtMTAuNTkyLTQ0LjYxMS02Ni4yOTQtNjYuMDQxLTk4LjE3NS0xNjAuOTQyLTEzNS41OTktMTg1LjIyNy0xNDUuMTY4LTE4OC41MjctMTQwLjA5NC0yMjIuNTExLTg3Ljc0My0xOTMuODIxLTc2LjQxOS0xMjguMzItNTAuNTg2LTEyOC4yOTMtNTAuNTg3LTkxLjM3Mi0zNi4wMzItMTQuNjA0LTUuNzVaIiBmaWxsPSIjMGYyNzE5Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDIzMS41Njc3LDExMS41NDkyODkpIiBkPSJNMCAwLTM3LjQ0Mi01NS42NzctMzcuNDY4LTU1LjY3Ni05My43OTktMTkuMTk2LTU2LjMzMiAzNi40NzhaIiBmaWxsPSIjMWU2MDQ4Ii8+CjwvZz4KPC9zdmc+Cg==");
  background-repeat: no-repeat;
  background-position: 82% 46%;
  background-size: auto min(52vh, 460px);
  opacity: .12;
}
[dir="rtl"] .hero-art::after { background-position: 18% 46%; }

.hero-slide-2 { --hero-art-bg: linear-gradient(150deg, #eef7f9 0%, #d6eef4 52%, #bbdbe2 100%); }
.hero-slide-3 { --hero-art-bg: linear-gradient(150deg, #f7f0e4 0%, #edd9b8 38%, #cfe6ec 100%); }

/* Controls — bottom inline-end, clear of the copy block */
.hero-controls {
  position: absolute; z-index: 4;
  /* sits clear of the supporters band, which is pulled up under the fade */
  inset-block-end: clamp(64px, 9vh, 96px);
  inset-inline-end: 6vw;
  display: flex; align-items: center; gap: 14px;
}
.hero-arrow {
  width: 42px; height: 42px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: color-mix(in srgb, var(--surface-1) 55%, transparent);
  backdrop-filter: blur(8px);
  color: var(--ink-100); cursor: pointer;
  transition: background .3s, color .3s, border-color .3s;
}
.hero-arrow:hover { background: var(--brand-teal); border-color: var(--brand-teal); color: var(--ink-50); }
.hero-arrow svg { width: 15px; height: 15px; }
/* the glyphs point along the reading direction */
[dir="rtl"] .hero-arrow svg { transform: scaleX(-1); }

.hero-dots { list-style: none; display: flex; align-items: center; gap: 9px; }
.hero-dots button {
  display: block; width: 28px; height: 3px; padding: 0;
  border: none; border-radius: 999px; cursor: pointer;
  background: var(--line-strong);
  transition: background .3s, width .3s;
}
.hero-dots button[aria-current="true"] { background: var(--brand-teal); width: 44px; }
.hero-dots button:focus-visible,
.hero-arrow:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }

@media (max-width: 767px) {
  .hero-controls { inset-inline-end: 50%; transform: translateX(50%); }
  [dir="rtl"] .hero-controls { transform: translateX(-50%); }
  .hero-arrow { display: none; }
}

/* A slider that moves on its own must not move for visitors who asked for
   stillness — the script also skips autoplay entirely under this query. */
@media (prefers-reduced-motion: reduce) {
  html.js .hero-slide { transition: opacity .01s; }
  html.js .hero-slide.is-active .hero-layer,
  html.js .hero-slide.is-active .hero-art { transition: none; transform: none; }
}


/* ── 8.3 · Meet our team ──────────────────────────────────────
   Adapted from the supplied reference card: logo at the top-start corner,
   repeated label panels, name in brand teal, cutout standing on a teal block
   that it overflows. Three per row on desktop, one per row on mobile. */
.team-grid {
  display: grid; gap: clamp(18px, 2.4vw, 30px);
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 979px) { .team-grid { grid-template-columns: 1fr; max-width: 440px; margin-inline: auto; } }

/* ── Team cards ───────────────────────────────────────────────
   Photo-led: the portrait fills the card, a scrim carries the name and role
   over its foot, and the whole card is one button that opens a profile
   drawer. Adapted from a Framer TeamCardDrawer the user supplied, with the
   proportions pulled back — that reference scales the card 1.05 on hover and
   throws a 12px radius; here it is 1.015 and the site's own 22px, because
   three of these sit in a row on a page that is otherwise very quiet.

   The card carries no visible chrome of its own: no border, no tag panel, no
   logo strip. The photograph is the design. */
.team-grid {
  display: grid; gap: clamp(18px, 2.4vw, 30px);
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 979px) { .team-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .team-grid { grid-template-columns: 1fr; max-width: 380px; margin-inline: auto; } }

.team-card { display: flex; }

/* the whole card is the control — one target, one accessible name */
.team-open {
  position: relative;
  display: block; width: 100%;
  padding: 0; border: 0; background: none;
  border-radius: 22px; overflow: hidden;
  cursor: pointer; text-align: start;
  color: inherit; font: inherit;
  box-shadow: 0 18px 34px -28px rgba(15, 39, 24, .55);
  /* opacity/transform restate the reveal's own timing — a later transition
     on the same element would replace it and lose the entrance stagger */
  transition:
    opacity   .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    transform .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    scale .45s cubic-bezier(.16,1,.3,1),
    box-shadow .45s ease;
}
.team-open:hover, .team-open:focus-visible { scale: 1.015; box-shadow: 0 26px 44px -28px rgba(15, 39, 24, .6); }
.team-open:active { scale: .995; }
.team-open:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }

.team-shot {
  position: relative; display: block;
  aspect-ratio: 3 / 4;
  background: linear-gradient(170deg, #eef4f6 0%, #dbe9ee 100%);
}
.team-shot img,
.team-shot .media-placeholder {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  display: block;
}
/* the scrim: transparent for the top two-thirds so the face is never dimmed,
   then deep enough at the foot to carry the name at 12:1 */
.team-shot::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(15, 39, 24, 0) 42%,
    rgba(15, 39, 24, .34) 66%,
    rgba(15, 39, 24, .82) 100%);
}
/* the brand mark, ice on the photograph, in the inline-start corner like
   every other card on the site */
.team-mark {
  position: absolute; z-index: 1;
  inset-block-start: 16px; inset-inline-start: 16px;
  width: 22px; height: 29px;
  background-color: var(--brand-ice);
  mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSI4OS41IDczLjAgMjMxLjUgMzI2LjUiPgo8ZyBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSI+Cgo8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwtMSwzMTkuMzcyOSwyNTIuMzEwNzkpIiBkPSJNMCAwLTk3Ljk3LTE0NS41ODctMTM0LjU0MS03OS43MzctNzEuMTUyIDE0LjQ1Ny00OS43MjEgNDYuMzM5LTEyLjI1MiAxMDIuMDQtNS4xMTEgMTEyLjYzMi00LjYxOCAxMTIuODM2LTMuOTUxIDk2LjY1OS0xLjcxMyA0MS44NDEtLjU5OCAxNC41NTFaIiBmaWxsPSIjZDZlZWY0Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDMxNC4yNjIxLDEzOS42Nzg5OSkiIGQ9Ik0wIDAtNy4xNDEtMTAuNTkyLTQ0LjYxMS02Ni4yOTQtNjYuMDQxLTk4LjE3NS0xNjAuOTQyLTEzNS41OTktMTg1LjIyNy0xNDUuMTY4LTE4OC41MjctMTQwLjA5NC0yMjIuNTExLTg3Ljc0My0xOTMuODIxLTc2LjQxOS0xMjguMzItNTAuNTg2LTEyOC4yOTMtNTAuNTg3LTkxLjM3Mi0zNi4wMzItMTQuNjA0LTUuNzVaIiBmaWxsPSIjYTRjZmQ1Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDIzMS41Njc3LDExMS41NDkyODkpIiBkPSJNMCAwLTM3LjQ0Mi01NS42NzctMzcuNDY4LTU1LjY3Ni05My43OTktMTkuMTk2LTU2LjMzMiAzNi40NzhaIiBmaWxsPSIjZDZlZWY0Ii8+CjwvZz4KPC9zdmc+Cg==") center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSI4OS41IDczLjAgMjMxLjUgMzI2LjUiPgo8ZyBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSI+Cgo8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwtMSwzMTkuMzcyOSwyNTIuMzEwNzkpIiBkPSJNMCAwLTk3Ljk3LTE0NS41ODctMTM0LjU0MS03OS43MzctNzEuMTUyIDE0LjQ1Ny00OS43MjEgNDYuMzM5LTEyLjI1MiAxMDIuMDQtNS4xMTEgMTEyLjYzMi00LjYxOCAxMTIuODM2LTMuOTUxIDk2LjY1OS0xLjcxMyA0MS44NDEtLjU5OCAxNC41NTFaIiBmaWxsPSIjZDZlZWY0Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDMxNC4yNjIxLDEzOS42Nzg5OSkiIGQ9Ik0wIDAtNy4xNDEtMTAuNTkyLTQ0LjYxMS02Ni4yOTQtNjYuMDQxLTk4LjE3NS0xNjAuOTQyLTEzNS41OTktMTg1LjIyNy0xNDUuMTY4LTE4OC41MjctMTQwLjA5NC0yMjIuNTExLTg3Ljc0My0xOTMuODIxLTc2LjQxOS0xMjguMzItNTAuNTg2LTEyOC4yOTMtNTAuNTg3LTkxLjM3Mi0zNi4wMzItMTQuNjA0LTUuNzVaIiBmaWxsPSIjYTRjZmQ1Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDIzMS41Njc3LDExMS41NDkyODkpIiBkPSJNMCAwLTM3LjQ0Mi01NS42NzctMzcuNDY4LTU1LjY3Ni05My43OTktMTkuMTk2LTU2LjMzMiAzNi40NzhaIiBmaWxsPSIjZDZlZWY0Ii8+CjwvZz4KPC9zdmc+Cg==") center / contain no-repeat;
  opacity: .85;
  /* ice on a pale photograph would vanish — the shadow keeps the mark
     readable whatever the portrait's top corner turns out to be */
  filter: drop-shadow(0 1px 3px rgba(15, 39, 24, .55));
}

.team-id {
  position: absolute; z-index: 1;
  inset-inline: 0; inset-block-end: 0;
  display: flex; flex-direction: column; gap: 2px;
  padding: 20px clamp(16px, 1.8vw, 22px);
}
.team-name {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.15rem, 1.5vw, 1.4rem);
  line-height: 1.1; letter-spacing: -.01em;
  color: #fff;
}
.team-role { font-size: .92rem; color: var(--brand-ice); }

/* the affordance: a quiet cue that there is more behind the card */
.team-open::after {
  content: "";
  position: absolute; z-index: 2;
  inset-block-end: 22px; inset-inline-end: 20px;
  width: 26px; height: 26px; border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .55);
  background:
    linear-gradient(currentColor, currentColor) center / 9px 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 9px no-repeat;
  color: #fff;
  opacity: .8;
  transition: opacity .3s ease, rotate .45s cubic-bezier(.16,1,.3,1);
}
.team-open:hover::after, .team-open:focus-visible::after { opacity: 1; rotate: 90deg; }

@media (prefers-reduced-motion: reduce) {
  .team-open, .team-open::after { transition: none; }
  .team-open:hover, .team-open:focus-visible, .team-open:active { scale: none; }
  .team-open:hover::after, .team-open:focus-visible::after { rotate: none; }
}

/* PLACEHOLDER copy and art are flagged in the markup, not styled differently —
   the page should look finished so the layout can be judged on its merits. */


/* ── Profile drawer ───────────────────────────────────────────
   Opened by a team card. A panel on the inline end rather than a centred
   modal, so the grid stays visible behind it and moving between people reads
   as paging rather than as opening and closing dialogs.

   Slides from the inline end in both languages: the panel is pinned with
   inset-inline-end and hidden by --drawer-out, which flips sign under RTL.
   That is the one thing logical properties cannot do for us — translate is
   physical. */
.drawer {
  position: fixed; inset: 0; z-index: 240;
  --drawer-out: 100%;
}
[dir="rtl"] .drawer { --drawer-out: -100%; }
.drawer[hidden] { display: none; }

.drawer-scrim {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--brand-forest) 55%, transparent);
  backdrop-filter: blur(4px);
  opacity: 0; transition: opacity .4s ease;
}
.drawer.is-open .drawer-scrim { opacity: 1; }

.drawer-panel {
  position: absolute; inset-block: 0; inset-inline-end: 0;
  width: min(480px, 100%);
  display: flex; flex-direction: column;
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--paper-bg);
  border-inline-start: 1px solid var(--paper-border);
  box-shadow: -30px 0 60px -40px rgba(15, 39, 24, .6);
  translate: var(--drawer-out) 0;
  transition: translate .42s cubic-bezier(.22, 1, .32, 1);
}
.drawer.is-open .drawer-panel { translate: 0 0; }
/* while a finger is on it the panel tracks the drag with no easing */
.drawer-panel.is-dragging { transition: none; }

.drawer-close {
  position: absolute; z-index: 2;
  inset-block-start: 16px; inset-inline-end: 16px;
  width: 38px; height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255, 255, 255, .5); border-radius: 999px;
  background: color-mix(in srgb, var(--brand-forest) 35%, transparent);
  backdrop-filter: blur(6px);
  color: #fff; cursor: pointer;
  transition: background .3s, border-color .3s;
}
.drawer-close:hover { background: color-mix(in srgb, var(--brand-forest) 60%, transparent); border-color: #fff; }
.drawer-close:focus-visible { outline: 2px solid var(--brand-sand); outline-offset: 2px; }
.drawer-close svg { width: 17px; height: 17px; }

.drawer-shot { position: relative; flex-shrink: 0; aspect-ratio: 4 / 3; background: var(--surface-2); }
.drawer-shot img,
.drawer-shot .media-placeholder {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center; display: block;
}

.drawer-body {
  padding: clamp(24px, 3vw, 40px);
  display: flex; flex-direction: column; gap: 10px;
}
.drawer-name { font-size: clamp(1.6rem, 3vw, 2rem); line-height: 1.08; }
.drawer-role { color: var(--ink-300); }
.drawer-bio { margin-top: 8px; }
.drawer-bio p { color: var(--ink-200); }

body.drawer-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .drawer-scrim, .drawer-panel { transition: opacity .01s; }
  .drawer-panel { translate: 0 0; }
  .drawer:not(.is-open) .drawer-panel { translate: var(--drawer-out) 0; }
}


/* ── 8.4 · Contact ────────────────────────────────────────────
   The layout the previous one-pager used — statement on one side, form on the
   other — with the form given more room and the secondary CON fields folded
   into a disclosure so the first ask stays short. */
.contact-cols {
  display: grid; grid-template-columns: 1fr 1.05fr;
  gap: clamp(28px, 4.5vw, 72px); align-items: start;
}
@media (max-width: 899px) { .contact-cols { grid-template-columns: 1fr; } }

.contact-aside { display: flex; flex-direction: column; gap: clamp(20px, 3vh, 30px); }
.contact-lead { max-width: 52ch; color: var(--ink-200); font-size: clamp(1.02rem, 1.3vw, 1.16rem); }

/* CON-04 reads as a run of facts — set it as separated chips, not a sentence */
.contact-facts { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.contact-facts li {
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-300);
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 8px 14px;
}

.contact-direct {
  border-top: 1px solid var(--line); padding-top: clamp(18px, 3vh, 26px);
  display: flex; flex-direction: column; gap: 12px;
}
.contact-direct address { font-style: normal; display: flex; flex-direction: column; gap: 6px; color: var(--ink-200); }
.contact-direct a { color: var(--brand-teal); transition: opacity .3s; }
.contact-direct a:hover { opacity: .7; }

/* progressive disclosure for CON-09/10/11/13/14 */
.form-more { border-top: 1px solid var(--line); padding-top: 14px; }
.form-more > summary {
  cursor: pointer; list-style: none;
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--brand-teal);
  display: flex; align-items: center; gap: 8px;
}
.form-more > summary::-webkit-details-marker { display: none; }
.form-more > summary::after { content: "+"; font-size: 15px; line-height: 1; }
.form-more[open] > summary::after { content: "\2013"; }
.form-more .form-body { margin-top: 16px; }

/* Six nav items plus a CTA is tight at the 1024px breakpoint — buy the space
   back from the tracking and gap rather than dropping a link. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .site-nav { gap: 15px; }
  .site-nav a { letter-spacing: .1em; }
  .header-logo, .header-logo img { height: 46px; }
}


/* ═══ §9 · INTEGRATIONS GRID · CONSULTATION PROMPT ══════════════
   Added 2026-08-05 alongside the remaining pages.                  */

/* ── 9.1 · Integrations hub ───────────────────────────────────
   Filters are progressive enhancement — with JS off every card shows and the
   buttons are hidden, so the page is still a complete list. */
.int-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: clamp(20px, 3vh, 30px); }
html:not(.js) .int-filters { display: none; }
.int-filters button {
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-300); cursor: pointer;
  background: transparent;
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 9px 16px;
  transition: background .3s, color .3s, border-color .3s;
}
.int-filters button:hover { border-color: var(--brand-teal); color: var(--brand-teal); }
.int-filters button[aria-pressed="true"] {
  background: var(--brand-teal); border-color: var(--brand-teal); color: var(--ink-50);
}
.int-filters button:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }
[dir="rtl"] .int-filters button { letter-spacing: 0; font-size: 12.5px; }

.int-grid { display: grid; gap: 14px; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 979px) { .int-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .int-grid { grid-template-columns: 1fr; } }

/* these are plain .info-card markup, so §12 owns their look — only the
   filter state and the badge live here */
.int-card[hidden] { display: none; }

/* the status badge used to sit centred in a banner; as a direct child of the
   card's flex column it would otherwise stretch to the full width */
.int-card > .stamp { align-self: start; }


/* ── 9.2 · Contact prompt ─────────────────────────────────────
   An interruption, so it is held to the rules that make one tolerable: it
   waits, it appears once, dismissal is remembered, Escape closes it, focus is
   trapped while it is open and returned afterwards, and it never appears on
   the contact page (the visitor is already there).

   The card is a deep glass panel rather than the site's usual paper one: it
   has to read as a layer floating above the page, not as another section of
   it. It carries .is-deep.is-navy, so the ink, lines, pills and labels inside
   are re-skinned by that token block (§11.2) instead of by one-off rules here
   — the only thing this section owns is the glass, the light and the tilt.

   Decoration is stacked in three layers behind the copy: .prompt-aura (two
   slow ice/teal blooms behind the card), .prompt-beams (a light running each
   border edge in turn, plus four corner sparks) and .prompt-grain (a faint
   noise wash so the glass is not perfectly flat). All three are aria-hidden,
   and all three stop entirely under prefers-reduced-motion. */
.prompt {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: max(16px, env(safe-area-inset-bottom)) 16px;
}
.prompt[hidden] { display: none; }

.prompt-backdrop {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--brand-navy) 62%, transparent);
  backdrop-filter: blur(5px);
  opacity: 0; transition: opacity .4s ease;
}
.prompt.is-open .prompt-backdrop { opacity: 1; }

/* two blooms behind the card — the glow the glass sits in */
.prompt-aura {
  position: absolute; inset: 0; overflow: hidden; pointer-events: none;
  opacity: 0; transition: opacity .8s ease;
}
.prompt.is-open .prompt-aura { opacity: 1; }
.prompt-aura::before, .prompt-aura::after {
  content: ""; position: absolute; left: 50%; border-radius: 50%;
  transform: translateX(-50%); filter: blur(70px);
}
.prompt-aura::before {
  top: -18%; width: min(760px, 120vw); height: 60vh;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--brand-ice) 34%, transparent), transparent);
  animation: promptBloom 9s ease-in-out infinite;
}
.prompt-aura::after {
  bottom: -22%; width: min(640px, 110vw); height: 55vh;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--brand-teal) 46%, transparent), transparent);
  animation: promptBloom 7s ease-in-out infinite 1s;
}
@keyframes promptBloom {
  0%, 100% { opacity: .5; transform: translateX(-50%) scale(.97); }
  50%      { opacity: .9; transform: translateX(-50%) scale(1.05); }
}

/* the stage owns the perspective and the entrance; the card owns the tilt,
   so the two transforms never overwrite one another */
.prompt-stage {
  position: relative; z-index: 1;
  width: min(520px, 100%);
  perspective: 1400px;
  opacity: 0; transform: translateY(16px) scale(.985);
  transition: opacity .5s cubic-bezier(.16,1,.3,1), transform .5s cubic-bezier(.16,1,.3,1);
}
.prompt.is-open .prompt-stage { opacity: 1; transform: none; }

.prompt-card {
  position: relative;
  /* the card itself never scrolls — .prompt-body does. If the card were the
     scroller, the border light (absolutely positioned inside it) would scroll
     away from the bottom edge on a short viewport. */
  display: flex; flex-direction: column;
  max-height: calc(100dvh - 32px); overflow: hidden;
  border: 1px solid rgba(214, 238, 244, .12);
  border-radius: 22px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .10) inset,
    0 50px 90px -40px rgba(15, 39, 24, .75);
  backdrop-filter: blur(18px);
  transform: rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: transform .5s cubic-bezier(.16,1,.3,1);
}
.prompt-card.is-tilting { transition: none; }

/* .is-deep.is-navy (§11.2) supplies the ink tokens and paints an opaque navy
   ground. Restate that same navy translucent — that is what lets the blur
   behind it read as glass. The selector has to out-specify §11.2's two-class
   rule, which is why all three classes are named. */
.prompt-card.is-deep.is-navy {
  background: linear-gradient(165deg, rgba(36, 49, 68, .84) 0%, rgba(30, 39, 53, .90) 55%, rgba(21, 29, 39, .93) 100%);
}

.prompt-body {
  position: relative; z-index: 2;
  overflow-y: auto;
  padding: clamp(26px, 3.4vw, 38px);
  display: flex; flex-direction: column; gap: 14px;
}

/* the origami mark, ringed — the reference's logo badge */
.prompt-mark {
  width: 44px; height: 44px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid rgba(214, 238, 244, .18);
  background: linear-gradient(160deg, rgba(255,255,255,.14), rgba(255,255,255,.02));
  margin-bottom: 2px;
}
.prompt-mark img { width: 22px; height: 22px; display: block; }

.prompt-title { font-size: clamp(1.4rem, 2.4vw, 1.85rem); line-height: 1.14; }
.prompt-body > .serif { color: var(--ink-200); }
.prompt-trust { margin-top: 2px; opacity: .8; }

.prompt-close {
  position: absolute; inset-block-start: 14px; inset-inline-end: 14px;
  z-index: 3;
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--ink-300); cursor: pointer;
  transition: background .3s, color .3s, border-color .3s;
}
.prompt-close:hover { background: rgba(214, 238, 244, .16); color: #fff; border-color: var(--line-strong); }
.prompt-close:focus-visible { outline: 2px solid var(--brand-sand); outline-offset: 2px; }
.prompt-close svg { width: 16px; height: 16px; }

.prompt-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 4px; }
.prompt-actions .pill { cursor: pointer; }

/* "Not now" is the third action but the least of the three, so it is a quiet
   text button rather than a third pill — two pills and a link read as one
   choice with an escape hatch; three pills read as three equal offers. */
.prompt-dismiss {
  background: none; border: 0; padding: 6px 4px;
  font: inherit; font-size: .875rem; color: var(--ink-300);
  cursor: pointer; text-underline-offset: 3px;
  transition: color .3s;
}
.prompt-dismiss:hover { color: #fff; text-decoration: underline; }
.prompt-dismiss:focus-visible { outline: 2px solid var(--brand-sand); outline-offset: 3px; border-radius: 4px; }

/* ── the travelling border light ──
   Four segments, each half the length of its edge, handed off clockwise at
   .8s intervals so one light appears to circle the card. They live in an
   overflow-clipped layer inset by the border so the glow rides the edge
   instead of spilling past the radius. */
.prompt-beams {
  position: absolute; inset: 0; z-index: 1;
  border-radius: inherit; overflow: hidden; pointer-events: none;
}
.prompt-beam {
  position: absolute; opacity: .9;
  /* the halo is what makes a 2px line read as light rather than as a hairline */
  box-shadow: 0 0 10px color-mix(in srgb, var(--brand-ice) 55%, transparent);
}
.prompt-beam--t, .prompt-beam--b {
  height: 2px; width: 50%;
  background: linear-gradient(90deg, transparent, var(--brand-ice), transparent);
}
.prompt-beam--r, .prompt-beam--l {
  width: 2px; height: 50%;
  background: linear-gradient(180deg, transparent, var(--brand-ice), transparent);
}
.prompt-beam--t { top: 0;    left: -50%;  animation: promptBeamX 3.2s cubic-bezier(.5,0,.5,1) infinite; }
.prompt-beam--r { top: -50%; right: 0;    animation: promptBeamY 3.2s cubic-bezier(.5,0,.5,1) infinite .8s; }
.prompt-beam--b { bottom: 0; right: -50%; animation: promptBeamXr 3.2s cubic-bezier(.5,0,.5,1) infinite 1.6s; }
.prompt-beam--l { bottom: -50%; left: 0;  animation: promptBeamYr 3.2s cubic-bezier(.5,0,.5,1) infinite 2.4s; }
@keyframes promptBeamX  { 0% { left: -50%; }   60%, 100% { left: 100%; } }
@keyframes promptBeamXr { 0% { right: -50%; }  60%, 100% { right: 100%; } }
@keyframes promptBeamY  { 0% { top: -50%; }    60%, 100% { top: 100%; } }
@keyframes promptBeamYr { 0% { bottom: -50%; } 60%, 100% { bottom: 100%; } }

.prompt-spark {
  position: absolute; width: 7px; height: 7px; border-radius: 999px;
  background: color-mix(in srgb, var(--brand-ice) 70%, transparent);
  filter: blur(2px);
  animation: promptSpark 2.4s ease-in-out infinite;
}
.prompt-spark--tl { top: 0; left: 0; }
.prompt-spark--tr { top: 0; right: 0; animation-delay: .5s; }
.prompt-spark--br { bottom: 0; right: 0; animation-delay: 1s; }
.prompt-spark--bl { bottom: 0; left: 0; animation-delay: 1.5s; }
@keyframes promptSpark { 0%, 100% { opacity: .2; } 50% { opacity: .55; } }

/* a faint noise wash so the glass is not perfectly flat */
.prompt-grain {
  position: absolute; inset: 0; z-index: 1;
  border-radius: inherit; pointer-events: none;
  opacity: .04; mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}

/* nothing moves for a visitor who asked for stillness — the card just
   appears, and every light holds still. An invitation is content; the glow
   around it is not. */
@media (prefers-reduced-motion: reduce) {
  .prompt-stage { transition: opacity .01s; transform: none; }
  .prompt-backdrop, .prompt-aura { transition: opacity .01s; }
  .prompt-card { transform: none; transition: none; }
  .prompt-aura::before, .prompt-aura::after,
  .prompt-beam, .prompt-spark { animation: none; }
  .prompt-beam { opacity: .28; }
}

/* the page behind must not scroll while the dialog is open */
body.prompt-open { overflow: hidden; }



/* ═══ §11 · COLOUR SYSTEM — 60 · 30 · 10 ════════════════════════
   Added 2026-08-05. The palette was all present but nearly all of it
   sat in hairlines and hover states, so the page read as white. This
   section spends it deliberately:

     60%  the ice ground — --bg, white cards, ordinary chapters
     30%  brand grounds — the green utility strip and footer, the navy
          closing band on every page, and the ice/sand tinted chapters
          that break the white run (.is-tint / .is-tint-sand)
     10%  teal — every primary action, label, numeral and active state,
          becoming sand on the deep grounds where teal cannot carry

   The deep grounds work by REDEFINING the ink/line/surface variables
   rather than restyling each component: every card, rule, accordion and
   outline numeral inside a deep section re-skins itself from the same
   tokens it already reads. Contrast for each pairing is noted inline;
   all body text clears WCAG AA 4.5:1, headings clear AAA.               */

/* ── 11.1 · Tinted bands (the light half of the 30%) ───────────── */
.is-tint {
  background: linear-gradient(180deg, #e2eff3 0%, #d9ebf1 100%);
  border-block: 1px solid var(--line);
}
.is-tint-sand {
  background: linear-gradient(180deg, #f6ecdd 0%, #f0e2ca 100%);
  border-block: 1px solid rgba(120, 86, 40, .2);
  /* on sand the teal label drops to 6.4:1 and navy body copy to 8.7:1 */
}
.is-tint-sand .chapter-num, .is-tint-sand .card-num { -webkit-text-stroke-color: var(--brand-green); }

/* cards keep their white so they lift off a tinted ground rather than
   dissolving into it */
/* .supporter is no longer a tile — it is a bare logo on the band's own
   ground — so it is deliberately absent here and from the deep-band list
   below. The marks are dark artwork: keep the strip off .is-deep sections. */
.is-tint .info-card, .is-tint-sand .info-card,
.is-tint .comparator-col, .is-tint-sand .comparator-col { background: #fff; }

/* ── 11.2 · Deep bands (the dark half of the 30%) ──────────────── */
.is-deep {
  background: linear-gradient(165deg, var(--deep-green) 0%, var(--deep-green-2) 62%, #103d2c 100%);
  color: #dbeae4;

  /* one redefinition re-skins every component inside */
  --cream-50:  #ffffff;
  --cream-100: #ffffff;          /* headings            7.4:1 on green */
  --cream-200: var(--brand-sand);
  --ink-100: #e6f2ec;
  --ink-200: #dbeae4;            /* body copy           6.0:1 */
  --ink-300: #bcd9cc;            /* labels              4.9:1 */
  --ink-600: #dbeae4;
  --ink-700: #e6f2ec;
  --accent:    var(--brand-sand);
  --peach-200: var(--brand-ice);
  --peach-300: var(--brand-sand);  /* accent            5.4:1 */
  --peach-400: var(--brand-sand);
  --line:        rgba(214, 238, 244, .22);
  --line-strong: rgba(214, 238, 244, .44);
  --surface-1: #2b7058;
  --surface-2: #24614c;
  --surface-3: #2b7058;
  --paper-bg: linear-gradient(170deg, rgba(255,255,255,.12) 0%, rgba(255,255,255,.05) 100%);
  --paper-border: rgba(214, 238, 244, .3);
  --paper-shadow: 0 1px 0 rgba(255,255,255,.14) inset, 0 22px 44px -30px rgba(0,0,0,.6);
}
/* navy variant — the closing band on every page, so it steps off the
   green footer directly beneath it instead of merging into it */
.is-deep.is-navy {
  background: linear-gradient(165deg, #243144 0%, var(--deep-navy) 55%, #151d27 100%);
  --surface-1: #2c3a4c;
  --surface-2: #26323f;
  --surface-3: #2c3a4c;
  /* ice reads 12.4:1 on navy, sand 10.7:1 — both far past AA */
  --ink-200: #dfeaef;
  --ink-300: #b9d2dc;
}

/* actions invert: solid white primary, sand on hover */
.is-deep .pill { background: #fff; border-color: #fff; color: var(--brand-forest); box-shadow: none; }
.is-deep .pill:hover { background: var(--brand-sand); border-color: var(--brand-sand); color: var(--brand-forest); }
.is-deep .pill-ghost { background: transparent; color: #fff; border-color: rgba(214, 238, 244, .5); }
.is-deep .pill-ghost:hover { background: rgba(214, 238, 244, .14); border-color: var(--brand-sand); color: #fff; }
.is-deep .pill:focus-visible { outline-color: var(--brand-sand); }
.is-deep .stamp { background: rgba(255,255,255,.1); }
.is-deep .note-box { background: rgba(255,255,255,.07); border-color: rgba(214,238,244,.3); border-inline-start-color: var(--brand-sand); }
.is-deep .info-card, .is-deep .comparator-col, .is-deep .peppol-node,
.is-deep .score-band, .is-deep .finder-results > article,
.is-deep .chips li, .is-deep .finder-opts button {
  background: rgba(255,255,255,.07); border-color: rgba(214,238,244,.26); box-shadow: none;
}
.is-deep .chips li { color: var(--brand-ice); }
.is-deep .service-list li::before { background: var(--brand-sand); }
.is-deep a:not(.pill):hover { color: var(--brand-sand); }

/* ── 11.3 · Chrome and set pieces ──────────────────────────────── */

/* subpage hero — an ice band under the fixed header, fading into the page */
.page-hero {
  background:
    radial-gradient(110% 90% at 88% 0%, rgba(22, 100, 135, .16) 0%, transparent 62%),
    linear-gradient(180deg, #d8eaf0 0%, #e6f2f5 68%, transparent 100%);
}
[dir="rtl"] .page-hero { background:
    radial-gradient(110% 90% at 12% 0%, rgba(22, 100, 135, .16) 0%, transparent 62%),
    linear-gradient(180deg, #d8eaf0 0%, #e6f2f5 68%, transparent 100%); }

/* the home marquee — a green rule drawn across the middle of the page */
.marquee-track.band {
  background: linear-gradient(90deg, var(--deep-green) 0%, var(--deep-green-2) 100%);
  border-block-color: rgba(15, 39, 24, .35);
}
.marquee-track.band .mq-group span { color: var(--brand-ice); }
.marquee-track.band .mq-group i { color: var(--brand-sand); }

/* the outline numerals carried the accent before and now they hold it —
   solid green fill at large sizes reads as decoration, so they stay outlined */
.chapter-num { -webkit-text-stroke-width: 1.5px; }

/* section rules pick up the accent instead of a grey hairline */
.chapter-rule { background: linear-gradient(90deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 24%, transparent) 42%, transparent 100%); height: 2px; }
[dir="rtl"] .chapter-rule { background: linear-gradient(270deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 24%, transparent) 42%, transparent 100%); }
.is-deep .chapter-rule { background: linear-gradient(90deg, var(--brand-sand) 0%, transparent 100%); }

/* The compliance guide's closing CTA lives inside the sticky-TOC grid column,
   so its deep band is a panel rather than a full-bleed strip. */
.guide-main .is-deep {
  border-radius: 20px;
  padding-inline: clamp(24px, 4vw, 46px);
  margin-top: clamp(30px, 5vh, 54px);
}



/* ═══ §12 · GLARE CARDS ═════════════════════════════════════════
   The default card treatment everywhere except home §03 and /resources
   (those take §13). Adapted from an Aceternity GlareCard: the card leans a
   couple of degrees towards the pointer and a soft sheen tracks it across
   the surface, with the Dhara mark in the corner on the inline start —
   left in English, right in Arabic, straight out of `inset-inline-start`.

   Departures from the reference, all deliberate:
     · the reference's holographic rainbow is replaced by a two-stop brand
       sheen (ice into teal) at low opacity. A rainbow on a document-heavy
       compliance site reads as a toy;
     · the tilt is ~4°, not the reference's ~12° — these cards carry three
       or four lines of copy that has to stay readable while it moves;
     · the sheen is a lighten pass over a light card rather than a bright
       overlay on a dark one, so the copy never loses contrast. Nothing here
       recolours text, which is what makes it safe: unlike a flood, a glare
       leaves every measured contrast pair exactly as it was.

   Mechanics: js/main.js §13 writes --mx/--my (pointer position, in %) and
   --rot-x/--rot-y/--rot-a (a rotation axis and angle) onto the card. The
   rotation uses the independent `rotate` property, and the depth layers in
   §13 use `translate`'s third value, because `transform` is already spoken
   for by the scroll reveal — see the transition note below. */

:root { --dhara-mark: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSI4OS41IDczLjAgMjMxLjUgMzI2LjUiPgo8ZyBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSI+Cgo8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwtMSwzMTkuMzcyOSwyNTIuMzEwNzkpIiBkPSJNMCAwLTk3Ljk3LTE0NS41ODctMTM0LjU0MS03OS43MzctNzEuMTUyIDE0LjQ1Ny00OS43MjEgNDYuMzM5LTEyLjI1MiAxMDIuMDQtNS4xMTEgMTEyLjYzMi00LjYxOCAxMTIuODM2LTMuOTUxIDk2LjY1OS0xLjcxMyA0MS44NDEtLjU5OCAxNC41NTFaIiBmaWxsPSIjMWU2MDQ4Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDMxNC4yNjIxLDEzOS42Nzg5OSkiIGQ9Ik0wIDAtNy4xNDEtMTAuNTkyLTQ0LjYxMS02Ni4yOTQtNjYuMDQxLTk4LjE3NS0xNjAuOTQyLTEzNS41OTktMTg1LjIyNy0xNDUuMTY4LTE4OC41MjctMTQwLjA5NC0yMjIuNTExLTg3Ljc0My0xOTMuODIxLTc2LjQxOS0xMjguMzItNTAuNTg2LTEyOC4yOTMtNTAuNTg3LTkxLjM3Mi0zNi4wMzItMTQuNjA0LTUuNzVaIiBmaWxsPSIjMGYyNzE5Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLC0xLDIzMS41Njc3LDExMS41NDkyODkpIiBkPSJNMCAwLTM3LjQ0Mi01NS42NzctMzcuNDY4LTU1LjY3Ni05My43OTktMTkuMTk2LTU2LjMzMiAzNi40NzhaIiBmaWxsPSIjMWU2MDQ4Ii8+CjwvZz4KPC9zdmc+Cg=="); }

/* the 3D has to come from an ancestor: `rotate` alone has no perspective */
.card-grid, .comparator, .peppol-flow, .score-bands, .team-grid, .int-grid {
  perspective: 1200px;
}

.info-card:not(.is-depth),
.comparator-col:not(.is-depth),
.peppol-node:not(.is-depth),
.score-band:not(.is-depth) {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 22px;
  /* the mark's own corner — without it the mark lands under the last line
     of copy on roughly half the cards */
  padding-block-end: 60px;
  rotate: var(--rot-x, 0) var(--rot-y, 0) 0 var(--rot-a, 0deg);
  /* This list has to re-state opacity and transform with the scroll
     reveal's own timing: a later `transition` on the same element replaces
     .reveal's wholesale, and the entrance stagger is silently lost. */
  transition:
    opacity   .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    transform .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    rotate .5s cubic-bezier(.16,1,.3,1),
    translate .5s cubic-bezier(.16,1,.3,1),
    box-shadow .45s ease,
    border-color .45s ease;
}
/* while the pointer is actually moving over the card the lean tracks it
   directly — easing here would make it lag behind the cursor */
.info-card:not(.is-depth).is-tracking,
.comparator-col:not(.is-depth).is-tracking,
.peppol-node:not(.is-depth).is-tracking,
.score-band:not(.is-depth).is-tracking { transition: none; }

/* ── the sheen ──
   A soft ellipse of light centred on the pointer, plus a fixed brand wash
   underneath it so the highlight picks up ice at the top and teal at the
   foot rather than reading as plain white. */
.info-card:not(.is-depth)::before,
.comparator-col:not(.is-depth)::before,
.peppol-node:not(.is-depth)::before,
.score-band:not(.is-depth)::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  background:
    radial-gradient(38% 55% at var(--mx, 50%) var(--my, 50%),
      rgba(255, 255, 255, .85) 0%, rgba(255, 255, 255, .35) 42%, transparent 72%),
    linear-gradient(150deg,
      color-mix(in srgb, var(--brand-ice) 60%, transparent) 0%,
      transparent 45%,
      color-mix(in srgb, var(--brand-teal) 26%, transparent) 100%);
  opacity: 0;
  transition: opacity .4s ease;
}
.info-card:not(.is-depth):hover::before,
.info-card:not(.is-depth):focus-within::before,
.comparator-col:not(.is-depth):hover::before,
.comparator-col:not(.is-depth):focus-within::before,
.peppol-node:not(.is-depth):hover::before,
.peppol-node:not(.is-depth):focus-within::before,
.score-band:not(.is-depth):hover::before,
.score-band:not(.is-depth):focus-within::before { opacity: 1; }

/* ── the mark ──
   Masked, so the source SVG's own fills are irrelevant and the colour is
   ours to drive. Bottom on the inline start, which mirrors itself under
   dir="rtl" with no override. */
.info-card:not(.is-depth)::after,
.comparator-col:not(.is-depth)::after,
.peppol-node:not(.is-depth)::after,
.score-band:not(.is-depth)::after {
  content: "";
  position: absolute; z-index: -1;
  inset-block-end: 14px; inset-inline-start: 16px;
  width: 26px; height: 34px;
  background-color: var(--card-mark, var(--brand-teal));
  mask: var(--dhara-mark) center / contain no-repeat;
  -webkit-mask: var(--dhara-mark) center / contain no-repeat;
  opacity: .34;
  transition: opacity .4s ease;
}
.info-card:not(.is-depth):hover::after,
.info-card:not(.is-depth):focus-within::after,
.comparator-col:not(.is-depth):hover::after,
.comparator-col:not(.is-depth):focus-within::after,
.peppol-node:not(.is-depth):hover::after,
.peppol-node:not(.is-depth):focus-within::after,
.score-band:not(.is-depth):hover::after,
.score-band:not(.is-depth):focus-within::after { opacity: .72; }

.info-card:not(.is-depth):hover,
.info-card:not(.is-depth):focus-within,
.comparator-col:not(.is-depth):hover,
.comparator-col:not(.is-depth):focus-within,
.peppol-node:not(.is-depth):hover,
.peppol-node:not(.is-depth):focus-within,
.score-band:not(.is-depth):hover,
.score-band:not(.is-depth):focus-within {
  border-color: color-mix(in srgb, var(--brand-teal) 45%, transparent);
  box-shadow:
    0 22px 40px -26px rgba(15, 39, 24, .45),
    0 0 0 1px color-mix(in srgb, var(--brand-ice) 60%, transparent) inset;
}

/* on deep bands the ground is dark, so the sheen inverts to a cool wash and
   the mark goes ice. No card currently sits inside .is-deep — this is here
   so one can, without arriving unstyled. */
.is-deep .info-card:not(.is-depth),
.is-deep .comparator-col:not(.is-depth),
.is-deep .peppol-node:not(.is-depth),
.is-deep .score-band:not(.is-depth) { --card-mark: var(--brand-ice); }
.is-deep .info-card:not(.is-depth)::before,
.is-deep .comparator-col:not(.is-depth)::before,
.is-deep .peppol-node:not(.is-depth)::before,
.is-deep .score-band:not(.is-depth)::before {
  background:
    radial-gradient(38% 55% at var(--mx, 50%) var(--my, 50%),
      rgba(214, 238, 244, .30) 0%, rgba(214, 238, 244, .12) 42%, transparent 72%),
    linear-gradient(150deg, rgba(214, 238, 244, .10) 0%, transparent 60%);
}

/* The Peppol steps take the sheen but not the mark: they are a numbered
   accordion whose inline-start corner already carries the step numeral, and
   a closed <details> would show the reserved corner as dead height. */
.peppol-node { padding-block-end: 0; }
.peppol-node::after { content: none; }

/* the comparator's e-invoicing column keeps its accent edge on hover */
.comparator-col.is-einvoice:hover,
.comparator-col.is-einvoice:focus-within { border-color: var(--brand-sand); }

/* The integrations hub is plain .info-card markup now, so §12's shared
   rules already cover it. Only the filter hook and the on-request state are
   specific to it, and both live in §9. */


/* ═══ §13 · DEPTH CARDS ═════════════════════════════════════════
   Home §03 ("An ordinary PDF is not an e-invoice") and the /resources list.
   Adapted from an Aceternity 3D card: the card leans towards the pointer and
   its contents sit at different depths, so they part company slightly as it
   moves. The reference throws the layers 50-100px forward; here the deepest
   layer is 26px, because these are text cards read at arm's length and a
   heading that leaps off the page is a distraction, not an effect.

   The Z offsets ride on `translate`'s third value rather than a transform,
   for the same reason as everything else in this stylesheet: .reveal owns
   `transform`, and overwriting it kills the entrance. */
.card-grid--depth { perspective: 1100px; }

.is-depth {
  transform-style: preserve-3d;
  rotate: var(--rot-x, 0) var(--rot-y, 0) 0 var(--rot-a, 0deg);
  transition:
    opacity   .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    transform .8s cubic-bezier(.16,1,.3,1) var(--d, 0s),
    rotate .5s cubic-bezier(.16,1,.3,1),
    filter .45s ease;
}
.is-depth.is-tracking { transition: none; }
.is-depth:hover, .is-depth:focus-within {
  filter: drop-shadow(0 18px 28px rgba(15, 39, 24, .20));
}

/* the layers. --z is per role, and only leaves the surface on hover. */
.is-depth > * {
  transition: translate .45s cubic-bezier(.16,1,.3,1);
}
.is-depth:hover > *, .is-depth:focus-within > * {
  translate: 0 0 var(--z, 0px);
}

/* Resources cards: heading, then copy, with the link furthest forward so the
   thing you can act on is the thing nearest to you. */
.card-grid--depth .is-depth > h3 { --z: 20px; }
.card-grid--depth .is-depth > p  { --z: 12px; }
.card-grid--depth .is-depth > p:last-child { --z: 26px; }


/* The mark belongs on these too — only /resources uses this section now, so
   this is where it goes.

   It cannot be hung off z-index:-1 + isolation the way §12 does it:
   `isolation` is a grouping property, so it would force transform-style flat
   and collapse the depth layers this section exists for. Instead the mark
   paints above the background at z-index 1, which is safe because the
   reserved corner keeps it clear of the copy. */
.card-grid--depth .is-depth {
  position: relative;
  border-radius: 22px;
  padding-block-end: 60px;
}
.card-grid--depth .is-depth::after {
  content: "";
  position: absolute; z-index: 1;
  inset-block-end: 14px; inset-inline-start: 16px;
  width: 26px; height: 34px;
  background-color: var(--brand-teal);
  mask: var(--dhara-mark) center / contain no-repeat;
  -webkit-mask: var(--dhara-mark) center / contain no-repeat;
  opacity: .34;
  transition: opacity .4s ease;
}
.card-grid--depth .is-depth:hover::after,
.card-grid--depth .is-depth:focus-within::after { opacity: .72; }

@media (prefers-reduced-motion: reduce) {
  .info-card:not(.is-depth),
  .comparator-col:not(.is-depth),
  .peppol-node:not(.is-depth),
  .score-band:not(.is-depth),
  .is-depth { rotate: none; transition: none; }
  .info-card:not(.is-depth)::before,
  .comparator-col:not(.is-depth)::before,
  .peppol-node:not(.is-depth)::before,
  .score-band:not(.is-depth)::before { transition: none; }
  .is-depth:hover > *, .is-depth:focus-within > * { translate: none; }
  .is-depth > * { transition: none; }
}


/* ── card CTA ──────────────────────────────────────────────────
   The bottom link on a card, with an arrow that follows the reading
   direction. Named .card-cta since the brushed treatment it came from was
   retired; the markup uses it on home §03. */
.card-cta { margin-top: auto; padding-top: 4px; }
.card-cta a {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display); font-weight: 600;
  color: var(--brand-teal);
}
.card-cta a::after { content: "→"; transition: transform .3s; }
[dir="rtl"] .card-cta a::after { content: "←"; }
.card-cta a:hover { text-decoration: underline; }
.card-cta a:hover::after { transform: translateX(3px); }
[dir="rtl"] .card-cta a:hover::after { transform: translateX(-3px); }
@media (prefers-reduced-motion: reduce) {
  .card-cta a::after, [dir="rtl"] .card-cta a::after { transition: none; }
}


/* ═══ §14 · CONTROLS ════════════════════════════════════════════
   The checkbox and the primary/secondary action button, both adapted from
   Uiverse references the user supplied, both recoloured to the brand.

   ── Checkbox ──
   Used by the readiness checklist (.check-item, eight per page) and by the
   consent boxes on the contact and guide forms (.opt.consent). One
   deliberate departure from the reference: it hides the real input with
   `display: none`, which takes it out of the tab order and leaves the
   control unreachable by keyboard. Here the input IS the box —
   `appearance: none` and style it directly — so focus, the space key, label
   association and screen-reader semantics all survive untouched. The tick
   rides on the input's own ::before, which is what `appearance: none`
   makes possible.

   Radios are left alone: the selectors are typed to [type="checkbox"] so
   the four radio inputs on the phase finder keep their accent-color. */

.opt input[type="checkbox"],
.check-item input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 24px; height: 24px; flex-shrink: 0;
  margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface-1);
  cursor: pointer;
  /* Everything answers the click at once. The reference eased the fill over
     1.3s, which reads as a lag — you click and the box sits there. The fill
     is quick, the spin runs its full .3s from the same instant, and the tick
     (below) is instant. */
  transition: background-color .16s ease, border-color .16s ease, transform .3s cubic-bezier(.2,.9,.3,1.3);
}
.opt input[type="checkbox"]::before,
.check-item input[type="checkbox"]::before {
  content: "\2713";
  font-size: 15px; line-height: 1;
  color: transparent;
  /* only for the way back out — see the :checked rule */
  transition: color .14s ease;
}

.opt input[type="checkbox"]:checked,
.check-item input[type="checkbox"]:checked {
  background: var(--brand-teal);
  border-color: var(--brand-teal);
  /* the reference's flourish, kept: a full turn on both axes as it fills */
  transform: scale(1.08) rotateZ(360deg) rotateY(360deg);
}
/* The tick lands on the same frame as the click. A transition is declared
   only on the base rule above, and a transition uses the value from the
   state being moved TO — so ticking is instant, and unticking still gets the
   short fade. */
.opt input[type="checkbox"]:checked::before,
.check-item input[type="checkbox"]:checked::before {
  color: #fff;
  transition: color 0s;
}

/* hovering anywhere on the label answers, not just the box itself */
.opt:hover input[type="checkbox"],
.check-item:hover input[type="checkbox"] {
  border-color: var(--brand-teal);
  background: color-mix(in srgb, var(--brand-ice) 45%, var(--surface-1));
  transform: scale(1.05);
}
.opt:hover input[type="checkbox"]:checked,
.check-item:hover input[type="checkbox"]:checked {
  background: var(--brand-green);
  border-color: var(--brand-green);
}

.opt input[type="checkbox"]:focus-visible,
.check-item input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--brand-teal);
  outline-offset: 3px;
}

/* the checklist reserves a 24px column and starts its rows at the top */
.check-item input[type="checkbox"] { margin-top: 2px; }
.consent input[type="checkbox"] { margin-top: 1px; }

@media (prefers-reduced-motion: reduce) {
  .opt input[type="checkbox"],
  .check-item input[type="checkbox"],
  .opt input[type="checkbox"]::before,
  .check-item input[type="checkbox"]::before { transition: none; }
  .opt input[type="checkbox"]:checked,
  .check-item input[type="checkbox"]:checked,
  .opt:hover input[type="checkbox"],
  .check-item:hover input[type="checkbox"] { transform: none; }
}


/* ── Action buttons ──
   Every .pill — primary and .pill-ghost secondary alike — sits on a solid
   edge, so it reads as a physical key: it travels down onto that edge on
   hover and meets it flush when pressed.

   The edge is a hard-offset box-shadow (0 blur, 0 spread), NOT a pseudo-
   element. The first attempt used a ::before at z-index:-1, which is wrong:
   inside a stacking context a negative-z child paints above its own
   element's background, so the edge tint washed across the whole face. That
   is invisible under the opaque primary and ruins the translucent secondary
   — it was why the ghost looked muddy. A shadow paints entirely behind the
   box, so it works under any face, transparent or frosted, and it costs no
   extra element, no stacking context and no layout height (these pills sit
   in tight rows — the header bar, the hero CTA row, the prompt — where a
   taller box would reflow the line).

   Travel and edge always sum to --pill-lift, so the bottom of the key stays
   put while the top of it sinks. Movement uses the independent `translate`
   property, not `transform`: `transform` belongs to the scroll reveal, and a
   pill inside a revealing block must not fight it. */
.pill {
  position: relative;
  --pill-edge: color-mix(in srgb, var(--accent) 55%, var(--brand-forest));
  --pill-lift: 6px;
  --pill-cast: 0 12px 22px -16px rgba(15, 39, 24, .75);
  --pill-inner: 0 0 rgba(0, 0, 0, 0);
  box-shadow: 0 var(--pill-lift) 0 0 var(--pill-edge), var(--pill-cast), var(--pill-inner);
  transition:
    background .3s, color .3s, border-color .3s,
    box-shadow .15s cubic-bezier(0, 0, .58, 1),
    translate .15s cubic-bezier(0, 0, .58, 1);
}
/* pressed halfway on hover, flush on click */
.pill:hover {
  translate: 0 calc(var(--pill-lift) / 2); transform: none;
  box-shadow: 0 calc(var(--pill-lift) / 2) 0 0 var(--pill-edge), var(--pill-cast), var(--pill-inner);
}
.pill:active {
  translate: 0 var(--pill-lift);
  box-shadow: 0 0 0 0 var(--pill-edge), var(--pill-cast), var(--pill-inner);
}

/* ── secondary: frosted glass ──
   The old ghost was a transparent box with a hairline, which next to a solid
   primary read as an empty slot rather than a button. It is now a real
   surface: a white veil thin enough to carry the hero photograph through it,
   blurred and slightly saturated so what shows through reads as glass rather
   than as dirt, a bright inner top edge for the lit rim, and an edge beneath
   in the same teal family as the primary's so the pair reads as one set.
   Ink stays brand forest — 11.4:1 on the veil over any of the site's light
   grounds, and the veil is opaque enough to hold that over photography. */
.pill-ghost {
  background: color-mix(in srgb, #ffffff 62%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  border-color: color-mix(in srgb, var(--brand-teal) 30%, transparent);
  color: var(--brand-forest);
  --pill-edge: color-mix(in srgb, var(--brand-teal) 30%, transparent);
  --pill-cast: 0 12px 24px -18px rgba(15, 39, 24, .55);
  --pill-inner: inset 0 1px 0 rgba(255, 255, 255, .85);
}
.pill-ghost:hover {
  background: color-mix(in srgb, #ffffff 80%, transparent);
  border-color: color-mix(in srgb, var(--brand-teal) 60%, transparent);
  color: var(--brand-teal);
}

/* the header's small pill sits in a shallow bar — less travel */
.pill-small { --pill-lift: 4px; }

/* On deep bands the face inverts to white, so the primary's edge takes the
   band's own accent, and the glass flips to a dark veil with a light rim.
   The edge has to be restated here, not just re-coloured: §11.2's
   `.is-deep .pill` sets `box-shadow: none` at two-class specificity, which
   beats §14's single-class `.pill` no matter what the source order is — so
   without this the pills inside every closing chapter and the contact
   prompt would quietly lose their edge. */
.is-deep .pill {
  --pill-edge: var(--brand-sand);
  box-shadow: 0 var(--pill-lift) 0 0 var(--pill-edge), var(--pill-inner);
}
.is-deep .pill:hover {
  box-shadow: 0 calc(var(--pill-lift) / 2) 0 0 var(--pill-edge), var(--pill-inner);
}
.is-deep .pill:active {
  box-shadow: 0 0 0 0 var(--pill-edge), var(--pill-inner);
}
.is-deep .pill-ghost {
  background: rgba(255, 255, 255, .12);
  border-color: rgba(214, 238, 244, .45);
  --pill-edge: rgba(214, 238, 244, .38);
  --pill-inner: inset 0 1px 0 rgba(255, 255, 255, .28);
}
.is-deep .pill-ghost:hover {
  background: rgba(255, 255, 255, .22);
  border-color: var(--brand-sand);
  color: #fff;
}

/* Stillness: the key keeps its edge — that is depth, not motion — but it
   stops travelling, so hover and press are colour changes only. */
@media (prefers-reduced-motion: reduce) {
  .pill { transition: background .3s, color .3s, border-color .3s; }
  .pill:hover, .pill:active {
    translate: none;
    box-shadow: 0 var(--pill-lift) 0 0 var(--pill-edge), var(--pill-cast), var(--pill-inner);
  }
  .is-deep .pill:hover, .is-deep .pill:active {
    box-shadow: 0 var(--pill-lift) 0 0 var(--pill-edge), var(--pill-inner);
  }
}
