/* ═══════════════════════════════════════════════════════════════
   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:        #fffcf6;
  --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);

  /* One shadow scale for the page body: resting card, card under the
     pointer, and the form's paper. Every card should pick from these. */
  --shadow-card:       0 1px 2px rgba(15, 39, 24, .04), 0 12px 28px -22px rgba(15, 39, 24, .32);
  --shadow-card-hover: 0 2px 4px rgba(15, 39, 24, .05), 0 20px 36px -22px rgba(15, 39, 24, .40);

  /* Semantic status — used sparingly, always with an icon and words, never
     as the colour of a whole card. The strong tone carries the icon and
     the edge; the soft one tints the surface. */
  --status-positive:      #1f6047;
  --status-positive-soft: rgba(31, 96, 71, .09);
  --status-negative:      #b3261e;
  --status-negative-soft: rgba(179, 38, 30, .07);
  --status-warning:       #9a6a10;
  --status-warning-soft:  rgba(196, 140, 32, .11);
  --status-info:          #166487;
  --status-info-soft:     rgba(22, 100, 135, .09);

  --hero-video-filter: brightness(.96) saturate(.95);
  /* cream fade at the BOTTOM (into the page) mirrored at the TOP */
  --hero-scrim:
    linear-gradient(180deg, #fffcf6c2 0%, #fffcf66b 12%, #fffcf61f 25%, transparent 38%),
    linear-gradient(0deg, #fffcf6c2 0%, #fffcf66b 24%, #fffcf61f 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: var(--bg); }

*,*::before,*::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }

/* `hidden` means hidden, whatever else the element's class sets.
   The UA's [hidden] rule is display:none, but ANY author `display`
   declaration outranks it — so a class with display:flex/grid silently
   keeps a hidden element on screen. That had already cost four separate
   per-class patches (.field, .finder-back, .int-card, .prompt), and it hid
   a fifth: .form-success sets display:flex, so every lead form rendered
   its "thank you" message permanently, and submitting changed nothing on
   screen because .form-body (also display:flex) would not hide either.
   One rule at the base ends the whole class of bug; the per-class patches
   below are now redundant but harmless. */
[hidden] { display: none !important; }
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; }
/* A heading breaks where its lines come out even, not wherever the first
   one happens to fill — no last line of one word under two full ones. */
h1, h2, h3 { text-wrap: balance; }
/* A word that must not be split at its hyphen (main.js §3a). */
.nowrap { white-space: nowrap; }

/* ── The parts of the page the browser draws ──────────────────
   Selected text, the caret, the scrollbar and the focus ring are on every
   page and belonged to none of them: the browser's blue on a green and sand
   site. They take the palette here, once.

   The focus ring is a floor, not a replacement. It is wrapped in :where(),
   so it weighs nothing and every control that already draws its own ring
   keeps it; what it catches is the link or button nobody gave one. */
::selection { background: var(--brand-ice-2); color: var(--brand-forest); }
.is-deep ::selection, .site-chrome ::selection, .site-footer ::selection { background: var(--brand-sand); color: var(--brand-forest); }
html { scrollbar-color: color-mix(in srgb, var(--brand-teal) 45%, transparent) transparent; }
input, textarea, select { caret-color: var(--brand-teal); }
:where(a, button, summary, [tabindex]):focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
:where(.is-deep, .site-chrome, .site-footer) :where(a, button, summary, [tabindex]):focus-visible { outline-color: var(--brand-sand); }

/* ── 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 ──
   Permanently NAVY since 2026-08-07: the header carries the white lockup,
   white nav ink and the neon-flow canvas (which renders opaque-dark in real
   browsers — its bloom pass writes solid pixels), so the bar is a dark band
   by design, not by scroll state. The ground lives HERE, on the chrome, not
   on .site-header: the canvas paints at z-index -1 inside this stacking
   context — above the chrome's background, below the header's in-flow
   content — so a background on the header itself would cover the tubes.
   Wherever the canvas is skipped (coarse pointers, reduced motion, no
   network, no JS) this navy is what keeps the white type legible. */
/* Height of the fixed chrome below 1024px, where the utility strip is hidden
   and the chrome is the header alone. Declared as a variable because the
   hero has to reserve it (see .hero-content) — two literals drifting apart
   is how the eyebrow ends up under the bar. */
:root { --chrome-h: 90px; }
.site-chrome { position: fixed; inset: 0 0 auto 0; z-index: 50; background: var(--brand-navy); }
/* relative, not static: the header is the positioning box for the neon-flow
   canvas layer. The mobile nav panel's containing block moves from the
   chrome to the header with this — visually identical below 1024px, where
   the utility strip is hidden and the two boxes coincide. */
.site-chrome .site-header { position: relative; }
/* the scrolled state keeps the same navy — only the edge below it appears */
body.header-solid .site-chrome {
  border-bottom: 1px solid rgba(15, 39, 24, .55);
  box-shadow: 0 14px 30px -26px rgba(15, 39, 24, .85);
}
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; }

/* ── Language selector — flag menu in the header bar ──────────
   A <details> disclosure, so it opens and closes with no JS at all;
   main.js §7b only adds outside-click and Escape closing. One instance at
   every width. The summary pill sits on the navy bar; the open list is the
   same light paper the mobile nav panel uses. All logical properties, so
   the RTL trees mirror it without overrides. */
.lang-menu { position: relative; }
.lang-menu summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em;
  color: #fff;
  border: 1px solid rgba(214, 238, 244, .35); border-radius: 999px;
  padding: 7px 12px;
  transition: background .3s, border-color .3s;
}
.lang-menu summary::-webkit-details-marker { display: none; }
.lang-menu summary:hover { background: rgba(214, 238, 244, .12); }
.lang-menu summary:focus-visible { outline: 2px solid var(--brand-ice); outline-offset: 2px; }
.lang-menu[open] summary { background: rgba(214, 238, 244, .16); border-color: rgba(214, 238, 244, .6); }
.lang-flag {
  width: 21px; height: 14px; display: block; object-fit: cover;
  border-radius: 2px;
  /* a hairline over the flag art — the US stripes are white-on-white
     against the open panel without it */
  box-shadow: 0 0 0 1px rgba(15, 39, 24, .25);
}
.lang-caret { width: 10px; height: 6px; }
.lang-menu[open] .lang-caret { transform: rotate(180deg); }
.lang-list {
  list-style: none;
  position: absolute; top: calc(100% + 8px); inset-inline-end: 0;
  min-width: 178px; padding: 8px; margin: 0;
  display: grid; gap: 2px; z-index: 5;
  background: var(--paper-bg, #fff);
  border: 1px solid var(--paper-border, var(--line));
  border-radius: 14px;
  box-shadow: var(--paper-shadow, 0 18px 40px -20px rgba(15, 39, 24, .4));
}
.lang-list a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: 9px;
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .04em;
  color: var(--ink-100);
  transition: background .25s, color .25s;
}
.lang-list a:hover { background: var(--surface-2); color: var(--brand-teal); }
.lang-list a.is-current { background: var(--surface-3); font-weight: 600; }

/* ── 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); }

/* On the navy bar the links are WHITE (2026-08-07 — they were unreadable
   dark-on-dark, see the ink-600 default above, which now serves only the
   light dropdown panel). Scoped to the two states where the links actually
   sit on the bar: the desktop inline row, and the no-JS inline fallback
   below 1024px. Hover/current go sand, the same move the utility strip
   makes — teal reads as mud on navy. */
@media (min-width: 1024px) {
  .site-nav a { color: #fff; }
  .site-nav a:hover { color: var(--brand-sand); }
  .site-nav a[aria-current="page"] { color: var(--brand-sand); border-bottom-color: var(--brand-sand); }
}
@media (max-width: 1023px) {
  html:not(.js) .site-nav a { color: #fff; }
  html:not(.js) .site-nav a:hover { color: var(--brand-sand); }
  html:not(.js) .site-nav a[aria-current="page"] { color: var(--brand-sand); border-bottom-color: var(--brand-sand); }
}

/* 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 rgba(214, 238, 244, .35); border-radius: 999px;
    background: rgba(214, 238, 244, .12); cursor: pointer;
  }
  .nav-toggle-bars { display: flex; flex-direction: column; gap: 4px; }
  .nav-toggle-bars span { display: block; width: 16px; height: 1.5px; background: #fff; 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; }
  /* The panel comes down from the bar that opened it and goes back up into
     it, a little quicker on the way out. The bars already turned into a
     cross on a transition; the panel they opened simply appeared. `display`
     joins the transition so the way out has time to be seen — a browser
     that cannot do that opens and closes it at once, as before. */
  html.js .site-nav {
    opacity: 0; transform: translateY(-8px); transform-origin: top;
    transition: opacity .15s cubic-bezier(.23, 1, .32, 1), transform .15s cubic-bezier(.23, 1, .32, 1), display .15s allow-discrete;
  }
  html.js body.nav-open .site-nav {
    opacity: 1; transform: none;
    transition: opacity .2s cubic-bezier(.23, 1, .32, 1), transform .2s cubic-bezier(.23, 1, .32, 1), display .2s allow-discrete;
  }
  @starting-style {
    html.js body.nav-open .site-nav { opacity: 0; transform: translateY(-8px); }
  }
  @media (prefers-reduced-motion: reduce) {
    html.js .site-nav, html.js body.nav-open .site-nav { transform: none; transition: opacity .15s ease, display .15s allow-discrete; }
    @starting-style { html.js body.nav-open .site-nav { transform: none; } }
  }
  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); }

  /* Below this width the bar holds the logo, the language switch and the
     toggle, and that is already 57px more than a 375px screen has. The CTA
     therefore moves into the panel rather than being dropped: without this
     the toggle itself was pushed off the right edge and the menu could not
     be opened on a phone at all. */
  .header-right .pill-small { display: none; }
  html.js .site-nav .nav-cta {
    display: inline-flex; justify-content: center;
    margin-top: 10px; border-bottom: none;
    font-size: 10px; padding: 13px 18px;
  }
  html.js .site-nav .nav-cta[aria-current="page"] { color: #fff; }
  /* with JS off the nav is an inline row, where a pill would look adrift */
  html:not(.js) .site-nav .nav-cta { display: none; }
}
@media (min-width: 1024px) {
  .nav-cta { display: none; }
  /* 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 ───────────────────────────────────────────────── */
/* Two chapters meet with this much above and this much below, so the gap
   a reader crosses is twice it. At 11vh that was two hundred pixels of
   nothing between one subject and the next on a laptop; this is a pause. */
.chapter { padding: clamp(52px, 7.5vh, 88px) 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; }
/* A head with no numeral has nothing to share its line with. */
.chapter-head:not(:has(.chapter-num)) { grid-template-columns: minmax(0, 1fr); }
.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 — long-form body copy ─────────────────────────
   Every page whose text is written rather than laid out: an article, a
   campaign landing page, the privacy and terms pages.

   This block exists because the base styles are built for the page frame,
   not for a column of text, and a body written in the dashboard's rich
   editor lands in that gap. The editor emits h2, h3, p, ul, ol, blockquote,
   strong, em and a — and of those, only `p` had a rule here. The rest fell
   through to the base, where `h2` is a 4.4rem chapter heading with a 24ch
   measure, a list has its padding reset to zero so the markers hang outside
   the column, and `a { color: inherit; text-decoration: none }` makes a link
   in a paragraph indistinguishable from the words around it. The result read
   as the right words in the wrong shapes.

   So the scale is set here from the top of the page down: the title is up to
   4.4rem, which leaves a subheading inside the text somewhere near 2rem and
   the one below it near 1.3rem. The hairline above each h2, the arrow marker
   on a bullet and the mono numeral on an ordered item are the same devices
   §4 already uses for .num-list, .service-list and .faq-list, so a written
   page belongs to the same site as a built one.

   Everything is a logical property, so the whole column mirrors in the
   Arabic and Urdu trees without a second rule. */
.prose { max-width: 66ch; color: var(--ink-200); }
/* The frame sets the space above and below the column. Without these, the
   first heading's margin pushes the text away from the picture it follows. */
.prose > :first-child { margin-block-start: 0; }
.prose > :last-child { margin-block-end: 0; }

.prose p { color: var(--ink-200); margin-bottom: 1.4em; font-size: 1.08rem; }

.prose h2 {
  font-size: clamp(1.4rem, 2.4vw, 1.95rem);
  line-height: 1.18; letter-spacing: -.015em; max-width: 40ch;
  margin-block: 2.2em .55em;
  padding-block-start: .85em;
  border-block-start: 1px solid var(--line);
}
/* The rule is there to separate a section from the one before it. Above the
   first heading there is nothing to separate it from. */
.prose > h2:first-child { padding-block-start: 0; border-block-start: 0; }
.prose h3 {
  font-size: clamp(1.08rem, 1.5vw, 1.3rem);
  line-height: 1.32; max-width: 46ch;
  margin-block: 1.9em .45em;
}
/* A heading pair reads as one unit: the second should sit under the first,
   not a section away from it. */
.prose h2 + h3 { margin-block-start: 1.1em; }
.prose h4 {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-300); font-weight: 500;
  margin-block: 1.8em .5em;
}

/* A link has to be visible as one. The base rule inherits the ink and drops
   the underline, which is right for a nav bar and wrong inside a sentence. */
.prose a {
  color: var(--brand-teal);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--brand-teal) 40%, transparent);
  text-underline-offset: 3px;
  transition: color .3s, text-decoration-color .3s;
}
.prose a:hover { color: var(--brand-forest); text-decoration-color: currentColor; }
.prose a:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; border-radius: 2px; }

.prose strong, .prose b { color: var(--cream-100); font-weight: 600; }
.prose em, .prose i { font-style: italic; }

/* Lists. The marker is drawn rather than left to the browser, because the
   base reset takes the padding off every list on the site — so a default
   bullet or numeral hangs outside the column and clips at the gutter. */
.prose ul, .prose ol { list-style: none; margin-block: 0 1.4em; padding: 0; }
.prose li { position: relative; padding-inline-start: 28px; margin-block-end: .62em; font-size: 1.04rem; }
.prose li:last-child { margin-block-end: 0; }
.prose li > ul, .prose li > ol { margin-block: .62em 0; }

/* Drawn, not typed. The marker was a ➤ character, which Rubik does not
   carry: on macOS the fallback chain reaches a font that does and it looks
   right, and on Windows it ends at Arial, which does not, so every bullet on
   the page rendered as a dotted box with the codepoint printed inside it. A
   triangle made of borders has no font to be missing from.

   The logical border sides are what mirror it: inset-inline-start is the left
   border in English and the right border in Arabic, so the triangle points
   the way the language reads without a second rule. */
.prose ul > li::before {
  content: "";
  position: absolute; inset-inline-start: 5px; top: .66em;
  inline-size: 0; block-size: 0;
  border-block: 4px solid transparent;
  border-inline-start: 6px solid var(--peach-400);
  border-inline-end: 0;
}

.prose ol { counter-reset: prose-ol; }
.prose ol > li { counter-increment: prose-ol; padding-inline-start: 34px; }
.prose ol > li::before {
  content: counter(prose-ol, decimal-leading-zero);
  position: absolute; inset-inline-start: 0; top: .15em;
  font-family: var(--font-mono); font-size: .78em; font-weight: 500;
  letter-spacing: .06em; color: var(--peach-300);
}

.prose blockquote {
  margin-block: 1.9em; padding-inline-start: 22px;
  border-inline-start: 2px solid var(--peach-400);
  font-size: clamp(1.1rem, 1.5vw, 1.24rem); line-height: 1.5;
  color: var(--ink-100);
}
.prose blockquote p { font-size: inherit; color: inherit; }
.prose blockquote > :last-child { margin-block-end: 0; }

.prose hr { border: 0; block-size: 1px; background: var(--line); margin-block: 2.4em; }

/* A picture the writer put inside the text, rather than the cover above it. */
.prose figure { margin-block: 0 1.6em; }
.prose img { border-radius: 2px; margin-block-end: 1.4em; }
.prose figure img { margin-block-end: 0; }
.prose figcaption {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-300); margin-block-start: 10px;
}

/* Not reachable from the editor's toolbar, but reachable by pasting — and an
   unstyled table in a column of text is the worst-looking thing on a page. */
.prose table { width: 100%; border-collapse: collapse; margin-block: 0 1.6em; font-size: .98rem; }
.prose th, .prose td { text-align: start; padding: 12px 10px; border-block-end: 1px solid var(--line); vertical-align: top; }
.prose th {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-300); font-weight: 500;
  border-block-end-color: var(--line-strong);
}
.prose td { color: var(--ink-200); }

.prose code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9em; background: var(--surface-2); border-radius: 4px; padding: .12em .38em;
}
.prose pre { background: var(--surface-2); border-radius: 8px; padding: 16px 18px; margin-block: 0 1.5em; overflow-x: auto; }
.prose pre code { background: none; padding: 0; }

@media (prefers-reduced-motion: reduce) {
  .prose a { transition: none; }
}
.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 — five of links and a wider one for the
   office.

   The office column is sized here rather than by spanning two of six tracks.
   Spanning was the bug: five link columns take five tracks and a span of two
   asks for a seventh, so on a six-track grid the office wrapped onto a row of
   its own and left the sixth track standing empty beside the links. The
   footer read as a block of columns with a hole punched in the corner and the
   address exiled underneath it.

   1.6fr because that column carries the longest single line in the footer —
   the office address, 216px — against 142px for the longest link beside it.
   The ratio holds that margin at every width this template applies to, and
   below it §6 replaces the whole template anyway. */
.footer-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr)) 1.6fr;
  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; }

/* ── Office block and social row ──────────────────────────────
   The contact details come from the dashboard now, and every one of them is
   a link: an address opens a map, a number dials or opens WhatsApp, an email
   opens a composer. The icon in front of each says which without a label
   having to, which is what keeps four rows from reading as a list of
   look-alike strings.

   Logical properties, so the block mirrors on the Arabic and Urdu trees. */
/* The ink is the ground's, not the footer's. This block is spliced over any
   <address> on the page, and the contact page has one of its own in the middle
   of the light page body — where ice on cream came out at 1.2:1. Light grounds
   inherit, which leaves a line of text as body ink and a line that links as a
   link; the deep grounds below restate the ice they always had. */
.footer-contact-line {
  display: inline-flex; align-items: center; gap: 9px;
}
:where(.is-deep, .site-footer) .footer-contact-line { color: var(--brand-ice); }
.footer-contact-line .icon { flex: 0 0 auto; opacity: .75; transition: opacity .3s; }
a.footer-contact-line:hover .icon { opacity: 1; }

/* The icons are the row's alignment: without this the second line of a
   wrapped address tucks under its own pin. */
.footer-contact-line > span { flex: 1 1 auto; }

/* The office column's extra width comes from the track it sits in, declared
   with the rest of the grid above. It is the only column carrying an address,
   three contact rows, a row of marks and a caption under them, so it is the
   one that needs the room; the nav columns beside it hold four short links
   each and lose nothing by giving it up.

   Nothing here spans, so the six columns stay on one row and the narrower
   templates in §6 can reflow them without a span left over to fight. */

/* `.footer-col ul` sets flex-direction: column for the footer's link lists,
   and it outranks a single class — so the marks stacked one per line even
   once there was room for them. Named through the column to win, and the
   direction is stated rather than left to the cascade. */
/* The row reset is the list's own, not the column's: off the footer there is
   no .footer-col to carry it, and the marks came back up as a bulleted list on
   the contact page. The column still has to be named once, to outrank
   `.footer-col ul` on the direction. */
.footer-social {
  list-style: none;
  display: flex; flex-direction: row; flex-wrap: wrap;
  gap: 10px;
  margin-block-start: 16px;
}
.footer-col .footer-social { flex-direction: row; }
.footer-social-note {
  margin-block-start: 10px;
  color: var(--ink-300);
}
.footer-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: 1px solid var(--line-strong); border-radius: 999px;
  color: var(--ink-300);
  transition: background .3s, border-color .3s, color .3s;
}
.footer-social a:hover {
  background: color-mix(in srgb, var(--brand-teal) 10%, transparent);
  border-color: var(--brand-teal);
  color: var(--brand-teal);
  /* the footer's underline-on-hover is for text links, not for a round icon */
  text-decoration: none;
}

/* On the deep grounds the marks and their caption keep the ice they were
   drawn in; the light ground above is what the contact page needed. */
:where(.is-deep, .site-footer) .footer-social-note { color: var(--brand-ice-2); }
:where(.is-deep, .site-footer) .footer-social a {
  border-color: rgba(214, 238, 244, .28);
  color: var(--brand-ice);
}
:where(.is-deep, .site-footer) .footer-social a:hover {
  background: rgba(214, 238, 244, .14);
  border-color: rgba(214, 238, 244, .55);
  color: #fff;
}
.footer-social a:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
:where(.is-deep, .site-footer) .footer-social a:focus-visible { outline-color: var(--brand-ice); }

/* An uploaded mark is somebody's file rather than one of ours: contained
   rather than stretched, so a square logo and a wide one both sit in the
   same round button without distorting. */
.icon-custom { width: 16px; height: 16px; object-fit: contain; }

.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: var(--shadow-card);
}
.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;
}
/* Drawn rather than set in type — see the note on .prose ul > li::before.
   The ➤ this used to print is absent from Rubik and from the Windows end of
   the fallback chain, so these markers were boxes on roughly half the
   machines that loaded the page. The logical borders mirror it for Arabic and
   Urdu, which is what the transform used to do. */
.service-list li::before {
  content: "";
  position: absolute; inset-inline-start: 5px; top: 1.08em;
  inline-size: 0; block-size: 0;
  border-block: 4px solid transparent;
  border-inline-start: 6px solid var(--peach-400);
  border-inline-end: 0;
}

/* ── Two services (home §02) ───────────────────────────────────
   Dhara Tax leads on the green band: its words beside the light mark,
   two columns on desktop. Dhara ACCT follows as one quiet strip on the
   section ground, dimmed a step, so it is present without taking the
   same weight. No pinning, no curtain.

   The band carries .is-deep, whose token block (§11.2) re-skins the type
   inside it; only its gradient is overridden so the ground is one flat
   green. Both marks are transparent PNGs, so the ground is the CSS.

   Sides come from the grid, not from left/right, so English reads
   text-left / mark-right and Arabic mirrors itself with no override. */
.svc-chapter {
  --svc-bg: #fffcf6;
  --svc-deep: #1a5f47;
  background-color: var(--svc-bg);
  border-block: none;
}

/* the lead band */
.svc-lead {
  position: relative; overflow: hidden;
  /* a soft light in the top-start corner and a lit top edge: enough depth
     for the band to read as a surface, not enough to read as an effect */
  background:
    radial-gradient(90% 80% at 0% 0%, rgba(214, 238, 244, .14) 0%, transparent 60%),
    var(--svc-deep);
  box-shadow: 0 1px 0 rgba(255,255,255,.10) inset, 0 24px 48px -32px rgba(15, 39, 24, .55);
  border-radius: 18px;
  padding: clamp(26px, 4vw, 52px);
  display: grid; gap: clamp(22px, 3vh, 34px);
  align-items: center;
}
[dir="rtl"] .svc-lead { background: radial-gradient(90% 80% at 100% 0%, rgba(214, 238, 244, .14) 0%, transparent 60%), var(--svc-deep); }
.svc-lead .svc-copy > .serif { max-width: 56ch; }
/* Stacked, the mark is an ornament above the heading rather than a figure
   beside it, so it is the size of one: at two hundred pixels it was the
   first screen of the band, and what the band is about came after it. */
.svc-lead .svc-shot { margin: 0; order: -1; height: 76px; }
.svc-lead img { display: block; width: 100%; height: 100%; object-fit: contain; object-position: left center; }
[dir="rtl"] .svc-lead img { object-position: right center; }
@media (min-width: 900px) {
  .svc-lead {
    grid-template-columns: minmax(0, 1fr) minmax(0, 30%);
    column-gap: clamp(36px, 5vw, 90px);
  }
  .svc-lead .svc-shot { order: 0; height: clamp(220px, 30vh, 300px); }
  .svc-lead img { object-position: center; }
}

.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; }
/* What the connection covers, as a list rather than a run-on sentence: six
   things in two columns, each behind a small sand tick. */
.svc-points {
  list-style: none; margin: clamp(18px, 2.6vh, 26px) 0 6px; padding: 0;
  display: grid; gap: 12px clamp(20px, 3vw, 40px);
  max-width: 68ch;
}
.svc-points li {
  position: relative; padding-inline-start: 26px;
  font-family: var(--font-serif); font-size: 1rem; line-height: 1.45; color: var(--ink-200);
}
.svc-points li::before {
  content: ""; position: absolute; inset-inline-start: 2px; top: .38em;
  width: 11px; height: 6px;
  border-inline-start: 2px solid var(--brand-sand); border-block-end: 2px solid var(--brand-sand);
  transform: rotate(-45deg);
}
[dir="rtl"] .svc-points li::before { transform: rotate(45deg); }
@media (min-width: 720px) { .svc-points { grid-template-columns: 1fr 1fr; } }
.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;
}
.svc-lead .svc-rn { -webkit-text-stroke-color: var(--brand-sand); }

/* the companion strip: a hairline box on the section ground, a step
   quieter than the band — smaller type, a small teal mark, muted ink */
.svc-aside {
  margin-top: clamp(22px, 3vh, 32px);
  border: 1px solid var(--line);
  background: color-mix(in srgb, #fff 55%, transparent);
  box-shadow: var(--shadow-card);
  border-radius: 18px;
  padding: clamp(20px, 2.8vw, 36px);
  display: grid; gap: clamp(16px, 2vw, 26px);
  align-items: center;
}
.svc-aside-mark { margin: 0; width: clamp(48px, 5.5vw, 68px); opacity: .8; }
.svc-aside-mark img { display: block; width: 100%; height: auto; }
.svc-aside .svc-rn { font-size: 1.7rem; -webkit-text-stroke-color: var(--line-strong); margin-bottom: 6px; }
.svc-aside .svc-copy h3 { font-size: clamp(1.15rem, 1.6vw, 1.4rem); color: var(--ink-200); }
.svc-aside .svc-copy > .serif { max-width: 64ch; margin: 10px 0 4px; color: var(--ink-300); font-size: .97rem; }
.svc-aside .chapter-cta { margin-top: clamp(14px, 2vh, 20px); }
@media (min-width: 900px) {
  .svc-aside { grid-template-columns: auto minmax(0, 1fr); column-gap: clamp(24px, 3.5vw, 48px); }
}

/* 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: 10px; margin-top: 18px; }
.chips li {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  color: var(--brand-teal); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); border-radius: 999px; padding: 9px 16px;
  background: color-mix(in srgb, #fff 78%, transparent);
  box-shadow: 0 1px 0 rgba(255,255,255,.7) inset;
  transition: border-color .3s, background .3s, color .3s;
}
/* A chip that names a system is the way to that system's page. The link
   takes the chip's whole box, so the target is the pill and not the word. */
.chips li:has(> a) { padding: 0; }
.chips li > a { display: block; padding: 9px 16px; border-radius: inherit; color: inherit; }
.chips li > a:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
.chips li:hover { background: #fff; border-color: var(--accent); color: var(--brand-forest); }

/* ── FAQ / accordion (native details) ───────────────────────── */
.faq-list { max-width: 78ch; border-top: 1px solid var(--line); }
.faq-list details { border-bottom: 1px solid var(--line); transition: background .3s; }
.faq-list summary {
  cursor: pointer; list-style: none;
  display: grid; grid-template-columns: 1fr 28px; gap: 16px; align-items: center;
  padding: 20px 8px;
  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; }
/* the indicator: a small ringed plus that turns into a minus when open */
.faq-list summary::after {
  content: "+";
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 999px;
  border: 1px solid var(--line-strong);
  font-family: var(--font-display); font-weight: 400; font-size: 1.25rem; line-height: 1;
  color: var(--peach-300);
  transition: transform .3s cubic-bezier(.16,1,.3,1), background .3s, border-color .3s, color .3s;
}
.faq-list details[open] summary::after { transform: rotate(45deg); background: var(--brand-teal); border-color: var(--brand-teal); color: #fff; }
.faq-list summary:hover { color: var(--peach-300); }
.faq-list summary:hover::after { border-color: var(--peach-300); }
.faq-list summary:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: -2px; border-radius: 10px; }
.faq-list details[open] { background: color-mix(in srgb, var(--brand-ice) 30%, transparent); border-radius: 12px; border-bottom-color: transparent; }
.faq-list details[open] summary { color: var(--brand-teal); }
.faq-list details p { padding: 0 8px 22px; color: var(--ink-200); max-width: 70ch; line-height: 1.6; }
.faq-list details p + p { margin-top: -8px; }
.faq-list details a { color: var(--brand-teal); text-decoration: underline; text-underline-offset: 3px; }
.faq-list details a:hover { color: var(--brand-green); }
/* The page numbers under a long list (main.js §5a). The page being read is
   filled; the rest are quiet until pointed at. */
.faq-pages { display: flex; flex-wrap: wrap; gap: 6px; margin-top: clamp(18px, 3vh, 26px); }
.faq-pages button {
  min-width: 40px; height: 40px; padding: 0 12px;
  font-family: var(--font-display); font-size: .9rem; font-weight: 500; font-variant-numeric: tabular-nums;
  color: var(--ink-200); background: transparent;
  border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
  transition: border-color .2s ease, background-color .2s ease, color .2s ease;
}
.faq-pages button[aria-current="page"] { background: var(--brand-green); border-color: var(--brand-green); color: #fff; cursor: default; }
.faq-pages button:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .faq-pages button:not([aria-current]):hover { border-color: var(--brand-green); color: var(--brand-forest); background: color-mix(in srgb, var(--brand-green) 6%, transparent); }
}
@media (max-width: 767px) { .faq-pages button { min-width: 44px; height: 44px; } }
.faq-list details[open] + details { border-top: 1px solid var(--line); }
/* An answer opens rather than appearing: the plus already turned, and the
   text it stood for snapped in beside it. Height is the one layout property
   worth animating, because an accordion has no transform that does the job.
   A browser that cannot interpolate to `auto` keeps the fade and snaps the
   height; one that does not know ::details-content drops the rule and
   behaves as before. */
.faq-list { interpolate-size: allow-keywords; }
.faq-list details::details-content {
  height: 0; opacity: 0; overflow: clip;
  transition: height .22s cubic-bezier(.23, 1, .32, 1), opacity .22s ease, content-visibility .22s allow-discrete;
}
.faq-list details[open]::details-content { height: auto; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .faq-list summary::after { transition: none; }
  .faq-list details::details-content { transition: opacity .2s ease, content-visibility .2s allow-discrete; }
}

/* ── 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; }

/* Phone is captured as dialling code + national number so it can be stored as
   E.164, but it has to read as one field: one label above, two controls sharing
   the row and the underline treatment they already inherit from `.field`.
   Grid rather than flex so the code column is sized by its content and the
   number takes the rest. Logical flow, so RTL mirrors it without a rule of its
   own — the controls themselves keep dir="ltr" for the digits.

   The code column is CAPPED rather than sized to its content: left to
   max-content it takes the width of the longest country name in the list
   ("+44 المملكة المتحدة" — 168px), which at 375px leaves barely 100px for the
   number, the field that actually matters. The cap truncates the closed
   control on the few long names; the open dropdown is drawn by the browser at
   its own width, so the full name is always readable where it is being read. */
.field-phone { display: grid; grid-template-columns: minmax(5.5rem, 8rem) 1fr; gap: 12px; align-items: end; }
.field-phone select { text-overflow: ellipsis; }

/* The conditional "Which system?" field. Authored visible and hidden by
   main.js §15, so with JS off it degrades to an always-visible optional
   field rather than one nobody can reach. `.field` sets display:flex, which
   beats the UA [hidden] rule — hence this. */
.field[hidden] { display: none; }
.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-error { color: var(--status-negative); }
.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); }
/* The one moment a lead form exists to reach, seen once. The form's fields
   are swapped for this in a single frame, so it arrives rather than being
   there: up a little and in, with its tick a beat behind. It enters from
   `hidden`, which is what @starting-style is for — no script knows about it,
   and a browser without it shows the message at once, as every browser did. */
.form-success { transition: opacity .26s cubic-bezier(.23, 1, .32, 1), transform .26s cubic-bezier(.23, 1, .32, 1); }
.form-success::before { transition: opacity .2s ease .08s, transform .2s cubic-bezier(.23, 1, .32, 1) .08s; }
@starting-style {
  .form-success { opacity: 0; transform: translateY(8px) scale(.98); }
  .form-success::before { opacity: 0; transform: scale(.9); }
}
@media (prefers-reduced-motion: reduce) {
  .form-success { transition: opacity .2s ease; }
  .form-success::before { transition: opacity .2s ease; }
  @starting-style {
    .form-success { transform: none; }
    .form-success::before { transform: none; }
  }
}
.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; } }

/* ── Brand splash — the logo preloader ────────────────────────
   The dark lockup on its forest ground, exactly as the brand guideline
   draws it: ice #d6eef4 wordmark, #a4cfd5 on the origami mark's middle
   facet, over --brand-forest.

   HIDDEN BY DEFAULT ON PURPOSE. Only `html.splash-on` reveals it, and that
   class is set by the inline script at the top of the header partial. With
   scripting off there is no class, so the splash never paints and can never
   strand the page behind an overlay that nothing will remove. It is also why
   the script must sit ABOVE the markup in the partial — by the time the
   browser parses .splash the decision has already been made, so the page
   never flashes into view first.

   The timeline below and the `4600` in that script are one number in two
   places. Change both together.

     0.15 – 1.05s   ذرى rises in
     0.45 – 1.35s   DHARA rises in
     0.80 – 1.85s   the origami mark flies in from the upper end and settles
     1.60 – 3.50s   the rule draws out from the centre
     1.90 – 3.30s   a light sweeps the panel
     3.90 – 4.50s   the whole thing lifts and fades
     4.60s          the script removes the node and unlocks the scroll        */
.splash { display: none; }

/* `scrollbar-gutter` is not decoration here. Locking the scroll takes the
   classic scrollbar away, and the page behind would shift by its width and
   shift back the instant the splash lifts — a visible jolt on exactly the
   frame the visitor first sees the site. Keeping the gutter reserved while
   locked holds the layout still. */
html.splash-on, html.splash-on body { overflow: hidden; scrollbar-gutter: stable; }

html.splash-on .splash {
  display: grid;
  place-items: center;
  position: fixed;
  inset: 0;
  z-index: 900;
  background: var(--brand-forest);
  animation: splash-out .6s cubic-bezier(.5, 0, .75, 0) 3.9s forwards;
}

.splash-stage {
  position: relative;
  width: clamp(240px, 76vw, 560px);
  animation: splash-lift .6s cubic-bezier(.5, 0, .75, 0) 3.9s forwards;
}

/* overflow must stay visible: the mark starts outside the viewBox, and an
   SVG root clips to its viewport by default */
.splash-logo { display: block; width: 100%; height: auto; overflow: visible; }

/* Percentage transform origins on an SVG child resolve against the whole
   SVG viewport unless the box is switched to the shape's own bounds, which
   is what makes the mark scale about itself rather than about the lockup. */
.splash-ar, .splash-word, .splash-mark { transform-box: fill-box; transform-origin: center; }

.splash-ar   { animation: splash-rise .9s cubic-bezier(.16, 1, .3, 1) .15s both; }
.splash-word { animation: splash-rise .9s cubic-bezier(.16, 1, .3, 1) .45s both; }
.splash-mark { animation: splash-fly 1.05s cubic-bezier(.22, 1, .28, 1) .8s both; }

@keyframes splash-rise {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}

/* The mark is an arrow, so it arrives travelling — in from the inline end,
   slightly past its seat, then back. Translations are in user units, so they
   scale with the lockup instead of drifting at small widths. */
@keyframes splash-fly {
  from { opacity: 0; transform: translate(72px, -54px) scale(.86); }
  70%  { opacity: 1; transform: translate(-7px, 5px) scale(1.02); }
  to   { opacity: 1; transform: none; }
}

.splash-rule {
  display: block;
  height: 2px;
  margin-block-start: clamp(18px, 3.4vw, 30px);
  background: linear-gradient(90deg, transparent, var(--brand-ice), transparent);
  transform: scaleX(0);
  animation: splash-draw 1.9s cubic-bezier(.65, 0, .35, 1) 1.6s forwards;
}

@keyframes splash-draw { to { transform: scaleX(1); } }

/* A light crossing the panel. It travels from the inline start, so the two
   custom properties — and only those — are what RTL has to flip. */
.splash-stage::after {
  --sweep-from: -70%;
  --sweep-to: 170%;
  --sweep-skew: -18deg;
  content: "";
  position: absolute;
  inset: -18% -40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(214, 238, 244, .14), transparent);
  transform: translateX(var(--sweep-from)) skewX(var(--sweep-skew));
  animation: splash-sweep 1.4s cubic-bezier(.4, 0, .3, 1) 1.9s both;
}

[dir="rtl"] .splash-stage::after { --sweep-from: 170%; --sweep-to: -70%; --sweep-skew: 18deg; }

@keyframes splash-sweep {
  from { transform: translateX(var(--sweep-from)) skewX(var(--sweep-skew)); }
  to   { transform: translateX(var(--sweep-to)) skewX(var(--sweep-skew)); }
}

@keyframes splash-out  { to { opacity: 0; visibility: hidden; } }
@keyframes splash-lift { to { transform: translateY(-16px); } }

/* Reduced motion keeps the splash — it is the brand mark, not decoration —
   but holds it still and hands the page over in about a second. The inline
   script shortens its own timeout to match. */
@media (prefers-reduced-motion: reduce) {
  .splash-ar, .splash-word, .splash-mark, .splash-stage::after, .splash-stage {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .splash-stage::after { display: none; }
  .splash-rule { animation: none; transform: scaleX(1); }
  html.splash-on .splash { animation: splash-out .35s linear .65s forwards; }
}

/* ── Neon flow header effect — luminous tubes behind the header bar ──
   The element is built by js/neon-flow.js, so no page carries markup for
   it. It lives INSIDE .site-header (made position: relative for exactly
   this), and the negative z-index does the layering: within .site-chrome's
   stacking context a negative-z child paints above the chrome's own
   ground — including the 97% wash the header gains on scroll — but below
   every in-flow descendant, so the logo, nav links and pills always sit on
   top of the tubes with no per-item z-index.

   pointer-events: none matters twice over: the layer must never eat a nav
   click, and the library reads the pointer from document.body against the
   canvas rect, so it needs no events of its own to follow the cursor.

   This opacity is the effect's master volume — turn it down to quieten the
   whole thing. Colours belong to js/neon-flow.js, not here.

   Reduced motion is handled in the script: this effect is pure motion, so
   unlike the old kinetic grid it skips entirely rather than freezing. */
.neon-flow {
  position: absolute; inset: 0; z-index: -1;
  overflow: hidden;
  pointer-events: none;
  opacity: 1;
}
.neon-flow canvas { width: 100%; height: 100%; display: block; }

@media print { .neon-flow { display: none; } }


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

/* ── Home hero (video/media hero) ─────────────────────────────
   The photography is 16:9, and `object-fit: cover` never distorts — it
   keeps the frame's height and cuts the SIDES. So the crop is decided
   entirely by how tall the hero box is relative to its width.

   The previous rule capped the height at the photo's own ratio but put a
   620px FLOOR under it, and that floor is what did the damage: below
   ~1102px wide the floor beat the ratio cap and the sides went, measured
   at 10.6% on a 1000px window. Worse, the cap only applied from 900px up,
   so a portrait tablet took 100dvh and hid 58.8% of the picture — you saw
   the middle 41% of every hero.

   Fixed by bounding the crop geometrically instead of pinning a pixel
   height. With a 16:9 source, the hidden fraction is
       1 − width / (height × 16/9)
   so height ≤ 62.5vw keeps at most 10% hidden, and height ≥ 56.25vw keeps
   the frame full-bleed (no letterbox bands). clamp() holds the box between
   those two, preferring 480px when it falls inside the range — that is the
   old floor's intent (comfortable copy on short windows) expressed as a
   preference that can never override the crop bound. `min(100dvh, …)` then
   stops a tall window making the hero taller than the screen.

   The height is NOT capped at 100dvh (changed on request 2026-08-07). That
   cap was the last remaining source of cropping: on a window shorter than
   16:9 it squeezed the frame vertically and `cover` took the top and bottom
   instead of the sides — 17% in a 904x421 window. Letting the box keep the
   photograph's ratio removes that crop entirely, and the cost is simply that
   on a short window the picture now runs past the fold, which a hero may do.

   That cost has one sharp edge, handled on .hero-content below: the hero copy
   is bottom-aligned, so a box taller than the screen would push the headline
   and the CTAs out of view on load. The COPY is therefore bounded by the
   viewport even though the PICTURE is not.

   Phones keep 100dvh: portrait always crops, and a 62.5vw hero on a 375px
   screen would be 234px of letterbox-thin photograph. That trade is
   deliberate and unchanged.

   Superseded above 600px by §8.2c: the hero there is as tall as its copy,
   and the picture gives up the bare paper at its top. */
:root { --hero-h: 100dvh; }
@media (min-width: 600px) {
  :root { --hero-h: clamp(56.25vw, 480px, 62.5vw); }
}
.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;
}
/* `min()`, not `var(--hero-h)` alone: the picture is allowed to be taller
   than the screen (see above), but this block is bottom-aligned, so matching
   it to the full picture height would drop the headline and the CTAs below
   the fold. Bounding it at the viewport keeps the message on screen while
   the photograph continues underneath. On every window where the hero is
   shorter than the screen — the common case — min() returns --hero-h and the
   old behaviour is unchanged. */
.hero-content {
  position: relative; z-index: 2; min-height: min(100dvh, var(--hero-h));
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 6vw 16vh;
}
/* Header clearance for the hero copy on phones and tablets.
   The block is bottom-aligned inside a box that is only min-height, so on a
   short screen the copy is TALLER than the box and grows upward out of it —
   the first line (the HERO-01 eyebrow) then lands behind the fixed chrome.
   Measured at 360×640: eyebrow at y=22 under a 76px bar, i.e. invisible.
   Reserving the bar's height as padding-top makes the overflow grow
   downward instead — the copy keeps its distance from the bottom, and what
   moves is the hero's own lower edge (375×812: hero 812 → 824, the CTAs and
   the trust line still 250px inside the fold). Scoped below 1024px because that is where
   --chrome-h describes the whole chrome; at desktop widths the copy is
   bounded by min(100dvh, --hero-h) and has never overflowed. */
@media (max-width: 1023px) {
  .hero-content { padding-top: calc(var(--chrome-h) + 20px); }
}
.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 ── */
/* One sheet ruled down the middle, not two cards side by side: the point of
   the section is that these are the same five questions answered twice, so
   the rows line up across the rule (subgrid) and the answer reads straight
   across. A cross or a tick marks each row; the headings carry the meaning,
   so nothing rides on the colour alone. */
.comparator {
  display: grid;
  border: 1px solid var(--paper-border);
  border-radius: 22px;
  background: var(--surface-1);
  box-shadow: var(--paper-shadow);
  overflow: hidden;
}
@media (min-width: 760px) { .comparator { grid-template-columns: 1fr 1fr; } }
/* six rows each: the heading and five list items */
.comparator-col {
  display: grid; grid-template-rows: subgrid; grid-row: span 6;
  padding: clamp(20px, 2.6vw, 30px) clamp(20px, 2.8vw, 34px);
}
.comparator-col + .comparator-col { border-block-start: 1px solid var(--line-strong); }
@media (min-width: 760px) {
  .comparator-col + .comparator-col { border-block-start: 0; border-inline-start: 1px solid var(--line-strong); }
}
.comparator-col h3 { font-size: 1.12rem; padding-block-end: 14px; border-bottom: 1px solid var(--line-strong); }
.comparator-col .service-list {
  display: grid; grid-template-rows: subgrid; grid-row: span 5;
  margin-top: 0; max-width: none;
}
.comparator-col .service-list li { padding-block: 13px; padding-inline-start: 30px; }
.comparator-col .service-list li:last-child { border-bottom: 0; padding-block-end: 0; }
/* the cross */
.comparator-col .service-list li::before {
  inset-inline-start: 2px; top: 1.2em;
  inline-size: 12px; block-size: 12px; border: 0;
  background:
    linear-gradient(var(--status-negative), var(--status-negative)) center / 100% 2px no-repeat,
    linear-gradient(var(--status-negative), var(--status-negative)) center / 2px 100% no-repeat;
  rotate: 45deg;
}
.comparator-col.is-einvoice { background: color-mix(in srgb, var(--brand-ice) 38%, transparent); }
.comparator-col.is-einvoice h3 { color: var(--ink-300); }
.comparator-col.is-einvoice .service-list li { color: var(--ink-100); }
/* the tick */
.comparator-col.is-einvoice .service-list li::before {
  inset-inline-start: 4px; top: 1.05em;
  inline-size: 6px; block-size: 11px;
  background: none;
  border: solid var(--status-positive); border-width: 0 2px 2px 0;
}
.is-deep .comparator { background: rgba(255,255,255,.07); border-color: rgba(214,238,244,.26); box-shadow: none; }
.is-deep .comparator-col { background: none; border-color: rgba(214,238,244,.26); }
/* the caveat under the sheet is a ruled footnote the sheet's own width, not
   a second, narrower box competing with it */
.comparator + .note-box {
  max-width: none;
  border: 0; border-block: 1px solid var(--line);
  border-radius: 0; background: none;
  padding: 14px clamp(20px, 2.8vw, 34px);
}

/* ── Peppol network — the invoice's route ────────────────────
   Four steps in order, plus the Tax Authority, which is NOT a fifth step:
   it reads the invoice where the provider puts it on the network, so it
   hangs off the link between steps 2 and 3.

   That relationship is the whole point of the section, so it is drawn
   rather than described. The Authority spans grid columns 2–3 and is
   centred in that span, which puts its centre exactly on the 2|3 boundary —
   the same place the arrow between those two steps sits — and a dashed
   riser joins the two. No magic numbers: move a column and the join
   follows.

   An abstract circles-and-lines sketch used to sit above this. It was
   removed on request: it carried no labels, so it said nothing the cards
   below did not, and it implied a fifth node in sequence.

   All connectors are decorative and aria-hidden by construction (CSS
   pseudo-elements). The markup's reading order already carries the
   sequence, so nothing here is load-bearing for a screen reader. */
.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 {
    /* minmax(0, 1fr), not 1fr: plain `1fr` is minmax(AUTO, 1fr), so a column
       whose card has the longest title ("Your customer's provider") grows
       wider than its neighbours. Unequal columns break the geometry the
       Authority's riser depends on — the centre of the 2–3 span stops being
       the 2|3 boundary, and the riser misses the arrow by ~11px. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    column-gap: 34px;        /* the arrows live in this gap */
    row-gap: 52px;           /* and the Authority's riser in this one */
  }

  /* Since the depth conversion (2026-08-07) §12 no longer clips cards and
     gives Peppol nodes no ::after of their own, so the connectors below
     stand on their own feet. The `overflow: visible` and the explicit
     resets in each rule are kept anyway: they are what protected these
     arrows from §12-the-glare's clip and corner mark, they cost nothing,
     and they keep working if a card treatment ever grows those properties
     back. `:not(.is-depth)` likewise stays as specificity headroom over
     §12's 0,2,1 selectors. */
  .peppol-flow .peppol-node:not(.is-depth) { overflow: visible; position: relative; }

  /* Each connector defines its ::after from scratch — content, box,
     insets — and explicitly resets mask/background/z-index/opacity, so it
     renders as an arrow in the gap regardless of what any card treatment
     puts on the same pseudo-element. */
  .peppol-flow .peppol-node--step:not(:nth-of-type(4))::after,
  .peppol-flow .peppol-node--authority:not(.is-depth)::after {
    z-index: 1; opacity: 1;
    mask: none; -webkit-mask: none;
    background: none;
    inset-block-end: auto; inset-inline-start: auto;
    pointer-events: none;
  }

  /* ── the chain ──
     An arrow after every step but the last, sitting in the column gap.
     `inset-inline-end` puts it after the card in reading order, so RTL
     needs only the glyph flipped, not the position. */
  .peppol-flow .peppol-node--step:not(:nth-of-type(4))::after {
    content: "→";
    position: absolute; inset-inline-end: -25px; top: 16px;
    width: 16px; height: auto; text-align: center;
    color: var(--peach-400); font-size: 1.05rem; line-height: 1;
  }
  [dir="rtl"] .peppol-flow .peppol-node--step:not(:nth-of-type(4))::after { content: "←"; }

  /* ── the Authority, tapped off the 2 → 3 link ──
     Columns 2–3, centred: its midpoint is the 2|3 boundary. */
  .peppol-flow .peppol-node--authority {
    grid-column: 2 / 4;
    justify-self: center;
    width: min(100%, 400px);
  }
  /* the riser, drawn up through the row gap to meet that arrow.
     width 0 — the dashed border IS the line. */
  .peppol-flow .peppol-node--authority:not(.is-depth)::after {
    content: "";
    position: absolute;
    inset-inline-start: 50%;
    inset-inline-end: auto;
    bottom: 100%; top: auto;
    width: 0; height: 52px;
    border-inline-start: 2px dashed var(--brand-teal);
  }
}

/* Below the grid the flow is a plain stack, which reads as a sequence on
   its own. The Authority keeps its teal edge to show it stands apart, but
   no connector is drawn — a riser between stacked cards would suggest it
   follows step 4, which is exactly the wrong idea. */

/* ── 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 .serif { color: var(--ink-200); }
.check-item b { color: var(--cream-100); font-weight: 600; }
/* The result is one card: the score and its meter in a tinted panel on the
   inline start, the verdict for that score beside it. Without JS there is no
   score and the card is the three verdicts as a ruled key, range beside
   meaning. The card's width is set on the wrapper, in its own font size —
   the score line's larger type would make the same `ch` a different width. */
.check-result { margin-top: 28px; max-width: 76ch; }
.check-score { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 1.15rem; color: var(--ink-300); white-space: nowrap; }
.check-score output { font-size: 3.2rem; line-height: 1; letter-spacing: -.02em; color: var(--brand-teal); font-variant-numeric: tabular-nums; margin-inline-end: 3px; }
.score-bands {
  display: grid;
  border: 1px solid var(--paper-border); border-radius: 22px;
  background: var(--surface-1); box-shadow: var(--paper-shadow);
  overflow: hidden;
}
.score-band {
  display: grid; grid-template-columns: 5.5ch minmax(0, 1fr); column-gap: 18px;
  padding: 18px 22px;
}
.score-band + .score-band { border-top: 1px solid var(--line); }
.score-band .band-range { grid-row: span 2; margin: 0; padding-block-start: .5em; font-variant-numeric: tabular-nums; }
.score-band h3 { font-size: 1.15rem; margin-bottom: 4px; }
.score-band .serif { color: var(--ink-200); }
.is-deep .score-bands, .is-deep .check-list.is-scored .check-result { background: rgba(255,255,255,.07); border-color: rgba(214,238,244,.26); box-shadow: none; }

/* with JS the checklist scores live: the wrapper becomes the card, the
   score takes its panel, and only the verdict for the current score shows */
html.js .check-list.is-scored .check-result {
  display: grid;
  border: 1px solid var(--paper-border); border-radius: 22px;
  background: var(--surface-1); box-shadow: var(--paper-shadow);
  overflow: hidden;
}
html.js .check-list.is-scored .check-score {
  align-content: center;
  padding: 22px 30px 24px;
  background: color-mix(in srgb, var(--brand-ice) 46%, var(--surface-1));
  border-block-end: 1px solid var(--line);
}
@media (min-width: 600px) {
  html.js .check-list.is-scored .check-result { grid-template-columns: auto minmax(0, 1fr); }
  html.js .check-list.is-scored .check-score { border-block-end: 0; border-inline-end: 1px solid var(--line); }
}
/* eight segments, filled to --score (js/main.js §14 writes it, 0 to 1) */
html.js .check-list.is-scored .check-score::after {
  content: "";
  display: block;
  inline-size: 156px; block-size: 6px;
  margin-block-start: 14px;
  background: linear-gradient(to right, var(--brand-teal) calc(var(--score, 0) * 100%), color-mix(in srgb, var(--brand-teal) 20%, transparent) 0);
  mask: repeating-linear-gradient(to right, #000 0 calc(12.5% - 4px), transparent 0 12.5%);
  -webkit-mask: repeating-linear-gradient(to right, #000 0 calc(12.5% - 4px), transparent 0 12.5%);
}
[dir="rtl"] .check-list.is-scored .check-score::after {
  background: linear-gradient(to left, var(--brand-teal) calc(var(--score, 0) * 100%), color-mix(in srgb, var(--brand-teal) 20%, transparent) 0);
  mask: repeating-linear-gradient(to left, #000 0 calc(12.5% - 4px), transparent 0 12.5%);
  -webkit-mask: repeating-linear-gradient(to left, #000 0 calc(12.5% - 4px), transparent 0 12.5%);
}
html.js .check-list.is-scored .score-bands {
  border: 0; border-radius: 0; background: none; box-shadow: none;
  align-content: center;
}
html.js .check-list.is-scored .score-band { display: none; border-top: 0; }
html.js .check-list.is-scored .score-band.active {
  display: block;
  padding: 24px 28px 26px;
}
/* the range the verdict covers, as a small tag over its heading */
html.js .check-list.is-scored .score-band .band-range {
  display: inline-block;
  padding: 4px 11px; margin-block-end: 12px;
  border: 1px solid color-mix(in srgb, var(--brand-teal) 24%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--brand-ice) 46%, var(--surface-1));
}
html.js .check-list.is-scored .score-band h3 { font-size: 1.3rem; margin-bottom: 6px; }

/* ── 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; }
/* 5.3:1 wordmark, so it sits with Chroma rather than the taller monograms */
.supporter--taxstar { --logo-h: 22px; }
/* 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.

   The section is a readiness check rather than a form: what it is and the
   three stages it moves through on the start side, the card that asks on
   the other. One column until there is room for two. */
.finder-layout { display: grid; gap: clamp(26px, 5vw, 40px); }
.finder-intro > .label { margin-bottom: 16px; }
.finder-intro .chapter-intro { margin-top: 18px; margin-bottom: 0; max-width: 44ch; }
/* The three dates, as a quieter line under the invitation. */
.finder-dates { margin-top: 12px; max-width: 46ch; font-size: .95rem; color: var(--ink-300); }
/* Check → action: where a visitor is, and what they leave with. Two ends
   of one line, and the line fills between them as the questions are
   answered, so the rail shows the same progress the card does instead of
   naming steps that never happen. It reads everything off classes the
   script already sets (.on on the progress segments, .has-result on the
   finder), so it keeps no state of its own. Phones go straight from the
   introduction to the card, which carries its own progress bar.

   Motion: a state change, seen a few times a visit. The fill is a
   transform on a transition, so stepping Back retargets it from wherever
   it is rather than restarting; the far end lights as the line reaches it. */
.finder-stages {
  --finder-progress: .12;
  display: none; position: relative; list-style: none;
  justify-content: space-between;
  max-width: 300px; margin-top: clamp(30px, 5vh, 48px); padding-top: 30px;
}
#phase-finder:has(.finder-dots li:nth-child(2).on) .finder-stages { --finder-progress: .46; }
#phase-finder:has(.finder-dots li:nth-child(3).on) .finder-stages { --finder-progress: .78; }
#phase-finder:has(.finder-dots li:nth-child(4).on) .finder-stages { --finder-progress: .88; }
/* a result fills every segment, so this has to outrank the three above */
#phase-finder:has(.finder.has-result .finder-dots li:first-child.on) .finder-stages { --finder-progress: 1; }
/* the line, and the part of it already travelled */
.finder-stages::before, .finder-stages::after {
  content: ""; position: absolute; top: 8px; inset-inline: 9px; height: 2px; border-radius: 2px;
}
.finder-stages::before { background: var(--line-strong); }
.finder-stages::after {
  background: var(--brand-green);
  transform: scaleX(var(--finder-progress)); transform-origin: 0 50%;
  transition: transform .28s cubic-bezier(.23, 1, .32, 1);
}
[dir="rtl"] .finder-stages::after { transform-origin: 100% 50%; }
.finder-stages li {
  position: relative;
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; line-height: 1.4;
  color: color-mix(in srgb, var(--ink-300) 70%, transparent);
  transition: color .2s ease;
}
.finder-stages li:last-child { text-align: end; }
/* the two ends: a disc sitting on the line, on the page's own ground so
   the line stops at its edge */
.finder-stages li::before {
  content: ""; position: absolute; z-index: 1; top: -30px; inset-inline-start: 0;
  width: 18px; height: 18px; border-radius: 999px; box-sizing: border-box;
  background: var(--bg); border: 2px solid var(--line-strong);
  transition: background-color .2s ease, border-color .2s ease;
}
.finder-stages li:last-child::before { inset-inline-start: auto; inset-inline-end: 0; }
/* Check is where the visitor already is */
.finder-stages li:first-child { color: var(--brand-forest); }
.finder-stages li:first-child::before { background: var(--brand-green); border-color: var(--brand-green); }
/* and it is ticked once there is an answer */
.finder-stages li:first-child::after {
  content: ""; position: absolute; z-index: 2; top: -25px; inset-inline-start: 5px;
  width: 8px; height: 4px;
  border-inline-start: 2px solid #fff; border-block-end: 2px solid #fff;
  transform: rotate(-45deg) scale(.9); opacity: 0;
  transition: opacity .16s ease, transform .16s cubic-bezier(.23, 1, .32, 1);
}
[dir="rtl"] .finder-stages li:first-child::after { transform: rotate(45deg) scale(.9); }
#phase-finder:has(.finder.has-result) .finder-stages li:first-child::after { opacity: 1; transform: rotate(-45deg); }
[dir="rtl"] #phase-finder:has(.finder.has-result) .finder-stages li:first-child::after { transform: rotate(45deg); }
/* Action lights as the line arrives, not before it */
#phase-finder:has(.finder.has-result) .finder-stages li:last-child { color: var(--brand-forest); transition-delay: .18s; }
#phase-finder:has(.finder.has-result) .finder-stages li:last-child::before {
  background: var(--brand-green); border-color: var(--brand-green); transition-delay: .18s;
}
@media (min-width: 960px) {
  .finder-layout { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: clamp(40px, 6vw, 104px); align-items: start; }
  .finder-stages { display: flex; }
}

.finder { --finder-shift: 10px; min-width: 0; }
[dir="rtl"] .finder { --finder-shift: -10px; }
.finder-app { display: none; }
/* With the script running the finder is one card: the question, then — in
   the same card — the answer it led to. */
html.js .finder.is-app {
  background: var(--surface-1);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 1px 2px rgba(15, 39, 24, .04), 0 22px 44px -32px rgba(15, 39, 24, .36);
  padding: clamp(22px, 3.4vw, 44px);
}
html.js .finder.is-app .finder-app { display: block; }
.finder-top { display: flex; align-items: center; gap: 14px; min-height: 36px; }
.finder-count { font-variant-numeric: tabular-nums; }
.finder-position { color: var(--brand-green); }
.finder-position, .finder.has-result .finder-count { display: none; }
.finder.has-result .finder-position { display: block; }
/* progress: one thin segment per question, filled from the start edge as
   each is reached. The script only toggles .on, as it did for the dots. */
.finder-dots { list-style: none; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; margin-top: 12px; }
.finder-dots li { height: 3px; border-radius: 999px; background: var(--line); overflow: hidden; }
.finder-dots li::after {
  content: ""; display: block; height: 100%; border-radius: inherit;
  background: var(--brand-green);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .4s cubic-bezier(.16,1,.3,1);
}
[dir="rtl"] .finder-dots li::after { transform-origin: 100% 50%; }
.finder-dots li.on::after { transform: scaleX(1); }
.finder-back {
  margin-inline-start: auto; min-height: 36px;
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid transparent; border-radius: 999px;
  background: transparent; color: var(--ink-300); cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  padding: 6px 12px 6px 8px;
  transition: background .3s, color .3s, border-color .3s;
}
.finder-back .icon { width: 16px; height: 16px; transition: transform .3s cubic-bezier(.16,1,.3,1); }
[dir="rtl"] .finder-back .icon { transform: scaleX(-1); }
.finder-back:hover { background: var(--brand-ice); color: var(--brand-forest); border-color: color-mix(in srgb, var(--brand-teal) 25%, transparent); }
.finder-back:hover .icon { transform: translateX(-2px); }
[dir="rtl"] .finder-back:hover .icon { transform: scaleX(-1) translateX(-2px); }
.finder-back:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
.finder-back[hidden] { display: none; }
.finder-step { margin-top: clamp(24px, 3.6vh, 34px); }
/* each question arrives rather than swapping in: [hidden] takes the step out
   of the flow, so the animation runs afresh every time one is shown */
html.js .finder.is-app .finder-step { animation: finder-arrive .32s cubic-bezier(.16,1,.3,1) both; }
@keyframes finder-arrive { from { opacity: 0; transform: translateX(var(--finder-shift)); } }
.finder-q { font-family: var(--font-display); font-weight: 600; font-size: clamp(1.3rem, 2.1vw, 1.75rem); line-height: 1.22; letter-spacing: -.01em; color: var(--cream-100); margin-bottom: clamp(18px, 2.6vh, 26px); outline: none; max-width: 26ch; }
.finder-opts { display: flex; flex-direction: column; gap: 10px; }
/* answers are form controls, not calls to action: a quiet surface, a radio
   ring on the start edge, and the brand green only once one is chosen */
.finder-opts button {
  position: relative;
  text-align: start; width: 100%; min-height: 56px;
  display: flex; align-items: center; gap: 14px;
  font-family: var(--font-serif); font-size: 1rem; font-weight: 500; color: var(--ink-100);
  background: var(--surface-1);
  border: 1px solid var(--line); border-radius: 12px;
  padding: 14px 18px; cursor: pointer;
  transition: border-color .2s, background .2s, transform .2s cubic-bezier(.16,1,.3,1);
}
.finder-opts button::before {
  content: ""; flex: none; width: 18px; height: 18px; border-radius: 999px;
  border: 1.5px solid var(--line-strong); background: var(--surface-1);
  transition: border-color .2s, box-shadow .2s;
}
.finder-opts button:hover {
  border-color: color-mix(in srgb, var(--brand-green) 55%, var(--line));
  background: color-mix(in srgb, var(--brand-green) 4%, var(--surface-1));
  transform: translateY(-1px);
}
.finder-opts button:hover::before { border-color: var(--brand-green); }
.finder-opts button:active { transform: none; }
.finder-opts button:active,
.finder-opts button[aria-current="true"] {
  border-color: var(--brand-green);
  background: color-mix(in srgb, var(--brand-green) 7%, var(--surface-1));
  box-shadow: inset 0 0 0 1px var(--brand-green);
}
.finder-opts button:active::before,
.finder-opts button[aria-current="true"]::before { border-color: var(--brand-green); box-shadow: inset 0 0 0 4px var(--brand-green); }
.finder-opts button:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
.finder-step > .form-fineprint { margin-top: 14px; }
.finder-foot { margin-top: clamp(22px, 3.4vh, 30px); padding-top: 16px; border-top: 1px solid var(--line); }
.finder.has-result .finder-foot { display: none; }

/* results: one card per outcome, toned by what it means — a small icon, a
   coloured start edge and a soft tint of the same colour. Colour never does
   the work alone; the icon and the title do. */
.finder-results { display: grid; gap: 14px; margin-top: 18px; }
.finder-results > article {
  --tone: var(--status-info); --tone-soft: var(--status-info-soft);
  position: relative;
  border: 1px solid var(--line); border-radius: 12px; padding: 22px 24px 22px 26px;
  background: var(--surface-1); outline: none;
  border-inline-start: 3px solid var(--tone);
  box-shadow: var(--shadow-card);
}
.finder-results > article[data-tone="positive"] { --tone: var(--status-positive); --tone-soft: var(--status-positive-soft); }
.finder-results > article[data-tone="warning"]  { --tone: var(--status-warning);  --tone-soft: var(--status-warning-soft); }
.finder-results > article[data-tone="neutral"]  { --tone: var(--ink-300); --tone-soft: rgba(22, 100, 135, .05); }
.finder-results > article h3 { font-size: 1.2rem; display: flex; align-items: flex-start; gap: 12px; }
.finder-results > article .finder-tone { flex: none; width: 22px; height: 22px; margin-top: 2px; color: var(--tone); }
.finder-results > article .finder-tone .icon { width: 22px; height: 22px; }
.finder-block { margin-top: 16px; }
.finder-block > .label { margin-bottom: 6px; }
.finder-results > article .serif { color: var(--ink-200); max-width: 62ch; }
.finder-results > article p:has(> .pill) { margin-top: 20px; }
/* in the card the result is not a second box: it takes the card over, with
   the tone carried by the icon's disc instead of an edge */
html.js .finder.is-app .finder-results { display: block; margin-top: 0; }
html.js .finder.is-app .finder-results > article { display: none; }
html.js .finder.is-app .finder-results > article.active {
  display: block; margin-top: clamp(24px, 3.6vh, 34px);
  border: 0; border-radius: 0; padding: 0; background: none; box-shadow: none;
  animation: finder-arrive .36s cubic-bezier(.16,1,.3,1) both;
}
html.js .finder.is-app .finder-results > article.active h3 { font-size: clamp(1.3rem, 2.1vw, 1.75rem); line-height: 1.22; align-items: center; gap: 14px; }
html.js .finder.is-app .finder-results > article.active .finder-tone {
  width: 44px; height: 44px; margin-top: 0; border-radius: 999px;
  display: grid; place-items: center; background: var(--tone-soft);
}
/* The disc carries the verdict, so it lands a beat after the card that
   holds it — the payoff of three questions, seen once a run. No bounce. */
html.js .finder.is-app .finder-results > article.active .finder-tone { animation: finder-tone-in .2s cubic-bezier(.23, 1, .32, 1) .12s both; }
@keyframes finder-tone-in { from { opacity: 0; transform: scale(.9); } }
html.js .finder.is-app .finder-results > article.active .finder-block { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
html.js .finder.is-app .finder-results > article.active:focus-visible { outline: 2px solid var(--tone); outline-offset: 8px; border-radius: 4px; }
.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; }
@media (prefers-reduced-motion: reduce) {
  /* less motion: the line and the tick change at once; the colours still ease */
  .finder-stages::after, .finder-stages li:first-child::after { transition: none; }
  #phase-finder:has(.finder.has-result) .finder-stages li:last-child,
  #phase-finder:has(.finder.has-result) .finder-stages li:last-child::before { transition-delay: 0s; }
  .finder-dots li::after, .finder-back .icon, .finder-opts button, .finder-opts button::before { transition: none; }
  .finder-opts button:hover { transform: none; }
  html.js .finder.is-app .finder-step, html.js .finder.is-app .finder-results > article.active,
  html.js .finder.is-app .finder-results > article.active .finder-tone { animation: none; }
}
@media (max-width: 767px) { .finder-back { min-height: 44px; } }

/* ── 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; }
  :root { --chrome-h: 76px; }
  .site-header { padding: 12px 16px; height: 76px; }
  .header-logo, .header-logo img { height: 40px; }
  .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 */

/* 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 cream veil under the copy, and a touch at the top for the header. */
  --hero-scrim:
    linear-gradient(180deg, #fffcf699 0%, #fffcf63d 14%, transparent 32%),
    linear-gradient(0deg,   #fffcf6a6 0%, #fffcf652 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; }

/* What the control does on a phone is with the rest of it, in the
   "Hero slider control" block further down. */

/* 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 ──────────────────────────────────────
   A plain directory: portrait, then an index, name, role and the profile
   link beneath it. Nothing sits over a photograph. Three per row on
   desktop, two on tablet, one on mobile.

   The portrait is 4:5 by aspect-ratio and object-fit: cover, so every
   portrait in a row is the same size whatever the source image. The crop
   anchors high (--team-focus) so heads are kept; set it inline on a member
   to override (for example style="--team-focus: 50% 15%"). */
.team-grid {
  display: grid; gap: clamp(44px, 5.5vw, 72px) clamp(24px, 3vw, 40px);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  max-width: 1080px; margin-bottom: clamp(48px, 6vw, 80px);
  margin-top: clamp(16px, 2.4vw, 28px);
}
@media (max-width: 979px) { .team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px) { .team-grid { grid-template-columns: minmax(0, 1fr); max-width: 440px; } }

.team-card { display: flex; flex-direction: column; min-width: 0; }

.team-figure {
  aspect-ratio: 4 / 5; overflow: hidden;
  border-radius: 12px; border: 1px solid var(--line);
  background: linear-gradient(160deg, #eef5f7 0%, #dfecf0 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.7) inset;
  transition: border-color .35s ease;
}
.team-card:hover .team-figure { border-color: var(--line-strong); }
.team-photo {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--team-focus, 50% 22%);
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
.team-card:hover .team-photo { transform: scale(1.02); }

/* no portrait: the same 4:5 footprint, a quiet ground and the initials */
.team-figure--empty { display: grid; place-items: center; }
.team-initials {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(3rem, 6vw, 4.4rem); letter-spacing: .06em;
  color: var(--brand-teal); opacity: .48; user-select: none;
}

/* the one technical detail: a small mono index with a short rule, in the
   same voice as the chapter number above the section */
.team-index {
  display: flex; align-items: center; gap: 10px;
  margin-top: clamp(18px, 1.8vw, 24px);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .2em;
  color: var(--ink-300); font-variant-numeric: tabular-nums;
}
.team-index::after { content: ""; width: 28px; height: 1px; background: var(--line-strong); }

.team-id { margin-top: 8px; }
.team-name {
  font-size: clamp(1.25rem, 1.75vw, 1.5rem); font-weight: 500;
  line-height: 1.2; letter-spacing: -.01em;
  color: var(--ink-100); overflow-wrap: anywhere;
  transition: color .3s;
}
.team-card:hover .team-name { color: var(--brand-teal); }
.team-role { margin-top: 6px; font-size: .95rem; line-height: 1.45; color: var(--ink-200); }

/* the profile link: text and a small arrow, underlined on hover */
.team-open {
  align-self: start; margin-top: clamp(16px, 1.6vw, 20px);
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display); font-weight: 500; font-size: .92rem;
  color: var(--brand-teal); background: none; border: 0; border-radius: 2px;
  padding: 4px 0; cursor: pointer;
  text-decoration: underline transparent; text-underline-offset: 5px;
  transition: text-decoration-color .3s, color .3s;
}
.team-open::after { content: "\2192"; display: inline-block; transition: transform .3s cubic-bezier(.16,1,.3,1); }
[dir="rtl"] .team-open::after { content: "\2190"; }
.team-open:hover { text-decoration-color: currentColor; }
.team-open:hover::after { transform: translateX(3px); }
[dir="rtl"] .team-open:hover::after { transform: translateX(-3px); }
.team-open:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .team-photo, .team-open::after, .team-figure, .team-name { transition: none; }
  .team-card:hover .team-photo { transform: none; }
}
@media (max-width: 767px) { .team-open { min-height: 44px; } }

/* ── 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 ───────────────────────────────────────
   The systems directory: a filter bar, six supported systems as full
   cards, five on-request systems as compact rows, and the custom API as
   a strip at the foot. Filters are progressive enhancement — with JS off
   the buttons are hidden and every card shows, so the page is still a
   complete list.

   Rendering rules, in one place:
     · no band. The list sits on the page's own ground, as every other
       section does; it used to sit in an ice-blue panel, which is a colour
       the page under it does not have, so the section read as an insert
     · one surface family: white cards, a hairline edge, one soft shadow —
       the same card as the readiness check and the guide form
     · one radius per thing: 14px cards, 10px tiles, pills only for filters
     · green is the brand's "yes": the filter in use, a supported system,
       the tile behind a monogram. Amber means on request. Teal stays the
       colour of a link. No platform gets a colour of its own
     · three tiers, three weights: supported systems are cards, systems on
       request are rows in one quiet list, and the custom API is the one
       deep-green strip that closes the section
     · every hover is a small, purposeful change on one timing token */

.int-band {
  display: grid; gap: clamp(14px, 2vw, 22px);
  margin-top: clamp(6px, 1.5vh, 14px);
}

/* Filters: words, not capitals. The one in use takes a green tint and a
   green edge; the count is lighter than its label so it reads as a note. */
.int-filters {
  display: flex; flex-wrap: wrap; gap: 8px; margin: 0;
  padding-bottom: clamp(14px, 2vw, 20px); border-bottom: 1px solid var(--line);
}
html:not(.js) .int-filters { display: none; }
.int-filters button {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display); font-size: .9rem; font-weight: 500; letter-spacing: 0; text-transform: none;
  color: var(--ink-200); cursor: pointer;
  background: transparent; border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 16px; min-height: 40px;
  transition: background var(--motion), color var(--motion), border-color var(--motion);
}
.int-filters button[aria-pressed="true"] {
  color: var(--brand-forest);
  background: color-mix(in srgb, var(--brand-green) 9%, var(--surface-1));
  border-color: var(--brand-green);
}
.int-filters button:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
.int-filters__n {
  font-family: var(--font-display); font-size: .78rem; font-weight: 500; letter-spacing: 0; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink-300); opacity: .75;
}
.int-filters button[aria-pressed="true"] .int-filters__n { color: var(--brand-green); opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .int-filters button:not([aria-pressed="true"]):hover { color: var(--brand-forest); border-color: color-mix(in srgb, var(--brand-green) 50%, var(--line)); }
}
/* on a phone the bar scrolls sideways inside itself, never the page */
@media (max-width: 620px) {
  .int-filters {
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    margin-inline: -6vw; padding-inline: 6vw;
    -webkit-mask: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
    mask: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
  }
  [dir="rtl"] .int-filters {
    -webkit-mask: linear-gradient(270deg, #000 calc(100% - 28px), transparent);
    mask: linear-gradient(270deg, #000 calc(100% - 28px), transparent);
  }
  .int-filters::-webkit-scrollbar { display: none; }
  .int-filters button { flex: none; min-height: 44px; }
}

.int-grid { display: grid; gap: clamp(12px, 1.4vw, 18px); 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; } }
.int-grid[hidden] { display: none; }

/* ── The card, all three kinds ── */
.int-card {
  display: flex; flex-direction: column;
  padding: clamp(18px, 1.8vw, 24px);
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface-1);
  box-shadow: var(--card-shadow);
  color: inherit; text-decoration: none;
  transition: translate var(--motion), border-color var(--motion), box-shadow var(--motion), background var(--motion), opacity .2s ease;
}
.int-card[hidden] { display: none; }
.int-card__cat {
  font-family: var(--font-display); font-weight: 500; font-size: .8rem;
  letter-spacing: 0; text-transform: none; color: var(--ink-300); margin: 0 0 2px;
}
.int-card__name {
  font-family: var(--font-display); font-weight: 600; font-size: 1.28rem; line-height: 1.2; letter-spacing: -.01em;
  color: var(--cream-100); margin: 0;
}
.int-card__edition { font-family: var(--font-display); font-size: .88rem; line-height: 1.4; color: var(--ink-200); margin: 3px 0 0; }
.int-card__line { font-family: var(--font-display); font-size: .95rem; line-height: 1.55; color: var(--ink-200); margin: 12px 0 0; }

/* Monogram: one system. A rounded square in the brand's green tint — the
   same size, radius and weight for "QB" as for "SAP", so they line up as
   identifiers rather than compete as logos. */
.int-mono {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 46px; height: 46px; border-radius: 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 14px; letter-spacing: .01em; line-height: 1;
  background: color-mix(in srgb, var(--brand-green) 9%, var(--surface-1));
  color: var(--brand-forest);
  transition: background var(--motion), color var(--motion);
}

/* Status: icon + word + colour, always the three together. */
.int-card__status { display: inline-flex; align-items: center; gap: 0; font-weight: 500; }
.int-card[data-status="supported"] .int-card__status { color: var(--ok); }
/* teal, not the warning amber: a system connected on request is something
   Dhara does, not something to be careful of */
.int-card[data-status="request"]   .int-card__status { color: var(--brand-teal); }
.int-card__status .ic { width: 15px; height: 15px; margin-inline-end: 5px; }

/* What a connection covers. It is the same three things on every supported
   system, so it is set as one line of text and not as three badges: six
   cards of three pills each was eighteen boxes saying one thing. */
.int-card__chips { list-style: none; display: flex; flex-wrap: wrap; gap: 2px 0; margin: 14px 0 0; padding: 0; }
.int-card__chips li { font-family: var(--font-display); font-size: .84rem; line-height: 1.5; color: var(--ink-300); }
.int-card__chips li + li::before { content: "·"; margin-inline: 8px; color: var(--line-strong); }

/* The action line: status at the start, the way in at the end, under a
   hairline that closes the card. */
.int-card__action {
  display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; justify-content: space-between;
  margin: auto 0 0; padding-top: 14px;
  font-family: var(--font-display); font-size: .86rem;
}
.int-card--featured .int-card__action { margin-top: 18px; border-top: 1px solid var(--line); }
.int-card--featured .int-card__chips + .int-card__action { margin-top: auto; }
.int-card--featured .int-card__chips { margin-bottom: 18px; }
.int-card__go {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 500; color: var(--brand-teal); text-decoration: none;
  transition: color var(--motion);
}
.int-card__arrow { width: 14px; height: 14px; flex: none; transition: translate var(--motion); }
[dir="rtl"] .int-card__arrow { transform: scaleX(-1); }

/* Featured: the tile and the name share a row. */
.int-card__head { display: flex; gap: 14px; align-items: flex-start; }
.int-card__head > div { min-width: 0; }

/* On request: one list. These are systems we will look at, not systems
   with a page of their own, so they are rows in a single card with a
   hairline between them — a different weight from the cards above, where
   they used to be five more boxes in two columns with one left over. */
.int-grid--compact {
  grid-template-columns: 1fr; gap: 0;
  border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  background: var(--surface-1);
}
.int-card--compact {
  flex-direction: row; align-items: center; gap: 14px;
  padding: 14px clamp(16px, 1.8vw, 24px);
  border: 0; border-radius: 0; box-shadow: none; background: none;
}
/* a rule above every row but the first one showing, whatever is filtered */
.int-card--compact:not([hidden]) ~ .int-card--compact:not([hidden]) { border-top: 1px solid var(--line); }
.int-card--compact .int-mono { width: 38px; height: 38px; font-size: 12px; border-radius: 9px; background: var(--surface-2); color: var(--ink-200); }
.int-card--compact .int-card__body { min-width: 0; flex: 1; }
.int-card--compact .int-card__name { font-size: 1.02rem; font-weight: 500; letter-spacing: 0; }
.int-card--compact .int-card__edition { margin-top: 1px; font-size: .84rem; color: var(--ink-300); }
.int-card--compact .int-card__action { margin: 0; padding: 0; flex: none; gap: 6px 22px; justify-content: flex-end; }

/* Custom: the deliberate fallback, and the section's last word — "even if
   yours is not listed, there is a path". The one deep-green surface here,
   the same green as the service band on the home page. */
.int-card--custom {
  flex-direction: row; align-items: center; gap: 18px;
  padding: clamp(20px, 2.2vw, 28px) clamp(20px, 2.6vw, 34px);
  background: var(--brand-forest); border-color: var(--brand-forest);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset, 0 20px 40px -30px rgba(15, 39, 24, .6);
}
.int-card--custom .int-card__body { flex: 1; min-width: 0; }
.int-card--custom .int-card__cat { color: var(--brand-sand); }
.int-card--custom .int-card__name { color: #fff; }
.int-card--custom .int-card__line { margin-top: 4px; color: #dbeae4; max-width: 60ch; }
.int-card--custom .int-mono { background: rgba(255, 255, 255, .12); color: #fff; }
.int-card--custom .int-card__action { margin: 0; padding: 0; flex: none; gap: 6px 22px; }
.int-card--custom[data-status="supported"] .int-card__status { color: var(--brand-sand); }
.int-card--custom .int-card__go { color: #fff; }

/* ── Hover ── one lift for the featured cards, a tint for a row in the
   list, a lighter green for the custom strip; the arrow slides on all of
   them. Hover is never the only way in: every card is a link or contains
   one. */
a.int-card:focus-visible, .int-card__go:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
a.int-card--custom:focus-visible, .int-card--custom .int-card__go:focus-visible { outline-color: var(--brand-sand); }
@media (hover: hover) and (pointer: fine) {
  a.int-card--featured:hover {
    translate: 0 -2px; box-shadow: var(--card-shadow-hover);
    border-color: color-mix(in srgb, var(--brand-green) 45%, var(--line));
  }
  a.int-card--featured:hover .int-mono { background: var(--brand-green); color: #fff; }
  .int-card--compact:has(.int-card__go:hover) { background: color-mix(in srgb, var(--brand-green) 4%, var(--surface-1)); }
  a.int-card--custom:hover { background: var(--brand-green); border-color: var(--brand-green); }
  a.int-card:hover .int-card__arrow, .int-card__go:hover .int-card__arrow { translate: 3px 0; }
  [dir="rtl"] a.int-card:hover .int-card__arrow, [dir="rtl"] .int-card__go:hover .int-card__arrow { translate: -3px 0; }
  a.int-card--featured:hover .int-card__go, .int-card--compact .int-card__go:hover { color: var(--brand-green); }
}
a.int-card--featured:active { translate: none; scale: .99; }

/* Filtering: a card that is leaving fades and drops a few pixels, and
   the grid reflows when it is gone. Immediate, not choreographed. */
.int-card.is-leaving { opacity: 0; translate: 0 4px; pointer-events: none; }

@media (max-width: 620px) {
  .int-card--custom { flex-wrap: wrap; }
  .int-card--custom .int-card__action { width: 100%; padding-top: 6px; justify-content: space-between; }
  .int-card--compact { flex-wrap: wrap; }
  .int-card--compact .int-card__action { width: 100%; padding-top: 2px; flex-wrap: nowrap; justify-content: space-between; }
  .int-card__go { min-height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .int-card, .int-mono, .int-card__go, .int-card__arrow, .int-filters button { transition: none; }
  a.int-card--featured:hover, a.int-card--featured:active { translate: none; scale: none; }
  a.int-card:hover .int-card__arrow, .int-card__go:hover .int-card__arrow { translate: none; }
  .int-card.is-leaving { opacity: 1; translate: none; }
}

/* ── Integrations · shared ────────────────────────────────────────
   Tokens the hub and the detail pages both draw on: the icon set and its
   sizes, the semantic colours, the one border family, the one shadow.

   Icons: assets/icons/ui.svg, one outline set, 1.75px stroke, three
   sizes and never a fourth. Every icon sits beside its word.

   Semantic colour is exactly that — green says valid, red says invalid,
   amber says pending — and appears nowhere else, so that when it does
   appear it means something. The brand teal stays the brand. */
.ic { width: 16px; height: 16px; flex: none; vertical-align: -3px; margin-inline-end: 6px; color: currentColor; }
.ic--node { width: 18px; height: 18px; vertical-align: -4px; }
.ic--lg { width: 22px; height: 22px; margin: 0; vertical-align: 0; }

.int-card, .corner-figure, main:has(.sys-hero) {
  --ok:        #1d7a4f;                              /* 4.7:1 on white */
  --ok-tint:   rgba(29, 122, 79, .10);
  --ok-line:   rgba(29, 122, 79, .32);
  --no:        #b3261e;                              /* 5.9:1 on white */
  --no-tint:   rgba(179, 38, 30, .09);
  --no-line:   rgba(179, 38, 30, .30);
  --warn:      #9a5b00;
  --line-hover: rgba(22, 100, 135, .46);
  --card-shadow: 0 1px 2px rgba(15, 39, 24, .04), 0 6px 20px rgba(15, 39, 24, .05);
  --card-shadow-hover: 0 1px 2px rgba(15, 39, 24, .05), 0 10px 26px rgba(15, 39, 24, .09);
  --motion: .22s cubic-bezier(.33, 0, .15, 1);
}


/* ── Integration detail pages ─────────────────────────────────────
   Five sections, all scoped to main:has(.sys-hero) where they touch a
   shared class (.is-tint, .is-deep, .chips, .faq-list), so nothing here
   reaches another page.

   The rendering rules, in one place:
     · one border family (var(--line) / --line-hover / --ok-line / --no-line)
     · one radius for cards (12px), pills only where the site already uses them
     · one shadow, and the border still does the structural work
     · white cards on an ice-tinted section, never a box on a box */

main:has(.sys-hero) { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* The tint. The site's .is-tint is the page colour, which is why the
   sections looked pasted together; here it is one step of ice. */
main:has(.sys-hero) .is-tint {
  background: color-mix(in srgb, var(--brand-ice) 26%, #fffcf6);
  border-block: 1px solid var(--line);
}

/* ── Hero ── */
.sys-hero__head { display: flex; gap: 18px; align-items: flex-start; margin-top: 4px; }
.sys-hero__head > div { min-width: 0; }
.sys-hero__head .page-title { margin-bottom: 12px; }
.int-mono--lg {
  width: 60px; height: 60px; font-size: 19px; border-radius: 14px; flex: none;
  /* aligned to the H1's cap height rather than its line box */
  margin-top: clamp(6px, .9vw, 12px);
  box-shadow: var(--card-shadow);
}
.sys-chips { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 6px; padding: 0; }
.sys-chips li {
  display: inline-flex; align-items: center;
  font-family: var(--font-display); font-size: .76rem; line-height: 1;
  padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--ink-300); background: var(--surface-1);
}
.sys-chips li.is-status { color: var(--ok); background: var(--ok-tint); border-color: var(--ok-line); }
.sys-chips li.is-status .ic { width: 14px; height: 14px; margin-inline-end: 5px; }
.sys-hero .page-lead { margin-top: 2px; }
.sys-hero .chapter-cta { margin-top: clamp(20px, 3vh, 30px); }
@media (max-width: 620px) {
  .int-mono--lg { width: 48px; height: 48px; font-size: 16px; border-radius: 12px; margin-top: 2px; }
  .sys-hero__head { gap: 14px; }
}

/* ── How it connects ── */
.conn-strip {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 28px;
}
.conn-strip__node { position: relative; min-width: 0; }
.conn-strip__box {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 56px; padding: 9px 16px 9px 10px; max-width: 100%;
  border: 1px solid var(--line-strong); border-radius: 12px;
  font-family: var(--font-display); font-weight: 500; font-size: 1rem; line-height: 1.2;
  color: var(--ink-100); background: var(--surface-1);
  box-shadow: var(--card-shadow);
  --sys: var(--brand-teal);
}
[dir="rtl"] .conn-strip__box { padding: 9px 10px 9px 16px; }
/* the glyph's container: soft brand tint, dark blue glyph */
.conn-strip__ic {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 34px; height: 34px; border-radius: 9px;
  background: color-mix(in srgb, var(--sys) 12%, #fff);
  color: color-mix(in srgb, var(--sys) 70%, #0f2718);
}
.conn-strip__ic .ic { margin: 0; vertical-align: 0; }
.conn-strip__box[data-system="xero"]       { --sys: #13b5ea; }
.conn-strip__box[data-system="quickbooks"] { --sys: #2ca01c; }
.conn-strip__box[data-system="zoho"]       { --sys: #e42527; }
.conn-strip__box[data-system="odoo"]       { --sys: #714b67; }
.conn-strip__box[data-system="tally"]      { --sys: #1e5aa8; }
.conn-strip__box[data-system="sage"]       { --sys: #00a54f; }
.conn-strip__box[data-system="custom"]     { --sys: var(--brand-green); }
.conn-strip__node:last-child .conn-strip__box { --sys: var(--brand-navy); }

/* Dhara is the centre and says so — a shade more border, a brand tint,
   the mark above the name — without being any larger than the others. */
.conn-strip__node--dhara .conn-strip__box {
  flex-direction: column; gap: 2px; padding: 9px 18px;
  background: color-mix(in srgb, var(--brand-ice) 40%, #fff);
  border: 1.5px solid var(--brand-green); color: var(--brand-forest);
  box-shadow: var(--card-shadow), 0 0 0 4px color-mix(in srgb, var(--brand-ice) 55%, transparent);
}
.conn-strip__node--dhara .conn-strip__box::before {
  content: ""; width: 14px; height: 20px; margin-bottom: 2px;
  background: var(--brand-green);
  mask: var(--dhara-mark) center / contain no-repeat;
  -webkit-mask: var(--dhara-mark) center / contain no-repeat;
}
.conn-strip__box small {
  display: block; font-weight: 500; font-size: .66rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--brand-green);
}
.conn-strip__node p { margin: 12px 0 0; font-size: .95rem; line-height: 1.55; color: var(--ink-200); max-width: 34ch; }

/* The line: drawn across the cell behind the (opaque) box so it appears
   to leave the box's edge in any language, and drawn in once when the
   section comes into view — data moving, shown once, then still. */
.conn-strip__node:not(:last-child)::after {
  content: ""; position: absolute; top: 28px; inset-inline-start: 0; inset-inline-end: -28px; height: 1.5px;
  background: var(--brand-teal); opacity: .6;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .75s cubic-bezier(.33, 0, .15, 1);
}
[dir="rtl"] .conn-strip__node:not(:last-child)::after { transform-origin: 100% 50%; }
.conn-strip__node + .conn-strip__node::before {
  content: ""; position: absolute; top: 24.5px; inset-inline-start: -8px; z-index: 1;
  border: 4.5px solid transparent; border-inline-start: 7px solid var(--brand-teal); opacity: 0;
  transition: opacity .3s ease .55s;
}
[dir="rtl"] .conn-strip__node + .conn-strip__node::before {
  border-inline-start: 4.5px solid transparent; border-inline-end: 7px solid var(--brand-teal);
  inset-inline-start: auto; inset-inline-end: -8px;
}
.conn-strip.is-live .conn-strip__node:not(:last-child)::after { transform: scaleX(1); }
.conn-strip.is-live .conn-strip__node + .conn-strip__node::before { opacity: .6; }
.conn-strip.is-live .conn-strip__node:nth-child(2)::after { transition-delay: .5s; }
.conn-strip.is-live .conn-strip__node:nth-child(3)::before { transition-delay: 1.05s; }
/* no script: lines simply present */
html:not(.js) .conn-strip__node:not(:last-child)::after { transform: none; }
html:not(.js) .conn-strip__node + .conn-strip__node::before { opacity: .6; }
@media (max-width: 760px) {
  .conn-strip { grid-template-columns: 1fr; gap: 22px 0; }
  .conn-strip__node:not(:last-child)::after {
    top: 0; bottom: -22px; inset-inline-start: 26px; inset-inline-end: auto; width: 1.5px; height: auto;
    transform: scaleY(0); transform-origin: 50% 0;
  }
  .conn-strip.is-live .conn-strip__node:not(:last-child)::after { transform: scaleY(1); }
  html:not(.js) .conn-strip__node:not(:last-child)::after { transform: none; }
  .conn-strip__node + .conn-strip__node::before,
  [dir="rtl"] .conn-strip__node + .conn-strip__node::before {
    top: -6px; inset-inline-start: 22.5px; inset-inline-end: auto;
    border: 4.5px solid transparent; border-top: 7px solid var(--brand-teal);
  }
}

/* The seven checked fields: compact, neutral, each with a small check —
   verification, not tags. */
.conn-checks { margin-top: clamp(22px, 3vh, 34px); padding-top: clamp(18px, 2.4vh, 26px); border-top: 1px solid var(--line); }
.conn-checks h3 { display: flex; align-items: center; font-size: 1rem; margin-bottom: 12px; }
.conn-checks h3 .ic { color: var(--brand-teal); margin-inline-end: 8px; }
main:has(.sys-hero) .conn-checks .chips { margin-top: 0; gap: 8px; }
main:has(.sys-hero) .conn-checks .chips li {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display); font-size: .82rem; letter-spacing: 0; text-transform: none;
  color: var(--ink-100); padding: 7px 12px 7px 9px;
  border: 1px solid var(--line); background: var(--surface-1);
}
main:has(.sys-hero) .conn-checks .chips li::before {
  content: ""; width: 14px; height: 14px; flex: none;
  background: var(--brand-teal);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E") center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* ── What Dhara does ── */
.feat-grid { display: grid; gap: 14px; grid-template-columns: repeat(3, 1fr); }
.feat-grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 979px) { .feat-grid, .feat-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .feat-grid, .feat-grid--4 { grid-template-columns: 1fr; } }
.feat-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 20px 22px 22px;
  border: 1px solid var(--line); border-top: 3px solid var(--brand-teal);
  border-radius: 0 0 12px 12px; background: var(--surface-1);
  box-shadow: var(--card-shadow);
  transition: translate var(--motion), border-color var(--motion), box-shadow var(--motion);
}
.feat-card:hover { translate: 0 -2px; border-color: var(--line-hover); border-top-color: var(--brand-teal); box-shadow: var(--card-shadow-hover); }
.feat-card__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 10px; margin-bottom: 2px;
  background: color-mix(in srgb, var(--brand-ice) 55%, #fff);
  color: var(--brand-teal);
  transition: background var(--motion), color var(--motion);
}
.feat-card:hover .feat-card__icon { background: color-mix(in srgb, var(--brand-ice) 85%, #fff); color: var(--brand-forest); }
/* the one semantic exception: validation reads as "checked, valid" */
.feat-card:nth-child(2) .feat-card__icon { background: var(--ok-tint); color: var(--ok); }
.feat-card h3 { font-size: 1.05rem; line-height: 1.25; margin: 0; }
.feat-card p { margin: 0; font-size: .94rem; line-height: 1.55; color: var(--ink-200); max-width: none; }
.feat-card__n {
  font-family: var(--font-display); font-weight: 600; font-size: .7rem; letter-spacing: .1em;
  color: var(--brand-teal); opacity: .8;
}

/* ── Who it is for · PDF vs e-invoice ── */
.pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(22px, 3vw, 44px); align-items: start; }
.pair__col { min-width: 0; }   /* so the table scrolls inside its wrapper, never the page */
.pair__col h3 { font-size: 1.12rem; margin-bottom: 14px; }
.pair-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
.pair-list { max-width: none; margin: 0; }
.pair-list li { padding-inline-start: 26px; position: relative; }
.pair-list li::before {
  content: ""; position: absolute; inset-inline-start: 0; top: .78em; width: 17px; height: 17px;
  background: var(--brand-teal);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m8.5 12 2.5 2.5 4.5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m8.5 12 2.5 2.5 4.5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* The comparison, in its own container. Four rows; a PDF fact beside the
   same fact for an e-invoice. Red says invalid, green says valid, each on
   its own small tinted disc, with the words in ink — the colour is the
   signal, the text is the content. The e-invoice column and header carry
   the faintest positive tint so the two columns can be compared at a
   glance without either turning into a coloured block. */
.cmp-wrap {
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: var(--surface-1); box-shadow: var(--card-shadow);
}
.cmp { width: 100%; border-collapse: collapse; font-family: var(--font-display); font-size: .92rem; }
.cmp th {
  text-align: start; font-weight: 500; font-size: .8rem; letter-spacing: .02em;
  color: var(--ink-300); padding: 12px 14px; border-bottom: 1px solid var(--line-strong);
  background: color-mix(in srgb, var(--surface-2) 55%, #fff);
}
.cmp th.is-einvoice { color: var(--ok); background: color-mix(in srgb, var(--ok-tint) 70%, #fff); }
.cmp td {
  padding: 12px 14px; border-bottom: 1px solid var(--line); color: var(--ink-100);
  vertical-align: top; line-height: 1.45;
  transition: background var(--motion);
}
.cmp tbody tr:last-child td { border-bottom: 0; }
.cmp td:last-child { background: color-mix(in srgb, var(--ok-tint) 35%, #fff); }
.cmp tbody tr:hover td { background: color-mix(in srgb, var(--surface-2) 45%, #fff); }
.cmp tbody tr:hover td:last-child { background: color-mix(in srgb, var(--ok-tint) 60%, #fff); }
.cmp-no, .cmp-yes {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 24px; height: 24px; border-radius: 50%; margin-inline-end: 9px; vertical-align: -6px;
}
.cmp-no { color: var(--no); background: var(--no-tint); }
.cmp-yes { color: var(--ok); background: var(--ok-tint); }
.cmp-no .ic, .cmp-yes .ic { width: 15px; height: 15px; margin: 0; vertical-align: 0; }
@media (max-width: 860px) { .pair { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 520px) {
  .pair-cols { grid-template-columns: 1fr; }
  /* the table keeps both columns side by side and scrolls on its own if
     it must — the point of it is the comparison */
  .cmp-wrap { overflow-x: auto; overscroll-behavior-x: contain; }
  .cmp { min-width: 460px; font-size: .86rem; }
  .cmp td, .cmp th { padding-inline: 10px; }
}

/* ── FAQ ── */
main:has(.sys-hero) .faq-list { max-width: 78ch; border-top: 0; }
main:has(.sys-hero) .faq-list details {
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface-1);
  margin-bottom: 8px; box-shadow: var(--card-shadow);
  transition: border-color var(--motion), box-shadow var(--motion);
}
main:has(.sys-hero) .faq-list details:hover { border-color: var(--line-hover); }
main:has(.sys-hero) .faq-list details[open] { border-color: var(--line-hover); box-shadow: var(--card-shadow-hover); }
main:has(.sys-hero) .faq-list summary {
  padding: 16px 18px; grid-template-columns: 1fr 24px; gap: 14px;
  font-size: 1.02rem; color: var(--ink-100); border-radius: 12px;
  transition: color var(--motion);
}
main:has(.sys-hero) .faq-list summary:hover { color: var(--brand-teal); }
main:has(.sys-hero) .faq-list details[open] summary { color: var(--brand-teal); }
main:has(.sys-hero) .faq-list summary:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: -2px; }
/* chevron, from the same outline set, turning over rather than a + becoming × */
main:has(.sys-hero) .faq-list summary::after {
  content: ""; width: 18px; height: 18px; justify-self: center;
  background: var(--brand-teal);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform .3s cubic-bezier(.33, 0, .15, 1);
}
main:has(.sys-hero) .faq-list details[open] summary::after { transform: rotate(180deg); }
main:has(.sys-hero) .faq-list details p { padding: 0 18px 18px; margin: 0; max-width: 68ch; }

/* ── Closing CTA ── */
main:has(.sys-hero) .is-deep.is-navy {
  position: relative; overflow: hidden;
}
main:has(.sys-hero) .is-deep.is-navy::before {
  /* one soft light behind the heading, and nothing that moves */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 80% at 12% 0%, rgba(214, 238, 244, .10), transparent 70%);
}
main:has(.sys-hero) .is-deep.is-navy > * { position: relative; }
main:has(.sys-hero) .is-deep.is-navy h2 { max-width: 22ch; }
main:has(.sys-hero) .is-deep.is-navy .chapter-cta { margin-top: clamp(22px, 3.5vh, 34px); gap: 12px; }

/* Buttons: the existing pill, with its transition on the tokens' rhythm
   and a shade more air. */
main:has(.sys-hero) .pill { transition: background var(--motion), border-color var(--motion), color var(--motion), box-shadow var(--motion); }

@media (prefers-reduced-motion: reduce) {
  .feat-card, .feat-card__icon, .cmp td, main:has(.sys-hero) .faq-list details,
  main:has(.sys-hero) .faq-list summary::after, main:has(.sys-hero) .pill { transition: none; }
  .feat-card:hover { translate: none; }
  .conn-strip__node:not(:last-child)::after,
  .conn-strip.is-live .conn-strip__node:not(:last-child)::after { transform: none; transition: none; }
  .conn-strip__node + .conn-strip__node::before,
  .conn-strip.is-live .conn-strip__node + .conn-strip__node::before { opacity: .6; transition: none; }
}


/* ── 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: #fffcf6;
  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 { background: #fff; }
.is-tint-sand .chips li { background: color-mix(in srgb, #fff 82%, transparent); border-color: rgba(120, 86, 40, .28); color: var(--brand-forest); }
.is-tint-sand .chips li:hover { background: #fff; border-color: var(--brand-green); }

/* ── 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 .peppol-node,
.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 { color: 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);
  box-shadow: 0 1px 0 rgba(255,255,255,.06) inset;
}
.marquee-track.band .mq-group span { color: var(--brand-ice); font-size: 11.5px; letter-spacing: .28em; }
/* the separator draws as a small sand dot rather than a typed middot, so it
   sits on the same optical centre as the caps either side of it */
.marquee-track.band .mq-group i { color: transparent; width: 5px; height: 5px; border-radius: 999px; background: var(--brand-sand); opacity: .85; }

/* 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 · DEPTH CARDS — THE SITE DEFAULT ══════════════════════
   One card treatment everywhere (2026-08-07, on request): the glare —
   pointer-tracking sheen, ice→teal wash, hover border recolour — is
   retired. Every card now takes the same animation home §03 and
   /resources already had (§13): it leans toward the pointer, its contents
   sit at different depths and part company slightly as it moves, and a
   soft drop shadow grows under the whole card. No colour change, no
   reflection.

   The `:not(.is-depth)` guards stay even though the two treatments now
   look identical: cards literally marked .is-depth take §13's rules, and
   the compliance page's Peppol connector overrides count on THIS
   section's selectors holding 0,2,1 specificity — see §"Peppol flow".

   Two structural rules carried over from §13, both load-bearing:
   · NO `isolation` and NO `overflow: hidden` here. Both are grouping
     properties: they force transform-style to flat and silently collapse
     the depth layers. That is also why the corner mark paints at
     z-index 1 inside its reserved corner, not at the old glare's
     z-index -1 behind an isolated stack.
   · the transition list re-states 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.

   Mechanics: js/main.js §13 writes --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 ride on `translate`'s third
   value, because `transform` is already spoken for by the scroll
   reveal. */

: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, .peppol-flow, .int-grid {
  perspective: 1100px;
}

.info-card:not(.is-depth),
.peppol-node:not(.is-depth) {
  position: relative;
  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;
}
/* 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,
.peppol-node:not(.is-depth).is-tracking { transition: none; }

/* the only hover change: the whole card comes toward you, so its shadow
   grows. drop-shadow, not box-shadow, so it hugs the leaned silhouette. */
.info-card:not(.is-depth):hover,
.info-card:not(.is-depth):focus-within,
.peppol-node:not(.is-depth):hover,
.peppol-node:not(.is-depth):focus-within {
  filter: drop-shadow(0 18px 28px rgba(15, 39, 24, .20));
}

/* ── the layers ──
   Contents lift by role on hover, same offsets as §13: heading forward,
   copy behind it, the last paragraph — where the action link lives —
   furthest forward. Children with no assigned role stay on the surface
   (--z defaults to 0). */
.info-card:not(.is-depth) > *,
.peppol-node:not(.is-depth) > * {
  transition: translate .45s cubic-bezier(.16,1,.3,1);
}
.info-card:not(.is-depth):hover > *,
.info-card:not(.is-depth):focus-within > *,
.peppol-node:not(.is-depth):hover > *,
.peppol-node:not(.is-depth):focus-within > * {
  translate: 0 0 var(--z, 0px);
}
.info-card:not(.is-depth) > h3 { --z: 20px; }
.info-card:not(.is-depth) > p,
.peppol-node:not(.is-depth) > p { --z: 12px; }
.info-card:not(.is-depth) > p:last-child { --z: 26px; }

/* ── the box and the mark ──
   The uniform 22px radius the glare established stays, as does the corner
   mark — the depth cards on /resources carry it too, so it is part of the
   target treatment, not part of the glare. 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.

   The Peppol steps take the lean but not the mark or its reserved corner:
   they are a numbered accordion whose inline-start corner already carries
   the step numeral, and a closed <details> would show the reserve as dead
   height. They are simply absent from these rules — nothing to suppress —
   while their connector arrows define their own ::after from scratch in
   §"Peppol flow". */
.info-card:not(.is-depth),
.peppol-node:not(.is-depth) { border-radius: 22px; }

.info-card:not(.is-depth) {
  /* 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;
}
.info-card: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 { opacity: .72; }

/* on deep bands the ground is dark, so the mark goes ice — a static colour
   mapping, not a hover effect. No card currently sits inside .is-deep;
   this is here so one can, without arriving unstyled. */
.is-deep .info-card:not(.is-depth) { --card-mark: var(--brand-ice); }

/* 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),
  .peppol-node:not(.is-depth),
  .is-depth { rotate: none; transition: none; }
  .info-card:not(.is-depth):hover > *, .info-card:not(.is-depth):focus-within > *,
  .peppol-node:not(.is-depth):hover > *, .peppol-node:not(.is-depth):focus-within > *,
  .is-depth:hover > *, .is-depth:focus-within > * { translate: none; }
  .info-card:not(.is-depth) > *,
  .peppol-node:not(.is-depth) > *,
  .is-depth > * { transition: none; }
}


/* ── Home closing band ────────────────────────────────────────
   A faint light rising from the top-start corner and a lit top edge, so
   the navy reads as a lit surface rather than a flat fill. Static. */
.home-closing { position: relative; overflow: hidden; }
.home-closing::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(70% 70% at 8% 0%, rgba(214, 238, 244, .12) 0%, transparent 60%),
    linear-gradient(180deg, rgba(255,255,255,.06) 0%, transparent 2px);
}
[dir="rtl"] .home-closing::before { background: radial-gradient(70% 70% at 92% 0%, rgba(214, 238, 244, .12) 0%, transparent 60%), linear-gradient(180deg, rgba(255,255,255,.06) 0%, transparent 2px); }
.home-closing > * { position: relative; }
.home-closing h2 { max-width: 22ch; }
.home-closing .chapter-intro { max-width: 58ch; }
.home-closing .chapter-cta { margin-top: clamp(26px, 4vh, 40px); }

/* ── Home §05 guide form ───────────────────────────────────────
   Scoped to #guide and to the contact page's .contact-cols: these are the
   site's two lead forms, and they are the same form.
   Here the fields are boxed — a white well, a hairline, the accent on
   focus with a soft ring — because a form that asks for a name and a work
   address should look like a form rather than a note. */
#guide .form-aside figure { margin: 0; }
#guide .form-aside img {
  display: block; border-radius: 10px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card-hover);
}
/* The guide form is the same card as the readiness check further up the
   page: the page's own white, a hairline edge and one soft shadow. It was a
   pale-blue gradient panel with teal-edged fields and letter-spaced capital
   labels — a different product's form, on a page that is otherwise cream,
   white and green. Labels are set as words; green is kept for the field in
   use, which is what it means everywhere else on the page. */
:is(#guide, .contact-cols) .lead-form {
  background: var(--surface-1);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 1px 2px rgba(15, 39, 24, .04), 0 22px 44px -32px rgba(15, 39, 24, .36);
  padding: clamp(22px, 3.4vw, 40px);
}
:is(#guide, .contact-cols) .form-body { gap: 18px; }
/* the form's title: a heading, not a caption */
:is(#guide, .contact-cols) .form-body > .label {
  margin-bottom: 4px;
  font-family: var(--font-display); font-size: clamp(1.2rem, 1.7vw, 1.4rem); font-weight: 600;
  letter-spacing: -.01em; text-transform: none; line-height: 1.25; color: var(--cream-100);
}
:is(#guide, .contact-cols) .field { gap: 7px; }
:is(#guide, .contact-cols) .field > .label {
  font-family: var(--font-display); font-size: .9rem; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--ink-100);
}
:is(#guide, .contact-cols) .field > .label .req { color: var(--ink-300); }
:is(#guide, .contact-cols) .field input[type="text"], :is(#guide, .contact-cols) .field input[type="email"], :is(#guide, .contact-cols) .field input[type="tel"],
:is(#guide, .contact-cols) .field select, :is(#guide, .contact-cols) .field textarea {
  min-height: 48px;
  background: var(--surface-1);
  border: 1px solid var(--line-strong); border-radius: 10px;
  padding: 11px 14px; font-size: 1rem;
  transition: border-color .2s ease, box-shadow .2s ease;
}
:is(#guide, .contact-cols) .field select {
  appearance: none; -webkit-appearance: none;
  padding-inline-end: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f6047' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-size: 18px; background-position: right 14px center;
}
[dir="rtl"] :is(#guide, .contact-cols) .field select { background-position: left 14px center; }
:is(#guide, .contact-cols) .field input:hover, :is(#guide, .contact-cols) .field select:hover, :is(#guide, .contact-cols) .field textarea:hover { border-color: color-mix(in srgb, var(--brand-green) 55%, var(--line-strong)); }
:is(#guide, .contact-cols) .field input:focus, :is(#guide, .contact-cols) .field select:focus, :is(#guide, .contact-cols) .field textarea:focus {
  border-color: var(--brand-green);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-green) 16%, transparent);
}
:is(#guide, .contact-cols) .field input:focus-visible, :is(#guide, .contact-cols) .field select:focus-visible, :is(#guide, .contact-cols) .field textarea:focus-visible { outline: none; }
:is(#guide, .contact-cols) .field input:user-invalid, :is(#guide, .contact-cols) .field select:user-invalid {
  border-color: var(--status-negative);
  box-shadow: 0 0 0 3px var(--status-negative-soft);
}
/* a choice, not a boxed panel inside a panel */
:is(#guide, .contact-cols) .consent { padding: 2px 0; border: 0; border-radius: 0; background: none; max-width: none; }
:is(#guide, .contact-cols) .consent input { accent-color: var(--brand-green); }
:is(#guide, .contact-cols) .form-fineprint { color: var(--ink-300); }
:is(#guide, .contact-cols) .form-fineprint a { color: var(--brand-teal); text-decoration: underline; text-underline-offset: 3px; }
:is(#guide, .contact-cols) .form-actions { margin-top: 4px; padding-top: 14px; border-top: 1px solid var(--line); }
:is(#guide, .contact-cols) .form-actions .pill { padding-inline: 26px; }
:is(#guide, .contact-cols) .form-error { padding: 10px 14px; border-radius: 10px; background: var(--status-negative-soft); border: 1px solid color-mix(in srgb, var(--status-negative) 30%, transparent); }

}

/* ── 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; }
}


/* ═══ §7b · SCRIPT ADAPTATIONS — the UR and ZH trees ════════════
   Added 2026-08-07 with the Urdu and Chinese translations. One stylesheet
   still serves every tree; these blocks adapt the type to each script.

   URDU — Nastaliq, not Naskh. Rubik's Arabic glyphs are Naskh and miss the
   Urdu-specific letters (ٹ ڈ ڑ ں ھ ہ ے), so the ur pages load Noto Nastaliq
   Urdu and put it FIRST in every stack (Rubik first would render most of
   the word in Naskh and only the odd letter in Nastaliq). Nastaliq is a
   steeply diagonal, tall script: it needs roughly double leading, and
   letter-spacing is fatal — added tracking breaks the cursive joins, so it
   is zeroed wholesale, including the label/nav styles' .1em+ values. The
   ur tree is RTL and rides the same [dir="rtl"] rules as Arabic. */
html[lang="ur"] {
  --font-display: "Noto Nastaliq Urdu", "Rubik", ui-sans-serif, system-ui, sans-serif;
  --font-serif:   "Noto Nastaliq Urdu", "Rubik", ui-sans-serif, system-ui, sans-serif;
  --font-mono:    "Noto Nastaliq Urdu", "Rubik", ui-sans-serif, system-ui, sans-serif;
}
html[lang="ur"] body { line-height: 2.05; }
html[lang="ur"] h1, html[lang="ur"] h2, html[lang="ur"] h3 { line-height: 1.9; }
html[lang="ur"] * { letter-spacing: 0 !important; }
/* the tall script clips inside fixed-height pills without this */
html[lang="ur"] .pill, html[lang="ur"] .lang-list a { line-height: 1.8; }
/* Arabic runs on an Urdu page (the العربية autonym in the language menu and
   on the contact form) must NOT inherit Nastaliq — Arabic is set in Naskh,
   which is exactly what Rubik provides. Keyed off lang="ar", so it only
   reaches text actually marked as Arabic. */
html[lang="ur"] [lang="ar"] {
  font-family: "Rubik", ui-sans-serif, system-ui, sans-serif;
  line-height: 1.6;
}

/* CHINESE — LTR, no joining, so the layout needs nothing structural; the
   stacks put Rubik first (it has no CJK, so Latin and digits keep the brand
   face and the hanzi fall through to the CJK fonts) and the body gets CJK
   leading. text-transform/uppercase styles are no-ops on hanzi and the
   existing tracking reads as deliberate air, so both are left alone. */
html[lang="zh"] {
  --font-display: "Rubik", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", ui-sans-serif, system-ui, sans-serif;
  --font-serif:   "Rubik", "Noto Serif SC", "Songti SC", "SimSun", serif;
  --font-mono:    "Rubik", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", ui-sans-serif, system-ui, sans-serif;
}
html[lang="zh"] body { line-height: 1.9; }


/* ═══ §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. */

/* The box is a small key, the same idea as the .pill buttons: it sits on a
   solid edge, tips back and travels down onto it while pressed, and comes
   back up filled. Depth is the edge and a lit top, both box-shadow, so the
   only things that move are transform and the shadow under it.

   Timing is asymmetric on purpose: 110ms down, because the press has to be
   felt under the finger, and 220ms back up on a strong ease-out, because
   that is the system answering. Transitions, not keyframes — a row can be
   ticked and unticked faster than either finishes. */
.opt input[type="checkbox"],
.check-item input[type="checkbox"] {
  --box-edge: color-mix(in srgb, var(--brand-teal) 30%, transparent);
  appearance: none; -webkit-appearance: none;
  width: 24px; height: 24px; flex-shrink: 0;
  margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line-strong);
  border-radius: 7px;
  background: linear-gradient(180deg, #fff 0%, color-mix(in srgb, var(--brand-ice) 34%, #fff) 100%);
  box-shadow: 0 2px 0 var(--box-edge), 0 0 0 0 transparent;
  cursor: pointer;
  outline: none;
  transition:
    transform .22s cubic-bezier(.23, 1, .32, 1),
    box-shadow .22s cubic-bezier(.23, 1, .32, 1),
    background-color .16s ease, border-color .16s ease;
}
.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 {
  --box-edge: var(--brand-forest);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand-teal) 88%, #fff) 0%, var(--brand-teal) 100%);
  border-color: var(--brand-teal);
}
/* 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 — colour
   only: a row is passed over far more often than it is pressed */
@media (hover: hover) and (pointer: fine) {
  .opt:hover input[type="checkbox"],
  .check-item:hover input[type="checkbox"] { border-color: var(--brand-teal); }
}

/* the press: tipped back a few degrees and down onto its edge. Pressing the
   label presses the box, so the whole row is the key. */
.opt:active input[type="checkbox"],
.check-item:active input[type="checkbox"] {
  transform: perspective(140px) rotateX(16deg) translateY(2px) scale(.96);
  box-shadow: 0 0 0 var(--box-edge), 0 0 0 0 transparent;
  transition-duration: .11s;
}

/* focus is a soft halo in the brand teal, not a hard frame. :focus clears
   whatever outline the browser would draw on a click; the halo itself is
   for :focus-visible, so keyboard users always get it. */
.opt input[type="checkbox"]:focus,
.check-item input[type="checkbox"]:focus { outline: none; }
.opt input[type="checkbox"]:focus-visible,
.check-item input[type="checkbox"]:focus-visible {
  border-color: var(--brand-teal);
  box-shadow: 0 2px 0 var(--box-edge), 0 0 0 4px color-mix(in srgb, var(--brand-teal) 22%, transparent);
}

/* 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; }
/* no grey flash over the row on a phone; the box itself answers the tap */
.check-item { -webkit-tap-highlight-color: transparent; }

/* reduced motion keeps the colour change and the halo, and drops the travel */
@media (prefers-reduced-motion: reduce) {
  .opt input[type="checkbox"],
  .check-item input[type="checkbox"] { transition: background-color .16s ease, border-color .16s ease; }
  .opt:active input[type="checkbox"],
  .check-item:active 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);
  }
}


/* ═══ §15 · MOBILE POLISH ═══════════════════════════════════════
   Findings from a 375px sweep of the site, fixed here rather than scattered
   through the sections they belong to, so the phone-only compromises are
   readable in one place.

   The two structural fixes are not here: the header CTA moving into the nav
   panel lives with the nav (§ site chrome), and the hero dots' tap target
   lives with the slider — both because they change how those components are
   built, not just their measurements. */

@media (max-width: 767px) {
  /* 10.5px of letter-spaced uppercase mono is legible on a desktop at arm's
     length and mean on a phone. A half-point back costs no layout. */
  .label, .eyebrow { font-size: 11px; }

  /* Breadcrumb links were 17px tall — under the 24px minimum for a target.
     Padding rather than font-size, so the line still reads as a breadcrumb. */
  .breadcrumb a, .breadcrumb span { padding-block: 5px; display: inline-block; }

  /* Form fields at 36px are usable but tight for a thumb. The font-size is
     already ≥16px sitewide, which is what stops iOS zooming the page on
     focus — do not let it fall below that here.
     Radios and checkboxes are excluded: they are square controls, and a
     blanket min-height turns a 22px radio into a 22×44 oval. */
  .field input:not([type="radio"]):not([type="checkbox"]),
  .field select, .field textarea,
  .form-row input:not([type="radio"]):not([type="checkbox"]),
  .form-row select, .form-row textarea { min-height: 44px; }

  /* Radios were left at the browser's 16px when the checkboxes went to 24
     (§14). Same treatment, same reasoning: a 16px circle is not a target.
     accent-color still does the painting — only the box grows. */
  .opt input[type="radio"] { width: 24px; height: 24px; min-height: 0; }

  /* Give the pills room to breathe when they stack, and stop a long CTA
     label from being squeezed into three lines. */
  .hero-ctas, .prompt-actions { gap: 12px; }
  .hero-ctas .pill, .prompt-actions .pill { width: 100%; justify-content: center; }
}


/* ── The phase finder's heading ───────────────────────────────
   A short phrase beside the card rather than above it, so it takes the
   column's measure and a size between a chapter heading and the question
   it introduces. No line-height here: Urdu sets its own. */
#phase-finder h2 {
  font-size: clamp(1.9rem, 3.3vw, 3.1rem);
  max-width: 13ch;
}

/* ── What counts as an e-invoice (home) ───────────────────────
   Four facts. They were four cards the size of a form, each holding a
   heading and one line, so the section was mostly the inside of empty
   boxes. They are a ruled list now: the question on the start side, the
   four answers down the other, each a row with its mark, its statement,
   the line that qualifies it and the way through to the guide. */
#what-fawtara .chapter-head { margin-bottom: clamp(20px, 3vh, 30px); }
#what-fawtara .chapter-close { margin-top: 0; }
#what-fawtara .chapter-cta { margin-top: clamp(20px, 3vh, 28px); }
.fact-list { margin-top: clamp(28px, 4vh, 40px); border-block-end: 1px solid var(--line); }
.fact {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(14px, 1.6vw, 20px); row-gap: 4px;
  padding-block: clamp(18px, 2.4vh, 24px);
  border-block-start: 1px solid var(--line);
}
/* The rows are met one after another, sixty milliseconds apart, on the
   reveal's own delay variable. Shorter and nearer than the page's other
   reveals, because four of them in a row at full length is a long wait for
   the last. Reduced motion already switches .reveal off. */
.fact.reveal { transition-duration: .4s; }
.fact.reveal:not(.in) { transform: translateY(12px); }
.fact:nth-child(2) { --d: .06s; }
.fact:nth-child(3) { --d: .12s; }
.fact:nth-child(4) { --d: .18s; }
.fact .card-head { grid-row: 1 / span 3; margin: 0; }
.fact .card-num { display: none; }
.fact .card-icon {
  display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--brand-teal) 8%, var(--surface-1));
  color: var(--brand-teal);
}
.fact .card-icon .icon { width: 20px; height: 20px; }
.fact h3 { grid-column: 2; font-size: clamp(1.08rem, 1.4vw, 1.22rem); line-height: 1.3; letter-spacing: -.005em; }
.fact > .serif { grid-column: 2; color: var(--ink-200); font-size: .98rem; max-width: 52ch; }
.fact .card-cta { grid-column: 2; margin-top: 6px; }
.fact .card-cta a {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-display); font-size: .88rem; font-weight: 500; color: var(--brand-teal);
  transition: color .2s cubic-bezier(.23, 1, .32, 1);
}
.fact .card-cta a::after {
  content: ""; width: 7px; height: 7px;
  border-block-start: 1.5px solid currentColor; border-inline-end: 1.5px solid currentColor;
  transform: rotate(45deg); transition: transform .2s cubic-bezier(.23, 1, .32, 1);
}
[dir="rtl"] .fact .card-cta a::after { transform: rotate(-45deg); }
/* Below the width where the link moves to the end of its row it is the last
   line of a block of text, and a line of text is 23px tall: half a touch
   target. The box grows; the words do not move. */
@media (max-width: 959px) {
  .fact .card-cta { margin-top: 0; }
  .fact .card-cta a { min-height: 44px; }
}
.fact .card-cta a:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; border-radius: 2px; }
@media (hover: hover) and (pointer: fine) {
  .fact .card-cta a:hover { color: var(--brand-green); }
  .fact .card-cta a:hover::after { transform: translateX(3px) rotate(45deg); }
  [dir="rtl"] .fact .card-cta a:hover::after { transform: translateX(-3px) rotate(-45deg); }
}
@media (min-width: 960px) {
  #what-fawtara {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(40px, 6vw, 104px); align-content: start;
    grid-template-rows: auto auto 1fr;
  }
  #what-fawtara .chapter-head { grid-column: 1; grid-row: 1; }
  #what-fawtara .chapter-head h2 { font-size: clamp(2rem, 3.4vw, 3.2rem); max-width: 14ch; }
  #what-fawtara .chapter-close { grid-column: 1; grid-row: 2; max-width: 40ch; }
  #what-fawtara .chapter-cta { grid-column: 1; grid-row: 3; align-self: start; }
  #what-fawtara .fact-list { grid-column: 2; grid-row: 1 / span 3; margin-top: 0; }
  /* wide enough for the way through to sit at the end of the row */
  .fact { grid-template-columns: auto minmax(0, 1fr) auto; }
  .fact .card-cta { grid-column: 3; grid-row: 1 / span 2; align-self: center; margin-top: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fact .card-cta a, .fact .card-cta a::after { transition: none; }
}

/* ── The guide (home) ─────────────────────────────────────────
   The cover is the guide's own first page, and it is shown as a document:
   upright, at a size its title can be read at, on a shadow that puts it on
   the desk rather than in the page. What is inside sits beside it as a
   list, so the offer is read in the time it takes to look at the cover. */
.guide-aside { display: grid; gap: clamp(22px, 3vw, 36px); align-items: start; }
.guide-cover { margin: 0; width: min(100%, 250px); }
.guide-cover img {
  display: block; width: 100%; height: auto;
  border-radius: 4px;
  box-shadow: 0 1px 1px rgba(15, 39, 24, .14), 0 10px 18px -8px rgba(15, 39, 24, .3), 0 34px 50px -30px rgba(15, 39, 24, .5);
}
.guide-copy { display: grid; gap: 14px; }
.guide-copy > .serif { color: var(--ink-200); max-width: 46ch; }
.guide-inside-label {
  margin-top: 8px;
  font-family: var(--font-display); font-weight: 600; font-size: .95rem; color: var(--cream-100);
}
.guide-inside { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.guide-inside li {
  position: relative; padding-inline-start: 26px;
  font-family: var(--font-serif); font-size: .97rem; line-height: 1.45; color: var(--ink-200);
}
.guide-inside li::before {
  content: ""; position: absolute; inset-inline-start: 2px; top: .36em;
  width: 11px; height: 6px;
  border-inline-start: 2px solid var(--brand-green); border-block-end: 2px solid var(--brand-green);
  transform: rotate(-45deg);
}
[dir="rtl"] .guide-inside li::before { transform: rotate(45deg); }
/* The offer and the form are two cards of one height. The form is the taller
   of the two by its nature, so the offer is given a panel that stretches to
   meet it and the cover and its list are centred inside: nothing is left
   hanging over an empty half-column. `.guide-aside` is also the name of the
   written guide's sticky contents rail (§ guide-layout), so its position and
   alignment are set back here. */
#guide .guide-aside {
  position: static; align-self: stretch; align-content: center;
  padding: clamp(22px, 3.4vw, 56px);
  border: 1px solid var(--line); border-radius: 16px;
  background: linear-gradient(160deg, color-mix(in srgb, var(--brand-green) 9%, var(--surface-1)), color-mix(in srgb, var(--brand-green) 3%, var(--surface-1)));
}
@media (min-width: 620px) {
  .guide-aside { grid-template-columns: minmax(0, 250px) minmax(0, 1fr); align-items: center; }
}
@media (min-width: 1024px) {
  /* the form at a form's width; the offer takes the rest */
  #guide .form-cols { grid-template-columns: minmax(0, 1fr) minmax(0, clamp(380px, 34vw, 500px)); gap: clamp(18px, 1.8vw, 28px); align-items: stretch; }
}
@media (min-width: 1024px) and (max-width: 1320px) {
  /* too narrow for the cover and its list side by side: the cover goes on top */
  .guide-aside { grid-template-columns: minmax(0, 1fr); }
  .guide-cover { width: min(100%, 210px); }
}
@media (min-width: 1321px) {
  .guide-aside { grid-template-columns: minmax(0, clamp(250px, 21vw, 340px)) minmax(0, 1fr); gap: clamp(28px, 3.6vw, 64px); }
  .guide-cover { width: 100%; }
}

/* ── The 5 Corner Model (compliance §05) ──────────────────────────
   The figure is inline SVG so it reads the tokens below rather than
   baking colours in: change the palette and the diagram follows. It is
   NOT aria-hidden — the arrow labels carry flow names the list beneath
   does not, so the <title>/<desc> pair is the accessible equivalent.

   The drawing is the content and is complete on its own. Everything
   under "explorer" at the foot of this block is selected state, and
   only §17 of main.js can reach it: with scripting off the diagram
   renders whole, every line at full strength, which is its resting
   state anyway.

   It is drawn twice. Across, for a column with room for five corners
   side by side; upright, for one without. The figure is a size container
   and chooses between them by its own width — not the window's, because
   the guide's rail takes a fixed strip out of this column. A browser that
   cannot ask that question shows the wide drawing and lets it scroll
   sideways inside its own box, which is what every browser used to get.

   Neither is allowed to be as large as the column will let it. A diagram
   of five boxes does not get more legible past the size its labels were
   set for; it only gets louder. */
.corner-model { margin-top: clamp(28px, 4vh, 48px); }
.corner-model > h3 { margin-bottom: 10px; }
.corner-model > p.serif { color: var(--ink-200); }

.corner-figure {
  container-type: inline-size;
  margin: clamp(18px, 3vh, 30px) 0 0;
  padding: clamp(16px, 2.2vw, 26px);
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface-1);
}

/* The prompt. One quiet line — it is an offer, not an instruction, and the
   section's own heading has already said what the picture is. */
.cm-intro__hint {
  font-family: var(--font-display); font-size: .84rem;
  color: var(--ink-300); margin: 0 0 clamp(10px, 1.6vw, 18px);
}
.cm-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.cm-canvas {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: 10px;
}
.cm-canvas:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }
.cm-svg { display: block; width: 100%; height: auto; margin-inline: auto; }
.cm-svg--wide { min-width: 620px; max-width: 780px; }
.cm-svg--tall { display: none; max-width: 400px; }
/* 700px is about where the wide drawing's words stop being readable: below it
   the choice is between scrolling sideways and standing the model up. */
@container (max-width: 700px) {
  .cm-svg--wide { display: none; }
  .cm-svg--tall { display: block; }
}

/* ── Corners ──────────────────────────────────────────────────────
   Taxpayers and providers share one restrained treatment; the Authority
   is the only box that carries a tint, because it is the only one every
   other corner reports to — and it carries it as a tint, not as a heavy
   border, so it leads without shouting.

   The weights live on the figure as four tokens rather than being spelled
   out at each rule, because "how loud is this diagram" is one decision and
   ought to be made in one place. They are deliberately light: at rest this
   is a drawing to be read, and the selected state has to have somewhere
   louder to go without reaching for near-black. */
.corner-figure {
  --cm-line:     rgba(22, 100, 135, .42);   /* a connector at rest        */
  --cm-line-on:  var(--brand-teal);         /* and when it is the subject */
  --cm-box:      rgba(22, 100, 135, .16);   /* a corner's edge at rest    */
  --cm-fill:     color-mix(in srgb, var(--brand-teal) 5%, var(--surface-1));
  --cm-box-on:   color-mix(in srgb, var(--brand-teal) 13%, var(--surface-1));
  --cm-ease:     cubic-bezier(.23, 1, .32, 1);
}

/* A corner is a soft tile, not an outlined box: with eight labelled
   routes around them, five hard rectangles were what made the picture
   read as a wiring diagram. The tint does the separating and the edge is
   barely there. */
.cm-node__box {
  fill: var(--cm-fill);
  stroke: var(--cm-box);
  stroke-width: 1;
  transition: fill .2s var(--cm-ease), stroke .2s var(--cm-ease), stroke-width .2s var(--cm-ease);
}
.cm-node--auth .cm-node__box {
  fill: var(--surface-sand);
  stroke: rgba(31, 96, 71, .26);
}
.cm-node__name {
  font-family: var(--font-display); font-weight: 600; font-size: 14px;
  fill: var(--ink-100);
}
.cm-node__role {
  font-family: var(--font-display); font-weight: 400; font-size: 11.5px;
  fill: var(--ink-200);
}
.cm-node__corner {
  font-family: var(--font-display); font-weight: 600; font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase;
  fill: var(--brand-teal); fill-opacity: .8;
}

/* ── Connectors ───────────────────────────────────────────────────
   One weight for every line. The dashes are not decoration: a dashed
   route is an acknowledgement travelling back the way a transmission
   came. The legend says so in words as well, so the distinction is
   never carried by appearance alone. */
.cm-conn__line {
  fill: none;
  stroke: var(--cm-line);
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  marker-end: url(#cm-arrow);
  transition: stroke .2s var(--cm-ease), stroke-width .2s var(--cm-ease);
}
.cm-conn--acknowledgement .cm-conn__line { stroke-dasharray: 5 4; }
/* A wide invisible companion, so a hairline is still a comfortable
   target on a touch screen. */
.cm-conn__hit { fill: none; stroke: transparent; stroke-width: 24; }
/* Drawn once on selection. Solid whatever the route's type, because a
   dash pattern and a travelling dash offset cannot share one path. */
.cm-conn__travel { fill: none; stroke: none; stroke-width: 2; stroke-linecap: round; }

.cm-conn__label {
  font-family: var(--font-display); font-weight: 400; font-size: 11px;
  fill: var(--ink-300);
  /* Knocks the connector out from behind the words. Script replaces this
     with a measured plate; this is what a no-script reader gets, and what
     keeps the labels readable if getBBox is ever refused. */
  paint-order: stroke fill;
  stroke: var(--surface-1);
  stroke-width: 4px;
  stroke-linejoin: round;
  transition: fill .2s var(--cm-ease);
}
.cm-svg.is-plated .cm-conn__label { stroke: none; }
/* The plate is a gap in the line, not a box of its own: it has no edge,
   so the only outlined things in the picture are the five corners. */
.cm-conn__plate { fill: var(--surface-1); }
/* The upright drawing is shown smaller than it is drawn, so its words are
   set a size up to land where the wide drawing's do. */
.cm-svg--tall .cm-node__name { font-size: 15px; }
.cm-svg--tall .cm-node__role { font-size: 12px; }
.cm-svg--tall .cm-node__corner { font-size: 10.5px; }
.cm-svg--tall .cm-conn__label { font-size: 12px; }

/* ── Legend and the sideways-scroll note ──────────────────────────
   The note only appears at the widths where scrolling is actually the
   answer, so it never claims a gesture that does nothing. */
.cm-swipe {
  display: none;
  margin: 10px 0 0;
  font-family: var(--font-display); font-size: .78rem; color: var(--ink-300);
}
.cm-legend {
  display: flex; flex-wrap: wrap; gap: 6px 24px; align-items: center; justify-content: center;
  margin-top: clamp(12px, 1.8vw, 20px);
  font-family: var(--font-display); font-size: .78rem; color: var(--ink-300);
}
.cm-legend__item { display: inline-flex; gap: 9px; align-items: center; }
.cm-legend__rule { width: 28px; height: 8px; flex: none; }
.cm-legend__rule path { fill: none; stroke: var(--brand-teal); stroke-width: 1.5; }
.cm-legend__rule--dashed path { stroke-dasharray: 6 5; }

/* Whether the canvas scrolls depends on the width of this column, not of
   the window — the guide's rail takes a fixed 230px out of it — so the
   viewport query is only the no-script approximation. With script, §17
   measures the canvas and marks the figure, which is the honest answer at
   every width. */
@media (max-width: 760px) {
  .cm-swipe { display: block; }
}
.js .cm-swipe { display: none; }
.js .cm--scrolls .cm-swipe { display: block; }

/* On a phone the card's own padding is the difference between seeing
   three corners and seeing four, so it gives most of it back and lets the
   canvas run to the edges. The diagram itself is not shrunk any further:
   below about 660px of canvas its labels stop being readable, and an
   unreadable diagram that fits is worth less than a readable one that
   scrolls. */
@media (max-width: 520px) {
  .corner-figure { padding: 14px 12px; }
  .cm-legend { gap: 5px 16px; justify-content: flex-start; }
  .cm-panel { padding: 14px 12px; }
}

/* ── Contextual panel ─────────────────────────────────────────────
   Under the diagram, never beside it: this column is narrow enough that
   a side panel would squeeze the drawing below the width its own labels
   need. min-height holds the space across selections so the page does
   not shift under the pointer between one corner and the next. */
.cm-panel {
  margin-top: 12px;
  padding: clamp(14px, 2vw, 20px);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface-1);
}
/* Occasional, and it answers a click: the panel arrives from just under
   the diagram that called it, quickly, and only as a fade for anyone who
   has asked for less motion. */
.cm-panel:not([hidden]) { animation: cm-panel-in .22s var(--cm-ease, cubic-bezier(.23, 1, .32, 1)) both; }
@keyframes cm-panel-in { from { opacity: 0; transform: translateY(6px); } }
.cm-panel__body { min-height: 96px; }
.cm-panel__eyebrow {
  font-family: var(--font-display); font-weight: 600; font-size: .7rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--brand-teal);
  margin: 0 0 3px;
}
.cm-panel__title {
  font-family: var(--font-display); font-weight: 500; font-size: 1.16rem;
  line-height: 1.25; color: var(--cream-100); margin: 0;
}
.cm-panel__role {
  font-family: var(--font-display); font-size: .87rem; color: var(--ink-200);
  margin: 3px 0 0;
}
.cm-panel__cols {
  display: grid; gap: 14px 30px;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--line);
}
.cm-panel__group h5 {
  font-family: var(--font-display); font-weight: 600; font-size: .71rem;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-300);
  margin: 0 0 7px;
}
.cm-panel__value {
  font-family: var(--font-display); font-size: .92rem; line-height: 1.35;
  color: var(--ink-100); margin: 0;
}
.cm-panel__corner {
  display: inline-block; margin-top: 2px;
  font-style: normal; font-family: var(--font-display); font-weight: 600;
  font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--brand-teal);
}
.cm-panel__related { margin-top: 14px; }
.cm-panel__list { list-style: none; display: grid; gap: 3px; margin: 0; padding: 0; }

/* Each route the panel lists is the route itself: choosing one here
   selects it in the drawing, so the panel is a second way in rather
   than a dead index. */
.cm-panel__flow {
  width: 100%; padding: 5px 7px; margin-inline-start: -7px;
  font-family: var(--font-display); font-size: .88rem; line-height: 1.4;
  color: var(--ink-200); text-align: start;
  background: none; border: 0; border-radius: 7px; cursor: pointer;
  display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: baseline;
  transition: background .18s ease, color .18s ease;
}
.cm-panel__flow:hover { background: var(--surface-2); color: var(--ink-100); }
.cm-panel__flow:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 1px; }
.cm-panel__flow em {
  font-style: normal; font-weight: 600; font-size: .68rem;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--brand-teal); white-space: nowrap;
}
.cm-panel__none {
  font-family: var(--font-display); font-size: .88rem; color: var(--ink-300); margin: 0;
}

.cm-link {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 9px; padding: 0;
  font-family: var(--font-display); font-weight: 500; font-size: .85rem;
  color: var(--brand-teal); background: none; border: 0;
  border-bottom: 1px solid var(--line-strong);
  cursor: pointer;
}
.cm-link:hover { color: var(--brand-green); border-bottom-color: var(--brand-green); }
.cm-link:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }

.cm-reset {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 16px; padding: 8px 16px;
  font-family: var(--font-display); font-weight: 500; font-size: .84rem;
  color: var(--ink-100); background: var(--surface-1);
  border: 1px solid var(--line-strong); border-radius: 999px;
  cursor: pointer;
  transition: background .2s ease, border-color .2s ease;
}
.cm-reset:hover { background: var(--surface-2); border-color: var(--brand-teal); }
.cm-reset:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }

@media (min-width: 620px) {
  .cm-panel__cols { grid-template-columns: 1fr 1fr; }
  .cm-panel__cols--three { grid-template-columns: repeat(3, 1fr); }
}

/* ── Explorer state ───────────────────────────────────────────────
   Unreachable until §17 of main.js marks the corners and connectors up
   as buttons, so the resting diagram is the one the markup describes.

   Emphasis is teal — the palette's own accent — and never the forest
   green, which at these weights reads as black and turned a selected
   route into a bar across the picture. The selected line is 2px against
   a 1.25px ground: the difference does the work, not the darkness.

   Faded is 38%: enough to read the whole model through, little enough
   that the chosen route is unmistakable. Nothing is ever hidden. */
.js [data-corner-model] .cm-node,
.js [data-corner-model] .cm-conn { cursor: pointer; }
.js [data-corner-model] .cm-node,
.js [data-corner-model] .cm-conn { transition: opacity .2s var(--cm-ease); }
/* Pressing a corner gives a little before anything else answers. */
.js [data-corner-model] .cm-node__box { transform-box: fill-box; transform-origin: center; }
.js [data-corner-model] .cm-node:active .cm-node__box { transform: scale(.98); transition: transform .12s var(--cm-ease); }

.js .cm-node:focus-visible,
.js .cm-conn:focus-visible { outline: none; }
.js .cm-node:focus-visible .cm-node__box { stroke: var(--cm-line-on); stroke-width: 2.25; }
.js .cm-conn:focus-visible .cm-conn__line { stroke: var(--cm-line-on); stroke-width: 2.25; }

/* Hover is a nudge. It never reveals anything that click and keyboard
   do not also reach. */
@media (hover: hover) and (pointer: fine) {
  .js .cm-node:hover .cm-node__box { stroke: var(--cm-line-on); stroke-width: 1.5; }
  .js .cm-conn:hover .cm-conn__line { stroke: var(--cm-line-on); stroke-width: 1.75; }
  .js .cm-conn:hover .cm-conn__label { fill: var(--brand-teal); }
}

.cm--active .cm-node.is-dim,
.cm--active .cm-conn.is-dim { opacity: .38; }

.cm--active .cm-node.is-on .cm-node__box {
  stroke: var(--cm-line-on);
  stroke-width: 1.75;
}
.cm--active .cm-node.is-on:not(.cm-node--auth) .cm-node__box { fill: var(--cm-box-on); }

.cm--active .cm-conn.is-on .cm-conn__line {
  stroke: var(--cm-line-on);
  stroke-width: 2;
  marker-end: url(#cm-arrow-on);
}
.cm--active .cm-conn.is-on .cm-conn__label { fill: var(--brand-teal); font-weight: 500; }

/* ── "These are clickable" ────────────────────────────────────────
   A diagram that responds to being clicked has to say so, and a line of
   text under a heading is easy to read past. So the five corners take
   one soft sweep, once, the first time the figure comes into view —
   staggered, so it reads as an invitation rather than a fault.

   Once. Not a loop, not a glow, and never again on that page: the class
   is taken off when it finishes and is not put back. */
.cm--invite .cm-nodes .cm-node:nth-child(1) .cm-node__box { animation: cm-invite 1.5s ease-out .0s both; }
.cm--invite .cm-nodes .cm-node:nth-child(2) .cm-node__box { animation: cm-invite 1.5s ease-out .1s both; }
.cm--invite .cm-nodes .cm-node:nth-child(3) .cm-node__box { animation: cm-invite 1.5s ease-out .2s both; }
.cm--invite .cm-nodes .cm-node:nth-child(4) .cm-node__box { animation: cm-invite 1.5s ease-out .3s both; }
.cm--invite .cm-nodes .cm-node:nth-child(5) .cm-node__box { animation: cm-invite 1.5s ease-out .4s both; }
@keyframes cm-invite {
  0%   { stroke: var(--cm-box);     stroke-width: 1; }
  35%  { stroke: var(--cm-line-on); stroke-width: 1.75; }
  100% { stroke: var(--cm-box);     stroke-width: 1; }
}

/* The hint that carries it in words, which is the part that still works
   for anyone who never sees the sweep. */
.cm-intro__hint { display: flex; gap: 7px; align-items: flex-start; justify-content: center; }
@media (max-width: 520px) { .cm-intro__hint { justify-content: flex-start; } }
.cm-intro__cue {
  flex: none; width: 15px; height: 15px; margin-top: 2px;
  color: var(--brand-teal);
}

/* The one animation on selection: the chosen route drawn once, origin to
   destination. pathLength="100" in the markup means every route is 100
   units long, so the same keyframes travel each of them at the same
   apparent speed however far it actually goes. The easing is slow out of
   the gate and long in the tail, which is what stops it reading as a
   switch being thrown. */
.cm-conn.is-travelling .cm-conn__travel {
  stroke: var(--cm-line-on);
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: cm-travel .72s cubic-bezier(.33, 0, .15, 1) forwards;
}
@keyframes cm-travel {
  to { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cm-node__box, .cm-conn__line, .cm-conn__label,
  .cm-node, .cm-conn { transition: none; }
  .cm-conn.is-travelling .cm-conn__travel { animation: none; stroke: none; }
  .cm--invite .cm-nodes .cm-node .cm-node__box { animation: none; }
  .js [data-corner-model] .cm-node:active .cm-node__box { transform: none; }
  .cm-panel:not([hidden]) { animation: cm-panel-fade .2s ease both; }
}
@keyframes cm-panel-fade { from { opacity: 0; } }

.corner-list { list-style: none; display: grid; gap: 12px; }
.corner-list li {
  display: grid; grid-template-columns: auto 1fr; gap: 14px; align-items: start;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-1);
}
.corner-list .corner-badge {
  font-family: var(--font-display); font-weight: 600; font-size: 1.1rem;
  line-height: 1.4; color: transparent;
  -webkit-text-stroke: 1px var(--peach-400);
  flex-shrink: 0;
}
.corner-list p { color: var(--ink-200); }
.corner-list b { color: var(--cream-100); font-weight: 500; }

/* ── The list as the diagram's stepper ────────────────────────────
   With the script (js/main.js §17) the five rows fold into one strip
   under the figure: five numbered stops and the text of the current one.
   The rows give up their boxes (display: contents) so the stops share
   one row and the five texts share one cell — stacked in it, so the
   strip is as tall as the longest and never shifts as they change.

   The text crossfades with a 4px rise; the stop fills. Both are
   transitions, because stops can be pressed faster than either ends. */
.corner-list.is-stepper {
  grid-template-columns: repeat(5, auto) 1fr;
  gap: 0 8px; align-items: center;
  margin-block: 14px 12px;
  padding: 14px 16px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface-1);
}
.corner-list.is-stepper li { display: contents; }
.corner-list.is-stepper .corner-badge {
  grid-row: 1;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--line-strong); border-radius: 50%;
  font-size: .95rem; line-height: 1;
  color: var(--ink-300); -webkit-text-stroke: 0;
  cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease,
    transform .16s cubic-bezier(.23, 1, .32, 1);
}
.corner-list.is-stepper .corner-badge:active { transform: scale(.94); }
.corner-list.is-stepper .corner-badge:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .corner-list.is-stepper .corner-badge:hover { border-color: var(--brand-teal); }
}
.corner-list.is-stepper li.is-current .corner-badge {
  background: var(--brand-teal); border-color: var(--brand-teal); color: #fff;
}
.corner-list.is-stepper p {
  grid-row: 2; grid-column: 1 / -1;
  margin-top: 12px;
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .2s ease, transform .22s cubic-bezier(.23, 1, .32, 1), visibility 0s .2s;
}
.corner-list.is-stepper li.is-current p {
  opacity: 1; visibility: visible; transform: none;
  transition-delay: 0s;
}
@media (prefers-reduced-motion: reduce) {
  .corner-list.is-stepper .corner-badge { transition: background-color .2s ease, border-color .2s ease, color .2s ease; }
  .corner-list.is-stepper .corner-badge:active { transform: none; }
  .corner-list.is-stepper p { transform: none; transition: opacity .2s ease, visibility 0s .2s; }
}
.corner-model > .note-plain { margin-top: clamp(16px, 2.4vh, 24px); }

/* ── Team profile drawer ──────────────────────────────────────────
   Replaces the Framer TeamCardDrawer component with the same behaviour
   built on the site's own tokens: click a card's button, a panel slides
   in from the reading edge with the portrait, bio and links.

   It follows the contact prompt's pattern exactly (§12 in main.js):
   [hidden] + .is-open, focus trapped, Escape closes, focus restored.

   Direction: the panel enters from the edge the language ends on, so
   LTR gets it on the right and RTL on the left. transform is physical,
   so the RTL case is a real override, not a logical property.

   No JS: the drawer is not display:none — it stays in the flow under the
   card as ordinary content, the way the peppol <details> stayed operable. */
.team-scrim {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(15, 39, 24, .42);
  opacity: 0; transition: opacity .45s cubic-bezier(.16,1,.3,1);
}
.team-scrim.is-open { opacity: 1; }

html.js .team-drawer {
  position: fixed; z-index: 91;
  inset-block: 0; inset-inline-end: 0;
  width: min(420px, 92vw);
  background: var(--surface-1);
  border-inline-start: 1px solid var(--line);
  box-shadow: -18px 0 48px -28px rgba(15, 39, 24, .5);
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
html.js [dir="rtl"] .team-drawer,
[dir="rtl"] html.js .team-drawer { transform: translateX(-100%); box-shadow: 18px 0 48px -28px rgba(15, 39, 24, .5); }
html.js .team-drawer.is-open { transform: translateX(0); }

.team-drawer-inner { padding: clamp(22px, 3vw, 34px); display: flex; flex-direction: column; gap: 12px; }
.team-drawer-close {
  align-self: flex-end; background: none; border: 0; cursor: pointer;
  font-size: 1.7rem; line-height: 1; color: var(--ink-200);
  padding: 2px 6px; transition: color .3s;
}
.team-drawer-close:hover { color: var(--peach-300); }
.team-drawer-photo {
  width: 100%; max-width: 240px; height: auto; align-self: center;
  border-radius: 16px; background: linear-gradient(170deg, #eef4f6 0%, #e4edf0 100%);
}
.team-drawer-name { font-size: clamp(1.4rem, 2.2vw, 1.8rem); margin-top: 6px; }
.team-drawer-role { color: var(--ink-300); font-size: .97rem; }
.team-drawer-bio  { color: var(--ink-200); margin-top: 4px; }
.team-social { list-style: none; display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 10px; }
.team-social a {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display); font-size: .9rem; color: var(--brand-teal);
}
.team-social .icon { flex: 0 0 auto; opacity: .8; transition: opacity .3s; }
.team-social a:hover .icon { opacity: 1; }

body.drawer-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  html.js .team-drawer, .team-scrim { transition: none; }
}

/* ── Hero slider control · a folio with a clock in it ─────────────
   Ring, numbered lines, ring — set straight on the hero, with no ground of
   its own. At the foot of the hero the sheet has already faded most of the
   way to the page, so the marks read on it, and without a container they
   belong to the hero rather than floating over it.

   The index is a folio: each slide is its number and a 2px line. The slide
   showing has the long line and the dark numeral, and its line is the
   slider's clock — it fills in the accent over the seven seconds the slide
   is held, so the control says when the picture will change instead of
   changing it by surprise. The numbers are CSS counters, so the markup the
   script writes is untouched.

   The clock keeps the script's time without being told it. The script stops
   the slider while the pointer or the focus is inside it and starts the hold
   again from nothing when they leave; the fill is switched off under the
   same two conditions, which shows the line whole while the slider is held
   and restarts it from nothing on the way out. --hero-hold is HOLD in
   main.js §10. A visitor who asked for stillness gets no autoplay from the
   script and no clock here: the line is simply whole.

   The arrows are glass buttons: a white veil the picture shows through,
   blurred, with a lit top edge and a soft cast shadow, so each sits a little
   proud of the hero and reads as something to press. It is the secondary
   pill's glass (§14), at a button's size. On hover it lifts a pixel, brightens
   and takes a faint ring of the accent, and the chevron leans the way it
   points; pressed, it goes down into its shadow, as the site's pills do. The
   lean is by `translate` so it composes with the mirror the right-to-left
   pages put on the glyph. They are shown on a phone too.

   The rail spans the hero and is pointer-transparent so it cannot swallow
   clicks meant for the copy; only the control takes pointer events. Where
   the control sits is set with the hero's own geometry, in §8.2a and §8.2c. */
.hero-rail {
  position: absolute; inset: 0; z-index: 4;
  pointer-events: none;
}
.hero-controls {
  --hero-hold: 7s;
  --hero-mark: color-mix(in srgb, var(--brand-navy) 26%, transparent);
  position: absolute; top: auto; inset-block-end: clamp(64px, 9vh, 96px); inset-inline: 0;
  width: max-content;
  margin-inline: auto;
  pointer-events: auto;
  /* flex, not inline-flex: an inline-level box ignores margin-inline:auto,
     which is what centres the control inside the rail. */
  display: flex; align-items: center; gap: 16px;
}
.hero-arrow {
  display: inline-flex;
  width: 40px; height: 40px;
  border: 1px solid rgba(255, 255, 255, .78); border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .82) 0%, rgba(255, 255, 255, .48) 100%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  backdrop-filter: blur(10px) saturate(150%);
  color: var(--brand-forest);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(15, 39, 24, .07),
    0 0 0 1px rgba(15, 39, 24, .07),
    0 1px 2px rgba(15, 39, 24, .10),
    0 10px 20px -10px rgba(15, 39, 24, .42);
  transition:
    translate .2s cubic-bezier(.16, 1, .3, 1), box-shadow .2s ease,
    background .2s ease, color .2s ease, border-color .2s ease;
}
.hero-arrow svg {
  width: 15px; height: 15px; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
  transition: translate .22s cubic-bezier(.16, 1, .3, 1);
}
@media (hover: hover) {
  .hero-arrow:hover {
    translate: 0 -1px;
    background: linear-gradient(180deg, rgba(255, 255, 255, .96) 0%, rgba(255, 255, 255, .7) 100%);
    border-color: #fff; color: var(--brand-teal);
    box-shadow:
      inset 0 1px 0 #fff,
      inset 0 -1px 0 rgba(15, 39, 24, .07),
      0 0 0 1px color-mix(in srgb, var(--brand-teal) 26%, transparent),
      0 0 0 5px color-mix(in srgb, var(--brand-teal) 9%, transparent),
      0 2px 3px rgba(15, 39, 24, .10),
      0 14px 24px -10px rgba(15, 39, 24, .46);
  }
  .hero-arrow[data-hero-prev]:hover svg { translate: -2px 0; }
  .hero-arrow[data-hero-next]:hover svg { translate: 2px 0; }
  [dir="rtl"] .hero-arrow[data-hero-prev]:hover svg { translate: 2px 0; }
  [dir="rtl"] .hero-arrow[data-hero-next]:hover svg { translate: -2px 0; }
  .hero-dots button:hover { color: var(--brand-forest); }
  .hero-dots button:hover::after { background-color: color-mix(in srgb, var(--brand-navy) 50%, transparent); }
}
/* pressed: down into its shadow */
.hero-arrow:active {
  translate: 0 1px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .7) 0%, rgba(255, 255, 255, .56) 100%);
  box-shadow:
    inset 0 1px 2px rgba(15, 39, 24, .14),
    0 0 0 1px rgba(15, 39, 24, .09),
    0 1px 1px rgba(15, 39, 24, .08);
}

.hero-dots { gap: 14px; padding-inline: 0; counter-reset: hero-slide; }
.hero-dots li { counter-increment: hero-slide; }
.hero-dots button,
.hero-dots button[aria-current="true"] {
  display: inline-flex; align-items: center; gap: 9px;
  width: auto; height: auto; padding: 13px 2px;
  background: none; border-radius: 8px;
  color: color-mix(in srgb, var(--brand-navy) 52%, transparent);
  transition: color .3s ease;
}
.hero-dots button[aria-current="true"] { color: var(--brand-forest); }
/* the numeral — Rubik by name: the Urdu pages swap every family for Nastaliq */
.hero-dots button::before {
  content: counter(hero-slide, decimal-leading-zero);
  font: 500 11px/1 "Rubik", ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .1em; font-variant-numeric: tabular-nums;
}
/* the line: a track, and over it the fill that is the clock */
.hero-dots button::after {
  content: ""; display: block;
  width: 20px; height: 2px; border-radius: 999px;
  background: linear-gradient(var(--brand-teal), var(--brand-teal)) no-repeat 0 0 / 0% 100% var(--hero-mark);
  transition: width .34s cubic-bezier(.16, 1, .3, 1), background-color .3s ease;
}
[dir="rtl"] .hero-dots button::after { background-position: 100% 0; }
.hero-dots button[aria-current="true"]::after { width: 56px; background-size: 100% 100%; }
@media (prefers-reduced-motion: no-preference) {
  .hero-slider:not(:hover):not(:focus-within) .hero-dots button[aria-current="true"]::after {
    animation: hero-hold var(--hero-hold) linear both;
  }
}
@keyframes hero-hold { from { background-size: 0% 100%; } to { background-size: 100% 100%; } }
.hero-dots button:focus-visible { outline-offset: -3px; }
.hero-arrow:focus-visible { outline-offset: 3px; }

@media (max-width: 1023px) {
  .hero-controls { gap: 12px; }
  .hero-dots { gap: 10px; }
}
@media (max-width: 767px) {
  .hero-arrow { width: 40px; height: 40px; }
  .hero-dots button,
  .hero-dots button[aria-current="true"] { padding-block: 15px; }
  .hero-dots button[aria-current="true"]::after { width: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-arrow, .hero-arrow svg, .hero-dots button::after { transition: none; }
  .hero-arrow:hover, .hero-arrow:active { translate: none; }
}

/* ── Mobile tap targets ───────────────────────────────────────────
   Touch guidance is a 44px minimum. Audited at 375px: the pill buttons
   land at ~39px and the team card's profile button at 26px. Both grow
   here by padding, so the visible shape is unchanged and only the hit
   area moves — the same trick the hero dots already use. */
@media (max-width: 767px) {
  .pill { min-height: 44px; }
}
}

/* ── 8.2b · Hero slide alignment ──────────────────────────────
   The dashboard offers each slide a side for its copy ("image right, text
   left" and the reverse). Nothing in the original stylesheet acted on it,
   so the control existed but changed nothing. The hero photograph is
   full-bleed rather than a column, so the side that can actually move is the
   copy block: `right` keeps the published default, `left` sends the copy to
   the opposite edge. Written with logical properties so it follows the
   language rather than fighting [dir="rtl"]. */
.hero-slide[data-align="left"] .hero-content { align-items: flex-end; text-align: end; }
.hero-slide[data-align="left"] .hero-ctas    { justify-content: flex-end; }
.hero-slide[data-align="left"] .hero-art::after { background-position: 18% 46%; }
[dir="rtl"] .hero-slide[data-align="left"] .hero-art::after { background-position: 82% 46%; }

/* ── 8.2a · The hero's picture on a phone ─────────────────────
   The hero's pictures are wide sheets with the drawing in the bottom corner
   at the end of the line and bare paper everywhere else, which is what lets
   the headline sit on them at desktop widths. A phone's hero is a tall
   column, and `object-fit: cover` filled it with the middle of the sheet —
   the bare paper — so on a phone there was no picture at all.

   Below 600px (where the hero stops being a wide box, see --hero-h) the
   picture is cropped to the drawing instead and given a band of its own at
   the head of the hero, above the words rather than behind them, so it is
   the first thing on the screen and nothing is ever set over it:

     · the sheet is set 230vw wide and pinned to the bottom end corner, so the
       third of it that holds the drawing fills most of the screen and its
       soft edge has room to run out into the page. `inset-inline-end`
       follows the language, and so do the pictures: the right-to-left ones
       are drawn mirrored, with the drawing on the left
     · the band is 70vw tall, which is the whole drawing and stops just short
       of the brand mark printed above it — the header a few pixels up
       already carries the mark
     · the band fades in under the header and out at its foot, so the drawing
       dissolves into the page instead of sitting in a box

   The slides are stacked in one grid cell rather than absolutely, so the
   hero is as tall as its longest slide. Before, a slide with more to say
   than the screen had room for ran on underneath the next section. And the
   slide control sits at the foot of the hero rather than riding the bottom
   of the screen, where on a hero taller than the screen it lay across the
   buttons. */
@media (max-width: 599px) {
  html.js .hero-slides { display: grid; }
  html.js .hero-slide { position: relative; inset: auto; grid-area: 1 / 1; }

  .hero-media {
    inset: var(--chrome-h) 0 auto 0; height: 70vw;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 14%, #000 76%, transparent 100%);
            mask-image: linear-gradient(180deg, transparent 0%, #000 14%, #000 76%, transparent 100%);
  }
  .hero-media .hero-video {
    inset: auto; inset-block-end: 0; inset-inline-end: 0;
    /* A ratio rather than `height: auto`: a lazy picture with no height yet
       has no box, and a picture with no box is never asked for — the second
       slide's stayed unloaded. Most sheets are 16:9; a wider one (the port
       is 2.5:1) is fitted to the same width and set on the same corner.
       `cover` would fit it to the box's height instead, which enlarges it
       by half again and takes the mountains off the top of the band. */
    width: 230vw; max-width: none; height: auto; aspect-ratio: 16 / 9;
    object-fit: contain; object-position: 100% 100%; background: none;
  }
  [dir="rtl"] .hero-media .hero-video { object-position: 0% 100%; }
  /* The brand ground is what a slide shows when it has no picture. Behind a
     picture that is still arriving it showed through this band as a mark the
     width of the screen; bare paper is the better thing to wait on. */
  .hero-art:has(+ .hero-video) { display: none; }
  /* the scrim is there to keep words legible over a picture; there are none
     over this one */
  .hero-media .hero-scrim { background: none; }

  .hero-content {
    justify-content: flex-start;
    padding-top: calc(var(--chrome-h) + 70vw - 6px);
    padding-bottom: 104px;
  }
  .hero-controls {
    position: absolute; top: auto; inset-block-end: 26px; inset-inline: 0;
  }
}

/* ── 8.2c · The hero is as tall as what it says ───────────────
   Above 600px the hero took its height from the picture: 56.25vw, the whole
   16:9 sheet, so that none of it was cropped (see --hero-h). The copy sits at
   the foot of that box, so everything the box had over the copy's own height
   became bare paper between the header and the first line — 170px of it on a
   1700px window, more on a taller one — and every change to the copy or the
   chrome moved it again. The top of every sheet is bare paper by design, so
   that is the part to crop.

   The hero now takes its height from the copy instead: a fixed clearance
   under the chrome, the longest slide, and the room the control needs
   beneath. The slides are stacked in one grid cell, as on a phone, so the
   longest sets the height and the others share it. The picture is pinned to
   its bottom edge, where the drawing is, and loses only its top.

   The floor of 34vw is the drawing's own height on the sheet (its lower
   half, a little over 29vw), so a very wide window with short copy still
   shows all of it. The control sits at the foot of the hero rather than
   riding the bottom of the screen: the hero is now shorter than the screen,
   and there is no distance left for it to travel. */
@media (min-width: 600px) {
  .hero, .hero-slides { min-height: 0; }
  html.js .hero-slides { display: grid; }
  html.js .hero-slide { position: relative; inset: auto; grid-area: 1 / 1; }

  .hero-content {
    min-height: min(34vw, 100dvh);
    padding-top: calc(var(--chrome-h) + clamp(28px, 5vh, 56px));
  }
  /* Pinned to the corner the drawing is in, not just the foot: a sheet wider
     than the hero (the port is 2.5:1) loses its sides, and the side to lose
     is the bare one. The right-to-left sheets are drawn mirrored. */
  .hero-media .hero-video { object-position: 100% 100%; }
  [dir="rtl"] .hero-media .hero-video { object-position: 0% 100%; }
}
/* The words get the head of the hero, and the picture starts under them.
   Two small moves, in opposite directions, at the widths where the drawing is
   large enough to run into the headline:

     · the sheet begins a short margin below the chrome instead of behind it,
       and comes in from nothing (the standing mask starts a third opaque,
       which behind the chrome was never seen and below it would be a line).
       That leaves a band of the page's own cream under the header, and the
       copy starts in it, closer to the header than before
     · the hero is given --hero-drop more at its foot. The picture is pinned
       to the foot, so the drawing moves down by that much and the headline
       by none of it

   Together they take the range's ridge off the end of the headline. Neither
   is large: the hero ends up some 30px taller than the copy alone made it. */
@media (min-width: 1024px) {
  .hero { --hero-chrome: calc(var(--chrome-h) + 34px); --hero-drop: clamp(32px, 5.5vh, 60px); }

  .hero-media {
    inset-block-start: calc(var(--hero-chrome) + clamp(16px, 2.6vh, 28px));
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.55) 9%, #000 24%, #000 55%, rgba(0,0,0,.74) 75%, rgba(0,0,0,.34) 88%, rgba(0,0,0,.10) 96%, transparent 100%);
            mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.55) 9%, #000 24%, #000 55%, rgba(0,0,0,.74) 75%, rgba(0,0,0,.34) 88%, rgba(0,0,0,.10) 96%, transparent 100%);
  }
  /* the chrome is the header and the 34px contact bar above it */
  .hero-content {
    padding-top: calc(var(--hero-chrome) + clamp(28px, 4.4vh, 44px));
    padding-bottom: calc(16vh + var(--hero-drop));
  }
}

/* ── 8.3 · Campaign strip and article cover ───────────────────
   A band across the very top of the site, above the fixed chrome, carrying
   whatever campaign is running.

   Sand rather than ice, which is the one warm note in the palette and the
   only ground on the site that is neither the page nor the chrome. That is
   the point: it has to read as an announcement sitting above the site rather
   than as a piece of the header, and against the green and navy chrome
   directly below it a warm band separates cleanly where another cool one
   would smear. Flat sand, though — the band is forty pixels tall, and a
   gradient across something that thin only reads as a stain.

   It says one thing and offers one thing: the message in the weight of
   running text, and what to do about it as a small solid pill. The message
   used to be set bold with the action as an underlined, letter-spaced
   caption beside it, which made the announcement shout and the link whisper.

   Sticky rather than fixed, and in flow. In flow, it pushes the page down by
   its own height, which is the same distance the chrome moves — so the gap
   between the header and the first line of every page is unchanged and no
   page needed its top spacing touched. Sticky, so it stays put as the reader
   scrolls and the chrome never has a strip-shaped hole above it.

   In flow is what makes the height forgiving. Only the chrome has to be told
   how tall the band is; the page is pushed down by the band itself, so a
   message that wraps to two lines cannot land on top of anything.

   Logical properties throughout, so it mirrors with the language instead of
   needing an [dir="rtl"] twin. */

/* The band's height, which the fixed chrome below has to clear. The default
   is one line at every width the type is set at; js/main.js §15b replaces it
   with the measured height, which only differs when a long message wraps.
   With scripting off the default stands, so the worst a long line costs is a
   few pixels of overlap between the band and the header. */
:root { --strip-h: 42px; }

.campaign-strip {
  position: sticky; top: 0; z-index: 60;
  background: var(--surface-sand);
  border-block-end: 1px solid rgba(120, 86, 40, .22);
}

/* The chrome is fixed to the top of the viewport. With a strip above it, it
   starts below the strip instead.

   A sibling selector rather than a class on <body>: the strip is spliced in
   as the chrome's preceding sibling on every page, converted or not, so this
   applies exactly when there is a strip and nothing has to remember to mark
   the page as carrying one. */
.campaign-strip ~ .site-chrome { top: var(--strip-h); }

.campaign-strip-item { position: relative; }
.campaign-strip-item[hidden] { display: none; }

.campaign-strip-face {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 6px 14px;
  min-height: 42px;
  /* The inline padding clears the close button at both edges, so a long
     message centres on the band rather than on the space left over. */
  padding: 7px clamp(46px, 9vw, 92px);
  color: var(--brand-forest);
  text-align: center;
}

a.campaign-strip-face:focus-visible { outline: 2px solid var(--brand-forest); outline-offset: -3px; }

.campaign-strip-text {
  margin: 0;
  font-family: var(--font-display);
  font-size: .875rem;
  font-weight: 500;
  line-height: 1.4;
  text-wrap: balance;
}

/* Sand on forest is 11.5:1, so the pill can be this small and still be read
   in passing. It is the band's only solid shape, which is what makes it the
   thing to press. */
.campaign-strip-cta {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 4px 11px 4px 13px;
  border-radius: 999px;
  background: var(--brand-forest); color: var(--surface-sand);
  font-family: var(--font-display); font-size: .76rem; font-weight: 600; line-height: 1.4;
  transition: background-color .2s cubic-bezier(.23, 1, .32, 1);
}
.campaign-strip-cta svg { width: 12px; height: 12px; transition: transform .2s cubic-bezier(.23, 1, .32, 1); }
/* The arrow points the way the language runs. */
[dir="rtl"] .campaign-strip-cta svg { transform: scaleX(-1); }

@media (hover: hover) and (pointer: fine) {
  a.campaign-strip-face:hover .campaign-strip-cta { background: var(--brand-green); }
  a.campaign-strip-face:hover .campaign-strip-cta svg { transform: translateX(2px); }
  [dir="rtl"] a.campaign-strip-face:hover .campaign-strip-cta svg { transform: scaleX(-1) translateX(2px); }
}

.campaign-strip-close {
  position: absolute;
  inset-block-start: 50%; inset-inline-end: clamp(6px, 1.6vw, 16px);
  transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  background: transparent; border: 0; border-radius: 999px;
  color: color-mix(in srgb, var(--brand-forest) 62%, transparent);
  cursor: pointer;
  transition: background-color .2s, color .2s;
}
/* The mark stays 30px, because it is a quiet dismissal rather than the thing
   to press. The thumb gets 44 either side of it: a band at the top of every
   page, missed on a phone, is pressed again — and the second press lands on
   whatever the band was covering. */
.campaign-strip-close::after {
  content: ""; position: absolute; inset: 50% auto auto 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.campaign-strip-close svg { width: 14px; height: 14px; }
.campaign-strip-close:hover { background: rgba(15, 39, 24, .09); color: var(--brand-forest); }
.campaign-strip-close:focus-visible { outline: 2px solid var(--brand-forest); outline-offset: 1px; }
/* On a phone the band kept room for the close button on both sides, which
   left a long message a column half the screen wide and ran it to three
   lines and a hundred pixels. Only the end has a button to clear. */
@media (max-width: 560px) {
  .campaign-strip-face { padding-inline: 14px 44px; gap: 6px 10px; }
  .campaign-strip-text { font-size: .8rem; }
}

@media (prefers-reduced-motion: reduce) {
  .campaign-strip-cta, .campaign-strip-cta svg { transition: none; }
  a.campaign-strip-face:hover .campaign-strip-cta svg { transform: none; }
  [dir="rtl"] a.campaign-strip-face:hover .campaign-strip-cta svg { transform: scaleX(-1); }
}

/* Article and campaign cover image. Sits above the prose column and matches
   its measure, so the picture and the text share one left edge. */
.article-cover {
  position: relative; isolation: isolate; overflow: hidden;
  margin: 0 0 clamp(24px, 4vh, 40px); max-width: 76ch;
  border-radius: 14px 14px 0 0;
}
.article-cover img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9; object-fit: cover;
  /* Every cover is given the same quieter register, whatever it was made
     with: a little colour and contrast taken out, so a rendered picture sits
     with the site's watercolours instead of shining out of the page. */
  filter: saturate(.78) contrast(.93) brightness(1.03);
}
/* …and the same wash over it: the hero's sand and ice laid across at a low
   strength, a thin veil of the page's cream, and the foot dissolved into the
   page as the hero's is, so the picture has no bottom edge. The fade starts
   late — diagrams in these pictures carry labels four-fifths of the way down. */
.article-cover::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg, transparent 78%, color-mix(in srgb, var(--bg) 62%, transparent) 92%, var(--bg) 100%),
    linear-gradient(120deg, color-mix(in srgb, var(--brand-sand) 26%, transparent) 0%, transparent 46%, color-mix(in srgb, var(--brand-ice) 24%, transparent) 100%),
    color-mix(in srgb, var(--bg) 9%, transparent);
}

/* ══════════════════ LEGAL PAGES ══════════════════
   The privacy policy and the terms were a column of text on the page's bare
   ground. They are documents, so they are set as one: a sheet of the site's
   white on the cream, with the hairline and soft shadow its cards have, and
   each clause numbered, because a clause is something people are sent to
   ("see 7") and a number is how they find it. The numbers are counters, so
   the text itself is untouched and every language gets them. */
.legal-doc .prose {
  max-width: 78ch; margin-inline: auto;
  padding: clamp(24px, 4.4vw, 60px);
  background: var(--surface-1);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 1px 2px rgba(15, 39, 24, .04), 0 26px 50px -36px rgba(15, 39, 24, .38);
  counter-reset: clause;
}
.legal-doc .prose > p:first-of-type { font-size: 1.12rem; color: var(--ink-100); }
.legal-doc .prose h3 {
  counter-increment: clause;
  display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 14px; align-items: baseline;
  max-width: none;
  margin-block: 2.1em .6em; padding-block-start: 1.5em;
  border-block-start: 1px solid var(--line);
  font-size: clamp(1.12rem, 1.5vw, 1.3rem);
}
.legal-doc .prose h3::before {
  content: counter(clause, decimal-leading-zero);
  font: 600 .78rem/1 "Rubik", ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .08em; font-variant-numeric: tabular-nums;
  color: var(--brand-green);
}
.legal-doc .prose p { font-size: 1.02rem; }

/* A published legal document has its own page (views/legal/show): the same
   sheet, under a plain bar with the mark and the way home instead of the
   site's full header. The summary, when there is one, opens the sheet. */
.legal-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 16px 6vw;
  background: var(--brand-navy);
}
.legal-bar__home img { display: block; height: 34px; width: auto; }
.legal-bar__back {
  font-family: var(--font-display); font-size: .9rem; font-weight: 500;
  color: #fff; opacity: .86; transition: opacity .2s ease;
}
.legal-bar__back:hover { opacity: 1; text-decoration: underline; text-underline-offset: 4px; }
.legal-bar a:focus-visible { outline: 2px solid var(--brand-sand); outline-offset: 4px; border-radius: 4px; }
.legal-hero { padding-top: clamp(40px, 8vh, 84px); }
.legal-hero .page-title { margin-top: 0; }
.legal-page .legal-doc { padding-top: 0; }
.legal-summary {
  padding: 16px 20px; border-radius: 12px;
  background: color-mix(in srgb, var(--brand-green) 7%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--brand-green) 22%, transparent);
}
.legal-foot { padding: 0 6vw clamp(40px, 8vh, 80px); text-align: center; color: var(--ink-300); }
.legal-foot a { color: var(--brand-teal); text-decoration: underline; text-underline-offset: 3px; }

/* four cards that are two pairs (the compliance page's where-you-stand) */
@media (min-width: 621px) { .int-grid--pair { grid-template-columns: repeat(2, 1fr); } }

/* the security page's eight measures, as the same card: its heading is an
   h2 there (the page has no chapter heading above them) at the card's size */
.sec-grid h2.int-card__name { font-size: 1.1rem; line-height: 1.28; }

/* ══════════════════ PLATFORM ══════════════════
   The platform page is set in the integrations page's language: its card,
   its monogram square, its filter bar. It was seventeen identical boxes of a
   heading and a paragraph, fourteen of them in one grid with nothing to
   tell them apart.

   The five steps of the flow are the page's key. Each has a mark, and each
   capability's card carries the mark and the name of the step it belongs
   to, so the grid can be read by step and filtered by step with the bar the
   integrations page already has. */

/* a mark in the monogram square, where a system has its initials */
/* The mark is alone in its square, so it gives up the margin and the baseline
   shift .ic carries for sitting beside a word: with them it stood three
   pixels off the square's centre, towards the start of the line. */
.int-mono .ic { width: 20px; height: 20px; margin: 0; vertical-align: 0; }

/* a card that is not a link: the same card, with a line of text where a
   system card has its chips */
.plat-card .int-card__name { font-size: 1.1rem; line-height: 1.28; }
.plat-card .int-card__head { align-items: center; }
.plat-card .int-card__line { margin-top: 14px; }
/* …and the same answer to the pointer as a system card on the integrations
   page: it lifts two pixels onto a deeper shadow, its edge takes the accent,
   and its mark's square fills with the accent and turns the mark white. The
   accent is the card's own (--cat) where it has one, as the platform's
   capabilities do, and the brand green where it has not. Nothing is behind
   the hover — these cards lead nowhere — so it is a response, not a door,
   and there is no pressed state. */
@media (hover: hover) and (pointer: fine) {
  .plat-card:hover {
    translate: 0 -2px; box-shadow: var(--card-shadow-hover);
    border-color: color-mix(in srgb, var(--cat, var(--brand-green)) 45%, var(--line));
  }
  .plat-card:hover .int-mono {
    background: var(--cat, var(--brand-green));
    border-color: var(--cat, var(--brand-green));
    color: #fff;
  }
}
@media (prefers-reduced-motion: reduce) {
  .plat-card:hover { translate: none; }
}

/* Each capability has its own mark (Lucide, in the sprite), and the step it
   belongs to is carried by colour instead: one quiet accent per step, on the
   mark's square here and on the step's own square in the flow above, so the
   two still read as one key. The accents are close neighbours on purpose —
   blue-green, muted blue, green, teal, deep green — so fourteen cards read as
   one set with five shades, not as five kinds of card.

   The square is tinted with its accent and edged with a hairline of it; the
   mark is the accent deepened towards the forest green. On hover the square
   fills with the accent and the mark turns white (see .plat-card:hover). */
#capabilities .plat-card, #flow .flow-step { --cat: var(--brand-green); }
#capabilities .plat-card[data-cat="connect"],  #flow .flow-step:nth-child(1) { --cat: #2a7d80; }
#capabilities .plat-card[data-cat="map"],      #flow .flow-step:nth-child(2) { --cat: #486f97; }
#capabilities .plat-card[data-cat="validate"], #flow .flow-step:nth-child(3) { --cat: var(--brand-green); }
#capabilities .plat-card[data-cat="exchange"], #flow .flow-step:nth-child(4) { --cat: var(--brand-teal); }
#capabilities .plat-card[data-cat="archive"],  #flow .flow-step:nth-child(5) { --cat: #34534a; }
#capabilities .plat-card .int-mono, #flow .flow-step .int-mono {
  width: 46px; height: 46px; border-radius: 13px;
  background: color-mix(in srgb, var(--cat) 9%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--cat) 20%, transparent);
  color: color-mix(in srgb, var(--cat) 78%, var(--brand-forest));
  transition: translate .2s cubic-bezier(.16, 1, .3, 1), background .2s ease, color .2s ease, border-color .2s ease;
}
#capabilities .plat-card .int-mono .ic { width: 22px; height: 22px; }
#capabilities .plat-card .int-card__cat { color: color-mix(in srgb, var(--cat) 78%, var(--brand-forest)); }
/* the id above outranks .plat-card:hover, so the fill is restated at its weight */
@media (hover: hover) and (pointer: fine) {
  #capabilities .plat-card:hover .int-mono { background: var(--cat); border-color: var(--cat); color: #fff; }
}
@media (prefers-reduced-motion: reduce) {
  #capabilities .plat-card .int-mono { transition: none; }
}

/* The compliance guide's four positions take the same square, and the accent
   says which kind of position it is: confirmed (green), waiting for a date
   (muted blue), outside for now (slate), and the risk of leaving it late
   (terracotta, not an alarm red — it is a caution, not an error). Only the
   mark's square is coloured; the eyebrow and the copy stay as they are. */
#where-you-stand .plat-card[data-status="in-scope"] { --cat: var(--brand-green); }
#where-you-stand .plat-card[data-status="pending"]  { --cat: #486f97; }
#where-you-stand .plat-card[data-status="outside"]  { --cat: #5c6f6a; }
#where-you-stand .plat-card[data-status="risk"]     { --cat: #a8523c; }
#where-you-stand .plat-card .int-mono {
  width: 46px; height: 46px; border-radius: 13px;
  background: color-mix(in srgb, var(--cat) 9%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--cat) 22%, transparent);
  color: color-mix(in srgb, var(--cat) 86%, var(--brand-forest));
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
#where-you-stand .plat-card .int-mono .ic { width: 23px; height: 23px; }
@media (hover: hover) and (pointer: fine) {
  #where-you-stand .plat-card:hover .int-mono { background: var(--cat); border-color: var(--cat); color: #fff; }
}
@media (prefers-reduced-motion: reduce) {
  #where-you-stand .plat-card .int-mono { transition: none; }
}

/* The flow: five steps on one line, joined through their marks. Below the
   width where five columns hold their text, the line turns and runs down
   the marks instead. */
.flow-steps {
  list-style: none; margin: clamp(28px, 4vh, 44px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0 clamp(18px, 2.2vw, 34px);
}
.flow-step { position: relative; display: grid; align-content: start; gap: 6px; }
.flow-step .int-mono { position: relative; z-index: 1; margin-block-end: 12px; background: var(--surface-1); border: 1px solid var(--line); }
.flow-step::before {
  content: ""; position: absolute; top: 23px;
  inset-inline: 46px calc(-1 * clamp(18px, 2.2vw, 34px));
  block-size: 1px; background: var(--line-strong);
}
.flow-step:last-child::before { display: none; }
.flow-step:nth-child(2) { --d: .06s; }
.flow-step:nth-child(3) { --d: .12s; }
.flow-step:nth-child(4) { --d: .18s; }
.flow-step:nth-child(5) { --d: .24s; }
.flow-step__name {
  font-family: var(--font-display); font-weight: 600; font-size: 1.14rem; line-height: 1.25;
  color: var(--cream-100);
}
.flow-step > .serif { color: var(--ink-200); font-size: .96rem; line-height: 1.55; }
@media (max-width: 1023px) {
  .flow-steps { grid-template-columns: 1fr; gap: 0; }
  .flow-step {
    grid-template-columns: 46px minmax(0, 1fr); column-gap: 18px;
    padding-block-end: clamp(22px, 3.4vh, 30px);
  }
  .flow-step .int-mono { grid-row: 1 / span 2; margin: 0; }
  .flow-step__name { align-self: end; }
  .flow-step > .serif { grid-column: 2; }
  .flow-step::before {
    top: 46px; bottom: 0; inset-inline: 23px auto;
    inline-size: 1px; block-size: auto;
  }
}

/* The same line with four steps on it (the services page's path). The mark
   is the step's number here, because the order is the point. */
@media (min-width: 1024px) {
  .flow-steps--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.flow-steps--4 .int-mono { font-size: 15px; color: var(--brand-green); }

/* The services page sets its second line in the home page's quieter card,
   with the same ticked points; on white the tick takes the green, since the
   sand it has on the green band would not be seen. */
.svc-aside .svc-points { margin-top: clamp(12px, 1.8vh, 18px); }
.svc-aside .svc-points li { font-size: .97rem; }
.svc-aside .svc-points li::before { border-color: var(--brand-green); }

/* Reports: the heading beside the list */
.plat-split { display: grid; gap: clamp(22px, 4vw, 64px); align-items: start; }
.plat-split .chapter-head { margin-bottom: 0; }
.plat-reports { padding: clamp(22px, 2.6vw, 34px); }
.plat-reports .guide-inside { gap: 0; }
.plat-reports .guide-inside li { padding-block: 13px; font-size: 1.02rem; }
.plat-reports .guide-inside li::before { top: calc(13px + .36em); }
.plat-reports .guide-inside li + li { border-block-start: 1px solid var(--line); }
.plat-reports .guide-inside li:first-child { padding-block-start: 0; }
.plat-reports .guide-inside li:first-child::before { top: .36em; }
.plat-reports .guide-inside li:last-child { padding-block-end: 0; }
@media (min-width: 1024px) {
  .plat-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
}

/* ══════════════════ RESOURCES · ARTICLE CARDS ══════════════════
   The articles were a list of titles on a navy band. They have covers now,
   and the covers are all made the same way and look it: eleven in one grid
   read as eleven of the same picture. So the page shows three pictures and
   shows each differently.

     · one article across the page, its cover as the article page shows it
       (the quieter register of .article-cover, keeping its foot)
     · two as a pair, each cover cropped to its head and printed in one ink
       on the ice ground, so they read as two plates from one set rather
       than as two more of the first picture
     · the rest as lines, set as the home page sets its four facts: no
       picture, a hairline, the date, the title, the standfirst

   The title carries the link and the link is stretched over the card or the
   line, so the whole of it is the target and there is one link per article. */
.story-lead { margin-top: clamp(28px, 4vh, 44px); }
.story-picks {
  display: grid; gap: clamp(30px, 4vh, 44px) clamp(20px, 2.6vw, 36px);
  margin-top: clamp(34px, 5vh, 56px); padding-top: clamp(34px, 5vh, 56px);
  border-block-start: 1px solid var(--line);
}
@media (min-width: 760px) { .story-picks { grid-template-columns: 1fr 1fr; } }
.story { position: relative; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.story__media {
  position: relative; isolation: isolate; overflow: hidden; margin: 0;
  border-radius: 14px;
  background: var(--surface-2);
  box-shadow: 0 1px 2px rgba(15, 39, 24, .05), 0 22px 40px -32px rgba(15, 39, 24, .45);
}
.story__media img {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  filter: saturate(.78) contrast(.93) brightness(1.03);
  transition: transform .7s cubic-bezier(.16, 1, .3, 1);
}
.story__media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(120deg, color-mix(in srgb, var(--brand-sand) 26%, transparent) 0%, transparent 46%, color-mix(in srgb, var(--brand-ice) 24%, transparent) 100%),
    color-mix(in srgb, var(--bg) 9%, transparent);
}
.story__body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.story__meta { color: var(--ink-300); }
.story__title {
  font-size: clamp(1.12rem, 1.5vw, 1.3rem); line-height: 1.24; letter-spacing: -.01em;
  color: var(--cream-100); text-wrap: balance;
}
.story__title a { color: inherit; transition: color .25s ease; }
.story__title a::after { content: ""; position: absolute; inset: 0; border-radius: 14px; }
.story__title a:focus-visible { outline: none; }
.story__title a:focus-visible::after { outline: 2px solid var(--brand-teal); outline-offset: 6px; }
.story__excerpt {
  color: var(--ink-200); font-size: .98rem; line-height: 1.55; max-width: 60ch;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
}
@media (hover: hover) {
  .story:hover .story__media img { transform: scale(1.035); }
  .story:hover .story__title a { color: var(--brand-teal); }
}

/* the one set across the page */
.story--lead .story__title { font-size: clamp(1.6rem, 3vw, 2.5rem); line-height: 1.1; letter-spacing: -.02em; max-width: 18ch; }
.story--lead .story__excerpt { font-size: clamp(1.02rem, 1.3vw, 1.14rem); -webkit-line-clamp: 4; line-clamp: 4; }
.story--lead .story__body { gap: 12px; }
@media (min-width: 900px) {
  .story--lead { flex-direction: row; align-items: center; gap: clamp(28px, 4vw, 60px); }
  .story--lead .story__media { flex: 1.2 1 0; }
  .story--lead .story__body { flex: 1 1 0; }
}

/* The pair: one ink on the ice ground, both of them. The picture is taken to
   grey and multiplied into the ground, so its lights become the tint and its
   darks a deep blue-grey.

   The crop is the head of the picture, centred. These covers put their
   subject at the top and in the middle (on the network picture it is the
   Tax Authority's building, with its flag and its mark, and the providers
   and the businesses fanning out beneath it), so the card shows that first
   and whole, and lets the foot of the picture go. */
.story--pick .story__media { background: linear-gradient(140deg, #e3f3f7 0%, var(--brand-ice-2) 100%); }
.story--pick .story__media img {
  aspect-ratio: 16 / 8; object-position: 50% 0%;
  filter: grayscale(1) contrast(1.12) brightness(1.04);
  mix-blend-mode: multiply; opacity: .86;
  scale: 1.22; transform-origin: 50% 0%;
}
.story--pick .story__media::after { background: linear-gradient(180deg, transparent 40%, color-mix(in srgb, var(--brand-forest) 12%, transparent) 100%); }
.story--pick .story__title { font-size: clamp(1.25rem, 1.9vw, 1.6rem); line-height: 1.18; }

/* The lines: no picture. Two columns of them on a wide page. */
.story-lines {
  display: grid; column-gap: clamp(28px, 4vw, 64px);
  margin-top: clamp(34px, 5vh, 56px);
  border-block-start: 1px solid var(--line);
}
@media (min-width: 900px) { .story-lines { grid-template-columns: 1fr 1fr; } }
.story--line {
  gap: 6px; padding-block: clamp(18px, 2.4vh, 24px);
  padding-inline-end: 34px;
  border-block-end: 1px solid var(--line);
}
.story--line .story__title { font-size: clamp(1.06rem, 1.35vw, 1.2rem); }
.story--line .story__title a::after { border-radius: 0; }
.story--line .story__excerpt { -webkit-line-clamp: 2; line-clamp: 2; font-size: .95rem; }
/* the way through, at the end of the line: the home page's small arrow */
.story--line::after {
  content: ""; position: absolute; inset-inline-end: 6px; top: 50%;
  inline-size: 8px; block-size: 8px; margin-top: -4px;
  border-block-start: 1.6px solid var(--ink-300); border-inline-end: 1.6px solid var(--ink-300);
  rotate: 45deg; transition: translate .25s ease, border-color .25s ease;
}
[dir="rtl"] .story--line::after { rotate: -45deg; }
@media (hover: hover) {
  .story--line:hover::after { translate: 3px 0; border-color: var(--brand-teal); }
  [dir="rtl"] .story--line:hover::after { translate: -3px 0; }
}

/* titles with no page yet */
.story-pending { max-width: 76ch; margin-top: clamp(30px, 5vh, 50px); }

@media (prefers-reduced-motion: reduce) {
  .story__media img, .story--line::after { transition: none; }
  .story:hover .story__media img { transform: none; }
  .story--line:hover::after { translate: none; }
}

/* ══════════════════ CAMPAIGN LANDING PAGE ══════════════════
   Where the strip and the floating card lead. It was the article template
   with a button under it, which is a page to read; this is a page that makes
   one offer, so it opens on the offer and its button beside the picture,
   sets out what is written as points and steps rather than as a column of
   text, and closes on the same button on the deep band the home page ends on.

   All of it is the campaign's own fields (see partials/campaign.blade.php).
   The body is rich text from the dashboard, and the layout is read off the
   markup: a list is a grid of points, a numbered list a run of steps, a
   quotation the page's one large line. */
.campaign-hero {
  display: grid; gap: clamp(26px, 4vw, 56px); align-items: center;
  padding: clamp(132px, 17vh, 190px) 6vw clamp(30px, 6vh, 64px);
  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"] .campaign-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%); }
.campaign-hero__title {
  font-size: clamp(2.1rem, 4.4vw, 3.9rem); line-height: 1.04; letter-spacing: -.02em;
  color: var(--cream-100); max-width: 17ch; margin: 14px 0 20px; text-wrap: balance;
}
.campaign-hero__lead { max-width: 54ch; font-size: clamp(1.04rem, 1.35vw, 1.2rem); color: var(--ink-700); }
.campaign-hero__action { margin-top: clamp(22px, 3.4vh, 34px); }
.campaign-hero__cover {
  margin: 0; max-width: none;
  border-radius: 18px 18px 0 0;
}
@media (min-width: 1024px) {
  .campaign-hero { grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); }
}

.campaign-offer { padding-top: clamp(30px, 6vh, 64px); }
.campaign-prose { max-width: 1060px; }
.campaign-prose > p { max-width: 64ch; }
/* the first paragraph is the offer in a sentence */
.campaign-prose > p:first-child { font-size: clamp(1.14rem, 1.6vw, 1.34rem); line-height: 1.5; color: var(--ink-100); }
.campaign-prose h2 {
  font-size: clamp(1.55rem, 2.7vw, 2.25rem); max-width: 26ch;
  margin-block: 2.5em .9em; padding-block-start: 0; border-block-start: 0;
}

/* a list: a grid of points, each a card with its mark */
.campaign-prose > ul {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  gap: 14px; margin-block: 0 2em;
}
.campaign-prose > ul > li {
  margin: 0; padding: 58px 22px 22px;
  background: var(--surface-1);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 1px 2px rgba(15, 39, 24, .04), 0 18px 36px -30px rgba(15, 39, 24, .36);
  font-size: 1rem; line-height: 1.55;
}
.campaign-prose > ul > li::before {
  top: 20px; inset-inline-start: 22px;
  inline-size: 26px; block-size: 26px; border: 0; border-radius: 999px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f6047' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 12.5 4 4 8-9'/%3E%3C/svg%3E") center / 15px no-repeat,
    color-mix(in srgb, var(--brand-green) 11%, var(--surface-1));
}
.campaign-prose > ul > li > strong:first-child {
  display: block; margin-block-end: 6px;
  font-family: var(--font-display); font-size: 1.06rem; line-height: 1.3; color: var(--brand-forest);
}

/* a numbered list: steps in a row, each under its own rule */
.campaign-prose > ol {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  gap: 22px clamp(20px, 3vw, 40px); margin-block: 0 2em;
}
.campaign-prose > ol > li {
  margin: 0; padding: 16px 0 0;
  border-block-start: 2px solid var(--brand-green);
  font-size: 1.02rem; line-height: 1.5;
}
.campaign-prose > ol > li::before {
  position: static; display: block; margin-block-end: 8px;
  font-family: var(--font-display); font-size: .82rem; font-weight: 600;
  letter-spacing: .1em; color: var(--brand-green);
}

/* a quotation: the one large line on the page */
.campaign-prose blockquote {
  margin-block: 2.8em; padding: 0; border: 0;
  max-width: 26ch;
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.5rem, 3vw, 2.3rem); line-height: 1.2; letter-spacing: -.015em;
  color: var(--brand-forest); text-wrap: balance;
}
.campaign-prose blockquote::before {
  content: ""; display: block; inline-size: 48px; block-size: 3px; border-radius: 999px;
  background: var(--brand-teal); margin-block-end: 22px;
}

.campaign-closing .chapter-intro { margin-top: 22px; }

/* ══════════════════ CAMPAIGN CARDS ══════════════════
   The floating campaign card: a small notice in the corner of the page.

   It was a book — a 168 by 216 block of gradient that swung open on a hinge
   when pointed at. That put a poster over the corner of whatever the visitor
   was reading, kept its second line behind a gesture a phone does not have,
   and looked like a different site's toy. What it has to do is smaller than
   that: say one thing, say where it leads, and get out of the way.

   So it is a card on the page's own paper, as wide as a line of text and as
   tall as two, with the campaign's line, the line under it and an arrow that
   takes the brand's green. Nothing is hidden, so nothing needs hovering. */
.campaign-cards {
  position: fixed;
  inset-block-end: clamp(14px, 3vh, 24px);
  inset-inline-end: clamp(14px, 2.4vw, 24px);
  z-index: 40;
  pointer-events: none;
}

.campaign-card {
  position: relative;
  pointer-events: auto;
  width: min(320px, calc(100vw - 28px));
  animation: campaign-card-in .32s cubic-bezier(.23, 1, .32, 1) both;
}

.campaign-card[hidden] { display: none; }

@keyframes campaign-card-in {
  from { opacity: 0; transform: translateY(10px); }
}

.campaign-card-link {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  column-gap: 14px;
  /* The end padding clears the close button, which sits over this corner. */
  padding-block: 16px; padding-inline: 18px 16px;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(15, 39, 24, .05), 0 18px 36px -22px rgba(15, 39, 24, .5);
  color: var(--ink-100);
  text-decoration: none;
  transition: border-color .2s cubic-bezier(.23, 1, .32, 1), box-shadow .2s cubic-bezier(.23, 1, .32, 1), transform .2s cubic-bezier(.23, 1, .32, 1);
}
.campaign-card-copy { display: grid; gap: 3px; padding-inline-end: 14px; }
.campaign-card-title {
  font-family: var(--font-display); font-size: .96rem; font-weight: 600; line-height: 1.3;
  color: var(--brand-forest);
}
.campaign-card-text {
  font-family: var(--font-display); font-size: .82rem; line-height: 1.45;
  color: var(--ink-200);
}
.campaign-card-go {
  display: grid; place-items: center;
  width: 34px; height: 34px; margin-block-start: 14px;
  border-radius: 999px;
  background: var(--brand-green); color: #fff;
  transition: background-color .2s cubic-bezier(.23, 1, .32, 1);
}
.campaign-card-go svg { width: 15px; height: 15px; transition: transform .2s cubic-bezier(.23, 1, .32, 1); }
[dir="rtl"] .campaign-card-go svg { transform: scaleX(-1); }

@media (hover: hover) and (pointer: fine) {
  .campaign-card-link:hover {
    border-color: color-mix(in srgb, var(--brand-green) 45%, var(--line));
    box-shadow: 0 2px 4px rgba(15, 39, 24, .06), 0 22px 40px -22px rgba(15, 39, 24, .55);
    transform: translateY(-1px);
  }
  .campaign-card-link:hover .campaign-card-go { background: var(--brand-forest); }
  .campaign-card-link:hover .campaign-card-go svg { transform: translateX(2px); }
  [dir="rtl"] .campaign-card-link:hover .campaign-card-go svg { transform: scaleX(-1) translateX(2px); }
}
.campaign-card-link:active { transform: scale(.985); }
.campaign-card-link:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }

/* Inside the card's own corner, not hanging off it: a quiet control on the
   same paper, with a hit area a thumb can find. */
.campaign-card-close {
  position: absolute;
  inset-block-start: 4px;
  inset-inline-end: 4px;
  z-index: 2;
  width: 30px;
  height: 30px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-300);
  cursor: pointer;
  transition: background-color .2s ease, color .2s ease;
}

.campaign-card-close svg { width: 12px; height: 12px; }

.campaign-card-close:hover,
.campaign-card-close:focus-visible {
  background: var(--surface-2);
  color: var(--brand-forest);
}
.campaign-card-close:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 1px; }

@media (prefers-reduced-motion: reduce) {
  .campaign-card { animation: campaign-card-fade .2s ease both; }
  .campaign-card-link, .campaign-card-go, .campaign-card-go svg { transition: none; }
  .campaign-card-link:hover, .campaign-card-link:active { transform: none; }
  .campaign-card-link:hover .campaign-card-go svg { transform: none; }
  [dir="rtl"] .campaign-card-link:hover .campaign-card-go svg { transform: scaleX(-1); }
}
@keyframes campaign-card-fade { from { opacity: 0; } }

/* On a phone the card takes the width of the screen less its margins, so it
   reads as a line across the foot of the page rather than a box in a corner. */
@media (max-width: 560px) {
  .campaign-cards { inset-block-end: 12px; inset-inline: 12px; }
  .campaign-card { width: auto; }
  .campaign-card-link { padding-block: 13px; }
}
