/**
 * The RTL stylesheet - loaded only on Arabic pages, only after every other
 * sheet (see inc/rtl.php, which prints this link on a late wp_head hook).
 * Nothing here is a blanket mirror: site.css, services.css, knowledge.css,
 * forms.css and pages.css already carry a first round of [dir="rtl"]
 * overrides from earlier phases (the spider map protection, the svbars fill
 * direction, the svpipe/svpager arrows, the footer hover-nudges and its
 * mandate text-align). This file does not repeat any of those. It only adds
 * what a page-by-page sweep of the live Arabic templates turned up as still
 * wrong: physical left/right, float, border-side, corner-radius and
 * transform-origin rules that do not know the page has turned around.
 *
 * Two things this file deliberately does NOT touch, because flipping them
 * would be wrong, not merely unnecessary:
 *  - the hero's three.js map canvas and its container. The globe/network is
 *    real-world geography; it keeps its LTR frame in both languages. Its
 *    overlay labels are ordinary text and already align themselves via
 *    `dir`.
 *  - anything built on logical properties (border-inline-start,
 *    padding-inline, inset-inline-*, margin-inline-start). Those already
 *    flip on their own with `dir`/`direction` and adding a mirror for them
 *    here would just fight the browser.
 */

/* ═══════════════════════ 1. Arabic type ═══════════════════════════════
   Only `body`'s font-family needs to move - it is the one place the theme
   sets it (grep confirms every other font-family declaration in the theme
   is either this same line or an already-Arabic-first caption style like
   .kcase__ar), and font-family inherits, so every heading and paragraph
   follows without a second rule.

   2026-09-06, on the client's instruction: Noto Kufi Arabic, in place of IBM
   Plex Sans Arabic. It is a Kufi face rather than a naskh one - flatter, more
   geometric, closer in feeling to the Latin - and it needs two things from the
   layout that Plex Arabic did not, both set below. It is now requested by the
   Google Fonts link in every template rather than by inc/rtl.php, because the
   English pages carry Arabic too; the note in that file says why. */
html[lang="ar"] body {
  font-family: 'Noto Kufi Arabic', 'IBM Plex Sans', system-ui,
    -apple-system, 'Segoe UI', Tahoma, sans-serif;
  /* The first thing Kufi needs. Measured against IBM Plex Sans Arabic at the
     same font-size, the word المركز is 40% wider and its ink is 15% taller -
     ascent plus descent comes to 1.05em, against 0.91em for Plex. The Latin's
     1.6 leaves about half a line of air between two Arabic lines at that ink
     height, which is tight rather than wrong; 1.85 gives the script the room its
     ascenders and its dots actually occupy. It also clears WCAG 1.4.12's 1.5
     with margin, which the Latin already did. */
  line-height: 1.85;
}

/* The second thing. `h1, h2, h3, h4 { line-height: 1.1 }` in css/site.css is a
   Latin number: with 1.05em of ink on the line it puts an Arabic descender into
   the next line's ascenders, and on a two-line display headline the two rows
   collide outright. 1.3 is the smallest value that keeps them apart at every
   size this build sets, from the 5.6rem section numerals down.

   Deliberately broad, but read the next rule before assuming it is enough: it
   is one class short of outranking a component that tunes a heading's leading
   through a class of its own, and the hero headline is exactly that. Those
   numbers were all solved against the Latin for the same reason this one has
   to replace them. */
html[lang="ar"] :is(h1, h2, h3, h4) {
  line-height: 1.3;
}

/* The hero headline, which the rule above does not reach. `.hero .title` in
   css/site.css is (0,2,0) and `html[lang="ar"] :is(h1, h2, h3, h4)` is (0,1,2),
   so the Latin's 0.98 was still winning on the Arabic page - and 0.98 with
   1.05em of ink is a two-line display headline whose rows physically overlap.
   Seen on an iPhone on 2026-09-05: قِس، ثم / تَحوّل, the shadda of the second
   line sitting in the descenders of the first.

   1.24 rather than the 1.3 above because this is display size, where the same
   ratio buys far more absolute space than it does at body size, and the hero
   has none to give.

   The tracking goes with it. -0.038em is a display-type correction for the
   Latin, where tighter fitting reads as more deliberate. Arabic is cursive:
   the letters in a word are already joined, and pulling them closer does not
   tighten the setting, it thickens the joins and closes the counters. `normal`
   is not a tuning here, it is the absence of one. */
/* THE SIZE. Added 2026-09-06 on the client's instruction: a 25% reduction on
   the hero headline in Arabic. site.css sets clamp(2.4rem, 7.4vw, 6.2rem),
   which at 1440px resolves to the 6.2rem ceiling - 99.2px. Every term of the
   clamp is scaled by the same 0.75 rather than just the ceiling, so the
   headline is 25% smaller at every viewport and not only at desktop; a
   ceiling-only change would have left the phone size untouched, which is not
   what was asked. 6.2rem -> 4.65rem (74.4px at 1440), 7.4vw -> 5.55vw,
   2.4rem -> 1.8rem. This reaches all three hero panels - front-page.php
   carries an h1.title and two h2.title, one per panel - because sizing only
   the h1 would leave the first panel smaller than the two that follow it.

   English is deliberately not changed. The instruction came from reading the
   Arabic pages, and Noto Kufi Arabic sets larger on the body than the Latin
   face at the same px; the Latin hero is not carrying the same problem. */
html[lang="ar"] .hero .title {
  font-size: clamp(1.8rem, 5.55vw, 4.65rem);
  line-height: 1.24;
  letter-spacing: normal;
}

/* Arabic script does not take letter-spacing - any tracking, positive or
   negative, breaks the cursive joins between letters. The theme carries
   tracking on close to thirty selectors (uppercase kickers, nav labels,
   headline letter-spacing, brand type...) at a range of specificities too
   wide to beat one at a time from a low-specificity sheet, and there is no
   legitimate case for tracked Arabic anywhere in it - so this is the one
   place in the whole file that goes broad instead of component by
   component. Western numerals inside these same elements (stat counters,
   the KPI band) are untouched either way; this only ever zeroes spacing
   between characters, never swaps the digits themselves. */
[dir="rtl"] * {
  letter-spacing: 0 !important;
}

/* ═══════════════════════ 2. Language switcher ═════════════════════════
   Same markup, same classes (inc/i18n.php's goic_lang_switch() is untouched)
   - just brought level with the rest of the nav on an Arabic page, where its
   label is now the longer word "English" sitting beside the primary CTA at
   laptop widths. */
[dir="rtl"] .lang {
  white-space: nowrap;
}

/* ═══════════════════════ 3. Arrow glyphs ═══════════════════════════════
   Every one of these is a literal "next" glyph (→ / &rarr;) inside an
   aria-hidden span or ::after, with a hover rule that nudges it further
   the way it points. `scaleX(-1)` mirrors the glyph so it reads as "back"
   in RTL; composed as `scaleX(-1) translateX(Npx)` on the hover rule it
   still nudges further in the glyph's (now-left) pointing direction,
   because the translate runs in local space before the mirror flips it -
   the same Npx becomes an Npx screen-space shift to the left instead of
   the right. */
[dir="rtl"] .btn__arrow,
[dir="rtl"] .khero__open span,
[dir="rtl"] .rail__cta span {
  display: inline-block;
  transform: scaleX(-1);
}
[dir="rtl"] .btn:hover .btn__arrow {
  transform: scaleX(-1) translateX(3px);
}
[dir="rtl"] .khero__open:hover span {
  transform: scaleX(-1) translateX(3px);
}
[dir="rtl"] .rail__cta:hover span {
  transform: scaleX(-1) translateX(4px);
}
/* .svdoc__arrow is a down-pointing chevron (see its inline SVG path) -
   vertically symmetric, so a horizontal mirror would be a no-op. Left
   deliberately alone. */

/* the "read more" corner mark on a publication card: a rotated border box
   drawing an up-right arrow (↗) that nudges further up-right on hover.
   Mirrored the same way, into an up-left arrow (↖) built from the top and
   left borders instead of top and right, and the card's CTA moves to the
   card's own inline-start corner (bottom-left in RTL) to match every other
   rail/tag CTA this file already flips. The artwork behind it (.pub__draw)
   is a deliberately non-flipped illustration - see the note at the bottom
   of this file. */
[dir="rtl"] .pub__more {
  right: auto;
  left: var(--pub-inset);
  /* its entrance, which slides the mark in from behind the card's own edge.
     site.css sets translateX(-8px), which was measured against the right-hand
     corner; with the mark moved to the left one the same offset carries it in
     across the card instead of out from under its own edge. */
  transform: translateX(8px);
}
[dir="rtl"] .pub__more i {
  border-right: 0;
  border-left: 1.6px solid currentColor;
  transform: rotate(-45deg);
}
[dir="rtl"] .pub:hover .pub__more i,
[dir="rtl"] .pub:focus-visible .pub__more i {
  transform: rotate(-45deg) translate(-2px, -2px);
}

/* ═══════════════════════ 4. Notched corners ═══════════════════════════
   `border-radius: X 0 X 0` rounds top-left/bottom-right and squares the
   other diagonal - a motif repeated across the route diagram and its GCC
   Ecosystem variant. Mirrored to `0 X 0 X` so the notch reads on the same
   diagonal relative to the page, not the viewport. */
[dir="rtl"] .route__hub,
[dir="rtl"] .route__node {
  border-radius: 0 10px 0 10px;
}
[dir="rtl"] .eco .route__hub {
  border-radius: 0 16px 0 16px;
}
[dir="rtl"] .eco .route__hub::before {
  border-radius: 0 18px 0 18px;
}
[dir="rtl"] .eco .route__hub::after {
  border-radius: 0 16px 0 16px;
}
[dir="rtl"] .eco .eco__chip {
  border-radius: 0 10px 0 10px;
}
[dir="rtl"] .eco .eco__chip::after {
  border-radius: 0 11px 0 11px;
}
[dir="rtl"] .eco .eco__chip-flag {
  border-radius: 0 9px 0 9px;
}

/* ═══════════════════════ 5. Asymmetric padding on flex/grid children ══
   Flex and grid items already reorder themselves under `dir="rtl"` (the
   container's writing direction drives auto-placement), so a flag-then-
   label chip or a dot-then-label toggle visually swaps sides on its own.
   What does not follow automatically is padding written with an explicit
   left/right split - it stays pinned to the same physical side while the
   content it was measured for moves to the other one. Each pair below
   mirrors that split back onto the side the content actually sits on now. */
[dir="rtl"] .eco__chip {
  padding: 0.35rem 0.35rem 0.35rem 0.85rem;
}
[dir="rtl"] .fw__compare-btn {
  padding: 0.55rem 0.6rem 0.55rem 1.1rem;
}
/* the toggle knob itself: parked at the inline-start edge at rest, and
   travelling further inline-start once pressed - both physical offsets,
   both need to swap edges. */
[dir="rtl"] .fw__compare-dot::after {
  left: auto;
  right: 2px;
}
[dir="rtl"] .fw__compare-btn[aria-pressed="true"] .fw__compare-dot::after {
  translate: -0.7rem 0;
}

/* ═══════════════════════ 6. Column/list dividers ═══════════════════════
   A `border-left` used as a divider between stats or gains, with the
   first item's copy zeroed out so the row does not open on a stray rule.
   Once the row's items reorder under RTL, "first" is now the item at the
   visual *right*, so the divider has to move to each item's own right
   edge and the zeroing has to follow the same item to its new edge. */
[dir="rtl"] .svm__stats > div {
  border-left: 0;
  border-right: 1px solid color-mix(in srgb, #fff 12%, transparent);
}
[dir="rtl"] .svm__stats > div:first-child {
  border-right: 0;
  padding-right: 0;
}
@media (max-width: 720px) {
  [dir="rtl"] .svm__stats > div:nth-child(odd) {
    border-right: 0;
  }
}

[dir="rtl"] .khero__gains li {
  border-left: 0;
  border-right: 1px solid color-mix(in srgb, #fff 10%, transparent);
}
[dir="rtl"] .khero__gains li:first-child {
  border-right: 0;
}

/* ═══════════════════════ 7. Marker/rule bullet lists ══════════════════ */
[dir="rtl"] .info-list li {
  padding-left: 0;
  padding-right: 1.5rem;
}
[dir="rtl"] .info-list li::before {
  left: auto;
  right: 0;
}

/* the two indentation lists in the form partial - one under a checked
   field's own note, one under the rejection summary - both hang their
   marker off a physical margin/padding-left. */
[dir="rtl"] .goic-form .acf-notice ul {
  margin: 0.4rem 1.1rem 0 0;
}
[dir="rtl"] .goic-note--error ul {
  padding-left: 0;
  padding-right: 1.15rem;
}

/* a real bug, not just a mirror: .goic-note's accent border is the
   logical border-inline-start, which already resolves to the right side
   under RTL - but .goic-note--error only ever recolours border-left,
   so the rejection state currently paints no red at all in Arabic. This
   restores the left side to its ordinary colour and puts the accent red
   where border-inline-start actually put the border. */
[dir="rtl"] .goic-note--error {
  border-left-color: var(--line);
  border-right-color: #b3261e;
}

/* the checkbox in an ACF true/false field floats past its own label so the
   two share a line; the float side and its clearance margin are physical */
[dir="rtl"] .goic-form .acf-true-false input[type="checkbox"] {
  float: right;
  margin: 0.28rem 0 0 0.65rem;
}

/* the select arrow and the padding that clears it for the caret icon */
[dir="rtl"] .goic-form select {
  padding-right: 0.85rem;
  padding-left: 2.4rem;
  background-position: left 0.75rem center;
}

/* ═══════════════════════ 8. Text alignment ═════════════════════════════ */
[dir="rtl"] .khero__pin {
  text-align: right;
}
[dir="rtl"] .kcase__head {
  text-align: right;
  padding: 1.15rem 0 1.15rem 0.5rem;
}
@media (max-width: 1080px) {
  [dir="rtl"] .kcase__head {
    padding-left: 0;
  }
}
[dir="rtl"] .kcase__body {
  padding: 0 0.75rem 1.6rem 1.5rem;
}

/* ═══════════════════════ 9. Self-drawing reveals ═══════════════════════
   Rules and value-bars that grow from one edge on scroll are anchored with
   `transform-origin: left`, so under RTL they draw against the reading
   direction instead of with it. */
[dir="rtl"] .rule,
[dir="rtl"] .card::before,
[dir="rtl"] .kpi__cell::after {
  transform-origin: right;
}
/* .usecase__bar i keeps its origin at the reading-start edge, which is the
   same physical edge (left) it already had a `[dir="rtl"] .usecase:hover`
   companion for in site.css; this is only the origin, not the transform. */
[dir="rtl"] .usecase__bar i {
  transform-origin: right;
}

/* the wipe reveal clips from the reading-start edge inward; under RTL that
   edge is the right one */
[dir="rtl"] .reveal--wipe {
  clip-path: inset(0 0 0 100%);
}
[dir="rtl"] .reveal--wipe.is-in {
  clip-path: inset(0 0 0 0);
}

/* The scroll entrance's horizontal pair. css/site.css names them for the
   direction of travel rather than for a side of the page, and left a note
   saying that when Arabic shipped the sign would have to flip - this is that.
   An element carrying .scrub--left is one that sits at the layout's start edge
   and should enter from outside it; under RTL that edge is the right one, so
   the sign reverses and each element still enters from its own outer edge
   rather than sliding in across the page it belongs to. */
[dir="rtl"] .scrub--left  { translate: calc((1 - var(--p)) * 30px) 0; }
[dir="rtl"] .scrub--right { translate: calc((1 - var(--p)) * -30px) 0; }

/* And the narrow-width switch back to the vertical entrance, restated. site.css
   drops the horizontal offset below 860px because a 30px translate inside a
   20px gutter is 10px of page wider than the screen - a horizontal scrollbar on
   every page, since every page carries the footer's two side columns. The pair
   above is a class more specific than that media block and is not in a media
   query itself, so it won at every width and handed Arabic the overflow back:
   the offset is +30px here, which under RTL runs off the *start* edge and shows
   as a strip of bare page down the left of every screen. Same breakpoint and
   same value as site.css, and the two must move together. */
@media (max-width: 859px) {
  [dir="rtl"] .scrub--left,
  [dir="rtl"] .scrub--right { translate: 0 calc((1 - var(--p)) * 30px); }
}

/* ═══════════════════════ 10. A cascade bug, fixed under RTL ═════════════
   `.kh__split .usecase:hover` (site.css) and `[dir="rtl"] .usecase:hover`
   (also site.css) both set `.usecase:hover`'s transform at equal
   specificity; the plain one simply comes later in the file and wins,
   which silently cancels the RTL flip for every usecase card inside the
   Knowledge Hub split layout. Scoping to both classes here outranks each
   of them on specificity as well as on load order. */
[dir="rtl"] .kh__split .usecase:hover {
  transform: translateX(-0.6rem);
}

/* ═══════════════════════ 11. Small physical leftovers ══════════════════ */
[dir="rtl"] .krep__size {
  margin-left: 0;
  margin-right: auto;
}
/* The .newscard__meta separator that used to need flipping here is gone with
   the card: the news index now shows .pub, whose .pub__cat carries the category
   and date as one string with a literal middot between them, so there is no
   physical margin left to reverse. */

/* the mandate diagram's three drop-lines are positioned with a physical
   `left` percentage tied to which actor (1/2/3) they run to; the actors
   sit in a 3-column CSS grid, and grid auto-placement mirrors under RTL
   (column 1 renders at the visual right, not the left) while the drop
   lines' own `left` offsets do not - so drop 1 and drop 3 currently run to
   the wrong actor in Arabic. Swapping their offsets puts each line back
   under its own actor; drop 2, on the shared centre column, needs nothing. */
[dir="rtl"] .mandate__drop[data-drop='1'] {
  left: 83.333%;
}
[dir="rtl"] .mandate__drop[data-drop='3'] {
  left: 16.667%;
}

/* The two mission/vision plates close on the join from their own sides as the
   section scrubs in. Same shape as .scrub--left / .scrub--right above and the
   same fix: "now" is the plate at the layout's start edge, so under RTL it
   enters from the right and "next" from the left. Without the flip the two
   plates cross over each other on the way in instead of closing on the join. */
[dir="rtl"] .mv-card--now  { translate: calc((1 - var(--lp, 1)) * 22px) 0; }
[dir="rtl"] .mv-card--next { translate: calc((1 - var(--lp, 1)) * -22px) 0; }

/* The gold rule across each plate's lid, drawn on hover from scaleX(0). */
[dir="rtl"] .mv-card::before {
  transform-origin: right;
}

/* The photo frame bleeds to both edges of the plate and rounds one corner - the
   plate's own leading top corner, so the picture cannot square it off. That
   corner is the top right in Arabic. */
[dir="rtl"] .mv-card__frame {
  border-radius: 0 var(--r-box) 0 0;
}

/* The specular sheen that crosses each plate as it lands, driven by a physical
   `left` that runs the band from off one edge to off the other. Anchoring the
   same expression to `right` instead sends it the other way, so the highlight
   still travels with the plate rather than against it. */
[dir="rtl"] .mv-card__sheen {
  left: auto;
  right: calc(var(--lp, 1) * 170% - 60%);
}

/* The operating-model flowmap's two connectors. Their geometry needs nothing:
   `::before { right: 100% }` and `::after { left: 100% }` are a symmetric pair
   either side of the hub, and the dash pattern they carry is symmetric too, so
   swapping which physical side each pseudo-element sits on would change nothing
   on screen. What does need it is the travel. The dash pattern is animated by
   pushing background-position-x forward, which reads as flow toward the right,
   and on a page that runs the other way that is flow backwards up the diagram.
   Reversing the animation is the whole of the fix and leaves the geometry
   alone. (template-about.php:233 carries this figure - an older note in
   css/pages.css claiming the theme has no counterpart is out of date.) */
[dir="rtl"] .flowmap__hub::before,
[dir="rtl"] .flowmap__hub::after {
  animation-direction: reverse;
}

/* The publication card's artwork. Superseded 2026-09-06: this was listed below
   as a deliberate non-flip, on the reasoning that the crop is illustration
   rather than layout. That held while the "read more" mark sat in the same
   corner as the drawing. It no longer does - .pub__more moved to the card's
   inline-start corner in section 3 - and the drawing has to follow it, or the
   mark lands on top of the artwork in Arabic and on bare card in English. The
   drawings are not themselves mirrored: several carry legible marks, and a
   mirrored diagram reads as a mistake in a way a mirrored anchor does not. */
[dir="rtl"] .pub__draw {
  right: auto;
  left: -25%;
}

/* ═══════════════════════ ARABIC TYPE SCALE ════════════════════════════
   Set by the client 2026-09-06, reading the Arabic pages side by side with the
   English ones. Three sizing decisions and one alignment fix.

   THE SECTION HEADS. site.css sizes them with two different clamps -
   `.section__head--wide h2` at clamp(2.1rem, 5vw, 4.1rem) and `.eco__head h2`
   one step larger at clamp(2.3rem, 5.6vw, 4.6rem). At 1440px that is 65.6px
   and 73.6px. Noto Kufi Arabic carries more visual weight per glyph than the
   Latin face at the same size, so the ecosystem head in particular read as
   shouting. A flat 65px settles every section head on one size: a small trim
   for the wide heads and a real reduction for the ecosystem one. The selector
   is `.section__head h2` at (0,1,2), which outranks both of site.css's
   (0,1,1) rules without needing !important. 65px is written as the ceiling of
   a clamp rather than as a flat size: both of site.css's clamps have a 5vw-ish
   middle term that carries the heads down to ~34px on a phone, and a fixed
   65px would have thrown that away and overflowed every narrow viewport. The
   lower bound stays site.css's own 2.1rem so nothing below ~1300px moves.

   THE EYEBROWS. --fs-micro resolves to 12px, which is legible in uppercase
   Latin but not in Arabic - Kufi has no case to lean on and the 0.2em tracking
   site.css applies is already stripped by the `letter-spacing: 0` rule above.
   15px is where the eyebrow reads as a label again rather than as fine print.

   THE NEWS LEDE. `.section__head--center > p` is capped at 46ch. The ch unit
   measures the advance of "0", and Arabic runs far wider per character than
   that, so the cap lands mid-phrase: the six-member-states lede broke after
   "الأعضاء" and dropped "الست." alone onto a second line 43px wide. Balancing
   splits it 212/239 instead. Scoped to Arabic because the English ledes fit
   inside 46ch on one or two full lines and have nothing to balance. */
html[lang="ar"] .section__head h2 { font-size: clamp(2.1rem, 5vw, 65px); }
html[lang="ar"] .eyebrow { font-size: 15px; }
html[lang="ar"] .section__head--center > p:not(.eyebrow) { text-wrap: balance; }

/* The phone number carries `dir="ltr"` in partials/footer.php so the country
   code and the digits order correctly. That isolates the run, and an LTR box
   inside an RTL column puts its text at the box's left edge - the number sat
   under the left end of the address above it while every other contact line
   sat right. text-align restores the shared right edge without touching the
   direction the digits need. */
html[lang="ar"] .footer__contact a[dir="ltr"] { text-align: right; }

/* THE COUNTRY BARS under "من يمكنه إجراء التقييم". The label column of
   .svbars__row is capped at 11rem, which was measured against "Saudi Arabia".
   The Arabic name is "المملكة العربية السعودية" - four words where the English
   has two - and it broke onto a second line, taking "الإمارات العربية المتحدة"
   with it. A wrapped label makes its row taller than the five beside it, which
   reads as a rendering fault rather than as a long name.

   The column sizes to its content instead of to a guess, so it fits whichever
   six states the register actually returns, and the track gives up the
   difference. nowrap on the label is what makes max-content mean one line: the
   flag and the name are flex items, and without it the name would still break
   inside its own box once the track claimed the rest of the row.

   The register rows below need none of this - .svrow__country has carried
   `white-space: nowrap` in a max-content column since it was built. */
html[lang="ar"] .svbars__row {
  grid-template-columns: minmax(6.5rem, max-content) minmax(0, 1fr) 3.2rem;
}
html[lang="ar"] .svbars__row span:first-child { white-space: nowrap; }

@media (max-width: 640px) {
  html[lang="ar"] .svbars__row {
    grid-template-columns: minmax(5.5rem, max-content) minmax(0, 1fr) 2.6rem;
  }
}

/* ═══════════════════════ deliberate non-flips ═══════════════════════════
 * - the hero's three.js map/network canvas and its wrapping element (see
 *   the file header above) - real-world geography, kept in its native
 *   orientation in both languages.
 * - .svdoc__arrow - was a vertically symmetric down-chevron, which had nothing
 *   to flip. It is now the conventional open-in-new-tab box (the reports open
 *   in a tab rather than downloading), which is not symmetric - but that glyph
 *   is a recognised mark rather than a directional cue, and it is drawn the
 *   same way in Arabic interfaces. Left alone deliberately, and the php build
 *   makes the same call.
 * - .mandate__beam - `left: 16.667%; right: 16.667%;` is already symmetric
 *   about the diagram's centre and needs no RTL counterpart.
 * - .nav__links a::after - full-width (`width: 100%`) underline; its own
 *   `left: 0` never has a visible second edge to be on the wrong side of,
 *   and hero-spider.css already overrides its transform-origin to `center`
 *   on every template, which is symmetric on its own.
 * - grid/flex re-ordering everywhere else in the theme (nav links, the
 *   footer columns, card grids) - direction-aware by default, nothing to
 *   add here.
 */
