/* Arqam Financial Group. Design system
   Ground: ink navy #171747 (brand). Metal: platinum #D2D2D2 (brand).
   Paper: cool ledger white. Brass #a98d54 for hairlines/eyebrows only.
   Display: Cinzel (brand face). Body: Source Serif 4. UI: system sans.
   Signature: the accountant's double-ruled total line under headings. */

/* A METRIC-MATCHED FALLBACK FOR CINZEL, so the webfont swap moves nothing.
 *
 * Cloudflare put 20% of real loads of this page in CLS "Poor", and named
 * #top>div.hero-lede>p.lead and #top>dl.ledger-strip at a score of 1.0. Neither
 * is the culprit. Both simply sit UNDER the h1.
 *
 * Measured in a browser rather than guessed: the h1 is 145px tall once Cinzel
 * arrives and 73px in the fallback, because Cinzel's advance widths are 138.2%
 * of Times and Georgia (1907px against 1380px for the headline at 100px). The
 * headline therefore wraps to two lines in Cinzel and fits on one in the
 * fallback, and the swap drops everything below it by 72px. With
 * `display=swap` on the Google Fonts link, that can happen to any visitor whose cache is
 * cold and whose font arrives after first paint, which is what a real-user metric measures and a warm local
 * reload does not.
 *
 * So the fallback is scaled to occupy Cinzel's box. size-adjust matches the
 * widths, which is what decides the line count; the ascent and descent
 * overrides are divided by that same 1.382 because they are read against the
 * ALREADY ADJUSTED em, and without that correction the line boxes would grow by
 * 38% and trade one shift for another. Cinzel's own metrics are 97.6% ascent
 * and 37.2% descent.
 *
 * ONE size-adjust FOR EVERY HEADING, swept rather than derived. Cinzel renders
 * lowercase as small caps, so the width ratio against a fallback depends on the
 * glyph mix: 138.2% for the home page headline, 141.2% for the bookkeeping one,
 * about 129% for a mixed-case line. A single value cannot be exact everywhere.
 *
 * The ratio is not what matters though. The LINE COUNT is, because that is what
 * moves the page, and a couple of percent only matters when a heading happens
 * to sit near a wrap boundary.
 *
 * So it was chosen by sweeping 134% to 143% against 83 real headings from all
 * seven pages AT 390px, where narrow columns make wrapping most sensitive.
 * Everything from 136% to 141.2% scores one mismatch; 134% and 143% score two.
 * 138.2% sits in the middle of that plateau, which is where a value should sit
 * when the edges are worse. Nothing reaches zero.
 *
 * The one that still differs is the /about h1, "The people behind your
 * numbers.", where the fallback takes three lines to Cinzel's two.
 *
 * An earlier version of this note claimed every element wrapped identically.
 * That was measured at desktop width only, where almost every heading is a
 * comfortable single line and the test could not fail. Mobile is the case worth
 * checking and it was not checked.
 *
 * Numbers to re-derive, not to trust, if the display face ever changes. */
@font-face {
  font-family: "Cinzel fallback";
  src: local("Times New Roman"), local("Georgia"), local("Liberation Serif");
  size-adjust: 138.2%;
  ascent-override: 70.6%;
  descent-override: 26.9%;
  line-gap-override: 0%;
  /* LATIN ONLY, and this is load-bearing rather than tidiness.
   *
   * Cinzel has no Arabic glyphs, so on the Arabic site a heading falls straight
   * past it to the next family in --display. Without this line that next family
   * is this one, and real Times New Roman DOES cover Arabic, so Arabic headings
   * would render 38.2% oversized PERMANENTLY, not just during a font swap.
   *
   * It does not reproduce on this laptop: Linux substitutes Liberation Serif
   * for Times, Liberation Serif has no Arabic, and the characters fall further
   * down the chain to a font with no adjustment. So the measurement here says
   * 1.03x and the measurement on a visitor's Windows or iOS device would say
   * 1.38x. Astra raised it; the platform hid it.
   *
   * Restricting the range means Arabic can never reach this face on any
   * platform, which makes the bug unrepresentable instead of undetected.
   * This is Google's own latin and latin-ext subset range, which is what
   * Cinzel itself ships. */
  unicode-range: U+0000-00FF, U+0100-024F, U+0131, U+0152-0153, U+02BB-02BC,
    U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+1E00-1EFF, U+2000-206F,
    U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+A720-A7FF,
    U+FEFF, U+FFFD;
}

:root {
  --navy: #171747;
  --navy-2: #1e1e5a;
  --night: #101038;
  --platinum: #d2d2d2;
  --platinum-2: #ebebe9;
  /* THE LIGHT RAMP. Measured, not chosen by eye, because "still too bright"
     survived two rounds of nudging hex values a couple of points at a time.
     What the measurement showed:
       ivory 83.8%   paper 88.6%   light 94.7%   .plan card 100.0%
     Four values inside the top 16% of the luminance range. They do not read as
     four materials, they read as one white field with faint seams. And the
     brightest of them was pure white, on the pricing cards, under a comment in
     this same file saying never to use pure white.
     Paper under office light is nearer 70% luminance. At 88% on a backlit
     panel, next to a 1.2% navy, the page is a lamp: that is a photometric
     fact about the surface, not a matter of taste.
     So the whole ramp drops about 10 points and the steps roughly double.
     Body text had 7.4:1 against a 4.5:1 requirement, so there was room. What
     actually bound the move was --brass-ink, the small uppercase eyebrows and
     tick marks, which fails AA once paper passes ~78%: hence the darker brass
     below. Ramp now 73.7 / 79.0 / 83.9 / 90.5, every pairing >= 5.3:1. */
  --paper: #d8d0bc;
  /* Warmer and darker than --paper. Used to mark the start and the end of the
     reading stretch so the page reads as movements rather than one long field. */
  --ivory: #cfc6b0;
  --ink: #1c1c34;
  --ink-soft: #4c4c66;
  --brass: #a98d54;
  --brass-soft: #c4b28c;
  /* Darkened twice, with the ramp each time. #7a6234 failed the first ramp's
     ivory at 4.3:1; #6b5529 failed the kraft ivory at 4.18:1. This is 5.08:1
     there and 5.62:1 on the main field. */
  --brass-ink: #5c4922;
  /* The pricing card, which has to lift off the light band it sits on without
     being the brightest thing on the site. */
  --card: #ece6d8;
  --line-dark: rgba(210, 210, 210, 0.22);
  --line-light: rgba(23, 23, 71, 0.18);
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --serif: "Source Serif 4", Georgia, serif;
  --display: "Cinzel", "Cinzel fallback", "Times New Roman", serif;
  /* ARABIC NEVER USES THE ADJUSTED FACE.
   *
   * unicode-range keeps Arabic LETTERS off it, but a heading also contains
   * SPACES, and U+0020 sits inside the Latin range, so the adjusted face still
   * supplied the word gaps at 138.2% and an Arabic headline measured 2.7% wide.
   * Small, real, and pointless to carry: Cinzel has no Arabic glyphs, so the
   * fallback face can never be doing useful work on an RTL page. Taking it out
   * of the stack entirely is simpler than trying to carve a space out of a
   * range. The language switcher sets dir="rtl" on <html>, so this follows it. */
}

[dir="rtl"] {
  --display: "Cinzel", "Times New Roman", serif;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

body {
  margin: 0;
  background: var(--navy);
  color: var(--platinum);
  font-family: var(--serif);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.skip-link {
  position: absolute; inset-inline-start: 1rem; top: -3rem; z-index: 50;
  background: var(--platinum); color: var(--navy); font-family: var(--sans);
  font-size: 0.85rem; font-weight: 600; padding: 0.5rem 1rem; border-radius: 0 0 6px 6px;
  transition: top 160ms ease;
}
.skip-link:focus { top: 0; }

a { color: inherit; }
a:focus-visible, button:focus-visible, select:focus-visible {
  outline: 2px solid var(--brass-soft); outline-offset: 3px;
}

/* ---------- header ---------- */
.top {
  --top-pad-y: 1.1rem;
  display: flex; align-items: center; gap: 1.25rem;
  /* Align the header's contents to the same 74rem column as the page body
     instead of to the viewport edge. max() keeps the comfortable mobile
     padding on narrow screens and snaps to the grid once there is room. */
  padding-block: var(--top-pad-y);
  padding-inline: max(clamp(1.25rem, 5vw, 3.5rem), calc((100% - 74rem) / 2));
  border-bottom: 1px solid var(--line-dark);
}
.brand img { display: block; height: clamp(54px, 8vw, 80px); width: auto; }
.top nav { display: flex; align-items: center; gap: 1.5rem; margin-inline-start: auto;
  /* Stretch to the header's full height, padding included, so a dropdown
     anchored to 100% of a nav item lands on the header's bottom border
     instead of 44px above it, punching up through the rule. The links stay
     vertically centred because this is align-items:center. */
  align-self: stretch;
  margin-block: calc(-1 * var(--top-pad-y)); padding-block: var(--top-pad-y); }
.top nav a {
  font-family: var(--sans); font-size: 0.85rem; font-weight: 500;
  letter-spacing: 0.02em; text-decoration: none; color: var(--platinum);
  opacity: 0.85;
}
.top nav a:hover { opacity: 1; text-decoration: underline; text-underline-offset: 4px; }
.menu-toggle {
  display: none; color: var(--platinum); background: transparent;
  border: 1px solid var(--line-dark); border-radius: 999px;
  padding: 0.38rem 0.75rem; font: 600 0.8rem var(--sans); cursor: pointer;
}
.lang select {
  appearance: none; font-family: var(--sans); font-size: 0.8rem; font-weight: 600;
  color: var(--platinum); background: transparent;
  border: 1px solid var(--line-dark); border-radius: 999px;
  padding: 0.35rem 1.6rem 0.35rem 0.9rem; cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23d2d2d2' fill='none' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.7rem center;
}
[dir="rtl"] .lang select { background-position: left 0.7rem center; padding: 0.35rem 0.9rem 0.35rem 1.6rem; }
.lang option { color: #111; }

/* The collapsed nav has to cover every width where the full nav does not FIT,
   not just phone widths. At 640px the hamburger disappeared while six links
   plus the wordmark and the language select still needed about 920px, so
   everything from 660px to 900px scrolled sideways: 170px of overflow at
   660px, and "Contact" clipped off the edge at 768px, which is iPad portrait.
   Measured in a browser across 600-1040px, not guessed. */
/* 1079, not 940. The desktop nav used to switch on at 941px, where its own
   contents do not fit: measured overflow was 50px in English and 75px in
   Spanish at 941px, and Spanish still overflowed at 1024px. Arabic fitted,
   which is why testing only English and only 1440/390 missed it. The header is
   a 230px logo, seven links and a language select; 1080px is where the widest
   locale stops overflowing. */
@media (max-width: 1079px) {
  .top nav { display: none; }
  .top { position: relative; flex-wrap: wrap; gap: 0.65rem; }
  .menu-toggle { display: inline-flex; margin-inline-start: auto; }
  .top nav.open {
    display: flex; flex: 1 0 100%; order: 10; margin: 0;
    padding-top: 0.75rem; border-top: 1px solid var(--line-dark);
    flex-direction: column; gap: 0;
  }
  .top nav.open a { padding: 0.7rem 0; font-size: 0.95rem; }
  .lang { margin-inline-start: auto; }
  .menu-toggle + nav + .lang { margin-inline-start: 0; }
}
@media (min-width: 1080px) { .lang { margin-inline-start: 0; } }

/* ---------- shared type ---------- */
.eyebrow {
  font-family: var(--sans); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--brass-soft); margin: 0 0 1.1rem;
}
.eyebrow-dark { color: var(--brass-ink); }

h1, h2 {
  font-family: var(--display); font-weight: 500;
  letter-spacing: 0.015em; text-wrap: balance; margin: 0 0 1.4rem;
}
h1 { font-size: clamp(2.2rem, 6.5vw, 4.2rem); line-height: 1.08; color: var(--platinum-2); }
h2 { font-size: clamp(1.5rem, 3.6vw, 2.3rem); line-height: 1.18; }

/* signature: the accountant's total line, one hairline, then a double rule */
h2 { padding-bottom: 0.9rem; position: relative; }
h2::after {
  content: ""; position: absolute; inset-inline-start: 0; bottom: 0;
  width: 5.5rem; height: 5px;
  border-top: 1px solid currentColor; border-bottom: 3px double currentColor;
  opacity: 0.55;
}

.lead, .body { max-width: 34em; font-size: clamp(1.05rem, 2.2vw, 1.2rem); }
.fineprint { font-family: var(--sans); font-size: 0.78rem; opacity: 0.7; max-width: 40em; }
/* On the light .paper sections the fade has no room to work with. Fine print
   there inherits --ink-soft, which is only 5.40:1 on paper and 4.88:1 on the
   ivory band, so opacity 0.7 took it to 2.98:1 (Lighthouse, 2026-09-24). That
   line is the "not tax advice" disclaimer, the one sentence that has to be
   readable. Its smaller size already sets it apart; it keeps full strength. */
.paper .fineprint { opacity: 1; }

/* ---------- buttons ---------- */
.cta-row { display: flex; flex-wrap: wrap; gap: 0.9rem; margin: 1.8rem 0 0; }
.cta-row.center { justify-content: center; }
.btn {
  font-family: var(--sans); font-size: 0.92rem; font-weight: 600;
  letter-spacing: 0.02em; text-decoration: none;
  padding: 0.8rem 1.6rem; border-radius: 4px;
  transition: transform 140ms ease, background 140ms ease, color 140ms ease;
}
.btn:hover { transform: translateY(-1px); }
.btn-solid { background: var(--platinum); color: var(--navy); }
.btn-solid:hover { background: var(--card); }  /* not #fff: see the light ramp */
.btn-line { border: 1px solid var(--platinum); color: var(--platinum); }
.btn-line:hover { background: rgba(210,210,210,0.12); }
.paper .btn-solid { background: var(--navy); color: var(--platinum-2); }
.paper .btn-solid:hover { background: var(--navy-2); }

/* ---------- hero: real photograph, darkened under navy, text left ---------- */
.hero {
  /* The homepage hero wraps its contents in .hero-lede (74rem). The service
     pages put the eyebrow and h1 straight inside .hero, so they were laid out
     against this padding alone and started 72px to the left of every other
     element on the page, header included. Snapping the inline padding to the
     grid fixes those pages without needing a wrapper in each one, and is a
     no-op on the homepage where .hero-lede already constrains the width. */
  padding-block: clamp(3.5rem, 8vw, 6rem) clamp(3rem, 7vw, 5rem);
  padding-inline: max(clamp(1.25rem, 5vw, 3.5rem), calc((100% - 74rem) / 2));
  position: relative;
  overflow: hidden;
  /* Drawn artwork, not a photograph. The previous hero was a stock image whose
     documents were legible Polish, a foreign company's tax ID and a
     remote-work survey, on the homepage of a Maryland accounting firm.
     What replaced it, hero-columns.svg, was its own mistake: an invented
     isometric skyline with Gaussian blur and cast-shadow ellipses, in a
     silhouette that rose and fell where the real mark only rises. It looked
     like clip art of a logo rather than the logo.
     hero-mark.svg carries the six bar paths verbatim out of
     assets/arqam-logo.svg. Flat, sheared, brass, one focal bar. 1.1KB. */
  /* Flat navy. The brass glow and the three-stop wash that were here read as
     haze rather than as light; with the artwork doing the work the ground
     should be quiet. */
  background: #14143c;
}
.hero::before {
  content: "";
  position: absolute;
  /* Fully contained. This mark has now been rebuilt four times and every
     version failed the same way: it was cut by the section edge. The first
     sized its box as a percentage of the hero and pinned the art to
     `right bottom`. The second centred a 300px square, where the gaps between
     bars are as wide as the bars and it reads as a wobbly chart rather than an
     identity. The third bled it past the inline end on purpose, on the theory
     that an intentional crop reads differently from an accidental one. It does
     not. Reported as "the transparent logo going off screen" on every page
     that has a hero, which is nine of them.
     A logo is the one graphic on a page that must never look damaged, so it is
     inset like everything else and the whole mark is visible. */
  /* Anchored near the top, not centred on the hero. Centred at 62% height it
     spanned 542px to 1070px down the viewport while the trust strip sits at
     739px to 889px, so the mark ran straight through "VIRTUAL OR LOCAL" and
     the QuickBooks badges. Measured, after it was reported as looking out of
     place. It now lives in the empty upper right beside the headline and
     finishes well above the strip. */
  /* Placed where it was asked for: the open middle of the hero's right half,
     large, ending above the trust strip rather than running through it.
     Pinned flush to the inline edge it sat in the corner; pinned to 50% of the
     hero it ran from 542px to 1070px down the viewport and crossed the strip
     at 739px. This sits roughly 70% across and stops at about 726px. */
  top: clamp(3.5rem, 7vw, 5.5rem);
  inset-inline-end: clamp(2rem, 13vw, 12rem);
  height: clamp(260px, 38vw, 520px);
  aspect-ratio: 1;
  background: url("/assets/hero-mark.svg") center / contain no-repeat;
  /* Platinum, not brass. Brass at any usable opacity turns to mud on #14143c
     and competes with the headline. */
  opacity: 0.085;
  pointer-events: none;
}
/* Below the copy's breakpoint the text needs the full width, and a decorative
   panel behind body copy is just noise. */
@media (max-width: 60rem) {
  /* Hidden, not faded. At 35% it still sat behind the paragraph, and texture
     behind body copy costs legibility for decoration nobody asked for. */
  .hero::before { display: none; }
}
.hero-lede { max-width: 74rem; margin: 0 auto; }
.hero-lede .lead { max-width: 32em; }
.hero .lead { color: var(--platinum); opacity: 0.94; }
.hero-lede .cta-row { margin-top: 2rem; }

/* ---------- trust strip ---------- */
.ledger-strip {
  max-width: 74rem; margin: clamp(2.5rem, 6vw, 4.5rem) auto 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0; border-top: 1px solid var(--line-dark);
}
.ledger-strip > div {
  padding: 1.2rem 1.4rem 1.2rem 0;
  border-bottom: 1px solid var(--line-dark);
}
.ledger-strip dt {
  font-family: var(--sans); font-size: 0.8rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--platinum-2);
  min-height: 1.35rem;
}
.ledger-strip .stars { color: var(--brass-soft); letter-spacing: 0.18em; font-size: 1.05rem; }
.ledger-strip dd {
  margin: 0.3rem 0 0; font-family: var(--sans); font-size: 0.85rem;
  color: var(--platinum); opacity: 0.75; line-height: 1.5;
}
.qb-badges { display: flex; gap: 0.7rem; margin-top: 0.8rem; }
.qb-badges img { height: 50px; width: auto; filter: drop-shadow(0 2px 6px rgba(0,0,0,0.35)); }

/* ---------- sections ---------- */
/* SECTION RHYTHM.
   The page was navy, then roughly 4,000px of one unbroken cream, then navy.
   Alternating at every boundary would just be another repeated pattern, so the
   sequence is dark, warm, light, dark, sustained light, warm, dark: the warm
   ivory opens and closes the reading stretch, the white middle carries the
   comparison work (pricing, process, testimonials), and navy marks the two
   moments that are not reading. */
/* Inline padding snaps to the same 74rem grid as the header and the hero.
   Sections that already wrap their contents in .measure are unaffected (the
   maths lands on the identical edge); it is the pages that put content
   straight inside .paper, privacy being the one, that stop drifting. */
.paper { background: var(--paper); color: var(--ink);
  --paper-pad-y: clamp(3rem, 8vw, 5.5rem);
  padding-block: var(--paper-pad-y);
  padding-inline: max(clamp(1.25rem, 5vw, 3.5rem), calc((100% - 74rem) / 2)); }
.paper.warm  { background: var(--ivory); }
/* Never pure white. #ffffff was the brightest value anywhere on the site
   and sat directly under a #171747 hero. See the light ramp in :root: this
   band came down from #faf9f5 (94.7% luminance) with the rest of it. */
.paper.light { background: #e2dbc9; }
/* Two adjacent light sections share one continuous field, so the boundary
   between them is carried by typography rather than a colour change. */
.paper.light + .paper.light { padding-top: clamp(1.5rem, 4vw, 2.5rem); }
.navy {
  background: var(--navy);
  color: var(--platinum);
  padding: clamp(3rem, 8vw, 5.5rem) clamp(1.25rem, 5vw, 3.5rem);
  border-top: 1px solid var(--line-dark);
}
/* AFGTracker section: a faceless "reviewing the numbers" photo, heavily
   darkened so the copy and phones stay crisp but the charts read through:
   meaningful texture, clearly visible, not a flat navy. */
/* No photograph here either: the previous background was a stock securities
   chart. Candlesticks, "Stop Loss", "Take Profit". Sitting behind copy that
   sells a bookkeeping app, on a regulated firm's site.
   What sits here now is the product itself, so the background's only job is to
   light it. year-months.svg used to be tiled behind this section at
   "center bottom"; once the screenshot went full width the chart was covered by
   it and showed only as a row of clipped shapes poking out underneath, which
   read as a rendering fault. It is still used, below the shot, where it has its
   own space and nothing can crop it. See .app-months. */
.navy#afgtracker {
  position: relative;
  overflow: hidden;
  background: #14143c;
}
.navy#afgtracker::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(64rem 34rem at 50% 74%, rgba(169, 141, 84, 0.10), transparent 70%);
  pointer-events: none;
}
.navy#afgtracker > * { position: relative; z-index: 1; }
.paper h2 { color: var(--navy); }
.paper p { color: var(--ink-soft); }
/* ONE page grid. This was 62rem while the hero, the trust strip, the services
   block and .app-layout were all 74rem, so the homepage stepped 128px, 224px,
   128px, 224px down the left edge as you scrolled, and the service pages ran
   their header at 56px and their body at 224px. Nothing was centred wrongly;
   every section was centred on a DIFFERENT width, which is what reads as "it
   does not look like the rest of the site".
   Prose does not get harder to read at this width because .lead and .body are
   capped at 34em independently of the container. */
.measure { max-width: 74rem; margin: 0 auto; }

/* ---------- services ---------- */
/* One photograph beside five open rows. The previous version was a five-column
   grid of rounded cards, and giving each card its own picture fixed the
   texture without touching the structure: five identical containers, five
   identical reading sequences, five equally weighted images. Rows share one
   rule system so the eye can compare services instead of re-reading the same
   shell five times, and on mobile they cost a fraction of the scroll. */
/* 74rem, not 76. The page has one outer grid and this section was 16px wider
   than the hero on each side, which does not read as a deliberate change of
   width, it reads as a section that missed the grid. 74rem is load-bearing
   elsewhere (.app-layout renders the 2368px capture at true 1:1 only at that
   width), so it is the measurement everything else aligns to. */
#services .measure { max-width: 74rem; }
.svc-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.85fr);
  gap: 0 4rem; align-items: start; margin-top: 0;
}
.svc-intro .eyebrow { margin-bottom: 0.6rem; }
.svc-intro h2 { margin-top: 0; }
.svc-intro .body { max-width: 26em; margin-top: 1rem; }
/* The figure sits BELOW the intro text, in normal flow, not behind it.
   It used to be position:absolute inset:0, which laid the photograph across
   the whole column including the words, so it had to be dropped to 5.5%
   opacity to keep the text readable. At 5.5% it was not a design element, it
   was a smudge: you could not tell it was a photograph unless you already
   knew one was there.
   In flow it overlaps nothing, so it can carry a real opacity, and it fills
   the empty lower half of the left column that the five rows tower over. */
.svc-intro { position: relative; }
.svc-rows { display: flex; flex-direction: column; }
@media (max-width: 62rem) {
}

/* Decorative photographs support the copy instead of occupying a content block. */
/* ---------- hero photograph ----------
   The service photograph lives INSIDE the navy hero, behind the words, rather
   than in a band underneath it.

   It was a band: first inside the column, then full bleed. Both read as a
   rectangle inserted between the hero and the body, and neither earned its
   height. In the hero the picture does a job, it gives the page a subject
   instead of a flat navy field, and it costs no vertical space at all.

   Contrast is the whole risk, so it is handled by construction rather than by
   eye: the photograph sits under a navy veil that is near solid where the
   words are and clears toward the far side, where the hero is empty. The veil
   is a physical gradient, so it is mirrored for RTL below. */
.hero[data-photo] { position: relative; isolation: isolate; }
.hero[data-photo]::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background-image: var(--hero-photo);
  background-size: cover;
  background-position: 72% 50%;
  /* 0.42 and a veil that stays solid until 46%. At 0.5/34% the worst-case
     headline contrast measured 3.24:1 against a 3.0 threshold, which passes
     and leaves nothing for a darker monitor or a future photograph with a
     brighter corner. Measured, not judged by eye: see verify_hero_contrast.py */
  opacity: 0.42;
  mask-image: linear-gradient(to right, transparent 0%, transparent 46%, #000 84%);
}
/* Right to left: the WHOLE layer is mirrored, photograph and veil together.
   The earlier version moved the photograph to 28% and flipped only the veil.
   But at hero widths the photograph is cover-scaled to the full width, so
   background-position cannot move it sideways: the subject stayed on the
   right, under the solid part of the flipped veil, and Arabic pages showed a
   dark empty hero (reported 2026-09-25). Mirroring puts the subject in the
   open half, opposite the text, as in English. Safe because none of the seven
   photographs contains text, a logo or a number; the logo mark is a separate
   element and is never mirrored. Desktop only: on a phone the photograph is
   centred and unmasked, and this rule used to override that too because
   [dir="rtl"] out-ranks the plain selector inside the media query. */
@media (min-width: 62.01rem) {
  [dir="rtl"] .hero[data-photo]::after { transform: scaleX(-1); }
}
/* The existing drawn bars artwork and a photograph in the same corner is two
   decorations fighting. The photograph wins on the pages that have one. */
.hero[data-photo]::before { display: none; }
@media (max-width: 62rem) {
  /* On a phone the hero text spans the full width, so a side-cleared veil
     would put type over the picture. Keep it faint and behind everything. */
  .hero[data-photo]::after {
    opacity: 0.22;
    mask-image: none;
    background-position: 50% 45%;
  }
}


/* The disclosure's own box has to reach the header's bottom rule, not stop at
   the nav's content edge. It stopped 18px short, so the panel hung below a
   strip of dead space: moving the pointer from "Services" down to the list
   crossed that strip, the disclosure lost hover, and the menu shut before you
   could reach it. Unusable on every page, and introduced by my own fix for the
   panel sitting too high.
   Padding extends the hover target down to the rule; the negative margin stops
   that padding adding to the header's height. */
.services-disclosure {
  position: relative; display: flex; align-items: center; align-self: stretch;
  padding-block-end: var(--top-pad-y);
  margin-block-end: calc(-1 * var(--top-pad-y));
}
/* opacity 0.85 to match .top nav a. Without it the trigger rendered at full
   strength beside links that are dimmed, so "Services" read brighter and
   whiter than every other item in the bar. */
.services-trigger {
  color: var(--platinum); opacity: 0.85;
  background: none; border: 0; padding: 0;
  font: 500 0.85rem var(--sans); letter-spacing: 0.02em; cursor: pointer;
  display: inline-flex; align-items: center; gap: 0.4em;
}
/* The hover half is gated on there actually BEING a hover device.
   On iOS a :hover rule attached to a control makes the first tap apply the
   hover state instead of activating it, so the control needs tapping twice and
   feels like it "sometimes doesn't do what you're trying to do". The
   aria-expanded half is a real state and applies everywhere. */
.services-trigger[aria-expanded="true"] { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .services-trigger:hover { opacity: 1; }
}
/* A drawn chevron, not the character U+2304. That glyph is missing from the UI
   font on most platforms, so it fell back to whatever did have it and arrived
   as a heavy stray mark at the wrong size and baseline. Two borders on a
   rotated square are identical everywhere. */
.services-trigger::after {
  content: ""; inline-size: 0.36em; block-size: 0.36em;
  border-inline-end: 1.5px solid currentColor;
  border-block-end: 1.5px solid currentColor;
  transform: translateY(-0.14em) rotate(45deg);
  transition: transform 0.15s ease;
}
.services-trigger[aria-expanded="true"]::after {
  transform: translateY(0.08em) rotate(-135deg);
}
/* The panel carries the HEADER's navy, not a lighter one. A different shade
   made it a foreign box pasted under the bar; matching it makes the panel read
   as the header extending downward. What separates it is the brass top edge
   and a real shadow, which is also what works when the page behind it is cream
   rather than navy. */
.services-panel {
  position: absolute;
  /* Plain 100% now: the disclosure itself reaches the rule, so the panel
     starts flush against it with no gap to cross. */
  inset-block-start: 100%;
  inset-inline-start: 0;
  padding: 0.5rem; min-width: 17rem; max-width: min(25rem, 85vw);
  background: var(--navy);
  border: 1px solid var(--line-dark);
  border-block-start: 2px solid var(--brass);
  box-shadow: 0 18px 36px rgba(0, 0, 0, 0.45);
  z-index: 20;
}
.services-panel[hidden] { display: none; }
.top nav .services-panel a { display: block; padding: 0.7rem; line-height: 1.45; opacity: 1; }
.top nav .services-panel a:focus-visible { background: #ffffff12; }
@media (hover: hover) and (pointer: fine) {
  .top nav .services-panel a:hover { background: #ffffff12; }
}
@media (max-width: 1079px) {
  /* The desktop bar stretches to the header's full height with its links
     centred, which needs align-items:center on .top nav and a flex disclosure.
     Both are wrong in the stacked menu: they centre every item, shrink each to
     its text, and turn Services into a left-hand label with the five links in
     a column beside it. Reset all three here. */
  .top nav { align-self: auto; align-items: stretch; margin-block: 0; padding-block: 0; }
  .services-disclosure { display: block; align-self: auto;
                         padding-block-end: 0; margin-block-end: 0; }
  .services-trigger { padding: 0.7rem 0; font-size: 0.95rem; width: 100%;
                      text-align: start; justify-content: space-between; }
  .services-panel { position: static; min-width: 0; max-width: none; box-shadow: none; border: 0; border-inline-start: 1px solid var(--line-dark); margin: 0 0 0.5rem; }
  .top nav.open .services-panel a { padding: 0.7rem; }
}

/* Hairlines, not boxes. Border, fill, radius and shadow each say "separate
   object"; spending all four on every service was what made the section read
   as a template. */
.svc-row {
  position: relative;
  display: grid; grid-template-columns: 3.2rem minmax(0, 1fr) minmax(11rem, auto);
  gap: 0 1.6rem; align-items: start;
  padding: 1.6rem 0; border-top: 1px solid var(--line-light);
}
.svc-row:first-child { border-top: none; padding-top: 0; }
.svc-row:hover { background: rgba(23, 23, 71, 0.02); }
.svc-num {
  font-family: var(--display); font-size: 0.9rem; font-weight: 700;
  letter-spacing: 0.1em; color: var(--brass-ink); padding-top: 0.3rem;
}
.svc-text h3 {
  font-family: var(--display); font-size: 1.28rem; font-weight: 600;
  letter-spacing: 0.02em; margin: 0 0 0.5rem; color: var(--navy);
}
.svc-text p { margin: 0; font-size: 0.97rem; line-height: 1.55; max-width: 46em; }
.svc-meta {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.45rem;
  padding-top: 0.15rem;
}
.svc-price {
  font-family: var(--sans); font-size: 0.8rem; font-weight: 700;
  letter-spacing: 0.02em; color: var(--brass-ink);
}
.svc-price a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.svc-meta a {
  font-family: var(--sans); font-size: 0.85rem; font-weight: 700;
  color: var(--navy); text-decoration: none; white-space: nowrap;
}
.svc-meta a:hover { text-decoration: underline; text-underline-offset: 4px; }

/* Whole-row click target. Same stretched-link technique as before, and
   .svc-more must stay position:static or its ::after resolves against the
   link instead of the row and the target silently does nothing. */
.svc-more::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.svc-more { position: static; }
.svc-price, .svc-alt { position: relative; z-index: 2; }
.svc-row:has(.svc-more) { cursor: pointer; }
.svc-row:focus-within { outline: 2px solid var(--brass); outline-offset: 3px; }
.svc-more:focus-visible { outline: none; }
@media (hover: hover) {
  .svc-row:hover .svc-more { text-decoration: underline; text-underline-offset: 4px; }
}

/* Target size. Measured, not assumed: these links rendered 22px tall, which
   misses WCAG 2.2 AA (2.5.8) at 24px on every device and is half the 44px a
   finger wants. The first version of this rule was keyed to viewport width,
   which is the wrong axis: a small window on a laptop is still a mouse, and a
   large tablet is still a finger. It keys on the pointer instead.
   Padding, not font size, so the type is unchanged and only the hit area
   grows; the negative margin keeps the row's visual rhythm identical. */
.svc-meta a, .svc-price a, .svc-note a {
  min-height: 26px; display: inline-flex; align-items: center;
}
@media (pointer: coarse) {
  .svc-meta a, .svc-price a, .svc-note a {
    min-height: 44px; padding-inline: 0.7rem; margin-inline: -0.7rem;
  }
}

@media (max-width: 62rem) {
  .svc-layout { grid-template-columns: minmax(0, 1fr); gap: 2.4rem; }
  
  .svc-row { grid-template-columns: 2.6rem minmax(0, 1fr); }
  .svc-meta { grid-column: 2; flex-direction: row; flex-wrap: wrap;
              align-items: baseline; gap: 0.4rem 1.2rem; padding-top: 0.8rem; }
}
.btn-call { display: inline-flex; align-items: baseline; gap: 0.5rem; }
.btn-call-num { font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
/* On a narrow screen the word is redundant next to the digits, and dropping it
   keeps the three actions from wrapping into three stacked rows. */
@media (max-width: 26rem) { .btn-call-label { display: none; } }

.svc-note { margin: 2rem 0 0; font-family: var(--sans); font-size: 0.98rem; color: var(--ink-soft); }
.svc-note a { color: var(--navy); font-weight: 700; text-decoration: none; }
.svc-note a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- pricing ---------- */
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1.5rem; margin-top: 2.4rem; }
/* Was #ffffff: the single brightest surface on the whole site, on the page
   people stare at longest, under a rule in this file forbidding pure white. */
.plan { display: flex; flex-direction: column; border: 1px solid var(--line-light); border-radius: 12px; padding: 1.8rem 1.6rem; background: var(--card); }
.plan.featured { border-color: var(--brass); box-shadow: 0 12px 40px rgba(23,23,71,0.08); }
.plan-name { font-family: var(--display); font-size: 1.1rem; font-weight: 600; color: var(--navy); letter-spacing: 0.02em; }
.plan-badge { display: inline-block; font-family: var(--sans); font-size: 0.66rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--brass-ink); margin-bottom: 0.6rem; }
.plan-price { font-family: var(--display); font-size: 2.2rem; color: var(--navy); margin: 0.4rem 0 0.2rem; font-variant-numeric: tabular-nums; }
.plan-price span { font-family: var(--sans); font-size: 0.9rem; font-weight: 600; color: var(--ink-soft); }
.plan ul { list-style: none; margin: 1.2rem 0 1.6rem; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; font-size: 0.92rem; color: var(--ink-soft); }
.plan li { position: relative; padding-inline-start: 1.4rem; line-height: 1.45; }
.plan li::before { content: "✓"; position: absolute; inset-inline-start: 0; color: var(--brass-ink); font-weight: 700; }
.plan .btn { margin-top: auto; text-align: center; }
.pricing-custom { margin-top: 2rem; font-family: var(--sans); font-size: 1rem; color: var(--ink-soft); max-width: 44rem; }
.pricing-custom strong { color: var(--navy); }
.pricing-custom a { color: var(--navy); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.pricing-other { margin-top: 1.4rem; display: flex; flex-wrap: wrap; gap: 1rem 2rem; font-family: var(--sans); font-size: 0.95rem; color: var(--ink-soft); }
.pricing-other b { color: var(--navy); font-weight: 700; }


/* ---------- afgtracker split ---------- */
.split {
  /* 74rem to match the hero and .app-layout. It was 68rem, a third container
     width on one page, 24px inside the hero on each side. */
  max-width: 74rem; margin: 0 auto;
  display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (max-width: 860px) { .split { grid-template-columns: 1fr; } }
/* The product, at a size where it can actually be read. Two 250px phone
   renders showed that the app exists; they did not show it doing anything.
   The replacement is a capture of the live demo, and the whole layout is built
   around one number: the wide capture is 2368 device px of an 1184 CSS px
   viewport, so it only renders at true 1:1 when the container gives it 74rem.
   That is why the copy sits in two columns above it instead of beside it.
   height:auto and no object-fit, because cropping a screenshot of an interface
   removes the part that was the point. */
.app-layout { max-width: 74rem; margin: 0 auto; }
.app-copy {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem); align-items: end;
}
.app-lede > :first-child { margin-top: 0; }
.app-aside { padding-bottom: 0.35rem; }
.app-aside .ticks { margin-top: 0; }
@media (max-width: 62rem) {
  .app-copy { grid-template-columns: 1fr; gap: 1.6rem; }
  .app-aside { padding-bottom: 0; }
}

.app-shot { margin: clamp(2.4rem, 5vw, 3.4rem) 0 0; }
.app-shot img {
  display: block; width: 100%; height: auto;
  border-radius: 12px;
  /* The interface is dark and so is the section behind it, so the shadow alone
     does not say where the app ends. The hairline does. */
  border: 1px solid rgba(169, 141, 84, 0.22);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5);
}

/* Twelve months filling up, drawn in the mark's sheared form: the section's
   actual claim, set as a closing band rather than a wash behind the copy, where
   it would have sat under the body text at exactly the width the text occupies. */
.app-months {
  width: min(100%, 62rem);
  margin: clamp(2.2rem, 5vw, 3.2rem) auto 0;
  aspect-ratio: 1500 / 420;
  background: url("/assets/year-months.svg") center / contain no-repeat;
  opacity: 0.3;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
}
.app-shot figcaption {
  margin-top: 0.9rem; font-family: var(--sans); font-size: 0.82rem;
  color: var(--platinum); opacity: 0.68;
}
@media (max-width: 74.9375rem) {
  /* Below the switch the phone capture is serving. It is 780 device px at
     dpr 2, so 390 CSS px, NOT the 342 an earlier version of this comment
     claimed. Capping at 342 therefore shows it at about 88% rather than 1:1,
     which is still a downscale and stays sharp; the point is to avoid
     stretching one phone screenshot across the whole section.

     74.9375rem is 1199px, deliberately NOT 75rem. The <source> in index.html
     switches on (min-width: 75rem) and media queries are inclusive at both
     ends, so a 75rem cap made both conditions true at exactly 1200px: the
     browser chose the 2560px wide capture and this rule then squeezed it into
     342px. That capture is 1280 CSS px, so 342 is about 0.27 of its own size
     and the app's 14px type lands near 4px. That is the illegibility this
     section was rebuilt to remove, and worse than the 0.40x it replaced. Measured at 1200px
     before the change: currentSrc afgtracker-demo-wide.webp, rendered 342px. */
  .app-shot img { max-width: 342px; margin-inline: auto; }
  .app-shot figcaption { text-align: center; }
}

.ticks { list-style: none; margin: 1.4rem 0 0; padding: 0; }
.ticks li {
  position: relative; padding-inline-start: 1.6rem; margin: 0.55rem 0;
  font-family: var(--sans); font-size: 0.95rem;
}
.ticks li::before {
  content: "✓"; position: absolute; inset-inline-start: 0;
  color: var(--brass-soft); font-weight: 700;
}
.ticks-dark li::before { color: var(--brass-ink); }
.ticks-dark li { color: var(--ink-soft); }

/* ---------- steps ---------- */
.steps { margin: 2.2rem 0 0; padding: 0 0 0 1.4rem; max-width: 44rem; }
[dir="rtl"] .steps { padding: 0 1.4rem 0 0; }
.steps li { margin: 0 0 1.1rem; padding-inline-start: 0.4rem; color: var(--ink-soft); }
.steps li::marker { font-family: var(--display); font-weight: 600; color: var(--brass-ink); }
.steps strong { color: var(--navy); font-family: var(--sans); font-size: 0.95rem; letter-spacing: 0.01em; }

.principles { margin-top: 3rem; border-top: 1px solid var(--line-light); padding-top: 2rem; }
.principles h3 {
  font-family: var(--serif); font-weight: 600; font-size: 1.15rem;
  color: var(--navy); margin: 0 0 0.5rem; max-width: 30em;
}
.principles .ticks { columns: 2; column-gap: 3rem; }
@media (max-width: 700px) { .principles .ticks { columns: 1; } }

/* ---------- reviews ---------- */
.quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 2rem; margin-top: 2.2rem; }
.quotes blockquote { margin: 0; border-inline-start: 3px double var(--brass); padding-inline-start: 1.2rem; }
.quotes p { font-size: 1.02rem; font-style: italic; margin: 0 0 0.6rem; }
.quotes footer { font-family: var(--sans); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--brass-ink); }
#reviews h2 span[aria-hidden] { color: var(--brass); letter-spacing: 0.1em; }
.rev-more { margin-top: 2rem; font-family: var(--sans); font-size: 0.9rem; }
.rev-more a { color: var(--navy); font-weight: 600; text-underline-offset: 4px; }

/* ---------- consolidated footer ---------- */
.site-footer {
  position: relative;
  background: var(--navy);
  color: var(--platinum);
  padding: clamp(3rem, 8vw, 5rem) clamp(1.25rem, 5vw, 3.5rem) 2.5rem;
  border-top: 1px solid var(--line-dark);
  font-family: var(--sans);
}
/* The stock photograph that used to sit here at 7% opacity was removed. At
   that opacity it carried no information, and `cover` cropped it differently
   at every width, so on a wide screen a disembodied hand surfaced behind the
   contact column. It read as a rendering fault rather than as texture. Flat
   navy, which is what the brand actually is. */
.site-footer > * { position: relative; z-index: 1; }
.foot-cta { text-align: center; max-width: 40rem; margin: 0 auto; }
.foot-cta h2::after { inset-inline-start: 50%; translate: -50% 0; }
[dir="rtl"] .foot-cta h2::after { translate: 50% 0; }
.foot-cta .body { margin-inline: auto; }
.foot-cta .cta-row { justify-content: center; }

.foot-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 2rem 2.5rem; max-width: 74rem; margin: clamp(2.5rem, 6vw, 4rem) auto 0;
  padding-top: 2.5rem; border-top: 1px solid var(--line-dark); text-align: start;
}
.foot-col { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; font-size: 0.9rem; }
.foot-col h3 {
  font-family: var(--sans); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--brass-soft); margin: 0 0 0.3rem;
}
.foot-col a { color: var(--platinum); opacity: 0.85; text-decoration: none; }
.foot-col a:hover { opacity: 1; text-decoration: underline; text-underline-offset: 4px; }
.foot-col p, .foot-col address { margin: 0; font-style: normal; opacity: 0.85; line-height: 1.6; }
/* The About page reuses this grid on a light .paper section, where the 0.85
   fade took --ink-soft to 3.98:1 (Lighthouse, 2026-09-24). Same rule as
   .paper .fineprint: fades are for the dark footer only. */
.paper .foot-col p, .paper .foot-col address { opacity: 1; }
.foot-logo { height: 48px; width: auto; opacity: 0.95; margin-bottom: 0.4rem; }
.foot-rating a { color: var(--platinum-2); }
.foot-social { display: flex; flex-direction: row; gap: 0.55rem; margin-top: 0.9rem; }
.foot-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; border-radius: 50%;
  color: var(--platinum); opacity: 0.9;
  border: 1px solid var(--line-dark); background: rgba(255,255,255,0.03);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.foot-social a:hover {
  opacity: 1; text-decoration: none; color: var(--navy);
  background: var(--brass-soft); border-color: var(--brass-soft);
}
.foot-legal { text-align: center; margin: clamp(2rem, 5vw, 3rem) auto 0; max-width: 46rem; opacity: 0.7; }

.quiet-link { color: inherit; text-decoration: none; border-bottom: 1px solid var(--line-dark); }
.quiet-link:hover { border-color: var(--brass-soft); }

/* ---------- faq ---------- */
.faq { margin-top: 2rem; border-top: 1px solid var(--line-light); max-width: 44rem; }
.faq details { border-bottom: 1px solid var(--line-light); padding: 1rem 0; }
.faq summary {
  cursor: pointer; font-family: var(--sans); font-weight: 600;
  font-size: 1rem; color: var(--navy); list-style-position: outside;
}
.faq summary:hover { color: var(--navy-2); }
.faq details[open] summary { margin-bottom: 0.5rem; }
.faq p { margin: 0; max-width: 40em; }

/* The "How we work" checklist on /about. A list item must never start in one
   column and finish in the next; without break-inside the second item split
   mid-sentence at 390px. Below 46rem the columns are dropped entirely, because
   two columns of a 44em measure on a phone is two very narrow columns. */
.about-how { columns: 2; column-gap: 3rem; }
.about-how li { break-inside: avoid; -webkit-column-break-inside: avoid; }
@media (max-width: 46rem) { .about-how { columns: 1; } }

/* ---------- helpful tools ---------- */
.tool-group {
  font-family: var(--sans); font-size: 0.78rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--brass-ink);
  margin: 2.4rem 0 0.9rem;
}
.tool-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}
/* Hairlines, matching the service rows, rather than cards. Four separate
   boxes per tool would turn eleven links into a wall of chrome. */
.tool {
  display: block; padding: 0.95rem 0;
  border-block-start: 1px solid var(--line-light);
  text-decoration: none; color: inherit;
}
/* Every item keeps its top rule. Exempting the "first row" cannot be
   expressed in CSS when auto-fit decides the column count: at four columns
   the exemption covered items 1 and 2 while 3 and 4 kept their rule, so a
   line appeared over half the first row and not the other half. */
@media (min-width: 40rem) { .tool { padding-inline-end: 2rem; } }
.tool-name {
  display: block; font-family: var(--serif); font-weight: 600;
  font-size: 1.02rem; color: var(--navy);
}
/* The arrow is a separate element so it can move on hover without dragging
   the label's letter-spacing with it. */
.tool-name::after {
  content: "\2197"; margin-inline-start: 0.4rem; color: var(--brass-ink);
  display: inline-block; transition: transform 0.15s ease;
}
.tool:hover .tool-name, .tool:focus-visible .tool-name { text-decoration: underline; text-underline-offset: 4px; }
.tool:hover .tool-name::after { transform: translate(2px, -2px); }
.tool-note {
  display: block; margin-block-start: 0.25rem;
  font-size: 0.92rem; line-height: 1.5; color: var(--ink-soft); max-width: 34em;
}
.tool:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

/* <address> is the right element for the office location, and every browser
   defaults it to italic. That made "Visit" and the street address the only
   italic text in the footer, beside four upright columns. Keep the semantics,
   drop the default styling. */
address.foot-col, address.foot-col h3, address.foot-col p { font-style: normal; }


/* Back to top. Ziyad noticed it missing on mobile, where these pages are long
   and the only way back to the nav is a lot of thumb work.

   NO JAVASCRIPT, deliberately. script-src is 'self' with pinned sha256 hashes
   and no unsafe-inline, so every inline script costs a hash recomputation in
   _headers and a chance to get it wrong. `href="#top"` needs none: the HTML
   spec defines the bare fragment "top" as "scroll to the top of the document"
   even when no element has that id.

   PROGRESSIVE ENHANCEMENT, and the direction matters. The default is VISIBLE.
   Browsers that support scroll-driven animations fade it in once you are a
   screen or so down; browsers that do not simply always show it. Written the
   other way round, with hidden as the default, every browser without
   animation-timeline would render an invisible button. */
.to-top {
  position: fixed;
  inset-inline-end: 1rem;     /* logical, so it moves to the LEFT in Arabic */
  inset-block-end: 1rem;
  z-index: 60;
  width: 46px; height: 46px;  /* above the 44px minimum touch target */
  display: grid; place-items: center;
  border-radius: 999px;
  background: rgba(23, 23, 71, 0.86);
  color: var(--platinum-2);
  border: 1px solid rgba(210, 210, 210, 0.28);
  text-decoration: none;
  font-size: 1.1rem; line-height: 1;
  backdrop-filter: blur(6px);
}
.to-top:hover { background: var(--navy-2); }
.to-top:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

@supports (animation-timeline: scroll()) {
  .to-top {
    opacity: 0;
    animation: to-top-in linear both;
    animation-timeline: scroll(root);
    animation-range: 320px 640px;
  }
  @keyframes to-top-in { to { opacity: 1; } }
}

/* The global reduced-motion rule sets `animation: none !important`, which
   would strand the button at opacity 0 in exactly the browsers that DO support
   scroll timelines. Someone who asked for less motion would get an invisible
   control. Put it back. */
@media (prefers-reduced-motion: reduce) {
  .to-top { opacity: 1 !important; }
}

/* Desktop has the sticky header, so this is a mobile affordance. */
@media (min-width: 900px) { .to-top { display: none; } }

/* At the very bottom of a page the button sat over the last line of the
   "not tax advice" fine print, cutting the Arabic sentence off mid-word
   (2026-09-25). On phones the footer keeps a strip the button's height plus
   its 1rem offset and a 1rem gap, so the last line always ends above it. */
@media (max-width: 899px) {
  .site-footer { padding-bottom: calc(46px + 2rem + env(safe-area-inset-bottom, 0px)); }
}

/* Right-to-left: the hero mark is the logo, so it is never mirrored (his call,
   2026-09-25). Only its PLACE mirrors. Pinned at 4rem from the left edge it
   read as "way off to the left" (his words, same day) while English sits
   about 190px in. The Arabic lead runs ~70px wider, so the English offset
   would cover more of the text than English does. 8vw gives the same
   relationship, measured on the glyphs: overlap 147/105/4/0px at
   1280/1440/1680/1920 wide against English 138/104/0/0. Below 80rem, where the
   Arabic headline alone reaches it, it stays hidden. */
[dir="rtl"] .hero::before { inset-inline-end: clamp(2rem, 8vw, 12rem); }
[dir="rtl"] .hero-lede .lead { max-width: 28em; }
@media (max-width: 79.99rem) { [dir="rtl"] .hero::before { display: none; } }

/* Client reviews are quoted in the client's own words, in English, on every
   language of the site. On the Arabic page the closing "!" and quote mark
   jumped to the start of each line (2026-09-25), so the paragraph is marked
   lang="en" dir="ltr". It stays aligned with the card's accent rule, which is
   on the right in Arabic. */
[dir="rtl"] .quotes p[dir="ltr"] { text-align: right; }

/* Touch target (design critique 2026-09-26): the language select measured
   92x31 on a phone. 44px is Apple's minimum; desktop keeps the slim pill. */
@media (max-width: 1079px) { .lang select { min-height: 44px; } }
