/* ═══════════════════════════════════════════════════════════════════════════
   public.css — the PUBLIC editorial shell.

   Loaded by app/templates/public/base.html on every public page (the Journal
   index, its archives, and the post page). On the post page it loads together
   with blog.css, which owns the article-reading furniture: the table of
   contents, the takeaways panel, the FAQ accordion, the sources list, the
   author card and the reading-progress bar.

   THE SPLIT, so the two files never fight:
     public.css  — the :root tokens (defined HERE and only here), the shell
                   (skip link, nav, footer, buttons, .micro, type scale, .num),
                   the masthead, the folio, the category rail, the card grid,
                   pagination and the archive-page layouts.
     blog.css    — everything inside a single article.

   Everything Journal-specific is namespaced `j-`. The handful of unprefixed
   names — .wrap .micro .btn .num .h1/.h2/.h3 .lead .chamber .sr-only .skip and
   the nav/footer classes — are the SHARED vocabulary, spelled exactly as
   app/templates/index.html spells them, so markup reads the same on the
   landing page and in the Journal. Treat those as public API.

   There are no element selectors carrying padding or type in here (no
   `section {}`, no `h2 {}` beyond a margin reset). Article HTML is authored
   copy: it must be blog.css's to style, and a bare `h2 { … }` here would win
   or lose by accident depending on file order.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── tokens ────────────────────────────────────────────────────────────────
   Lifted verbatim from index.html. A dental lab is a cold room with money in
   it: grey benches, white powder, cool light, and colour only where there is
   a number. Three colours, three jobs — oxblood is the ask, credit is money
   staying, emax is the system. A colour on a public page that is not one of
   those three or a neutral is a bug.                                        */
:root {
  --plate:   #EEF1F3;   /* page ground. cold, blue-cast — not a warm cream */
  --panel:   #FFFFFF;
  --rule:    #C9D0D6;
  --chamber: #10151A;   /* the one dark */

  --ink:     #14181C;
  --ink-2:   #5B6772;

  --oxblood: #6B1521;   /* brand */
  --credit:  #1F5F46;
  --emax:    #4E5FA6;

  /* The base three all FAIL 4.5:1 on --chamber. These are their dark-surface
     counterparts; never put the base colours on the dark band. */
  --oxblood-hi: #D9515F;
  --credit-hi:  #4FBF92;
  --emax-hi:    #8FA3DE;

  /* Dark-band neutrals, named so blog.css doesn't have to re-guess them. */
  --on-dark:    #C3CCD4;
  --on-dark-2:  #9AA6B1;
  --on-dark-3:  #7E8B96;
  --rule-dark:  rgba(201, 208, 214, .16);

  --tint-ox:   rgba(107, 21, 33, .05);
  --tint-emax: rgba(78, 95, 166, .07);

  --radius: 3px;        /* never 0 (broadsheet pastiche), never a pill */

  --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  --wrap: 1200px;
  --pad: clamp(20px, 4vw, 40px);
  --section: clamp(56px, 7vw, 96px);

  --nav-h: 64px;
}

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

/* The font stack names BOTH faces on purpose. fonts.css declares each with a
   unicode-range, so a page with no Arabic characters never fetches the Arabic
   subset and vice versa — listing both costs nothing and means a stray Arabic
   phrase inside an English post still renders in Plex instead of a system
   fallback. _seo_head.html preloads only the ACTIVE locale's face. */
html {
  font-family: 'Hubot Sans', 'IBM Plex Sans Arabic', system-ui, -apple-system, sans-serif;
  -webkit-text-size-adjust: 100%;
}
html[lang="ar"] {
  font-family: 'IBM Plex Sans Arabic', 'Hubot Sans', system-ui, -apple-system, sans-serif;
}

body {
  margin: 0;
  background: var(--plate);
  color: var(--ink);
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Margin reset only. Size and weight are opt-in via .h1/.h2/.h3 so that
   blog.css can own the headings inside an article without a specificity war. */
h1, h2, h3, h4, h5, h6, p, figure, blockquote { margin: 0; }

/* Deliberately NOT `ul, ol { margin: 0; padding: 0 }`. That reset is the
   normal shell reflex and it would silently un-indent every list inside an
   article — the bullets render outside the content box and get clipped. Each
   list the shell owns zeroes itself where it is defined below; ordinary prose
   lists keep the user-agent indentation blog.css expects to inherit.
   `.j-list-reset` is here for any list blog.css needs to strip. */
.j-list-reset { list-style: none; margin: 0; padding: 0; }

img, svg, video { max-width: 100%; }

/* Article link colour belongs to blog.css. This only stops every link in the
   shell that has no explicit colour from rendering browser-blue. */
a { color: inherit; }

/* Every figure on a public page. Tabular so a count never reflows its
   neighbours — it should read like a till, not a jitter. */
.num {
  font-family: 'Hubot Sans', sans-serif;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: .02em;
}
/* In ar the body face is Plex Arabic, whose latin subset has NO tabular
   figures, so `tabular-nums` above would silently do nothing. 'LS Num' is a
   14 KB digits-only cut of Hubot Sans that has them; naming 'Hubot Sans' here
   would drag in the full 47 KB latin face for a handful of digits. */
html[lang="ar"] .num { font-family: 'LS Num', sans-serif; }

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

/* Class, not `section {}` — see the header note. */
.j-section { padding-block: var(--section); }
.j-section-tight { padding-block: clamp(40px, 5vw, 64px); }


/* ── type scale ────────────────────────────────────────────────────────────
   The landing page's expressive device is WEIGHT, not a second typeface:
   Hubot Sans runs 200–900, so a headline can go from 800 to 250 mid-sentence
   and the second half reads as the thought thinning out. The Journal keeps
   that device and adds nothing to it.                                       */
.h1 { font-size: clamp(2.5rem, 3.2vw + 1rem, 4rem); line-height: 1.0;
      letter-spacing: -.035em; text-wrap: balance; }
.h2 { font-size: clamp(1.75rem, 2.4vw + .6rem, 2.75rem); font-weight: 800;
      line-height: 1.08; letter-spacing: -.025em; text-wrap: balance; }
.h3 { font-size: 1.25rem; font-weight: 700; letter-spacing: -.01em; line-height: 1.3; }

/* Plex Arabic tops out at 700, has no true optical tightening, and needs air
   between lines to stay readable. Every heading rule gets an ar counterpart. */
html[lang="ar"] .h1 { line-height: 1.25; letter-spacing: 0; }
html[lang="ar"] .h2 { font-weight: 700; letter-spacing: 0; line-height: 1.35; }
html[lang="ar"] .h3 { letter-spacing: 0; line-height: 1.5; }

.lead { font-size: 1.1875rem; line-height: 1.6; color: var(--ink-2); max-width: 62ch; }
html[lang="ar"] .lead { font-size: 1.25rem; line-height: 1.85; }

/* Stamped field label. NOT a pill, not a badge — a rule with a word on it. */
.micro {
  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);
}
.micro.ox      { color: var(--oxblood); border-inline-start-color: var(--oxblood); }
.micro.cr      { color: var(--credit);  border-inline-start-color: var(--credit); }
.micro.on-dark { color: var(--on-dark-2); border-inline-start-color: var(--emax-hi); }
/* Arabic has no case, and letter-spacing shatters cursive joining. The
   uppercase + tracking device is replaced by weight and the rule — which
   still reads unmistakably as a label. Same swap for .btn and every
   small-caps micro-label below; it is the single most important RTL rule in
   this file. */
html[lang="ar"] .micro {
  text-transform: none; letter-spacing: 0; font-weight: 600; font-size: .75rem;
}


/* ── buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 12px 22px;
  font-size: .8125rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  border-radius: var(--radius); border: 1px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: background-color .15s, border-color .15s, color .15s;
}
html[lang="ar"] .btn {
  letter-spacing: 0; text-transform: none; font-weight: 700; font-size: .9375rem;
}
.btn-primary { background: var(--oxblood); color: #fff; }
.btn-primary:hover { background: #571019; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn-ghost:hover { border-color: var(--emax); color: var(--emax); }

/* The secondary action is a text link with a rule that changes colour — never
   a twin button competing with the primary. */
.btn-text {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .8125rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); text-decoration: none; padding-block: 10px;
  border-bottom: 2px solid var(--rule); transition: border-color .18s, color .18s;
}
.btn-text:hover { color: var(--oxblood); border-bottom-color: var(--oxblood); }
html[lang="ar"] .btn-text {
  letter-spacing: 0; text-transform: none; font-weight: 700; font-size: .9375rem;
}

/* Directional glyphs must mirror in RTL: an arrow means "onward" or "back",
   never "east" or "west". There is one arrow in the sprite and it points to
   the inline-end of an LTR page, so:
     .icon-dir   onward  — as drawn in ltr, mirrored in rtl
     .icon-back  back    — turned around in ltr, as drawn in rtl
   These must be classes, not inline transforms: an inline `transform` wins
   over the [dir] rule and silently ships a backwards arrow in Arabic. */
html[dir="rtl"] .icon-dir  { transform: scaleX(-1); }
.icon-back                 { transform: rotate(180deg); }
html[dir="rtl"] .icon-back { transform: none; }


/* ── nav ───────────────────────────────────────────────────────────────────
   Sticky, not fixed. index.html's nav is `position: fixed` and hides on scroll
   from JS; the Journal ships zero JS of its own, and a reading page wants the
   masthead to leave with the scroll and come back with it. Sticky gives that
   for free, reserves its own space (no CLS) and stays correct with JS off.
   z-index 50 leaves 51+ for blog.css's reading-progress bar, which must sit
   over this on the post page.                                               */
#main-nav {
  position: sticky; inset-block-start: 0; z-index: 50;
  background: rgba(238, 241, 243, .92);
  backdrop-filter: blur(16px) saturate(180%);
  border-bottom: 1px solid var(--rule);
}
.nav-in {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s5);
  height: var(--nav-h); max-width: var(--wrap); margin-inline: auto;
  padding-inline: var(--pad);
}
.nav-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--ink); }
.nav-brand img { width: 28px; height: 28px; object-fit: contain; }
.nav-brand b { font-weight: 800; letter-spacing: -.02em; font-size: 1.0625rem; }
html[lang="ar"] .nav-brand b { letter-spacing: 0; }

.nav-links { display: none; gap: var(--s5); align-items: center; }
.nav-links a {
  font-size: .875rem; font-weight: 500; color: var(--ink-2); text-decoration: none;
  padding-block: 4px; border-bottom: 2px solid transparent;
  transition: color .15s, border-color .15s;
}
.nav-links a:hover { color: var(--oxblood); }
/* You are here. The Journal link is the only nav item that can be "current",
   because it is the only one that is a page rather than an anchor. */
.nav-links a[aria-current="page"] {
  color: var(--oxblood); font-weight: 700; border-bottom-color: var(--oxblood);
}

.nav-right { display: flex; align-items: center; gap: var(--s4); }
.lang {
  display: flex; align-items: center; gap: 6px;
  padding-inline-end: var(--s4); border-inline-end: 1px solid var(--rule);
}
.lang a {
  font-size: .625rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none;
}
.lang a.on { color: var(--oxblood); }
.lang .sep { color: var(--rule); }
.nav-signin { display: none; font-size: .875rem; font-weight: 600; color: var(--ink); text-decoration: none; }
.nav-signin:hover { color: var(--oxblood); }
@media (min-width: 980px) { .nav-links, .nav-signin { display: flex; } }
/* Below 980px the nav collapses to brand · language · one action. No burger
   menu: a hidden drawer would need JS, and the four items it would hide are
   all reachable from the footer, which is two thumb-flicks away. */


/* ══ THE MASTHEAD ═════════════════════════════════════════════════════════
   The signature. index.html's ledger closes on a 2px --ink rule and states
   its total underneath; the Journal masthead closes on the same 2px rule and
   states ITS totals underneath — how many articles, how many sections, when
   it was last updated, in the same tabular figures. The publication is
   audited exactly like a case. That rule and the folio line beneath it are
   the one bold move on these pages; everything else is hairlines and air.
   ═════════════════════════════════════════════════════════════════════════ */
.j-mast { background: var(--plate); }
.j-mast-in {
  display: grid; gap: var(--s6);
  padding-block: clamp(40px, 6vw, 76px) clamp(28px, 3.5vw, 44px);
}
@media (min-width: 900px) {
  .j-mast-in {
    grid-template-columns: minmax(0, 1fr) minmax(240px, 320px);
    align-items: end; gap: var(--s7);
  }
}
.j-mast-copy > * + * { margin-block-start: var(--s5); }

/* The author page's masthead carries a person, not a search box, so it runs
   full width and keeps only the masthead's vertical rhythm. */
.j-mast-solo { padding-block: clamp(40px, 6vw, 76px) clamp(28px, 3.5vw, 44px); }
.j-mast-solo > * + * { margin-block-start: var(--s5); }

/* The wordmark. Two words, two weights, one face — the .h1 .a/.b device from
   the landing hero. */
.j-wordmark {
  font-size: clamp(2.75rem, 5.2vw + 1rem, 5rem);
  line-height: .95; letter-spacing: -.04em;
}
.j-wordmark .a { display: block; font-weight: 800; }
.j-wordmark .b { display: block; font-weight: 250; color: var(--oxblood); letter-spacing: -.03em; }
html[lang="ar"] .j-wordmark { line-height: 1.15; letter-spacing: 0; }
html[lang="ar"] .j-wordmark .a { font-weight: 700; }
html[lang="ar"] .j-wordmark .b { font-weight: 400; letter-spacing: 0; }

/* Archive pages put the term here instead of the wordmark. Smaller than the
   wordmark on purpose: a section of the Journal is not the Journal. */
.j-term {
  font-size: clamp(2rem, 3.4vw + .9rem, 3.25rem);
  font-weight: 800; line-height: 1.05; letter-spacing: -.035em; text-wrap: balance;
}
html[lang="ar"] .j-term { font-weight: 700; letter-spacing: 0; line-height: 1.3; }
/* A searched or tagged term is data, not our copy — set it apart in oxblood
   so it never reads as an editor's headline. */
.j-term .term { color: var(--oxblood); }

.j-say { max-width: 46ch; }

.j-back {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .6875rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none;
}
.j-back:hover { color: var(--oxblood); }
html[lang="ar"] .j-back { letter-spacing: 0; text-transform: none; font-weight: 600; font-size: .8125rem; }


/* ── search ───────────────────────────────────────────────────────────────
   A GET form. No autocomplete panel, no debounce, no JS: submitting lands on
   a real URL a reader can bookmark and a crawler can follow.                */
.j-search { display: flex; align-items: stretch; }
.j-search input[type="search"] {
  flex: 1; min-width: 0; min-height: 46px; padding: 11px 14px;
  font-family: inherit; font-size: .9375rem; color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-start-start-radius: var(--radius); border-end-start-radius: var(--radius);
  border-inline-end: 0;
  -webkit-appearance: none; appearance: none;
}
.j-search input[type="search"]::placeholder { color: var(--ink-2); opacity: 1; }
.j-search button {
  display: grid; place-items: center;
  min-height: 46px; width: 52px; flex: none;
  color: var(--panel); background: var(--ink);
  border: 1px solid var(--ink);
  border-start-end-radius: var(--radius); border-end-end-radius: var(--radius);
  cursor: pointer; transition: background-color .15s, border-color .15s;
}
.j-search button:hover { background: var(--oxblood); border-color: var(--oxblood); }
/* The focus ring belongs to the whole control, not to half of it. */
.j-search:focus-within input[type="search"] { border-color: var(--emax); }


/* ── the folio ────────────────────────────────────────────────────────────
   One thin line of true facts under the total rule. Nothing here is
   decorative and nothing here is estimated: if the route doesn't know a
   number, the template doesn't print the cell.                              */
.j-folio { border-block-start: 2px solid var(--ink); background: var(--panel); }
.j-folio-in {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--s4);
  min-height: 46px; padding-block: 10px;
}
.j-folio-list { display: flex; flex-wrap: wrap; align-items: center; list-style: none; margin: 0; padding: 0; }
.j-folio-list li { display: flex; align-items: baseline; gap: 7px; }
/* Hairline between entries, drawn as a border rather than a "·" so it holds
   its position when the line wraps. */
.j-folio-list li + li {
  margin-inline-start: var(--s4); padding-inline-start: var(--s4);
  border-inline-start: 1px solid var(--rule);
}
.j-folio-list .v { font-size: .9375rem; font-weight: 800; letter-spacing: -.01em; }
.j-folio-list .k {
  font-size: .625rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-2);
}
html[lang="ar"] .j-folio-list .k {
  letter-spacing: 0; text-transform: none; font-weight: 600; font-size: .75rem;
}
.j-folio-feeds { display: flex; align-items: center; gap: var(--s4); }
.j-folio-feeds a {
  font-size: .625rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none;
}
.j-folio-feeds a:hover { color: var(--oxblood); }
html[lang="ar"] .j-folio-feeds a {
  letter-spacing: 0; text-transform: none; font-weight: 600; font-size: .75rem;
}


/* ── category rail ────────────────────────────────────────────────────────
   The five-bench rail from index.html, laid on its side. Scrolls horizontally
   on narrow screens rather than wrapping into a ragged block of chips.       */
.j-rail { background: var(--panel); border-block-end: 1px solid var(--rule); }
.j-rail-in { overflow-x: auto; scrollbar-width: thin; -webkit-overflow-scrolling: touch; }
.j-rail ul { display: flex; align-items: stretch; list-style: none; margin: 0; padding: 0; white-space: nowrap; }
.j-rail a {
  display: inline-flex; align-items: center; min-height: 48px; padding-inline: var(--s4);
  font-size: .8125rem; font-weight: 600; color: var(--ink-2); text-decoration: none;
  border-block-end: 2px solid transparent;
  transition: color .15s, border-color .15s, background-color .15s;
}
.j-rail li:first-child a { padding-inline-start: 0; }
.j-rail a:hover { color: var(--ink); background: var(--tint-emax); }
.j-rail a[aria-current="page"] {
  color: var(--oxblood); font-weight: 800; border-block-end-color: var(--oxblood);
}
html[lang="ar"] .j-rail a[aria-current="page"] { font-weight: 700; }


/* ══ THE LEAD STORY ═══════════════════════════════════════════════════════
   7fr image / 5fr copy — the landing hero's proportion, mirrored. One 1px gap
   over a --rule background makes the divider; the image bleeds to the block's
   edge on its side, the copy gets air on the other.
   ═════════════════════════════════════════════════════════════════════════ */
.j-lead {
  position: relative;
  display: grid; gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
}
@media (min-width: 900px) {
  .j-lead { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}
.j-lead-fig {
  position: relative; margin: 0; background: var(--plate);
  aspect-ratio: 16 / 9;
}
@media (min-width: 900px) { .j-lead-fig { aspect-ratio: auto; min-height: 380px; } }
.j-lead-fig img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.j-lead-copy {
  background: var(--panel); padding: clamp(24px, 3.4vw, 44px);
  display: flex; flex-direction: column; justify-content: center; gap: var(--s4);
}
.j-lead-kick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.j-lead-title {
  font-size: clamp(1.625rem, 1.9vw + .85rem, 2.5rem);
  font-weight: 800; line-height: 1.08; letter-spacing: -.03em; text-wrap: balance;
}
html[lang="ar"] .j-lead-title { font-weight: 700; letter-spacing: 0; line-height: 1.4; }
.j-lead-title a { text-decoration: none; transition: color .15s; }
.j-lead:hover .j-lead-title a { color: var(--oxblood); }
/* The whole lead block is the link, image included — one tab stop, one
   accessible name, and the big photograph is clickable like a reader expects. */
.j-lead-title a::after { content: ""; position: absolute; inset: 0; }
.j-lead-excerpt { color: var(--ink-2); font-size: 1rem; max-width: 54ch; }
html[lang="ar"] .j-lead-excerpt { font-size: 1.0625rem; line-height: 1.85; }
/* The card footline pins itself to the bottom of a card so rows end level.
   In the lead block the copy is optically centred against a tall image, and an
   auto margin would eat that free space and undo the centring. */
.j-lead-copy .j-card-foot { margin-block-start: 0; }


/* ══ THE INDEX GRID ═══════════════════════════════════════════════════════
   The risk worth taking on this page: NO GUTTERS. Cells are flush and
   separated only by 1px rules — the printed contents page of a trade journal,
   not a tray of floating rounded cards. It is index.html's .fgrid device,
   unchanged, doing the job it was designed for.
   ═════════════════════════════════════════════════════════════════════════ */
.j-grid {
  display: grid; gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
}
@media (min-width: 680px)  { .j-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .j-grid { grid-template-columns: repeat(3, 1fr); } }

.j-card {
  position: relative; display: flex; flex-direction: column;
  background: var(--panel); transition: background-color .12s;
}
/* No lift, no glow, no shadow. Instruments are bolted down. */
.j-card:hover { background: var(--tint-emax); }

.j-card-fig { margin: 0; background: var(--plate); aspect-ratio: 16 / 9; position: relative; }
.j-card-fig img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.j-card-body { padding: var(--s5); display: flex; flex-direction: column; gap: var(--s3); flex: 1; }
.j-card-title { font-size: 1.1875rem; font-weight: 700; line-height: 1.3; letter-spacing: -.015em; }
html[lang="ar"] .j-card-title { font-size: 1.25rem; letter-spacing: 0; line-height: 1.55; }
.j-card-title a { text-decoration: none; transition: color .15s; }
.j-card:hover .j-card-title a { color: var(--oxblood); }
/* One link covers the whole cell, so the card is a single tab stop with a
   single accessible name. Nothing else inside the cell is interactive — the
   author is reachable from the post itself. */
.j-card-title a::after { content: ""; position: absolute; inset: 0; }

.j-card-excerpt {
  color: var(--ink-2); font-size: .9375rem; line-height: 1.55;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow: hidden;
}
html[lang="ar"] .j-card-excerpt { font-size: 1rem; line-height: 1.8; }

/* Footline: who, when, how long. Pushed to the bottom so every card in a row
   ends on the same line regardless of title length. */
.j-card-foot {
  margin-block-start: auto; padding-block-start: var(--s4);
  border-block-start: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: .75rem; color: var(--ink-2);
}
.j-card-foot .who { font-weight: 700; color: var(--ink); }
.j-card-foot .dot { color: var(--rule); }
html[lang="ar"] .j-card-foot { font-size: .8125rem; }


/* ── pagination ───────────────────────────────────────────────────────────
   The same hairline-joined device as the grid, so the page turn belongs to
   the same object as the pages.                                             */
.j-pager {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s4); margin-block-start: var(--s7);
}
.j-pager-nums { display: flex; align-items: center; list-style: none; margin: 0; padding: 0; gap: 8px; }
.j-pager-nums a, .j-pager-nums span {
  display: grid; place-items: center; min-width: 40px; min-height: 40px; padding-inline: 10px;
  font-size: .875rem; font-weight: 700; text-decoration: none; color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--radius); background: var(--panel);
  transition: border-color .15s, color .15s, background-color .15s;
}
.j-pager-nums a:hover { color: var(--oxblood); border-color: var(--oxblood); }
.j-pager-nums [aria-current="page"] {
  background: var(--oxblood); border-color: var(--oxblood); color: #fff;
}
.j-pager-nums .gap { border-color: transparent; background: transparent; min-width: 20px; padding: 0; }
/* Disabled ends keep their box so the row never changes width between pages. */
.j-pager-step[aria-disabled="true"] { opacity: .38; pointer-events: none; }


/* ── the one dark band ────────────────────────────────────────────────────
   Exactly one --chamber block in the body of a page (the footer is the shell,
   not the page). It lives on the Journal index only: the archives end on the
   pager and go straight to the footer, which keeps the front page the one
   that asks for something.                                                  */
.chamber { background: var(--chamber); color: #fff; }
.chamber .lead { color: var(--on-dark-2); }
.chamber :focus-visible { outline-color: var(--emax-hi); }

.j-band-in {
  display: grid; gap: var(--s5); align-items: center;
  padding-block: clamp(48px, 6vw, 80px);
}
@media (min-width: 900px) {
  .j-band-in { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s8); }
}
.j-band-in > div > * + * { margin-block-start: var(--s5); }
.j-band-act { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s4); }
@media (min-width: 900px) { .j-band-act { align-items: flex-end; } }
.j-band-note { font-size: .8125rem; color: var(--on-dark-3); max-width: 32ch; }
@media (min-width: 900px) { .j-band-note { text-align: end; } }


/* ── author header ────────────────────────────────────────────────────────
   The avatar is the ONE circle in the system. A person is not a component;
   everything else keeps the 3px radius.                                     */
.j-author {
  display: grid; gap: var(--s5);
  background: var(--panel); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: clamp(24px, 3.4vw, 44px);
}
@media (min-width: 760px) { .j-author { grid-template-columns: 132px minmax(0, 1fr); gap: var(--s7); align-items: start; } }
.j-avatar {
  width: 108px; height: 108px; border-radius: 50%; overflow: hidden; flex: none;
  background: var(--tint-ox); border: 1px solid var(--rule);
}
.j-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* No stock silhouette when there is no photo: the initial is honest about the
   fact that we have a name and not a face. */
.j-avatar-mono {
  display: grid; place-items: center; width: 100%; height: 100%;
  font-size: 2.5rem; font-weight: 800; color: var(--oxblood); letter-spacing: -.02em;
}
.j-author-body > * + * { margin-block-start: var(--s4); }
.j-author-role { font-size: 1rem; font-weight: 700; color: var(--oxblood); }
.j-author-bio { color: var(--ink-2); max-width: 66ch; line-height: 1.7; }
html[lang="ar"] .j-author-bio { line-height: 1.9; }

/* Credentials are claims. They get a hairline box each so they read as
   discrete, checkable facts rather than a marketing sentence. */
.j-creds { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
.j-creds li {
  padding: 5px 10px; font-size: .75rem; font-weight: 700; color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--radius); background: var(--plate);
}
.j-links { display: flex; flex-wrap: wrap; gap: var(--s4); list-style: none; margin: 0; padding: 0; }
.j-links a {
  font-size: .8125rem; font-weight: 600; color: var(--ink-2);
  text-decoration: none; border-bottom: 1px solid var(--rule);
  transition: color .15s, border-color .15s;
}
.j-links a:hover { color: var(--oxblood); border-bottom-color: var(--oxblood); }


/* ── result meta + empty state ─────────────────────────────────────────── */
.j-result-line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  margin-block-end: var(--s5); font-size: .875rem; color: var(--ink-2);
}

/* An empty screen is an invitation to act, never an apology. */
.j-empty {
  background: var(--panel); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: clamp(32px, 5vw, 64px); text-align: start;
}
.j-empty > * + * { margin-block-start: var(--s4); }
.j-empty-title { font-size: 1.375rem; font-weight: 800; letter-spacing: -.02em; }
html[lang="ar"] .j-empty-title { font-weight: 700; letter-spacing: 0; }
.j-empty p { color: var(--ink-2); max-width: 54ch; }
.j-suggest { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
.j-suggest a {
  display: inline-block; padding: 8px 12px; font-size: .8125rem; font-weight: 600;
  color: var(--ink); text-decoration: none;
  border: 1px solid var(--rule); border-radius: var(--radius); background: var(--plate);
  transition: border-color .15s, color .15s;
}
.j-suggest a:hover { border-color: var(--oxblood); color: var(--oxblood); }


/* ── footer ──────────────────────────────────────────────────────────────
   Lifted from index.html so the bottom of a Journal page is the bottom of the
   site, not the bottom of a blog.                                           */
.site-footer { background: var(--chamber); color: var(--on-dark-2); padding-block: var(--s8) var(--s6); }
.foot-grid { display: grid; gap: var(--s7); }
@media (min-width: 640px)  { .foot-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .foot-grid { grid-template-columns: 2fr 1fr 1fr 1fr 1.3fr; gap: var(--s6); } }
.site-footer h2 {
  margin: 0 0 var(--s4); font-size: .625rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--on-dark-3);
}
html[lang="ar"] .site-footer h2 { letter-spacing: 0; text-transform: none; font-weight: 600; font-size: .75rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li + li { margin-block-start: 10px; }
.site-footer a { color: var(--on-dark-2); text-decoration: none; font-size: .875rem; }
.site-footer a:hover { color: #fff; }
.foot-brand { color: #fff; }
.foot-say { margin-block-start: var(--s4); font-size: .875rem; max-width: 34ch; }
.foot-site { margin-block-start: var(--s4); }
.foot-site a { color: var(--oxblood-hi); }
.foot-bot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s4);
  margin-block-start: var(--s8); padding-block-start: var(--s5);
  border-block-start: 1px solid rgba(201, 208, 214, .12);
  font-size: .75rem; color: var(--on-dark-3);
}


/* ── utilities ───────────────────────────────────────────────────────────── */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; inset-block-start: -60px; inset-inline-start: var(--s4); z-index: 100;
  padding: 12px 18px; background: var(--oxblood); color: #fff; border-radius: var(--radius);
  text-decoration: none; font-weight: 700; transition: inset-block-start .15s;
}
.skip:focus { inset-block-start: var(--s3); }

:focus-visible { outline: 2px solid var(--emax); outline-offset: 2px; border-radius: var(--radius); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
