/* ═══════════════════════════════════════════════════════════════════════════════
   THE ARTICLE PAGE — /blog/<slug>
   ═══════════════════════════════════════════════════════════════════════════════

   This file owns the article page and nothing else. The tokens it consumes
   (--plate --panel --rule --chamber --ink --ink-2 --oxblood --credit --emax,
   the -hi variants, --tint-ox, --radius, --s3..--s8, --wrap, --pad, --section)
   are declared once, in public.css. Nothing here re-declares :root.

   THE ARGUMENT
   The landing page is a lab bench: a cold room, rules instead of shadows, and
   colour only where there is a number. An article is the same room after hours
   — one long column of reading and an instrument at the edge telling you where
   you are. So the page has exactly two moving parts, and they are the same
   instrument at two scales:

     · the 2px oxblood bar at the top    — where you are in the piece
     · the oxblood tick on the TOC rail  — which section you are in

   That rail is a direct descendant of the five-tick production rail on the
   landing page (.stages .tick.now): a case walks five benches, a reader walks
   N sections, and both are read by looking for the one live tick. Numbering
   the TOC would have been decoration; the tick carries real state.

   Everything else is quiet on purpose. No card shadows, no gradients, no dark
   band — the shell's footer is already --chamber and the rule of "one dark band
   per page" is spent there. Structure comes from 1px rules and whitespace.

   ORDER OF SECTIONS BELOW MIRRORS THE PAGE, TOP TO BOTTOM.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── 0 · page scope and the only local knobs ─────────────────────────────────
   These four live on .post, not :root, so they are article-page state rather
   than site tokens. --post-sticky-top is the one number an integrator may need
   to touch: it must clear the shell's fixed nav. */
.post {
  --toc-col: 15rem;
  --shell-gap: clamp(28px, 3.5vw, 64px);
  --post-sticky-top: 88px;            /* 64px nav + 24px air */
  --measure: 68ch;                    /* prose. the reading column. */
  --measure-wide: 82ch;               /* rules, tables, figures. the structure column. */
  padding-block-start: var(--s7);
  color: var(--ink);
}

/* Plex Arabic's '0' is narrow relative to the script it sets, so 68ch overshoots
   the comfortable 70–90 glyph line and Arabic paragraphs run long. 62ch lands in
   the same optical place the Latin 68ch does. */
[lang="ar"] .post { --measure: 62ch; --measure-wide: 76ch; }

.post-wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* The landing page's .micro, re-declared under a blog-scoped name. The article
   page must not depend on which utility classes public.css happens to export;
   the values are identical, so the two render the same wherever both apply. */
.blog-label {
  display: inline-block;
  font-size: .6875rem;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--ink-2);
  padding-inline-start: 10px;
  border-inline-start: 2px solid var(--rule);
}
.blog-label.ox { color: var(--oxblood); border-inline-start-color: var(--oxblood); }
/* Arabic has no case, and letter-spacing shatters cursive joining. The uppercase
   + tracking device is carried by weight and the rule instead — exactly the swap
   the landing page makes. */
[lang="ar"] .blog-label {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  font-size: .75rem;
}

/* ── 15 · reading progress bar ───────────────────────────────────────────────
   Declared first because it paints above everything; it is element 15 in the
   document, where it belongs in the reading order (it is decorative and
   aria-hidden, so it must not open the page for a screen reader).

   z-index sits above the shell nav (50): the bar is 2px and simply caps the
   viewport whether the nav is pinned, hidden or absent. position:fixed means it
   can never contribute to CLS.

   No transition: it tracks the scroll position directly, so there is nothing
   for prefers-reduced-motion to switch off. */
.reading-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 60;
  block-size: 2px;
  pointer-events: none;
}
.reading-progress__fill {
  block-size: 100%;
  background: var(--oxblood);
  transform: scaleX(0);               /* JS-off: the bar simply never appears */
  transform-origin: 0 50%;
  will-change: transform;
  box-shadow: 0 1px 2px rgba(16, 21, 26, .18);   /* the page's one shadow */
}
/* Reading right-to-left, the bar has to grow from the right edge. */
[dir="rtl"] .reading-progress__fill { transform-origin: 100% 50%; }


/* ── draft preview banner (super-admins only; not part of the 15) ──────────── */
.draft-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s3);
  margin-block-end: var(--s6);
  padding: var(--s4) var(--s5);
  background: var(--tint-ox);
  border: 1px solid var(--oxblood);
  border-radius: var(--radius);
  color: var(--oxblood);
}
.draft-banner p { margin: 0; font-size: .875rem; color: var(--ink-2); }


/* ── 1 · breadcrumb ──────────────────────────────────────────────────────────
   Rule-under, not a chip row. The separator is a bare middle dot inserted with
   ::before so it never lands before the first crumb and never needs an RTL
   mirror — a dot has no direction. */
.crumbs { margin-block-end: var(--s5); }
.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .8125rem;
  color: var(--ink-2);
}
.crumbs li + li::before {
  content: "·";
  margin-inline-end: 6px;
  color: var(--rule);
}
.crumbs a { color: var(--ink-2); text-decoration: none; }
.crumbs a:hover { color: var(--oxblood); text-decoration: underline; text-underline-offset: .2em; }
.crumbs [aria-current="page"] {
  display: block;                     /* max-inline-size + ellipsis need a block box */
  color: var(--ink);
  max-inline-size: 34ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* ── 2 · header meta strip ─────────────────────────────────────────────────── */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s3);
  font-size: .8125rem;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.post-kicker {
  font-size: .6875rem;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--oxblood);
  text-decoration: none;
  padding-inline-start: 10px;
  border-inline-start: 2px solid var(--oxblood);
}
.post-kicker:hover { text-decoration: underline; text-underline-offset: .25em; }
[lang="ar"] .post-kicker {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 700;
  font-size: .8125rem;
}
/* One separator dot, used in the meta strip, the byline and the card footlines. */
.post .sep { color: var(--rule); }
.post-updated { color: var(--ink); font-weight: 600; }


/* ── 3 · the h1 ──────────────────────────────────────────────────────────────
   The only h1 on the page, and the first entry in the speakable cssSelector
   list — so it is the sentence an answer engine reads aloud. Sized to break at
   a deliberate place rather than wherever the viewport lands. */
.post-title {
  margin-block: var(--s5) 0;
  font-size: clamp(2.125rem, 2.6vw + 1.1rem, 3.25rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.03em;
  text-wrap: balance;
  max-inline-size: 26ch;
}
[lang="ar"] .post-title {
  line-height: 1.3;
  letter-spacing: 0;
  font-weight: 700;                   /* Plex Arabic caps at 700 */
}


/* ── 4 · standfirst ──────────────────────────────────────────────────────────
   Class name is load-bearing: `.standfirst` is in SPEAKABLE_SELECTORS
   (app/utils/seo.py). Renaming it silently removes the block from the
   speakable schema. */
.standfirst {
  margin-block-start: var(--s5);
  font-size: clamp(1.125rem, .55vw + 1rem, 1.375rem);
  font-weight: 250;
  line-height: 1.5;
  letter-spacing: -.01em;
  color: var(--ink-2);
  max-inline-size: 54ch;
  text-wrap: pretty;
}
/* Plex Arabic ships 400/600/700 only — asking for 250 would be synthesised into
   a smeared face. Weight 400 against the 700 title carries the same contrast. */
[lang="ar"] .standfirst {
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.9;
  font-size: clamp(1.0625rem, .5vw + .95rem, 1.25rem);
}


/* ── 5 · byline ──────────────────────────────────────────────────────────── */
.byline {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 2px var(--s4);
  align-items: center;
  margin-block-start: var(--s6);
  padding-block: var(--s5);
  border-block: 1px solid var(--rule);
}
.byline-figure { grid-row: span 2; align-self: start; }

/* The one circle in the whole design system. A person is not a component. */
.avatar {
  display: block;
  inline-size: 48px;
  block-size: 48px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--panel);
  border: 1px solid var(--rule);
}
.avatar--fallback {
  display: grid;
  place-items: center;
  font-size: 1.125rem;
  font-weight: 800;
  color: var(--ink-2);
  background: var(--plate);
}
.byline-id { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; font-size: .9375rem; }
.byline-name { font-weight: 700; color: var(--ink); text-decoration: none; }
.byline-name:hover { color: var(--oxblood); text-decoration: underline; text-underline-offset: .2em; }
.byline-role { color: var(--ink-2); }
.byline-creds {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .75rem;
  color: var(--ink-2);
}
.byline-creds li + li::before { content: "·"; margin-inline-end: 6px; color: var(--rule); }
.byline-review {
  grid-column: 1 / -1;
  margin: 6px 0 0;
  font-size: .8125rem;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.byline-review a { color: var(--ink); text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--rule); }
.byline-review a:hover { text-decoration-color: var(--oxblood); color: var(--oxblood); }
@media (min-width: 640px) {
  /* Hang the review line under the name column, not under the portrait. */
  .byline-review { grid-column: 2; }
}


/* ── 6 · hero figure ─────────────────────────────────────────────────────────
   aspect-ratio + explicit width/height attributes mean the box is reserved
   before the bytes arrive: zero CLS on the LCP element. */
.post-hero { margin: var(--s7) 0 0; }
.post-hero-img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.post-hero-cap {
  margin-block-start: var(--s3);
  padding-inline-start: var(--s3);
  border-inline-start: 2px solid var(--rule);
  font-size: .75rem;
  color: var(--ink-2);
}


/* ── 7 · key takeaways — the AEO extraction target ───────────────────────────
   #key-takeaways is quoted verbatim in SPEAKABLE_SELECTORS, so this panel is
   what a voice assistant reads back. It is the loudest thing on the page and
   the only tinted surface: everything else earns its structure from rules. */
.takeaways {
  margin-block-start: var(--s7);
  padding: var(--s5);
  background: var(--tint-ox);
  border: 1px solid var(--rule);
  border-inline-start: 2px solid var(--oxblood);
  border-radius: var(--radius);
}
.takeaways-list {
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
  max-inline-size: var(--measure);
}
.takeaways-list li {
  position: relative;
  padding-inline-start: var(--s5);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
}
.takeaways-list li + li {
  margin-block-start: var(--s3);
  padding-block-start: var(--s3);
  border-block-start: 1px solid var(--rule);
}
/* A 2px rule, not a bullet: the same mark the landing page uses for a field. */
.takeaways-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .68em;
  inline-size: 10px;
  block-size: 2px;
  background: var(--oxblood);
}
[lang="ar"] .takeaways-list li { line-height: 1.9; }
[lang="ar"] .takeaways-list li::before { inset-block-start: .85em; }


/* ── 8 · shell: sticky TOC + body ────────────────────────────────────────────
   Named areas rather than explicit column numbers, because grid columns follow
   the inline direction: in Arabic the rail lands on the right with no extra
   rule. The rail spans both rows so it can stick for the whole read. */
.article-shell {
  display: grid;
  gap: 0;
  margin-block-start: var(--s7);
}
/* Inside the shell the grid owns the leading gap, so the panel only has to clear
   the body beneath it — the row gap is 0 by design, because the TOC rail has to
   run unbroken past both rows. */
.article-shell .takeaways { margin-block-start: 0; margin-block-end: var(--s6); }

@media (min-width: 1024px) {
  .article-shell {
    grid-template-columns: var(--toc-col) minmax(0, 1fr);
    grid-template-areas:
      "toc lede"
      "toc body";
    column-gap: var(--shell-gap);
    align-items: start;
  }
  .article-shell .takeaways { grid-area: lede; }
  .toc { grid-area: toc; }
  .article-body { grid-area: body; }

  /* Sections after the shell keep the body column's inline start, so the rail's
     gutter runs unbroken to the bottom of the article. */
  .post:not(.post--notoc) .post-aligned {
    margin-inline-start: calc(var(--toc-col) + var(--shell-gap));
  }

  .post--notoc .article-shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "lede" "body";
  }
}

/* ── the reading rail ─────────────────────────────────────────────────────── */
.toc { min-inline-size: 0; }
@media (min-width: 1024px) {
  .toc {
    position: sticky;
    inset-block-start: var(--post-sticky-top);
    align-self: start;
    max-block-size: calc(100vh - var(--post-sticky-top) - var(--s6));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}
.toc-box {
  border-block-start: 1px solid var(--rule);
}
.toc-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  padding-block: var(--s4);
  cursor: pointer;
  list-style: none;
}
.toc-summary::-webkit-details-marker { display: none; }
/* A disclosure caret points DOWN, which has no direction — building it from
   logical borders would rotate it into a diagonal under RTL. Physical on purpose. */
.toc-caret {
  flex: none;
  inline-size: 7px;
  block-size: 7px;
  border-right: 1.5px solid var(--ink-2);
  border-bottom: 1.5px solid var(--ink-2);
  transform: rotate(45deg);
  transform-origin: center;
  transition: transform .18s ease;
  margin-block-end: 3px;
}
.toc-box[open] .toc-caret { transform: rotate(225deg); margin-block-end: -2px; }

.toc-list {
  margin: 0 0 var(--s5);
  padding: 0;
  list-style: none;
  border-inline-start: 1px solid var(--rule);
}
.toc-link {
  display: block;
  padding: 7px var(--s3);
  margin-inline-start: -1px;                       /* sit the tick on the rail */
  border-inline-start: 2px solid transparent;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--ink-2);
  text-decoration: none;
  transition: color .15s, border-color .15s;
}
.toc-link:hover { color: var(--ink); border-inline-start-color: var(--rule); }
/* The live tick. Same grammar as the production rail's .tick.now. */
.toc-link.is-active {
  color: var(--oxblood);
  font-weight: 700;
  border-inline-start-color: var(--oxblood);
}
.toc-item--l3 .toc-link { padding-inline-start: var(--s5); font-size: .78125rem; }
/* Sections the article carries but the body markup does not: takeaways, sources,
   FAQ. Set apart so the rail stays an honest map of the page. */
.toc-item--aux .toc-link { color: var(--ink-2); }
/* The first of them carries the break: a dashed rule says "past the argument". */
.toc-aux-start { border-block-start: 1px dashed var(--rule); margin-block-start: 6px; padding-block-start: 6px; }


/* ── 9 · the prose ───────────────────────────────────────────────────────────
   THE MEASURE GOVERNS TEXT; THE COLUMN GOVERNS STRUCTURE.
   Paragraphs and lists hold 68ch. Rules, tables and figures run wider, to 82ch,
   so a section break and a data table read as architecture around the text
   rather than as more text. That single asymmetry is what makes a long page
   feel edited. */
.article-body { min-inline-size: 0; }

.article-prose {
  font-size: 1.125rem;
  line-height: 1.75;
  color: var(--ink);
}
.article-prose > * { max-inline-size: var(--measure); }
.article-prose > h2,
.article-prose > figure,
.article-prose > table,
.article-prose > .table-scroll,
.article-prose > hr { max-inline-size: var(--measure-wide); }

/* Arabic sets looser and never tracks: cursive joining is broken by
   letter-spacing, and 1.75 is too tight for the ascender/descender load. */
[lang="ar"] .article-prose {
  line-height: 1.9;
  letter-spacing: 0;
  font-size: 1.0625rem;
}

.article-prose p { margin: 0; text-wrap: pretty; }
.article-prose > p + p { margin-block-start: var(--s5); }

/* THE ANSWER PARAGRAPH.
   Answer-first is the whole AEO strategy: the first two sentences answer the
   question the title implies, and this is the block that gets lifted into an AI
   overview. So it is set one step up the scale, in full --ink, and closed with a
   hairline — the reader is told "the answer is right here" before scrolling.
   Deliberately NOT a drop cap: Arabic has no capital forms, so a drop cap would
   have to be switched off in ar and the two locales would stop being the same
   page. Size and colour work in both scripts. */
.article-prose > p:first-of-type {
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--ink);
  padding-block-end: var(--s5);
  border-block-end: 1px solid var(--rule);
  max-inline-size: var(--measure-wide);
}
[lang="ar"] .article-prose > p:first-of-type { font-size: 1.1875rem; line-height: 1.85; }

/* Hanging structure: a lot of air above a heading, very little below it, so the
   heading belongs to the text that follows and the rule reads as a section break. */
.article-prose h2 {
  margin-block-start: var(--s8);
  margin-block-end: 0;
  padding-block-start: var(--s5);
  border-block-start: 1px solid var(--rule);
  font-size: clamp(1.5rem, 1.1vw + 1.1rem, 1.875rem);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -.02em;
  text-wrap: balance;
  scroll-margin-block-start: var(--post-sticky-top);
}
.article-prose h3 {
  margin-block-start: var(--s6);
  margin-block-end: 0;
  font-size: 1.1875rem;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -.01em;
  scroll-margin-block-start: var(--post-sticky-top);
}
.article-prose h4 {
  margin-block-start: var(--s5);
  margin-block-end: 0;
  font-size: 1rem;
  font-weight: 700;
}
[lang="ar"] .article-prose h2,
[lang="ar"] .article-prose h3,
[lang="ar"] .article-prose h4 { letter-spacing: 0; line-height: 1.45; font-weight: 700; }

/* The heading anchor. Injected by blog.js, so it is invisible until there is a
   pointer to hover with — and it never sits in the tab order ahead of the text. */
.hanchor {
  margin-inline-start: .4em;
  font-size: .7em;
  font-weight: 400;
  color: var(--ink-2);
  text-decoration: none;
  opacity: 0;
  transition: opacity .15s;
}
.article-prose h2:hover .hanchor,
.article-prose h3:hover .hanchor,
.hanchor:focus-visible { opacity: 1; }
.hanchor:hover { color: var(--oxblood); }

/* Lists: a rule, not a bullet. Same mark as the takeaways panel. */
.article-prose ul,
.article-prose ol { margin: var(--s5) 0 0; padding: 0; list-style: none; }
.article-prose li { position: relative; padding-inline-start: var(--s5); }
.article-prose li + li { margin-block-start: 10px; }
.article-prose ul > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .82em;
  inline-size: 10px;
  block-size: 1px;
  background: var(--oxblood);
}
.article-prose ol { counter-reset: prose-item; }
.article-prose ol > li { counter-increment: prose-item; }
/* Western digits in both locales, as everywhere else on this site — the Arabic
   dental trade writes lot numbers, shades and prices in Western figures. */
.article-prose ol > li::before {
  content: counter(prose-item, decimal) ".";
  position: absolute;
  inset-inline-start: 0;
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: .875em;
  color: var(--oxblood);
}
.article-prose li > ul,
.article-prose li > ol { margin-block-start: 10px; }

/* Links in running text: black text, oxblood underline. The underline is the
   signal; recolouring the word would speckle the paragraph. */
.article-prose a:not(.hanchor) {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--oxblood);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  transition: color .15s;
}
.article-prose a:not(.hanchor):hover { color: var(--oxblood); }

.article-prose strong { font-weight: 800; color: var(--ink); }
[lang="ar"] .article-prose strong { font-weight: 700; }
/* Arabic has no italic tradition and Plex Arabic ships no italic face, so an
   <em> would be a synthesised slant. Emphasis moves to weight, which is how the
   script has always carried it. */
[lang="ar"] .article-prose em { font-style: normal; font-weight: 600; }

.article-prose blockquote {
  margin: var(--s6) 0 0;
  padding-inline-start: var(--s5);
  border-inline-start: 2px solid var(--emax);
  font-size: 1.25rem;
  font-weight: 250;
  line-height: 1.4;
  letter-spacing: -.01em;
  color: var(--ink);
}
.article-prose blockquote p + p { margin-block-start: var(--s4); }
.article-prose blockquote cite {
  display: block;
  margin-block-start: var(--s3);
  font-size: .75rem;
  font-weight: 800;
  font-style: normal;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[lang="ar"] .article-prose blockquote { font-weight: 400; letter-spacing: 0; line-height: 1.8; }
[lang="ar"] .article-prose blockquote cite { letter-spacing: 0; text-transform: none; font-weight: 600; }

/* Tables read like a trade journal's: a heavy rule under the head, a hairline
   between rows, a heavy rule to close, tabular figures, and NO zebra stripes —
   stripes are a dashboard habit that fights a page of type. */
.table-scroll {
  margin-block-start: var(--s6);
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.table-scroll:focus-visible { outline: 2px solid var(--emax); outline-offset: 2px; }
.article-prose table {
  inline-size: 100%;
  margin-block-start: var(--s6);
  border-collapse: collapse;
  font-size: .9375rem;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}
.table-scroll > table { margin-block-start: 0; min-inline-size: 34rem; }
.article-prose caption {
  caption-side: bottom;
  padding-block-start: var(--s3);
  font-size: .75rem;
  color: var(--ink-2);
  text-align: start;
}
.article-prose th {
  padding-block: 10px;
  padding-inline: 0 var(--s4);
  text-align: start;
  vertical-align: bottom;
  font-size: .6875rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-block-end: 2px solid var(--ink);
}
[lang="ar"] .article-prose th { letter-spacing: 0; text-transform: none; font-weight: 700; font-size: .8125rem; }
.article-prose td {
  padding-block: 11px;
  padding-inline: 0 var(--s4);
  border-block-end: 1px solid var(--rule);
  vertical-align: top;
}
.article-prose tbody tr:last-child td { border-block-end: 2px solid var(--ink); }
.article-prose tbody th {
  font-size: .9375rem;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  border-block-end: 1px solid var(--rule);
}
/* Plex Arabic's Latin subset has no tabular figures, so font-variant-numeric is
   a no-op there and a column of prices drifts. 'LS Num' is the digits-only cut of
   Hubot Sans that has them — 14 KB, and only fetched when an Arabic page actually
   contains a table. */
[lang="ar"] .article-prose table { font-family: 'LS Num', 'IBM Plex Sans Arabic', sans-serif; }

.article-prose figure { margin: var(--s6) 0 0; }
.article-prose figure img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
}
.article-prose figcaption {
  margin-block-start: var(--s3);
  padding-inline-start: var(--s3);
  border-inline-start: 2px solid var(--rule);
  font-size: .75rem;
  line-height: 1.5;
  color: var(--ink-2);
}
.article-prose img { max-inline-size: 100%; block-size: auto; }

.article-prose hr {
  margin-block: var(--s7);
  border: 0;
  border-block-start: 1px solid var(--rule);
}

/* Code is Latin and mechanical: it never mirrors, in any locale. Same reasoning
   as the FDI tooth chart on the landing page — a physical string does not flip. */
.article-prose code,
.article-prose pre {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  direction: ltr;
  unicode-bidi: isolate;
}
.article-prose code {
  font-size: .875em;
  padding: .1em .35em;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.article-prose pre {
  margin-block-start: var(--s6);
  padding: var(--s5);
  overflow-x: auto;
  font-size: .875rem;
  line-height: 1.6;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.article-prose pre code { padding: 0; background: none; border: 0; font-size: 1em; }

/* The other half of the hanging structure, and the last word on block spacing:
   whatever follows a heading sits close to it. Declared last on purpose — it ties
   on specificity with every element rule above and has to win the tie, which is
   cheaper to read than an !important. */
.article-prose h2 + *,
.article-prose h3 + *,
.article-prose h4 + * { margin-block-start: var(--s4); }


/* ── 10 · sources — the GEO citation signal ──────────────────────────────── */
.post-sec { margin-block-start: var(--s8); }
.post-sec-title {
  margin: var(--s4) 0 0;
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.2;
  scroll-margin-block-start: var(--post-sticky-top);
}
[lang="ar"] .post-sec-title { letter-spacing: 0; font-weight: 700; line-height: 1.45; }

.sources-list {
  margin: var(--s5) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: source;
  max-inline-size: var(--measure-wide);
  border-block-start: 1px solid var(--rule);
}
.sources-list li {
  counter-increment: source;
  position: relative;
  padding-block: var(--s4);
  padding-inline-start: var(--s6);
  border-block-end: 1px solid var(--rule);
}
.sources-list li::before {
  content: "[" counter(source) "]";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: var(--s4);
  font-size: .75rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--oxblood);
}
.sources-link {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-underline-offset: .18em;
  overflow-wrap: anywhere;
}
.sources-link:hover { color: var(--oxblood); text-decoration-color: var(--oxblood); }
.sources-pub {
  display: block;
  margin-block-start: 4px;
  font-size: .75rem;
  color: var(--ink-2);
}


/* ── 11 · FAQ accordion — native <details>, feeds FAQPage ─────────────────── */
.faq-list {
  margin-block-start: var(--s5);
  max-inline-size: var(--measure-wide);
  border-block-start: 1px solid var(--rule);
}
.faq-item { border-block-end: 1px solid var(--rule); }
.faq-q {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  padding-block: var(--s4);
  cursor: pointer;
  list-style: none;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--ink);
  transition: color .15s;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q:hover { color: var(--oxblood); }
/* Physical borders again: the caret points down, and down does not mirror. */
.faq-q::after {
  content: "";
  flex: none;
  align-self: center;
  inline-size: 8px;
  block-size: 8px;
  border-right: 1.5px solid var(--ink-2);
  border-bottom: 1.5px solid var(--ink-2);
  transform: rotate(45deg);
  transform-origin: center;
  transition: transform .18s ease;
}
.faq-item[open] > .faq-q { color: var(--oxblood); }
.faq-item[open] > .faq-q::after { transform: rotate(225deg); border-color: var(--oxblood); }
.faq-a {
  padding-block-end: var(--s5);
  max-inline-size: var(--measure);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-2);
}
.faq-a p { margin: 0; }
[lang="ar"] .faq-a { line-height: 1.9; }


/* ── 12 · author card — the full E-E-A-T block ───────────────────────────── */
.author-card {
  margin-block-start: var(--s8);
  padding: var(--s6) var(--s5);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  max-inline-size: var(--measure-wide);
}
.author-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 4px var(--s5);
  align-items: center;
  margin-block-start: var(--s5);
}
.author-head .avatar { inline-size: 72px; block-size: 72px; grid-row: span 3; align-self: start; }
.author-head .avatar--fallback { font-size: 1.625rem; }
.author-name { margin: 0; font-size: 1.25rem; font-weight: 800; letter-spacing: -.01em; }
[lang="ar"] .author-name { letter-spacing: 0; font-weight: 700; }
.author-role { font-size: .9375rem; color: var(--ink-2); }
.author-creds {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  font-size: .75rem;
  color: var(--ink-2);
}
.author-creds li + li::before { content: "·"; margin-inline-end: 6px; color: var(--rule); }
.author-bio {
  margin-block-start: var(--s5);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-2);
  max-inline-size: var(--measure);
}
[lang="ar"] .author-bio { line-height: 1.9; }
.author-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin: var(--s5) 0 0;
  padding: 0;
  list-style: none;
}
.author-links a {
  display: inline-block;
  padding: 6px 12px;
  font-size: .75rem;
  color: var(--ink-2);
  text-decoration: none;
  background: var(--plate);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow-wrap: anywhere;
}
.author-links a:hover { color: var(--oxblood); border-color: var(--oxblood); }
.author-more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-block-start: var(--s5);
  padding-block: 8px;
  font-size: .8125rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  border-block-end: 2px solid var(--rule);
  transition: color .18s, border-color .18s;
}
.author-more:hover { color: var(--oxblood); border-block-end-color: var(--oxblood); }
[lang="ar"] .author-more { letter-spacing: 0; text-transform: none; font-weight: 700; font-size: .9375rem; }


/* ── 13 · related posts ──────────────────────────────────────────────────────
   The 1px gap over a --rule background is the landing page's card grid: the
   dividers ARE the gaps, so three cards read as one ruled block. */
.related { margin-block-start: var(--section); }
.related-grid {
  display: grid;
  gap: 1px;
  margin-block-start: var(--s5);
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (min-width: 640px)  { .related-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .related-grid { grid-template-columns: repeat(3, 1fr); } }
.related-card {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  background: var(--panel);
  padding: var(--s5);
  transition: background-color .12s;
}
.related-card:hover { background: var(--tint-emax); }
.related-media {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--plate);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.related-media--empty { border-style: dashed; }
.related-kicker {
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
[lang="ar"] .related-kicker { letter-spacing: 0; text-transform: none; font-weight: 600; font-size: .75rem; }
.related-title { margin: 0; font-size: 1.0625rem; font-weight: 700; line-height: 1.3; letter-spacing: -.01em; }
[lang="ar"] .related-title { letter-spacing: 0; line-height: 1.5; }
.related-title a { color: var(--ink); text-decoration: none; }
.related-card:hover .related-title a { color: var(--emax); }
.related-excerpt {
  margin: 0;
  font-size: .875rem;
  line-height: 1.55;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.related-foot {
  margin-block-start: auto;
  padding-block-start: var(--s3);
  font-size: .75rem;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  border-block-start: 1px solid var(--rule);
}


/* ── 14 · share row ──────────────────────────────────────────────────────────
   Typographic, not iconographic. There is not one third-party logo anywhere in
   this design system, and four of them in a row at the end of an article would
   be the loudest thing on the page. Rule-bordered words, no SDKs, no trackers. */
.share {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s4);
  margin-block-start: var(--s8);
  padding-block: var(--s5);
  border-block: 1px solid var(--rule);
}
.share-actions { display: flex; flex-wrap: wrap; gap: var(--s3); }
.share-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-block-size: 40px;
  padding: 9px 16px;
  font-family: inherit;
  font-size: .75rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s, color .15s, background-color .15s;
}
.share-btn:hover { border-color: var(--oxblood); color: var(--oxblood); }
.share-btn.is-done {
  color: var(--credit);
  border-color: var(--credit);
  background: rgba(31, 95, 70, .06);
}
[lang="ar"] .share-btn { letter-spacing: 0; text-transform: none; font-weight: 700; font-size: .875rem; }


/* ── accessibility + motion ──────────────────────────────────────────────── */
.post :focus-visible,
.reading-progress :focus-visible {
  outline: 2px solid var(--emax);
  outline-offset: 2px;
  border-radius: var(--radius);
}
@media (prefers-reduced-motion: reduce) {
  .post *,
  .post *::before,
  .post *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* Reduced motion must stay CORRECT, not merely still: the anchor link is
     revealed on hover with no fade, and the carets still flip. */
  .hanchor { transition: none; }
}
