@charset "UTF-8";

/* ==========================================================================
   00 FONTS — self-hosted, so this site makes ZERO third-party requests.
   No <link> to fonts.googleapis.com, no CDN, nothing that describes a visitor
   to anyone else. That matters more here than on most sites: someone reading
   this page may be looking up trauma counselling from a household where being
   seen doing so is not safe. A site that phones home is a site that leaks.

   Literata and Manrope are variable — the whole weight range is one file.
   IBM Plex Sans Arabic serves ar.html. All three are SIL OFL 1.1.
   Only the subsets actually used are shipped; anything outside them falls back
   to the system stack, which is correct behaviour rather than a bug.
   See fonts/README.md before replacing any of them.
   ========================================================================== */

@font-face {
  font-family: 'Literata';
  src: url('fonts/literata-latin.woff2') format('woff2');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;   /* the fallback paints immediately; no invisible text */
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Manrope';
  src: url('fonts/manrope-latin.woff2') format('woff2');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plex Arabic';
  src: url('fonts/plex-arabic-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1,
                 U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
                 U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

/* ==========================================================================
   ALI KHALAF — COUNSELLING · styles.css
   The single stylesheet for the whole site. No framework, no build step,
   no third-party CSS, no CDN. Edit this file directly.

   ————————————————————————————————————————————————————————————————————————
   THE IDEA — "THE REED HOUSE."
   ————————————————————————————————————————————————————————————————————————
   In the marshes of southern Iraq people have built the MUDHIF for about five
   thousand years: a hall made entirely of reeds. No nail, no wire, no wood, no
   metal. Its roof is a row of parabolic arches, each one made by bending a
   BUNDLE of reeds and lashing it. A single reed carries nothing at all. Bundled,
   it carries a roof. UNESCO inscribed the craft on its Intangible Cultural
   Heritage list in 2023.

   And the building is not a shelter. It is a GUEST HOUSE — the room a village
   keeps for receiving people, hearing what happened to them, and settling what
   is unsettled. It is, literally and for five millennia, a room you are received
   in and listened to.

   In the 1990s those marshes were drained on purpose. The reeds died and the
   people left. After 2003 the dykes were broken and the water came back — not
   all of it, not everywhere, but really. Reeds grew again.

   So this site is a reed house. Its structure is THE BUNDLE: thin things that
   hold, together. Its motion is THE WATER RETURNING. Its light is the light that
   comes through a reed wall — banded, warm, and moving.

   Stated without the metaphor, that is the practice: a room you are received in;
   strength that does not come from muscle; and a return that is partial, real,
   and worth having.

   This is not ornament borrowed from a heritage. It is a structural argument
   about where strength comes from, made by a counsellor who works from a
   wheelchair, whose muscles are weakening, and who came out of a drained country.
   Written up in docs/adr/0002_the_reed_house.md. Read it before changing anything
   visual, and read the two LAWS below before adding any colour or any motion.
   They are binding.

   ————————————————————————————————————————————————————————————————————————
   THE PALETTE LAW — read this before adding any colour
   ————————————————————————————————————————————————————————————————————————
   Every ratio below was COMPUTED, not estimated — relative luminance and
   (L1 + 0.05) / (L2 + 0.05), the WCAG 2 formula. The calculator that produced
   them is reproduced in tests/invariants.test.mjs, which fails the build if any
   token drifts. If you change a hex, run `npm run lint` before you believe it.

   1. PAPER IS THE GROUND. This site is LIGHT by default and the dark bands are
      the named exceptions, listed under DARK GROUNDS below. That is the opposite
      of most editorial sites and it is deliberate: this is a reading site for
      people who are tired, and the brief was brightness.

   2. A DARK BAND MEANS ONE THING: YOU ARE INSIDE THE ROOM. The hero, the
      journey, the crisis block and the footer are dark because in each of them
      you are being received rather than reading a document. Light means you are
      reading. Do not use a dark band for rhythm or for relief. Every section in
      the HTML carries a comment naming its ground — keep it accurate.

   3. SUN AND GLAZE ARE DARK-GROUND COLOURS AND MAY NEVER SET TYPE ON PAPER.
          --sun    #E9A020  on --reed   2.01:1   FAILS
          --glaze  #5FD6CE  on --reed   1.60:1   FAILS
      Their paper twins are the only members of those families allowed on light:
          --sun-ink    #7A5310  on --reed   6.24:1   AA
          --glaze-ink  #0B6E69  on --reed   5.56:1   AA
      The DARK GROUNDS token swap performs that substitution for you, so no rule
      needs an .on-light twin. Never write one.

   4. CLAY IS A DISPLAY-ONLY GROUND. It is the one dark ground that carries a
      single text colour and no other — measured:
          --on-dark       on --clay   5.94:1   AA    (the only one allowed)
          --on-dark-soft  on --clay   4.12:1   FAILS
          --sun           on --clay   2.95:1   FAILS
          --glaze         on --clay   3.72:1   FAILS
      So --clay holds a short headline in --on-dark and nothing else. No body
      copy, no secondary tone, no accent. If a clay band needs a paragraph, it is
      the wrong ground — use --lapis (which carries all four).

   5. COLOUR IS SPENT, NOT SPREAD. One accent per band, or none. The full set
      appears together exactly once, around the choice of how to meet — where the
      colour is carrying information rather than decorating. The two doors take
      --lapis and --clay; the three virtual modes underneath take a hairline in
      --lapis, --marsh and --glaze-ink. Everywhere else the default is --hair.
      (Amended by ADR 0007, which reduced four doors to two. ADR 0002 records the
      original clause.)

   6. ABUT, NEVER BLEND. No gradient between two different accents anywhere. A
      gradient WITHIN one hue is allowed and is how the reed light is made — that
      is light falling, not two colours negotiating.

   7. --hair IS A BOUNDARY LINE AND NEVER A GROUND FOR TEXT. Interactive borders
      and focus rings do not use it: they use --lapis on paper and --sun on dark,
      both of which clear 3:1 against their ground for WCAG 2.2 SC 1.4.11.

   8. THE PALETTE IS MESOPOTAMIAN ON PURPOSE AND CAN BE DEFENDED. Lapis, gold and
      turquoise glaze are the three colours of the Ishtar Gate. Lapis was traded
      through Mesopotamia and was worth more than gold. Marsh green and clay are
      the water and the ground the reed house stands on. It is colourful because
      the brief asked for colour, and it is THIS colour because of where the man
      is from — not because a palette generator produced a pleasing triad.

   ————————————————————————————————————————————————————————————————————————
   THE MOTION LAW
   ————————————————————————————————————————————————————————————————————————
   There is ONE motion idea: IT RETURNS. Nothing on this site simply appears.
   Everything arrives the way the water came back to the marshes — from below,
   unevenly, and then it stays. Nothing fades in for no reason, and nothing that
   has arrived ever leaves again.

   The four named gestures, and nothing else:

     · THE FLOOD — a band's content arrives from its bottom edge upward, via
       clip-path: inset(100% 0 0 0) relaxing to inset(0). Once per band.

     · THE BUNDLE — vertical strands arrive staggered on --i and close toward one
       another. This is the reed wall, the arch, and every card row. It is the
       site's one signature and it says the only thing the site is really about:
       thin things hold when they are held together.

     · THE LIGHT THROUGH — a warm sweep crossing a headline once, the way sun
       crosses a reed wall. ONCE PER PAGE, on the h1, and never on body copy.
       It is background-clip: text, so it needs a solid-colour fallback and it
       gets one on the same rule.

     · THE LEAN — 8px of settle and nothing else. Elements arrive TOWARD their
       neighbour rather than upward, because an arch stands by leaning. Three
       elements per page, maximum.

   Everything is transform / opacity / filter / clip-path, so it composites on the
   GPU and never lays out. Nothing animates width, height, top, left or margin.

   MOTION FAILS OPEN, ALWAYS. The base state of every animated thing is its
   FINISHED state. The unfinished state is applied only under
   `html:not(.no-js)` — that is, only where the JavaScript that can undo it is
   actually running. A browser with JavaScript disabled, or an old browser, or a
   visitor with prefers-reduced-motion: reduce, gets a complete page in full
   colour with nothing hidden. This is not a courtesy. A person looking for a
   trauma counsellor may be doing it on a locked-down work laptop, an old phone,
   or a library computer, and a blank page is the site failing at the only moment
   that matters.

   REDUCED MOTION IS HONOURED LIVE. site.js listens for changes to the media
   query mid-visit, so turning it on does not require a reload.
   ========================================================================== */

/* ==========================================================================
   01 TOKENS
   ========================================================================== */

:root {
  /* — grounds ————————————————————————————————————————————————— */
  --reed:        #FAF4E8;   /* the paper ground, warm. The default everywhere. */
  --reed-2:      #F2E9D6;   /* the warmer tint, for an inset panel on paper    */
  --lapis:       #123A78;   /* the signature dark band. Carries all four inks. */
  --night:       #0A2450;   /* the deepest ground — hero and footer            */
  --marsh:       #07352F;   /* the marsh band                                  */
  --clay:        #A8371C;   /* DISPLAY-ONLY ground — see palette law clause 4  */

  /* — inks on paper ——————————————————————————————————————————— */
  --ink:         #171310;   /* 16.86:1 on --reed  · AAA · body copy            */
  --ink-soft:    #4A4139;   /*  9.10:1 on --reed  · AAA · secondary            */
  --sun-ink:     #7A5310;   /*  6.24:1 on --reed  · AA  · the only sun on light*/
  --glaze-ink:   #0B6E69;   /*  5.56:1 on --reed  · AA  · the only glaze there */

  /* — inks on the dark bands ——————————————————————————————————— */
  --on-dark:     #FAF4E8;   /* 10.08 lapis · 13.88 night · 12.29 marsh · 5.94 clay */
  --on-dark-soft:#D6CDBA;   /*  6.99 lapis ·  9.63 night ·  8.53 marsh · FAILS clay */

  /* — accents ————————————————————————————————————————————————— */
  --sun:         #E9A020;   /* 5.00 lapis · 6.89 night · 6.10 marsh · FAILS paper */
  --glaze:       #5FD6CE;   /* 6.31 lapis · 8.69 night · 7.69 marsh · FAILS paper */

  /* — lines ——————————————————————————————————————————————————— */
  --hair:        #E0D5BE;   /* decorative boundary only. Never a text ground.  */
  --hair-strong: #C9BA9B;
  --edge:        var(--lapis);       /* interactive borders + focus, 10.08:1   */

  /* — role aliases. Components address THESE, never a raw hex. ————— */
  --ground:      var(--reed);
  --ground-2:    var(--reed-2);
  --text:        var(--ink);
  --text-soft:   var(--ink-soft);
  --accent:      var(--lapis);       /* type-safe accent for the current ground */
  --accent-warm: var(--sun-ink);     /* swapped to --sun on dark grounds        */
  --accent-cool: var(--glaze-ink);   /* swapped to --glaze on dark grounds      */
  --rule:        var(--hair);
  --focus:       var(--lapis);

  /* — measure and rhythm ——————————————————————————————————————— */
  --measure:     62ch;               /* body copy never runs wider than this   */
  --measure-narrow: 46ch;
  --gutter:      clamp(1.15rem, 0.7rem + 2.2vw, 3rem);
  --band-y:      clamp(2.6rem, 1.8rem + 3.6vw, 5rem);
  --stack:       clamp(0.75rem, 0.62rem + 0.7vw, 1.05rem);
  --shelf:       clamp(1.15rem, 0.9rem + 1.4vw, 2rem);
  --page:        76rem;

  /* — type ————————————————————————————————————————————————————— */
  --serif: 'Literata', 'Iowan Old Style', 'Palatino Linotype', Palatino,
           'Book Antiqua', Georgia, 'Times New Roman', serif;
  --sans:  'Manrope', ui-sans-serif, system-ui, -apple-system, 'Segoe UI',
           Roboto, 'Helvetica Neue', Arial, sans-serif;
  --arabic:'Plex Arabic', 'Noto Naskh Arabic', 'Geeza Pro', 'Traditional Arabic',
           'Segoe UI', Tahoma, sans-serif;

  /* Whitespace inside clamp() around + and - is MANDATORY. Without it the whole
     declaration is silently dropped and the type quietly renders at the inherited
     size with nothing to tell you why. `npm run lint` checks every clamp in this
     file for it. */
  --t-hero:  clamp(2.15rem, 1.1rem + 4.6vw, 4.3rem);
  --t-h1:    clamp(1.85rem, 1.15rem + 2.9vw, 2.9rem);
  --t-h2:    clamp(1.4rem, 1.05rem + 1.5vw, 2rem);
  --t-h3:    clamp(1.08rem, 0.98rem + 0.55vw, 1.28rem);
  --t-lead:  clamp(1rem, 0.96rem + 0.34vw, 1.14rem);
  --t-body:  clamp(0.93rem, 0.9rem + 0.18vw, 1.02rem);
  --t-small: clamp(0.82rem, 0.8rem + 0.1vw, 0.88rem);
  --t-label: clamp(0.72rem, 0.7rem + 0.1vw, 0.78rem);

  /* — motion ——————————————————————————————————————————————————— */
  --ease-return: cubic-bezier(0.16, 0.84, 0.32, 1);   /* water finding a level */
  --ease-lean:   cubic-bezier(0.32, 0.72, 0.28, 1);
  --dur-flood:   1100ms;
  --dur-bundle:  760ms;
  --dur-lean:    560ms;
  --stagger:     58ms;

  color-scheme: light;
}

/* ==========================================================================
   02 DARK GROUNDS — the token swap
   This site is light by default, so this list names the EXCEPTIONS. Adding a
   dark section means adding its selector here; everything inside then adapts,
   including the two accent families, which is why no rule in this file needs an
   .on-light or .on-dark twin. Never write one.
   Note --accent-warm and --accent-cool flip to their dark-ground members here:
   that single substitution is what makes palette law clause 3 automatic.
   ========================================================================== */

.band--lapis,
.band--night,
.band--marsh,
.band--clay,
.site-head--over-dark,
.site-foot,
.reedwall,
.crisis {
  --ground:      var(--lapis);
  --ground-2:    var(--night);
  --text:        var(--on-dark);
  --text-soft:   var(--on-dark-soft);
  --accent:      var(--sun);
  --accent-warm: var(--sun);
  --accent-cool: var(--glaze);
  --rule:        rgba(250, 244, 232, 0.22);
  --focus:       var(--sun);
  color-scheme: dark;
}

.band--night, .site-foot, .reedwall { --ground: var(--night); --ground-2: #061A3B; }
.band--marsh                        { --ground: var(--marsh); --ground-2: #052823; }

/* CLAY — palette law clause 4. Only --on-dark clears AA here (5.94:1), so the
   soft tone and both accents are forced back to the one legal colour rather
   than left to fail quietly. A clay band is a headline and nothing else. */
.band--clay {
  --ground: var(--clay); --ground-2: #8E2C14;
  --text-soft:   var(--on-dark);
  --accent:      var(--on-dark);
  --accent-warm: var(--on-dark);
  --accent-cool: var(--on-dark);
  --focus:       var(--on-dark);
}

/* ==========================================================================
   03 RESET AND BASE
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;   /* the sticky header must not cover an anchor */
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--reed);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t-body);
  font-variation-settings: 'opsz' 14;
  line-height: 1.56;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;           /* belt and braces; nothing should overflow    */
}

img, svg, video { max-width: 100%; height: auto; display: block; }
/* CSS beats a presentation attribute, so a bare `svg { fill: currentColor }`
   would override every icon's own fill="none" and turn the line icons into
   solid blobs. Only fill the ones that have not said what they want. */
svg:not([fill]) { fill: currentColor; }

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.018em;
  margin: 0 0 var(--stack);
  text-wrap: balance;
  font-variation-settings: 'opsz' 44;
}
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); font-variation-settings: 'opsz' 20; letter-spacing: -0.01em; }

p { margin: 0 0 var(--stack); max-width: var(--measure); text-wrap: pretty; }
:where(p, li) strong { font-weight: 620; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.22em; }
a:hover { text-decoration-thickness: 2px; }

/* WCAG 2.2 SC 2.4.11 — a focused element must never be hidden by the sticky
   header. scroll-padding-top above does the scrolling half; the outline offset
   keeps the ring outside the element's own box so it is never clipped. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--sun); color: var(--ink); }

hr { border: 0; border-top: 1px solid var(--rule); margin: var(--shelf) 0; }

/* Every interactive target clears WCAG 2.2 SC 2.5.8 (24px) and in practice the
   AAA 44px, because a proportion of this site's visitors have limited hand
   strength or tremor — including, on his own site, the practitioner. */
a, button, summary, [role='button'] { touch-action: manipulation; }

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

/* ==========================================================================
   04 LAYOUT
   ========================================================================== */

.wrap { width: min(100% - (var(--gutter) * 2), var(--page)); margin-inline: auto; }
.wrap--narrow { width: min(100% - (var(--gutter) * 2), 46rem); }

/* A band is a full-width horizontal section that owns its ground. Its ground
   comes from the DARK GROUNDS swap above, or defaults to paper. Every band in
   the HTML carries a comment naming its ground — palette law clause 2. */
.band {
  background: var(--ground);
  color: var(--text);
  padding-block: var(--band-y);
  position: relative;
}
.band--tight { padding-block: clamp(2.4rem, 1.6rem + 3vw, 4rem); }
.band--flush { padding-block: 0; }
.band + .band--reed2 { --ground: var(--reed-2); }
.band--reed2 { --ground: var(--reed-2); background: var(--reed-2); }

/* The seam between two dark bands of different hue. Palette law clause 6:
   they ABUT. This is a 1px line, not a 60px gradient. */
.band + .band { border-top: 0; }

.band__head { margin-bottom: var(--shelf); }
.band__head p { color: var(--text-soft); font-size: var(--t-lead); }

.eyebrow {
  font-family: var(--sans);
  font-size: var(--t-label);
  font-weight: 620;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-warm);
  margin: 0 0 0.9rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.eyebrow::after {
  content: ''; flex: 1 1 auto; height: 1px; background: var(--rule); max-width: 6rem;
}

.lede {
  font-size: var(--t-lead);
  line-height: 1.45;
  color: var(--text);
  max-width: var(--measure-narrow);
  font-variation-settings: 'opsz' 20;
}

.grid { display: grid; gap: var(--shelf); }
@media (min-width: 44em) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 60em) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 52em) { .grid--sidebar { grid-template-columns: 1fr 18rem; align-items: start; } }

/* ==========================================================================
   05 THE VAULT — the site's one drawn object
   Nested parabolic arches receding down the length of a mudhif, with the light
   at the far end. Drawn in code, never photographed: it costs no request, it is
   sharp at any size, and it is the one image on this site that cannot be got
   wrong by a stock library. Geometry is documented in docs/ARCHITECTURE.md.
   ========================================================================== */

.vault { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.vault svg { width: 100%; height: 100%; display: block; }
.vault path { vector-effect: non-scaling-stroke; }

/* Each arch is FILLED as well as stroked, and an unclosed path still fills as
   though closed — so the fill is the arch's area and the stroke follows only
   the curve, never the floor line.

   The fills are deliberately faint and deliberately overlap: six of them stack
   toward the middle, so the light accumulates at the vanishing point on its own
   rather than being painted there. That is what makes it read as the inside of
   a vaulted hall instead of six loose curves — which is exactly how the first
   version of this looked. Nested flat fills also satisfy palette law clause 6:
   they abut, they do not blend. */
.vault__ring {
  fill: rgba(233, 160, 32, 0.07);
  stroke: var(--sun);
  stroke-width: 1.3;
  opacity: 0.62;
}
.vault__ring:nth-child(2n) { stroke: var(--glaze); fill: rgba(95, 214, 206, 0.06); }
.vault__ring:last-of-type  { opacity: 0.9; stroke-width: 1.8; }

/* THE COMPOSITION. Stretched across a wide viewport the six arches scale up
   until only their legs are on screen, and they stop reading as nested arches
   and start reading as stray diagonals. So above 64em the vault becomes a
   discrete object occupying the right of the band — type on the left, the
   inside of the reed house on the right — and below that it goes full width
   and quiet, behind the text. */
@media (min-width: 64em) {
  /* A box the whole arch set fits inside. Anchoring it to the bottom of a tall
     band puts the apexes below the fold and leaves only the legs on screen,
     which is how six nested arches turn into six stray diagonals. */
  .vault { left: auto; right: 1%; top: 2%; bottom: 2%; width: min(56%, 46rem); }
}
@media (max-width: 63.99em) {
  .vault { opacity: 0.5; top: auto; height: 62%; bottom: 0; }
}

/* The light at the vanishing point. One hue, so palette law clause 6 holds. */
.vault__light {
  position: absolute; left: 50%; bottom: 12%; translate: -50% 30%;
  width: min(52vw, 30rem); aspect-ratio: 1.6 / 1;
  background: radial-gradient(ellipse at 50% 100%,
              rgba(233, 160, 32, 0.55) 0%,
              rgba(233, 160, 32, 0.20) 38%,
              rgba(233, 160, 32, 0) 72%);
  filter: blur(2px);
}

/* ==========================================================================
   06 THE REED WALL — the hero
   N vertical strands. Each is one <span> so THE BUNDLE can stagger them. They
   are decorative and live inside aria-hidden, so a screen reader never meets
   them. With JavaScript off they are simply there, static and complete.
   ========================================================================== */

.reedwall {
  position: relative;
  background: var(--night);
  color: var(--on-dark);
  isolation: isolate;
  padding-block: clamp(2.2rem, 1.4rem + 4.2vw, 4.2rem) clamp(1.7rem, 1.1rem + 2.8vw, 3.2rem);
  overflow: hidden;
}

.reedwall__strands {
  position: absolute; inset: 0; display: flex; gap: 0; pointer-events: none;
}
.reedwall__strands span {
  flex: 1 1 0;
  background: linear-gradient(to top,
              rgba(233, 160, 32, 0.00) 0%,
              rgba(233, 160, 32, 0.22) 26%,
              rgba(95, 214, 206, 0.14) 62%,
              rgba(233, 160, 32, 0.00) 100%);
  border-right: 1px solid rgba(250, 244, 232, 0.10);
  transform-origin: 50% 100%;
}
/* Every fourth strand is a thicker reed. A real reed wall is not a ruled grid. */
.reedwall__strands span:nth-child(4n) {
  background: linear-gradient(to top,
              rgba(233, 160, 32, 0.00) 0%,
              rgba(233, 160, 32, 0.34) 30%,
              rgba(233, 160, 32, 0.00) 100%);
}
.reedwall__strands span:nth-child(7n) { border-right-color: rgba(95, 214, 206, 0.20); }

/* ——— THE SCRIM ————————————————————————————————————————————————————
   Decoration must never be the ground under running text.

   The vault and the reed strands are drawn behind the whole band. Computed
   against flat --night every pairing here passes comfortably — 13.88:1 for
   --on-dark. But a gold arch stroke or a turquoise one passing behind a line
   of body copy lifts the REAL ground under those pixels, and the measured
   ratio collapses. Sampling actual rendered pixels found --on-dark-soft at
   1.29:1 over a glaze stroke on the Arabic hero. Computation cannot catch
   this; only sampling can. See docs/runbooks/verify_visuals.md.

   So the text column carries its own ground: a radial wash of the SAME hue as
   the band (one hue, so palette law clause 6 still holds) that is opaque where
   the type is and clears completely where the decoration should show. Because
   .reedwall__body establishes a stacking context, a z-index:-1 pseudo-element
   sits above the decoration and below the text — exactly the layer needed. */
.reedwall__body,
.has-vault > .wrap { position: relative; z-index: 2; }

.reedwall__body::before,
.has-vault > .wrap::before {
  content: '';
  position: absolute;
  inset: -3rem -4rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(88% 118% at 12% 50%,
              rgba(10, 36, 80, 0.975) 0%,
              rgba(10, 36, 80, 0.95) 46%,
              rgba(10, 36, 80, 0.55) 72%,
              rgba(10, 36, 80, 0.00) 92%);
}
.band--lapis.has-vault > .wrap::before {
  background: radial-gradient(88% 118% at 12% 50%,
              rgba(18, 58, 120, 0.975) 0%,
              rgba(18, 58, 120, 0.95) 46%,
              rgba(18, 58, 120, 0.55) 72%,
              rgba(18, 58, 120, 0.00) 92%);
}
/* Narrow screens: the text spans the full width, so the wash has to as well. */
@media (max-width: 63.99em) {
  .reedwall__body::before,
  .has-vault > .wrap::before {
    background: linear-gradient(to bottom,
                rgba(10, 36, 80, 0.94) 0%,
                rgba(10, 36, 80, 0.94) 82%,
                rgba(10, 36, 80, 0.00) 100%);
  }
  .band--lapis.has-vault > .wrap::before {
    background: linear-gradient(to bottom,
                rgba(18, 58, 120, 0.94) 0%,
                rgba(18, 58, 120, 0.94) 82%,
                rgba(18, 58, 120, 0.00) 100%);
  }
}
/* RTL: the type sits on the right, so the wash is anchored there instead. */
html[dir='rtl'] .reedwall__body::before,
html[dir='rtl'] .has-vault > .wrap::before {
  background: radial-gradient(88% 118% at 88% 50%,
              rgba(10, 36, 80, 0.975) 0%,
              rgba(10, 36, 80, 0.95) 46%,
              rgba(10, 36, 80, 0.55) 72%,
              rgba(10, 36, 80, 0.00) 92%);
}

.reedwall h1 {
  font-size: var(--t-hero);
  font-weight: 400;
  max-width: 17ch;
  font-variation-settings: 'opsz' 72, 'wght' 400;
  letter-spacing: -0.028em;
  max-width: 15ch;
  margin-bottom: var(--shelf);
}
.reedwall .lede { color: var(--on-dark-soft); max-width: 52ch; }

.hero__meta {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem;
  font-family: var(--sans); font-size: var(--t-small);
  color: var(--on-dark-soft);
  margin-top: var(--shelf);
  padding-top: var(--stack);
  border-top: 1px solid rgba(250, 244, 232, 0.18);
  max-width: 52ch;
}
.hero__meta b { color: var(--sun); font-weight: 600; }

/* ==========================================================================
   07 SHARED CHROME — header, nav, footer, crisis strip
   Duplicated in all 8 English pages between the SHARED CHROME markers.
   `npm run lint` asserts they stay identical. ar.html carries an RTL variant
   which the linter checks separately — see tests/invariants.test.mjs.
   ========================================================================== */

.skip {
  position: absolute; left: 0.75rem; top: -4rem; z-index: 200;
  background: var(--lapis); color: var(--reed);
  padding: 0.8rem 1.2rem; border-radius: 4px;
  font-family: var(--sans); font-weight: 600; text-decoration: none;
  transition: top 160ms var(--ease-lean);
}
.skip:focus { top: 0.75rem; }

.site-head {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--reed) 92%, transparent);
  border-bottom: 1px solid var(--hair);
  backdrop-filter: blur(10px);
}
@supports not (backdrop-filter: blur(10px)) { .site-head { background: var(--reed); } }

.site-head__in {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: 4.25rem;
}

.brand {
  display: flex; align-items: center; gap: 0.7rem;
  font-family: var(--serif); font-weight: 600; font-size: 1.06rem;
  color: var(--ink); text-decoration: none; letter-spacing: -0.01em;
  padding: 0.5rem 0; line-height: 1.15;
}
.brand:hover { text-decoration: none; }
.brand__mark { width: 30px; height: 30px; flex: none; color: var(--lapis); }
.brand__name { display: block; }
.brand__role {
  display: block; font-family: var(--sans); font-weight: 500;
  font-size: 0.68rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--ink-soft);
}

.nav { display: flex; align-items: center; gap: 0.15rem; }
.nav a {
  font-family: var(--sans); font-size: 0.92rem; font-weight: 500;
  color: var(--ink); text-decoration: none;
  padding: 0.75rem 0.7rem; border-radius: 4px;
  display: inline-flex; align-items: center; min-height: 44px;
}
.nav a:hover { background: var(--reed-2); text-decoration: none; }
.nav a[aria-current='page'] { color: var(--lapis); font-weight: 700; }
.nav a[aria-current='page']::after {
  content: ''; position: absolute; /* placed by .nav__item below */
}
.nav__item { position: relative; }
.nav a[aria-current='page'] .nav__dot {
  display: block; width: 5px; height: 5px; border-radius: 50%;
  background: var(--lapis); margin: 0 auto;
  position: absolute; left: 0; right: 0; bottom: 0.35rem;
}

/* The one always-available action. It is not "Book" — this practice takes no
   bookings through the website (there are no forms; see ADR 0003). It is the
   crisis route, because that is the link that has to be reachable in one tap
   from every page on the site. */
.nav__urgent {
  font-family: var(--sans); font-size: 0.9rem; font-weight: 700;
  background: var(--clay); color: var(--reed);
  padding: 0.66rem 1rem; border-radius: 999px; text-decoration: none;
  display: inline-flex; align-items: center; gap: 0.45rem; min-height: 44px;
  margin-left: 0.4rem; white-space: nowrap;
}
.nav__urgent:hover { background: #8E2C14; text-decoration: none; }
.nav__urgent svg { width: 15px; height: 15px; }

.site-head__actions { display: flex; align-items: center; gap: 0.5rem; flex: none; }

.nav__toggle {
  display: none;
  font: inherit; font-family: var(--sans); font-size: 0.92rem; font-weight: 600;
  background: transparent; border: 1px solid var(--hair-strong);
  color: var(--ink); border-radius: 6px;
  min-height: 44px; min-width: 44px; padding: 0.5rem 0.85rem;
  align-items: center; gap: 0.5rem; cursor: pointer;
}
.nav__toggle svg { width: 18px; height: 18px; }

/* The mobile panel is a native popover, so the platform owns the top layer,
   light dismiss, Escape and focus return. site.js keeps a class fallback for
   browsers without popover support, and with JavaScript off the header falls
   back to a plain wrapped list of links at every width — three independent
   paths, so the navigation cannot end up unreachable. */
.nav__panel {
  border: 0; padding: 0; margin: 0; width: min(22rem, calc(100vw - 1.5rem));
  background: var(--reed); color: var(--ink);
  border-left: 1px solid var(--hair);
  box-shadow: -18px 0 50px rgba(10, 36, 80, 0.14);
  inset: 0 0 0 auto; height: 100dvh; max-height: 100dvh; overflow-y: auto;
}
.nav__panel::backdrop { background: rgba(10, 36, 80, 0.45); }
.nav__panel-in { padding: 1.1rem var(--gutter) 2.5rem; }
.nav__panel .nav { flex-direction: column; align-items: stretch; gap: 0.1rem; }
.nav__panel .nav a { font-size: 1.06rem; padding: 0.85rem 0.6rem; }
.nav__panel .nav__urgent { margin: 1rem 0 0; justify-content: center; }
.nav__close {
  font: inherit; font-family: var(--sans); font-weight: 600;
  background: transparent; border: 1px solid var(--hair-strong);
  border-radius: 6px; min-height: 44px; min-width: 44px; padding: 0.5rem 0.9rem;
  margin-bottom: 0.9rem; cursor: pointer; color: var(--ink);
}

@media (max-width: 63.99em) {
  .nav__toggle { display: inline-flex; }
  .site-head .nav--main { display: none; }
}

/* On a narrow phone the header has to carry the brand, the crisis link and the
   menu button in about 320px. The crisis link is the one that does not shrink:
   the brand loses its subtitle and the menu button loses its word first. */
@media (max-width: 29.99em) {
  .brand__role { display: none; }
  .brand { font-size: 1rem; }
  .nav__toggle-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .nav__toggle { padding: 0.5rem; }
  .nav__urgent { padding: 0.6rem 0.8rem; font-size: 0.84rem; margin-left: 0; }
}

@media (max-width: 63.99em) {
  /* JS OFF: the toggle cannot work, so the links are shown as a plain wrapped
     list instead. Motion and enhancement fail open; navigation especially. */
  .no-js .site-head .nav--main { display: flex; flex-wrap: wrap; }
  .no-js .nav__toggle { display: none; }
  .no-js .site-head__in { flex-wrap: wrap; }
}

/* ——— header states, set by site.js ——————————————————————————————————
   is-scrolled : the page has moved, so the header earns a shadow
   is-tucked   : the visitor is reading downward, so it gets out of the way.
                 site.js never applies this while focus is inside the header
                 or the panel is open — hiding a focused element is SC 2.4.11.
   nav-open    : the panel is open, so the header must stay put. */
.site-head.is-scrolled { box-shadow: 0 1px 20px rgba(10, 36, 80, 0.10); }
.site-head { transition: transform 320ms var(--ease-lean), box-shadow 220ms linear; }
.site-head.is-tucked { transform: translateY(-100%); }
.site-head.nav-open { transform: none; }
@media (prefers-reduced-motion: reduce) { .site-head.is-tucked { transform: none; } }

/* the class fallback for browsers with no popover support (site.js §04) */
.nav__panel.is-open {
  display: block; position: fixed; z-index: 190;
  inset: 0 0 0 auto; height: 100dvh;
}
.nav__panel[hidden] { display: none; }

/* ——— the crisis strip: on every page, above the footer ——————————————— */
.crisis { background: var(--night); color: var(--on-dark); padding-block: var(--shelf); }
.crisis__in { display: grid; gap: var(--stack); }
@media (min-width: 48em) {
  .crisis__in { grid-template-columns: 1fr auto; align-items: center; gap: var(--shelf); }
}
.crisis p { margin: 0; color: var(--on-dark-soft); font-size: var(--t-small); max-width: 62ch; }
.crisis strong { color: var(--on-dark); font-size: var(--t-body); display: block; margin-bottom: 0.3rem; }
.crisis__nums { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.crisis__num {
  font-family: var(--sans); font-weight: 700; font-size: 1rem;
  color: var(--night); background: var(--sun);
  padding: 0.7rem 1.15rem; border-radius: 999px; text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px; white-space: nowrap;
}
.crisis__num:hover { background: #F5B23E; text-decoration: none; }
.crisis__num--ghost {
  background: transparent; color: var(--sun); border: 2px solid var(--sun);
}
.crisis__num--ghost:hover { background: rgba(233, 160, 32, 0.16); }

.site-foot { background: var(--night); color: var(--on-dark); padding-block: var(--band-y) var(--shelf); }
.site-foot a { color: var(--on-dark); }
.site-foot__grid { display: grid; gap: var(--shelf); }
@media (min-width: 46em) { .site-foot__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
.site-foot h2, .site-foot h3 {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sun);
  margin-bottom: 0.9rem;
}
.site-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.15rem; }
.site-foot li a {
  display: inline-flex; align-items: center; min-height: 40px;
  font-family: var(--sans); font-size: 0.95rem; text-decoration: none;
}
.site-foot li a:hover { text-decoration: underline; }
.site-foot__legal {
  margin-top: var(--shelf); padding-top: var(--stack);
  border-top: 1px solid rgba(250, 244, 232, 0.18);
  font-family: var(--sans); font-size: var(--t-small); color: var(--on-dark-soft);
  display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem;
}
.site-foot__legal p { margin: 0; max-width: 70ch; }

/* ==========================================================================
   08 COMPONENTS
   ========================================================================== */

/* ——— buttons ————————————————————————————————————————————————————— */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.55rem;
  font-family: var(--sans); font-size: 1rem; font-weight: 640;
  min-height: 52px; padding: 0.85rem 1.5rem;
  border-radius: 999px; border: 2px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: transform 180ms var(--ease-lean), background-color 180ms linear,
              border-color 180ms linear, color 180ms linear;
}
.btn:hover { text-decoration: none; transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn svg { width: 18px; height: 18px; flex: none; }

.btn--solid { background: var(--lapis); color: var(--reed); }
.btn--solid:hover { background: var(--night); }
.btn--ghost { background: transparent; color: var(--accent); border-color: currentColor; }
.btn--ghost:hover { background: color-mix(in srgb, currentColor 12%, transparent); }
.band--lapis .btn--solid, .band--night .btn--solid, .band--marsh .btn--solid,
.reedwall .btn--solid, .site-foot .btn--solid { background: var(--sun); color: var(--night); }
.band--lapis .btn--solid:hover, .band--night .btn--solid:hover,
.band--marsh .btn--solid:hover, .reedwall .btn--solid:hover { background: #F5B23E; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: var(--shelf); }

/* ——— THE DOORS — TWO ways to meet, not four ——————————————————————————
   ADR 0007. Four equal cards asked a frightened person to evaluate four things
   at once, and a row of four reads as a price table. The real decision is
   binary — do you want to leave the house or not — so the page asks that, and
   only then offers the three ways of doing it virtually.

   Both grounds clear AA against --reed: lapis 10.08, clay 5.94. */
.doors { display: grid; gap: var(--shelf); list-style: none; margin: 0; padding: 0; }
.doors > li { display: flex; }          /* so every card fills its row */
.doors > li > .door { width: 100%; }
@media (min-width: 46em) { .doors { grid-template-columns: repeat(2, 1fr); } }

.door {
  display: flex; flex-direction: column;
  background: var(--reed); border: 1px solid var(--hair);
  border-radius: 4px 4px 0 0; overflow: hidden;
  text-decoration: none; color: var(--ink);
  transition: transform 220ms var(--ease-lean), box-shadow 220ms var(--ease-lean),
              border-color 220ms linear;
}
a.door:hover, a.door:focus-visible {
  transform: translateY(-4px);
  box-shadow: 0 14px 34px rgba(10, 36, 80, 0.13);
  border-color: var(--hair-strong); text-decoration: none;
}
.door__arch {
  /* the doorway itself: a parabolic arch of colour, clipped in CSS so it needs
     no SVG per card. The mudhif profile, at card scale. */
  position: relative; height: 7.5rem; display: grid; place-items: center;
  background: var(--door, var(--lapis));
  clip-path: ellipse(78% 100% at 50% 100%);
  color: var(--reed);
}
.door__n {
  font-family: var(--sans); font-weight: 300; font-size: 2.6rem;
  line-height: 1; letter-spacing: -0.03em; opacity: 0.9;
  display: grid; justify-items: center; gap: 0.5rem;
}
.door__n svg { width: 34px; height: 34px; opacity: 0.95; }
.door__n b { font-size: 1.05rem; font-weight: 600; letter-spacing: 0.02em; }
.door__body { padding: 1.1rem 1.25rem 1.4rem; display: flex; flex-direction: column; flex: 1; }
.door h3 { margin-bottom: 0.45rem; }
.door p { font-size: var(--t-small); color: var(--ink-soft); margin-bottom: 0.9rem; }
.door__need {
  margin-top: auto; padding-top: 0.8rem; border-top: 1px solid var(--hair);
  font-family: var(--sans); font-size: var(--t-label); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--sun-ink); font-weight: 640;
}
.door--virtual { --door: var(--lapis); }
.door--room    { --door: var(--clay); }
.door h2 { font-size: var(--t-h3); margin-bottom: 0.5rem; }
.door__body p { font-size: var(--t-body); }

/* ——— the three virtual modes, offered only after the first choice ————
   Deliberately quieter than the two doors: these are a detail of one choice,
   not a third, fourth and fifth choice competing with it. */
.modes { display: grid; gap: var(--stack); list-style: none; margin: 0; padding: 0; }
@media (min-width: 54em) { .modes { grid-template-columns: repeat(3, 1fr); } }
.mode {
  border-top: 3px solid var(--mode, var(--lapis));
  padding-top: var(--stack);
}
.mode h3 { margin-bottom: 0.4rem; }
.mode p { font-size: var(--t-small); color: var(--text-soft); }
.mode__need {
  display: block; margin-top: 0.6rem;
  font-family: var(--sans); font-size: var(--t-label); font-weight: 640;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--accent-warm);
}
.mode--phone { --mode: var(--lapis); }
.mode--zoom  { --mode: var(--marsh); }
.mode--teams { --mode: var(--glaze-ink); }

/* ——— the reassurance line that follows every choice on this site ————— */
.choice-note {
  display: flex; align-items: flex-start; gap: 0.8rem;
  margin-top: var(--shelf); padding: 1rem 1.2rem;
  border-left: 3px solid var(--accent-warm);
  background: color-mix(in srgb, var(--accent-warm) 7%, transparent);
  border-radius: 0 4px 4px 0; max-width: var(--measure);
}
.choice-note svg { width: 22px; height: 22px; flex: none; color: var(--accent-warm); margin-top: 2px; }
.choice-note p { margin: 0; font-size: var(--t-small); }

/* ——— cards ———————————————————————————————————————————————————————— */
.card {
  background: var(--reed); border: 1px solid var(--hair);
  border-radius: 4px; padding: clamp(1.15rem, 0.9rem + 1vw, 1.85rem);
}
.band--reed2 .card { background: var(--reed); }
.card--bare { background: transparent; border: 0; padding: 0; border-top: 2px solid var(--rule); padding-top: var(--stack); }
.card h3 { color: var(--text); }
.card p:last-child { margin-bottom: 0; }
.card__k {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 700;
  letter-spacing: 0.15em; text-transform: uppercase; color: var(--accent-warm);
  display: block; margin-bottom: 0.6rem;
}

/* ——— the object roll: what he works with ————————————————————————— */
.roll { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.roll > li, .roll > div {
  border-top: 1px solid var(--rule); padding: 0.7rem 0;
  display: grid; gap: 0.2rem 1.5rem;
}
@media (min-width: 44em) { .roll > li, .roll > div { grid-template-columns: 15rem 1fr; align-items: baseline; } }
.roll > :last-child { border-bottom: 1px solid var(--rule); }
.roll dt, .roll b {
  font-family: var(--sans); font-weight: 680; font-size: 0.98rem; color: var(--text);
}
.roll dd, .roll span { margin: 0; color: var(--text-soft); font-size: var(--t-small); }

/* ——— steps ——————————————————————————————————————————————————————— */
.steps { list-style: none; counter-reset: s; margin: 0; padding: 0; display: grid; gap: var(--shelf); }
@media (min-width: 56em) { .steps { grid-template-columns: repeat(3, 1fr); } }
.steps li { counter-increment: s; position: relative; padding-top: 2.6rem; }
.steps li::before {
  content: counter(s, decimal-leading-zero);
  position: absolute; top: 0; left: 0;
  font-family: var(--sans); font-weight: 300; font-size: 1.7rem;
  color: var(--accent-warm); letter-spacing: -0.03em; line-height: 1;
}
.steps li::after {
  content: ''; position: absolute; top: 2.1rem; left: 0; width: 2.2rem;
  height: 2px; background: var(--accent-warm); opacity: 0.5;
}
.steps h3 { margin-bottom: 0.4rem; }
.steps p { font-size: var(--t-small); color: var(--text-soft); margin-bottom: 0; }

/* ——— the timeline on about.html —————————————————————————————————
   Two threads: the verified public history of a country on one side, and one
   person's line through it on the other. The history is sourced and checkable.
   The personal thread is Ali's to write — see .note below. */
.thread { list-style: none; margin: 0; padding: 0; }
.thread > li {
  position: relative; padding: 0 0 var(--stack) 1.8rem;
  border-left: 2px solid var(--rule);
}
.thread > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.thread > li::before {
  content: ''; position: absolute; left: -7px; top: 0.5rem;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--ground); border: 2px solid var(--accent-warm);
}
.thread__when {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-warm);
  display: block; margin-bottom: 0.35rem;
}
.thread h3 { font-size: var(--t-h3); margin-bottom: 0.5rem; }
.thread p { font-size: var(--t-small); color: var(--text-soft); }
.thread__src {
  font-family: var(--sans); font-size: 0.76rem; color: var(--text-soft);
  opacity: 0.85; display: block; margin-top: 0.3rem;
}

/* ——— the comparison table on sessions.html ————————————————————————
   A real <table> with real headers, because it is real tabular data and a
   screen reader should be able to say "Phone, needs: a telephone". It becomes
   a stack of labelled rows below 46em rather than a horizontally scrolling
   grid, because a person on a phone should not have to scroll sideways to
   compare the thing they came to compare. */
.compare-wrap { overflow-x: auto; }
.compare { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.compare caption { text-align: left; color: var(--text-soft); padding-bottom: 0.8rem; }
.compare th, .compare td {
  text-align: left; padding: 0.85rem 0.9rem; border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.compare thead th {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-warm);
  border-bottom: 2px solid var(--rule);
}
.compare tbody th { font-family: var(--sans); font-weight: 680; color: var(--text); }
@media (max-width: 45.99em) {
  .compare, .compare tbody, .compare tr, .compare td, .compare th { display: block; }
  .compare thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .compare tr { border: 1px solid var(--rule); border-radius: 4px; margin-bottom: var(--stack); padding: 0.4rem 0.9rem; }
  .compare td, .compare th { border-bottom: 0; padding: 0.5rem 0; }
  .compare td::before {
    content: attr(data-th) '  ';
    font-family: var(--sans); font-size: var(--t-label); font-weight: 700;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-warm);
    display: block; margin-bottom: 0.15rem;
  }
}

/* ——— THE HONEST PLACEHOLDER ————————————————————————————————————————
   One convention, whole site: A DASHED FRAME MEANS NOTHING HAS BEEN SUPPLIED
   YET; A SOLID ONE MEANS IT IS REAL. Every placeholder names exactly what
   would fill it and who fills it. Nothing on this site ever states a fact
   about a real person that nobody has verified — not a credential, not a fee,
   not a phone number, and above all not a biography. */
.note {
  border: 2px dashed var(--sun-ink); border-radius: 4px;
  background: color-mix(in srgb, var(--sun) 8%, transparent);
  padding: 1rem 1.15rem; margin: 0 0 var(--stack);
  max-width: var(--measure);
}
.note > :last-child { margin-bottom: 0; }
.note__k {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 800;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sun-ink);
  display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;
}
.note__k::before { content: '✎'; font-size: 0.95rem; }
.note p { font-size: var(--t-small); color: var(--ink-soft); }
.band--lapis .note, .band--night .note, .band--marsh .note, .reedwall .note {
  border-color: var(--sun); background: rgba(233, 160, 32, 0.12);
}
.band--lapis .note__k, .band--night .note__k, .band--marsh .note__k, .reedwall .note__k { color: var(--sun); }
.band--lapis .note p, .band--night .note p, .band--marsh .note p, .reedwall .note p { color: var(--on-dark-soft); }

/* ——— THE IMAGE SLOT ——————————————————————————————————————————————
   Every photograph on this site is a slot, and until a real file lands in it
   the slot shows what belongs there rather than a broken image icon.

   IT IS DELIBERATELY NOT AN <img> POINTING AT A MISSING FILE. That would fire a
   404 on every page load for every missing photograph, print a console error
   beside it, and show a broken-image glyph with JavaScript off. It is also not
   probed by script: the Content-Security-Policy sets connect-src 'none', and a
   speculative Image() probe would produce exactly the same 404 noise.

   So the slot is plain markup, and each one carries — in an HTML comment right
   beside it — the exact <img> line to paste in when the file exists, alt text
   already written. Adding a photograph is a copy, a paste and a delete.

   `npm run lint` asserts that every <img src> in the site points at a file that
   actually exists, so a typo in that paste is caught rather than shipped.

   --ar holds the aspect ratio, so the page does not reflow when the real
   photograph replaces the placeholder. Set it on the figure, and give the <img>
   matching width and height attributes. */
.shot { margin: 0 0 var(--stack); }
.shot img {
  width: 100%; height: auto; display: block; border-radius: 4px;
  aspect-ratio: var(--ar, 3 / 2); object-fit: cover;
}
.shot__ph {
  /* The placeholder is scaffolding for whoever is building the site, not reader
     content: its filenames, dimensions and English notes are inherently
     left-to-right and get reordered by the bidi algorithm inside ar.html. */
  direction: ltr;
  aspect-ratio: var(--ar, 3 / 2);
  border: 2px dashed var(--sun-ink);
  border-radius: 4px;
  background:
    color-mix(in srgb, var(--sun) 7%, transparent);
  display: grid; align-content: center; justify-items: center; gap: 0.45rem;
  padding: clamp(1rem, 0.7rem + 1.4vw, 2rem); text-align: center;
}
.shot__k {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 800;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sun-ink);
  display: flex; align-items: center; gap: 0.45rem;
}
.shot__k::before { content: '⌸'; font-size: 0.95rem; }
.shot__what {
  margin: 0; font-size: var(--t-small); color: var(--ink-soft);
  max-width: 34ch; line-height: 1.45;
}
.shot__file {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78rem; color: var(--sun-ink);
  background: color-mix(in srgb, var(--sun) 14%, transparent);
  padding: 0.2rem 0.5rem; border-radius: 3px;
  /* break at the slashes, not mid-word — a path split as "marsh es-01.jpg"
     reads as a rendering fault in a narrow column */
  word-break: normal; overflow-wrap: anywhere;
}
.shot__spec {
  font-family: var(--sans); font-size: 0.72rem; letter-spacing: 0.06em;
  color: var(--ink-soft); opacity: 0.9;
}
.shot__cap {
  font-family: var(--sans); font-size: var(--t-small); color: var(--text-soft);
  margin-top: 0.55rem; line-height: 1.45; max-width: 46ch;
}

/* on the dark bands the dashed frame uses the dark-ground member of the family */
.band--lapis .shot__ph, .band--night .shot__ph, .band--marsh .shot__ph, .reedwall .shot__ph {
  border-color: var(--sun); background: rgba(233, 160, 32, 0.11);
}
.band--lapis .shot__k, .band--night .shot__k, .band--marsh .shot__k, .reedwall .shot__k { color: var(--sun); }
.band--lapis .shot__what, .band--night .shot__what, .band--marsh .shot__what,
.reedwall .shot__what { color: var(--on-dark-soft); }
.band--lapis .shot__file, .band--night .shot__file, .band--marsh .shot__file, .reedwall .shot__file {
  color: var(--sun); background: rgba(233, 160, 32, 0.16);
}
.band--lapis .shot__spec, .band--night .shot__spec, .band--marsh .shot__spec,
.reedwall .shot__spec { color: var(--on-dark-soft); }

/* The mudhif profile, for a photograph that wants to be a doorway.
   ONLY the real image is arched. Clipping the placeholder too cuts straight
   through its dashed frame, leaving an arch of fill floating above a
   three-sided rectangle — which reads as a rendering bug rather than a
   deliberate empty slot. The placeholder stays an honest rectangle. */
.shot--arch img { clip-path: ellipse(78% 100% at 50% 100%); }

/* a full-bleed band of photograph */
.shot--wide { --ar: 21 / 9; }
.shot--tall { --ar: 4 / 5; }
.shot--square { --ar: 1 / 1; }

/* The introduction under the hero: a small portrait beside two lines of text,
   not a feature image. Sized deliberately small — at 7rem the file's real 274px
   is roughly four times what the box needs, so this is the one photograph on the
   site that stays sharp on a retina screen. It wraps to a stacked layout on a
   narrow phone rather than squeezing the text into a column. */
.intro { display: flex; flex-wrap: wrap; gap: var(--shelf); align-items: flex-start; }
.intro__pic { flex: 0 0 7rem; width: 7rem; margin: 0; }
.intro__text { flex: 1 1 18rem; }
.intro__text p:last-child { margin-bottom: 0; }

/* a row of them */
.shots { display: grid; gap: var(--stack); }
@media (min-width: 46em) { .shots--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62em) { .shots--3 { grid-template-columns: repeat(3, 1fr); } }

/* ——— a plain, quiet callout for things that ARE true ————————————— */
.said {
  border-left: 3px solid var(--accent-warm); padding: 0.2rem 0 0.2rem 1.2rem;
  margin: 0 0 var(--stack); max-width: var(--measure);
}
.said p { font-size: var(--t-lead); line-height: 1.45; font-variation-settings: 'opsz' 24; }
.said p:last-child { margin-bottom: 0; }

/* ——— contact rows: the two real ways to reach a person ——————————— */
.reach { display: grid; gap: var(--stack); list-style: none; margin: 0; padding: 0; }
@media (min-width: 44em) { .reach { grid-template-columns: repeat(2, 1fr); } }
.reach a {
  display: flex; align-items: center; gap: 1rem;
  border: 1px solid var(--rule); border-radius: 4px;
  padding: 1.1rem 1.25rem; min-height: 76px;
  text-decoration: none; color: var(--text);
  transition: border-color 180ms linear, transform 180ms var(--ease-lean);
}
.reach a:hover { border-color: var(--accent); transform: translateY(-2px); text-decoration: none; }
.reach svg { width: 26px; height: 26px; color: var(--accent-warm); flex: none; }
.reach b { display: block; font-family: var(--sans); font-size: 1.05rem; font-weight: 700; }
.reach span { display: block; font-size: var(--t-small); color: var(--text-soft); }

/* ——— the Arabic invitation band ————————————————————————————————— */
[lang='ar'], .ar { font-family: var(--arabic); direction: rtl; text-align: right; line-height: 1.85; }
.ar-band__in { display: grid; gap: var(--shelf); }
@media (min-width: 52em) { .ar-band__in { grid-template-columns: 1fr 1fr; align-items: center; } }
.ar-band .ar h2 { font-family: var(--arabic); font-size: var(--t-h2); line-height: 1.5; letter-spacing: 0; }
.ar-band .ar p { font-size: var(--t-lead); margin-inline-start: 0; }

/* ==========================================================================
   09 MOTION — the four gestures
   Read the MOTION LAW at the top of this file first. The single rule that
   governs everything here:

       THE BASE STATE OF EVERY ANIMATED THING IS ITS FINISHED STATE.

   Every unfinished state below is written under `html:not(.no-js):not(.rm)`,
   so it only ever applies where the JavaScript that can undo it is actually
   running and the visitor has not asked for reduced motion. Delete site.js and
   the site still renders completely — that is the test.

   `.no-js` is an ATTRIBUTE on <html> that site.js removes. It must never be set
   by an inline script: with JavaScript disabled the script cannot run, so the
   fallback would never apply and every animated element would stay invisible.
   `.rm` is added by site.js when prefers-reduced-motion is (or becomes) reduce.
   ========================================================================== */

/* ——— shared arrival ——————————————————————————————————————————————— */
html:not(.no-js):not(.rm) [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--dur-bundle) var(--ease-return),
    transform var(--dur-bundle) var(--ease-return);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
html:not(.no-js):not(.rm) [data-reveal].is-in { opacity: 1; transform: none; }

/* ——— GESTURE 1 · THE FLOOD ————————————————————————————————————————
   The band's content arrives from its bottom edge upward, the way water came
   back into the marshes. inset(100% 0 0 0) is fully closed; inset(0) is open. */
html:not(.no-js):not(.rm) .floods {
  clip-path: inset(100% 0 0 0);
  transition: clip-path var(--dur-flood) var(--ease-return);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
html:not(.no-js):not(.rm) .floods.is-in { clip-path: inset(0 0 0 0); }

/* ——— GESTURE 2 · THE BUNDLE ————————————————————————————————————————
   Strands arrive staggered and close toward one another. This is the site's
   signature and it says the only thing the site is really about: thin things
   hold when they are held together. */
html:not(.no-js):not(.rm) .bundles > * {
  opacity: 0;
  transform: translateY(20px) scaleY(0.92);
  transform-origin: 50% 100%;
  transition:
    opacity var(--dur-bundle) var(--ease-return),
    transform var(--dur-bundle) var(--ease-return);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
html:not(.no-js):not(.rm) .bundles.is-in > * { opacity: 1; transform: none; }

/* the reed wall's own strands grow from the ground, slower and further apart */
html:not(.no-js):not(.rm) .reedwall__strands span {
  opacity: 0; transform: scaleY(0.2);
  transition: opacity 900ms var(--ease-return), transform 1200ms var(--ease-return);
  transition-delay: calc(var(--i, 0) * 26ms);
}
html:not(.no-js):not(.rm) .reedwall.is-in .reedwall__strands span { opacity: 1; transform: none; }

/* the vault rings draw themselves. pathLength="1" on each <path> normalises
   every arch to a length of 1 regardless of its real geometry, so one pair of
   values draws all six correctly and nothing has to be measured in JS. */
html:not(.no-js):not(.rm) .vault__ring {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 1700ms var(--ease-return);
  transition-delay: calc(var(--i, 0) * 130ms);
}
html:not(.no-js):not(.rm) .is-in .vault__ring { stroke-dashoffset: 0; }
html:not(.no-js):not(.rm) .vault__light {
  opacity: 0; transition: opacity 1800ms var(--ease-return) 500ms;
}
html:not(.no-js):not(.rm) .is-in .vault__light { opacity: 1; }

/* ——— GESTURE 3 · THE LIGHT THROUGH ————————————————————————————————
   A warm sweep crossing the h1 once, the way sun crosses a reed wall. Once per
   page, never on body copy.

   The base rule sets a normal `color` and does NOT make the text transparent.
   Transparency is added only inside the @supports test AND only where motion is
   allowed, so a browser without background-clip: text — or a visitor with
   reduced motion — gets ordinary, fully legible type instead of nothing at all.
   Getting this wrong is how a headline silently disappears. */
.lightthrough { color: var(--text); }

@media (prefers-reduced-motion: no-preference) {
  @supports ((background-clip: text) or (-webkit-background-clip: text)) {
    html:not(.no-js):not(.rm) .lightthrough.is-in {
      background-image: linear-gradient(100deg,
        var(--text) 0 40%,
        var(--sun) 47%,
        var(--glaze) 53%,
        var(--text) 60% 100%);
      background-size: 340% 100%;
      background-repeat: repeat;
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
      animation: light-through 2600ms var(--ease-return) 260ms both;
    }
  }
}
@keyframes light-through {
  /* 0%..100% only. Outside that range the background stops covering the text
     box and background-clip: text turns the uncovered glyphs invisible. This
     shipped once as a hero headline with its left third missing. */
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

/* ——— GESTURE 4 · THE LEAN ————————————————————————————————————————
   8px of settle, and elements arrive TOWARD their neighbour rather than
   upward, because an arch stands by leaning. Three per page, maximum. */
html:not(.no-js):not(.rm) .leans > * {
  opacity: 0; transform: translateX(8px);
  transition:
    opacity var(--dur-lean) var(--ease-lean),
    transform var(--dur-lean) var(--ease-lean);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
html:not(.no-js):not(.rm) .leans > *:nth-child(even) { transform: translateX(-8px); }
html:not(.no-js):not(.rm) .leans.is-in > * { opacity: 1; transform: none; }

/* ——— the scroll progress rule ——————————————————————————————————————
   Native scroll-driven animation where it exists; site.js sets --p otherwise.
   Purely decorative, so it carries aria-hidden and is never the only signal. */
.progress { position: fixed; inset: 0 0 auto; height: 3px; z-index: 150; pointer-events: none; }
.progress span {
  display: block; height: 100%; transform-origin: 0 50%;
  transform: scaleX(var(--p, 0));
  background: linear-gradient(90deg, var(--lapis), var(--glaze-ink), var(--sun-ink));
}
@supports (animation-timeline: scroll()) {
  html:not(.no-js):not(.rm) .progress span {
    transform: scaleX(0);
    animation: progress-grow linear;
    animation-timeline: scroll();
  }
}
@keyframes progress-grow { to { transform: scaleX(1); } }

/* ——— REDUCED MOTION ————————————————————————————————————————————————
   Belt and braces. site.js adds .rm, which every rule above already respects;
   this query catches the case where the preference is set before site.js has
   run, and forces any remaining animation to a single frame. Nothing is hidden,
   because nothing was hidden in the base state. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .btn:hover, a.door:hover, .reach a:hover { transform: none; }
}

/* ==========================================================================
   10 THE ARABIC PAGE — ar.html
   Right-to-left, and not a translated skin: the whole page is authored in
   Arabic. The logical properties used throughout this stylesheet mean almost
   nothing needs flipping; what does is here.
   ========================================================================== */

html[dir='rtl'] body { font-family: var(--arabic); }
html[dir='rtl'] h1, html[dir='rtl'] h2, html[dir='rtl'] h3 {
  font-family: var(--arabic); letter-spacing: 0; line-height: 1.42;
}
html[dir='rtl'] .eyebrow { letter-spacing: 0; }
html[dir='rtl'] .thread > li { border-left: 0; border-right: 2px solid var(--rule); padding: 0 2.1rem var(--shelf) 0; }
html[dir='rtl'] .thread > li::before { left: auto; right: -7px; }
html[dir='rtl'] .said { border-left: 0; border-right: 3px solid var(--accent-warm); padding: 0.2rem 1.2rem 0.2rem 0; }
html[dir='rtl'] .steps li::before, html[dir='rtl'] .steps li::after { left: auto; right: 0; }
html[dir='rtl'] .skip { left: auto; right: 0.75rem; }
html[dir='rtl'] .progress span { transform-origin: 100% 50%; }
/* Latin runs inside Arabic text — "Zoom", "Teams", a phone number — must not
   have their characters reordered by the bidi algorithm. */
.ltr { direction: ltr; unicode-bidi: isolate; display: inline-block; }

/* ==========================================================================
   11 PRINT
   Someone may print the crisis numbers and put them on a fridge. That is a
   real use of this site and it is worth two dozen lines.
   ========================================================================== */

@media print {
  .site-head, .nav, .progress, .vault, .reedwall__strands, .skip { display: none !important; }
  html, body { background: #fff !important; color: #000 !important; font-size: 11pt; }
  .band, .crisis, .site-foot, .reedwall {
    background: #fff !important; color: #000 !important; padding-block: 0.6cm;
  }
  .crisis__num { border: 1pt solid #000 !important; background: #fff !important; color: #000 !important; }
  a { text-decoration: underline; }
  /* the destination of a link is invisible on paper unless it is printed */
  main a[href^='http']::after, main a[href^='tel:']::after, main a[href^='mailto:']::after {
    content: ' (' attr(href) ')'; font-size: 9pt; word-break: break-all;
  }
  .note { border: 1pt dashed #666 !important; background: #fff !important; }
  h1, h2, h3 { break-after: avoid; }
  li, p { break-inside: avoid; }
}
