/* ============ Tokens ============ */
:root {
  --color-ink: #14202e;
  --color-heading: #14202e;
  --color-navy: #0e2a4a;
  --color-navy-deep: #081a30;
  --color-gold: #a9822f;
  --color-gold-bright: #c79b3d;
  --color-paper: #faf8f4;
  --color-paper-dim: #f2efe8;
  --color-line: #e2ddd0;
  --color-text: #1c1c1c;
  --color-text-muted: #5a5a56;
  --color-text-on-navy: #f4f1e8;
  --color-danger: #8a2a2a;
  --color-link: #0e2a4a;
  --color-sponsored: #7a5b12;
  /* Text-safe gold: #a9822f only clears WCAG AA (4.5:1) at large sizes. Kickers,
     nav labels, and widget numerals are small text and need this darker value. */
  --color-gold-text: #7a5b12;

  --font-serif: Georgia, "Times New Roman", Cambria, "Iowan Old Style", serif;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;

  --container-max: 1280px;
  --tab-overlap: 7px;
  --radius: 2px;
  --border: 1px solid var(--color-line);
  --shadow-card: 0 1px 2px rgba(20, 32, 46, 0.06), 0 1px 1px rgba(20, 32, 46, 0.04);
  /* Overlay panels (mega-menu) need far more separation from the page than a
     card does -- --shadow-card is a 1px hairline and left the dropdown reading
     as part of the page rather than floating above it. Both themes get their
     own value: a navy-tinted shadow is invisible against the dark paper. */
  --shadow-panel: 0 18px 44px rgba(8, 26, 48, 0.18), 0 2px 8px rgba(8, 26, 48, 0.10);
  /* Hairline around 4:3 flag chips. Real flags include white and near-white
     fields (Japan, Switzerland's cross, the US stripes) that would otherwise
     bleed into the tile background and lose their edge. */
  --flag-border: rgba(20, 32, 46, 0.22);

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-paper: #10161f;
    --color-paper-dim: #161d27;
    --color-line: #2a3341;
    --color-text: #eae7de;
    --color-text-muted: #a3a79b;
    --color-navy: #14304f;
    --color-navy-deep: #0a1826;
    --color-link: #d8c58a;
    --color-heading: #f2efe8;
    --color-gold: #c79b3d;
    --color-sponsored: #d9ae4e;
    --color-gold-text: #c79b3d;
    --shadow-panel: 0 18px 44px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4);
    --flag-border: rgba(244, 241, 232, 0.28);
    color-scheme: dark;
  }
}

/* ============ Reset ============ */
*, *::before, *::after { box-sizing: border-box; }
/* Matches the sticky header's real height (masthead + nav row) so the
   skip-link target and in-page anchors don't land hidden underneath it. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 7rem; }
@media (max-width: 900px) {
  html { scroll-padding-top: 0; } /* header is non-sticky below 900px, see .site-header */
}
body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.55;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}
img, picture, svg, video { max-width: 100%; display: block; }
a { color: var(--color-link); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { font-family: var(--font-serif); font-weight: 700; line-height: 1.15; margin: 0 0 var(--space-3); color: var(--color-heading); }
/* Headings are frequently links (headlines). Without this, dark mode's gold
   --color-link paints every headline on the page gold instead of just accents
   -- reserve gold for kickers/meta and let headlines read in the ink color. */
h1 a, h2 a, h3 a, h4 a { color: inherit; }
h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover { text-decoration: underline; }
p { margin: 0 0 var(--space-4); }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; }
input, select, textarea { font: inherit; }
[hidden] { display: none !important; } /* keep the hidden attribute authoritative over display rules */

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

/* ============ Utility ============ */
.container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--space-4); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; inset-inline-start: 0; top: -3rem; z-index: 200;
  background: var(--color-navy); color: var(--color-text-on-navy);
  padding: var(--space-3) var(--space-4); transition: top .15s ease;
}
.skip-link:focus { top: 0; }
/* --color-gold-bright is only 2.42:1 on paper (fails the 3:1 non-text-contrast
   minimum) -- var(--color-link) passes in both themes. Navy surfaces (footer,
   cookie banner) keep the brighter gold, which reads fine against navy. */
:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }
.site-footer :focus-visible, .cookie-banner :focus-visible {
  outline-color: var(--color-gold-bright);
}
.eyebrow {
  font-family: var(--font-sans); font-size: .72rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--color-gold-text);
}
.section-heading {
  display: flex; align-items: baseline; justify-content: space-between;
  border-bottom: 2px solid var(--color-heading); padding-bottom: var(--space-2);
  margin-bottom: var(--space-5);
}
.section-heading h2 { margin: 0; font-size: clamp(1.3rem, 1rem + 1.2vw, 1.85rem); }
.section-heading .see-all { font-family: var(--font-sans); font-size: .85rem; font-weight: 600; white-space: nowrap; }

/* Shared page-header component for templates that only ever printed a bare,
   unsized <h1>/<p class="dek"> (country, continent, topic, search, 404) --
   without this they fell back to the browser default 2em, smaller than the
   lead story's headline below them. */
.page-header { padding-block: var(--space-4) var(--space-6); }
.page-header h1 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.3rem); }
.page-header .dek { font-size: 1.05rem; color: var(--color-text-muted); max-width: 65ch; margin-top: var(--space-2); }
.section-block { padding-block: var(--space-6); }
.section-block--tight { padding-block: var(--space-4) var(--space-7); }

/* ============ Header & Nav ============ */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--color-paper);
}
/* A sticky header this tall (masthead + wrapping region nav) eats a quarter
   to a third of a phone's viewport permanently. Below 900px it scrolls away
   like the rest of the page instead. */
@media (max-width: 900px) {
  .site-header { position: static; }
}
.masthead { display: flex; align-items: center; justify-content: space-between; padding-block: var(--space-4); gap: var(--space-4); }
.logo { display: flex; align-items: center; gap: var(--space-2); }
.logo-mark { width: 42px; height: 42px; flex-shrink: 0; }
.logo-text { display: flex; flex-direction: column; line-height: 1; }
.logo-text .mark { font-family: var(--font-serif); font-weight: 700; font-size: 1.7rem; letter-spacing: .04em; color: var(--color-heading); }
.logo-text .full { font-family: var(--font-sans); font-size: .62rem; letter-spacing: .14em; text-transform: uppercase; color: var(--color-text-muted); margin-top: 2px; }

.masthead-actions { display: flex; align-items: center; gap: var(--space-3); }
.icon-button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border: var(--border); background: transparent;
  border-radius: var(--radius); cursor: pointer; color: var(--color-heading);
}
.icon-button:hover { background: var(--color-paper-dim); }
/* The trigger's visible label is the raw locale code ("ZH-HANS" for
   Simplified Chinese) -- let it size to content instead of clipping out of a
   fixed 40px square. */
.lang-switcher > .icon-button { width: auto; min-width: 40px; padding-inline: var(--space-2); }

/* The region bar is a row of folder tabs. The dim fill replaces the rule that
   used to sit between the masthead and the tabs: the strip is its own surface,
   so it separates itself from the masthead above and the page below without a
   line, and unselected tabs read as recessed against it.

   ::after is the gold rule, drawn edge to edge of the viewport at the bottom of
   the strip and sitting behind the tabs. Unselected tabs redraw it as their own
   gold bottom border so it reads as one unbroken line; the selected tab swaps
   that border for --color-paper, which breaks the line and sends it up the
   tab's left side, across its top and back down its right. Every gold edge in
   here is 1px -- the rule and the three sides of the selected tab are the same
   stroke, so the detour looks like one continuous line rather than a thick
   baseline meeting thin uprights. */
.primary-nav { background: var(--color-paper-dim); position: relative; }
.primary-nav::after {
  content: ""; position: absolute; inset-inline: 0; bottom: 0;
  height: 1px; background: var(--color-gold); z-index: 0;
}
/* Positioned so the mega-menu can fall back to anchoring against the whole nav
   row instead of its own item -- see the max-width: 1119px block below. */
.primary-nav .container { display: flex; align-items: stretch; position: relative; }
.primary-nav-list { display: flex; flex-wrap: wrap; flex: 1; }

/* Tabs butt into each other and overlap by --tab-overlap, each stacked above
   the one to its right, so the row reads as a fanned stack rather than as
   separate buttons. Descending z-index produces that; the selected tab and any
   open dropdown are lifted above the whole run so their gold edge is never
   clipped by a neighbour, and so a mega-menu (a child of its own li, and
   therefore trapped in that li's stacking context) cannot be painted under the
   next tab along. */
/* The base z-index is the safety net. A tab past the end of the ladder below
   would otherwise resolve to z-index:auto and, being later in the DOM, paint
   over every tab to its LEFT -- inverting the overlap for exactly the newest
   item in the bar. Pinning the floor at 1 makes an unenumerated tab land at the
   bottom of the stack instead, which is the correct direction for something
   further right. The ladder runs past the current tab count on purpose. */
.primary-nav-list > li { position: relative; z-index: 1; }
.primary-nav-list > li + li { margin-inline-start: calc(var(--tab-overlap) * -1); }
.primary-nav-list > li:nth-child(1) { z-index: 12; }
.primary-nav-list > li:nth-child(2) { z-index: 11; }
.primary-nav-list > li:nth-child(3) { z-index: 10; }
.primary-nav-list > li:nth-child(4) { z-index: 9; }
.primary-nav-list > li:nth-child(5) { z-index: 8; }
.primary-nav-list > li:nth-child(6) { z-index: 7; }
.primary-nav-list > li:nth-child(7) { z-index: 6; }
.primary-nav-list > li:nth-child(8) { z-index: 5; }
.primary-nav-list > li:nth-child(9) { z-index: 4; }
.primary-nav-list > li:nth-child(10) { z-index: 3; }
.primary-nav-list > li:nth-child(11) { z-index: 2; }
.primary-nav-list > li.is-current { z-index: 15; }
.primary-nav-list > li:hover, .primary-nav-list > li:focus-within,
.primary-nav-list > li.is-open { z-index: 20; }

/* Opaque fill, not transparent: it is what lets a tab hide the left edge of the
   tab beneath it. Uniform 1px border on all four sides so every tab keeps
   identical box metrics in every state -- only the colours change. */
/* .65rem block padding rather than --space-4's 1rem: the bar now carries a
   second row beneath it (the country strip), so it gives up 20% of its own
   height -- 56px to 45px -- to keep the pair from dominating the viewport. The
   two rows together come to roughly 80px, and Global, where the country strip
   does not render at all, ends up shorter than the single row used to be. */
.primary-nav-list > li > a {
  display: flex; align-items: center; justify-content: center; height: 100%;
  padding: .65rem var(--space-5); font-weight: 600; font-size: .88rem;
  letter-spacing: .02em; color: var(--color-heading);
  border: 1px solid var(--color-line);
  border-bottom-color: var(--color-gold);
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--color-paper-dim);
  transition: background-color .15s ease, border-color .15s ease;
}
@media (min-width: 1120px) {
  .primary-nav-list > li { flex: 1 1 auto; }
}
.primary-nav-list > li > a:hover { background: var(--color-paper); text-decoration: none; }
/* The tab "in front": gold on three sides, filled with the page's own paper,
   and its bottom edge painted paper so the gold rule breaks there and the tab
   runs continuously into the content below it. */
.primary-nav-list > li.is-open > a, .primary-nav-list > li.is-current > a {
  border-color: var(--color-gold);
  border-bottom-color: var(--color-paper);
  background: var(--color-paper);
  text-decoration: none;
}

/* Two-column dropdown anchored to its own nav item: a gold kicker + the "All
   X Markets" link on the left, a gold "Countries in X" kicker + a single-column
   country list on the right -- the kickers are what make the link underneath
   them read as a distinct clickable item rather than a plain heading. Logical
   properties (inset-inline-start, not left) so it opens on the correct side
   under RTL automatically; items in the right-hand half of the bar anchor from
   the end instead so their panel doesn't run past the edge of the viewport.

   min-width is sized off the widest kicker pair the panel can hold ("Countries
   in North America" beside "All North American Markets"), both of which are
   nowrap -- at the old 340px the right-hand kicker wrapped onto a second line.
   A gold top rule (the same 3px marker .digest-card uses) plus a real drop
   shadow are what separate the panel from the page: at --shadow-card's 1px
   hairline on a --color-paper background it read as flat page furniture. */
.mega-menu {
  display: none; position: absolute; inset-inline-start: 0; top: 100%;
  min-width: 540px; max-width: calc(100vw - var(--space-6));
  /* --color-paper-dim, not --color-paper: the panel opens over a --color-paper
     page, so matching it left the dropdown reading as a hole cut in the page
     rather than a surface on top of it. Dim is one step off the page tone in
     both themes and is already the site's "raised surface" (.digest, tiles). */
  background: var(--color-paper-dim); border: var(--border); border-top: 3px solid var(--color-gold);
  box-shadow: var(--shadow-panel);
  padding: var(--space-6) var(--space-7) var(--space-7); z-index: 50;
}
.primary-nav-list > li:nth-last-child(-n+4) .mega-menu { inset-inline-start: auto; inset-inline-end: 0; }
.primary-nav-list > li.is-open .mega-menu,
.primary-nav-list > li:hover .mega-menu,
.primary-nav-list > li:focus-within .mega-menu { display: block; } /* keyboard users can Tab into the dropdown */
.mega-menu-grid { display: grid; grid-template-columns: auto auto; gap: var(--space-8); }
.mega-menu-region h3 {
  font-family: var(--font-sans); font-size: .72rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--color-gold-text);
  margin-bottom: var(--space-3); white-space: nowrap;
}
.mega-menu-all-link {
  display: block; font-size: 1rem; font-weight: 700; color: var(--color-heading); white-space: nowrap;
}
.mega-menu-all-link:hover { text-decoration: underline; }
/* Full-width tappable rows rather than bare text links, matching the language
   switcher's panel -- the negative inline margin lets the hover fill bleed to
   the panel's padding edge instead of hugging the word. */
.mega-menu-countries li a {
  display: block; padding: var(--space-2) var(--space-3); margin-inline: calc(var(--space-3) * -1);
  border-radius: var(--radius); font-size: .95rem; color: var(--color-text); white-space: nowrap;
}
/* --color-line rather than --color-paper-dim: the panel itself is now dim, so
   the usual hover tone would be invisible against it. Line is the next step
   along the same neutral ramp and keeps body text above 4.5:1 in both themes. */
.mega-menu-countries li a:hover {
  background: var(--color-line); color: var(--color-heading); text-decoration: none;
}

/* Below the width where the region bar spreads out, per-item anchoring stops
   being safe: the bar starts wrapping to a second row, and a 540px panel hung
   off an item near either edge runs off the viewport (an end-anchored panel
   under a wrapped item resolves to a negative inline start). Dropping
   position:relative from the item hands the panel's containing block to the
   nav container instead, so every panel opens from that one fixed start edge
   at its natural width and cannot overhang either side. The nth-last-child
   selector is repeated here because it out-specifies a bare .mega-menu rule
   and would otherwise keep winning. */
@media (max-width: 1119px) {
  .primary-nav-list > li { position: static; }
  .primary-nav-list > li .mega-menu,
  .primary-nav-list > li:nth-last-child(-n+4) .mega-menu {
    inset-inline-start: 0; inset-inline-end: auto;
  }
}

/* Below 1120px the bar wraps, and the folder-tab illusion above stops being an
   illusion and starts being a mess: every unselected tab redraws the gold rule
   as its own bottom border, so a wrapped bar painted a full-width gold line
   across the middle of the nav as well as along its base -- with the selected
   tab's detour cut into whichever line it happened to land on. Three rows of
   tabs on a phone gave three competing baselines and one notch.

   So the metaphor is dropped rather than patched. Tabs stop overlapping and
   stop drawing the rule; each is a discrete box, and the selected one is a
   complete gold rectangle -- all four sides, closed. The nav keeps its own
   ::after rule edge to edge underneath the whole block, which is what still
   ties the country strip to the bar below it. */
@media (max-width: 1119px) {
  .primary-nav-list { gap: 6px; padding-block: 7px; }
  /* Undoes the -7px that butted each tab into the one before it; `gap` above
     is what separates them now. */
  .primary-nav-list > li + li { margin-inline-start: 0; }
  .primary-nav-list > li > a {
    border-color: var(--color-line);
    border-radius: var(--radius);
  }
  .primary-nav-list > li.is-open > a, .primary-nav-list > li.is-current > a {
    border-color: var(--color-gold);
  }
}

/* Country sub-nav — the second row of the region bar (see partials/sub-nav.njk).
   Flat underline tabs rather than a second run of folder tabs: two overlapping
   folder rows would read as two peers competing for the same job, where the
   point is that this row is subordinate to the continent above it. Smaller
   type, muted until selected, and a gold underline instead of a gold outline.

   The row only exists on pages that resolve to a region, so it animates itself
   in on load rather than sitting there. These are static pages -- there is no
   client-side state change to hang a transition off -- so a keyframe with
   `both` fill does the job: the wrapper opens from 0 while the inner strip
   slides down from -100%, and because the wrapper clips its overflow the tabs
   look like they are emerging from behind the region bar rather than fading in.
   Landing on a country or article page plays the same motion, which is correct:
   the row is new to the page either way. */
:root { --sub-nav-h: 35px; }
/* +20% on phones (35px -> 42px). This row is the one piece of chrome a touch
   reader has to both tap AND drag sideways, and at 35px a thumb starting a
   swipe on "South Africa" could clear the strip's top or bottom edge and take
   the page with it instead. Everything downstream is expressed in the variable
   -- the container min-height, the a's height:100%, the opening keyframe -- so
   only the one number moves. */
@media (max-width: 700px) {
  :root { --sub-nav-h: 42px; }
}
.sub-nav {
  background: var(--color-paper-dim);
  box-sizing: border-box; overflow: hidden;
  height: var(--sub-nav-h);
  border-bottom: 1px solid var(--color-line);
  animation: sub-nav-open .34s cubic-bezier(.4, 0, .2, 1) both;
}
/* Horizontal scroll for regions with more countries than fit (and for narrow
   viewports generally). The scrollbar is hidden rather than thin: at a fixed
   35px a visible one would eat a tenth of the row. */
.sub-nav .container {
  display: flex; align-items: stretch; min-height: calc(var(--sub-nav-h) - 1px);
  overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
  animation: sub-nav-slide .34s cubic-bezier(.4, 0, .2, 1) both;
}
.sub-nav .container::-webkit-scrollbar { display: none; }
.sub-nav-list { display: flex; flex-wrap: nowrap; }
.sub-nav-list > li { flex: 0 0 auto; }
.sub-nav-list > li > a {
  display: flex; align-items: center; height: 100%;
  padding: 6px var(--space-4);
  font-family: var(--font-sans); font-size: .78rem; font-weight: 600;
  letter-spacing: .02em; color: var(--color-text-muted);
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.sub-nav-list > li > a:hover {
  color: var(--color-heading); background: var(--color-paper); text-decoration: none;
}
.sub-nav-list > li.is-current > a {
  color: var(--color-heading); background: var(--color-paper);
  border-bottom-color: var(--color-gold);
}
/* The "All European Markets" item reads as the row's own heading until it is
   the selected one, at which point it behaves like any other tab. */
.sub-nav-list > .sub-nav-all > a { color: var(--color-gold-text); }
.sub-nav-list > .sub-nav-all.is-current > a { color: var(--color-heading); }
.sub-nav .flag {
  width: 18px; height: 13px; margin-inline-end: 6px;
  border: 1px solid var(--flag-border); border-radius: 1px;
}

/* border-bottom-width rides along so the rule arrives with the row instead of
   sitting under the region bar on its own for the first frame. */
@keyframes sub-nav-open {
  from { height: 0; border-bottom-width: 0; }
  to { height: var(--sub-nav-h); border-bottom-width: 1px; }
}
@keyframes sub-nav-slide {
  from { transform: translateY(-100%); }
  to { transform: none; }
}
/* Already down when the reader arrived, so it should not roll out again. Set by
   assets/js/head.js before first paint on any page whose predecessor in this
   tab also carried the row -- moving between countries, or between regions,
   leaves the strip sitting still while only its contents change. Arriving from
   Global, search or a policy page still plays the motion, because there the row
   really is new. */
.sub-nav-instant .sub-nav, .sub-nav-instant .sub-nav .container { animation: none; }
/* The row still belongs on the page for these readers -- only the travel goes. */
@media (prefers-reduced-motion: reduce) {
  .sub-nav, .sub-nav .container { animation: none; }
}

/* Language switcher */
.lang-switcher { position: relative; }
.lang-switcher-panel {
  display: none; position: absolute; inset-inline-end: 0; top: calc(100% + 8px);
  background: var(--color-paper); border: var(--border); box-shadow: var(--shadow-card);
  padding: var(--space-2); min-width: 200px; z-index: 60;
}
.lang-switcher.is-open .lang-switcher-panel { display: block; }
.lang-switcher-panel a {
  display: flex; justify-content: space-between; padding: var(--space-2) var(--space-3);
  border-radius: var(--radius); color: var(--color-text); font-size: .9rem;
}
.lang-switcher-panel a:hover { background: var(--color-paper-dim); text-decoration: none; }
.lang-switcher-panel a[aria-current="true"] { font-weight: 700; color: var(--color-heading); }

/* Mobile nav: no hamburger -- the region bar stays visible and wraps, and the
   hover mega-menu (no-op on touch) is hidden so a tap always just navigates.
   The header itself un-sticks below (see .site-header), which is what
   actually keeps this from eating the screen on a phone. */
@media (max-width: 900px) {
  .primary-nav-list > li:hover .mega-menu,
  .primary-nav-list > li:focus-within .mega-menu { display: none; }
  .primary-nav-list > li > a { padding: var(--space-2) var(--space-3); font-size: .82rem; min-height: 44px; }
}

/* ============ Hero / Featured ============ */
.hero { padding-block: var(--space-6); }
.hero-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--space-6); }
.hero-lead { position: relative; }
/* Media now follows the headline/dek (see home.njk) rather than leading them,
   so the lead's own headline is what a reader sees first, not a bare photo. */
.hero-lead .media { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--color-paper-dim); margin-top: var(--space-4); }
.hero-lead .media img { width: 100%; height: 100%; object-fit: cover; }
.hero-lead h1, .hero-lead h2 { font-size: clamp(1.6rem, 1.1rem + 2.4vw, 2.6rem); margin-top: 0; }
.hero-lead .dek { font-size: 1.05rem; color: var(--color-text-muted); max-width: 62ch; }
/* Right rail of the hero: compact horizontal cards, each stretching to share
   the column evenly, so the rail matches the lead's height instead of
   overshooting it and leaving a gap under the lead. */
.hero-secondary { display: flex; flex-direction: column; }
.hero-secondary .article-card {
  flex: 1 1 0;
  display: grid;
  grid-template-columns: 104px 1fr;
  column-gap: var(--space-3);
  align-content: center; /* center each card inside its equal share of the rail */
  padding-block: var(--space-3);
  border-bottom: var(--border);
}
.hero-secondary .article-card:first-child { padding-top: 0; }
.hero-secondary .article-card:last-child { border-bottom: none; padding-bottom: 0; }
.hero-secondary .article-card .media {
  grid-column: 1;
  grid-row: 1 / span 3;
  aspect-ratio: 1 / 1;
  margin-bottom: 0;
}
.hero-secondary .article-card > :not(.media) { grid-column: 2; }
.hero-secondary .article-card h3 { font-size: 1.05rem; margin-bottom: var(--space-1); }
.hero-secondary .article-card .dek { display: none; }
.hero-secondary .article-card .card-meta { margin-bottom: var(--space-1); }

@media (max-width: 860px) {
  .hero-grid { grid-template-columns: 1fr; }
}

/* ============ Weekly regional digest ============ */
/* One card per continent (never per-country) -- a gold top-rule marks each as
   a distinct dispatch, echoing the masthead rule without borrowing any single
   publisher's specific digest layout. */
.digest { background: var(--color-paper-dim); border: var(--border); padding: var(--space-5); }
.digest-header { margin-bottom: var(--space-4); }
.digest-header h2 { font-size: clamp(1.2rem, 1rem + 1vw, 1.6rem); margin-bottom: var(--space-1); }
/* No max-width: this is one short standfirst line under the section heading,
   and a 60ch cap was wrapping it onto a second line on a container more than
   twice that wide. It wraps when the viewport actually runs out, not before. */
.digest-header .dek { font-size: .92rem; color: var(--color-text-muted); margin: 0; }
/* Four across at most. At 210px five tracks fitted the desktop row, which
   squeezed each headline into four or five lines and pushed the date onto its
   own; the seventh and last card then sat alone in a mostly empty second row.
   240px is the number that stops the fifth: the grid's content box tops out at
   1200px (1280 container - 2x --space-4 - 2x --space-5 of .digest padding), and
   five 240px tracks plus four 24px gaps need 1296. Seven cards therefore read
   4 + 3, and auto-fit (not auto-fill) still collapses the tracks nothing was
   placed in, so a three-region week gets three wide cards, not three narrow
   ones and a hole. Narrower viewports step down to 3 / 2 / 1 on their own. */
.digest-grid {
  display: grid; gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.digest-card { border-top: 3px solid var(--color-gold); padding-top: var(--space-3); }
.digest-card .continent-label {
  display: block; font-family: var(--font-sans); font-size: .68rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--color-gold-text); margin-bottom: var(--space-1);
}
.digest-card h3 { font-size: 1rem; margin-bottom: var(--space-1); }
.digest-card .dek {
  font-size: .85rem; color: var(--color-text-muted); margin: 0 0 var(--space-1);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ============ Sector index ============ */
/* A preview grid, not a full listing: cards keep a stable size whatever the
   section happens to hold, so five sections down the page read as one system.
   auto-fit still collapses tracks nothing was placed in -- which is what stops
   a two-article sector ending in three dead columns -- but the 340px ceiling
   stops those two cards from stretching to half the container and burying the
   next section below the fold. Out-specifies .card-grid--fit, which main.js
   adds to any short reveal list. */
.sector-preview .card-grid {
  grid-template-columns: repeat(auto-fit, minmax(230px, 340px));
}
.sector-dek {
  color: var(--color-text-muted); max-width: 70ch;
  margin-top: calc(var(--space-3) * -1); margin-bottom: var(--space-5);
}

/* ============ Cards & Headlines ============ */
/* Container-driven instead of a fixed 3-up: a fixed column count paired with
   the .two-col breakpoint (960px, by viewport not container width) meant
   cards got *narrower* on wider viewports whenever the rail was present
   (961-1150px) than they were just below the breakpoint. auto-fill sizes off
   the grid's own available width, so it can't invert like that. */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--space-5); }
/* auto-fit for the fixed-size rows that can't be topped up by revealing more
   (related stories is limit(3)): auto-fill leaves a dead 4th track sitting
   empty at 1040px, auto-fit collapses it so the three cards divide the row.
   Only applied when there are enough items that stretching them stays sane --
   see the guard in layouts/article.njk. */
.card-grid--fit { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.article-card { display: flex; flex-direction: column; }
/* Gives a flat river of identical cards (continent/topic hubs) a single
   weighted lead instead of every story reading as equally important. Only
   above 620px: on an auto-fill grid, "span 2" doesn't just clamp to what's
   there when just ONE 230px column fits -- it forces the grid to create a
   second, narrow *implicit* column to satisfy the span, squeezing every
   card after it and overflowing the viewport. Below 620px the grid is
   already single-column, so a lead treatment has nothing to span across. */
@media (min-width: 620px) {
  .article-card--lead { grid-column: span 2; }
}
.article-card--lead .media { aspect-ratio: 21 / 9; }
.article-card--lead h3 { font-size: clamp(1.3rem, 1rem + 1.5vw, 1.8rem); }
.article-card .media { display: block; aspect-ratio: 4 / 3; overflow: hidden; background: var(--color-paper-dim); margin-bottom: var(--space-3); }
.article-card .media img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; }
.article-card:hover .media img { transform: scale(1.03); }
.article-card h3 { font-size: 1.1rem; margin-bottom: var(--space-2); }
.article-card .dek {
  font-size: .92rem; color: var(--color-text-muted); margin-bottom: var(--space-2);
  /* Hub grids show a dozen-plus cards at once; an unclamped 5-8 line dek made
     row heights vary wildly and the grid read as a wall of gray text. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.card-meta { font-size: .78rem; color: var(--color-text-muted); display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-2); }

.headline-list { display: flex; flex-direction: column; }
.headline-item { padding-block: var(--space-3); border-bottom: var(--border); }
.headline-item:first-child { padding-top: 0; }
.headline-item a { color: var(--color-heading); font-weight: 600; font-size: 1rem; }
.headline-item .card-meta { margin-top: var(--space-1); }

/* The rail is opt-in, exactly like .ad-slot itself. Reserving a 1fr column
   unconditionally is what left a tall empty gutter down the right of continent,
   topic and article pages -- their <aside> holds nothing but a sidebar ad, and
   that ad collapses to zero height whenever AdSense does not fill (which,
   before consent or with a blocker, is always). It also pushed article body
   copy off-centre for no reason.

   .has-rail is added either at build time, when the aside has real content of
   its own (the homepage's Editor's Picks, the country hub's Sections widget),
   or by main.js the moment a sidebar ad confirms a fill. Without it the aside
   is a zero-height second row, so row-gap has to go too or it contributes
   --space-7 of blank space on its own.

   minmax(0, ...) rather than bare fr: a long unbroken string in a card would
   otherwise blow the content column past its share and squeeze the rail. */
/* No align-items:start here: grid items must keep the default stretch so the
   <aside> rail grows to the full row height -- the sticky ad slot inside it
   can only travel within its parent's box, so a content-height (start-aligned)
   aside would pin it in place with zero travel. Block content inside both
   columns still renders from the top, so stretch has no visual cost. */
.two-col {
  display: grid; grid-template-columns: minmax(0, 1fr);
  column-gap: var(--space-7); row-gap: var(--space-7);
}
.two-col:not(.has-rail) { row-gap: 0; }
@media (min-width: 961px) {
  .two-col.has-rail { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); row-gap: 0; }
}

.tag-badge {
  display: inline-block; font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--color-heading); background: var(--color-paper-dim);
  border: 1px solid var(--color-line); padding: 5px 10px; border-radius: var(--radius);
}
.sponsored-badge { color: var(--color-sponsored); border-color: var(--color-sponsored); }

/* ============ Region & country tiles ============ */
/* These tiles used to lead with the two-letter code ("NA", "EU", "US") set
   large in the serif face, with the real name relegated underneath. A reader
   scanning "Browse by Region" got NA / EU / AS as the primary label, which
   carries no meaning. The place name is now the headline, and the codes are
   either gone (continents, which have no standard code anyone recognises) or
   demoted to a caption under the country name. */
.region-grid { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.region-tile {
  flex: 1 1 200px; max-width: 240px;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  border: var(--border); padding: var(--space-4); text-align: center; background: var(--color-paper-dim);
  transition: border-color .15s ease, background-color .15s ease;
}
.region-tile:hover { border-color: var(--color-gold); background: var(--color-paper); text-decoration: none; }
.region-tile .name {
  font-family: var(--font-serif); font-size: 1.1rem; font-weight: 700; line-height: 1.2;
  color: var(--color-heading);
}
.region-tile .code {
  font-family: var(--font-sans); font-size: .7rem; font-weight: 700;
  letter-spacing: .1em; color: var(--color-text-muted);
}
/* Continent tiles carry the flags of the markets GSN actually covers there, so
   the tile says what is inside it without spending a line of text on the list. */
.region-tile-flags { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }

/* One 4:3 set (flag-icons, vendored under assets/img/flags) at one aspect ratio,
   never emoji: emoji flags render in each platform's own house style, which is
   both inconsistent across devices and too playful for a markets masthead. */
.flag {
  width: 22px; height: auto; aspect-ratio: 4 / 3; display: block;
  border: 1px solid var(--flag-border); border-radius: 1px; object-fit: cover;
}
.region-tile .flag { width: 40px; }
.region-tile-flags .flag { width: 22px; }

/* ============ Article page ============ */
/* .article-body/.article-footer share one 65ch measure and one padding-inline
   -- previously the header alone ran 780px against the body's 720px (a visible
   left-edge mismatch), and none of them had inline padding, so text ran flush
   against the viewport edge on mobile. */
.article-body, .article-footer {
  max-width: 65ch; margin-inline: auto; padding-inline: var(--space-4);
}
/* The header is the exception, and matches .article-hero-media instead: same
   1040px, same padding-inline, so the headline starts on the photo's own left
   edge. On 65ch it measured barely half the width of the image directly below
   it, which read as a narrow column floating over a wide one. Only the header
   widens -- body copy stays at 65ch, where a line is short enough to skim. */
.article-header {
  max-width: 1040px; margin-inline: auto; padding-inline: var(--space-4);
  padding-block: var(--space-6) var(--space-4);
}
.article-header h1 { font-size: clamp(1.7rem, 1.2rem + 2.2vw, 2.8rem); }
/* The dek is prose, not a headline: it keeps a reading measure of its own so it
   doesn't run the full 1040px as a single 100-character line. */
.article-header .dek {
  font-size: 1.15rem; color: var(--color-text-muted); margin-top: var(--space-3);
  max-width: 70ch;
}
.byline { display: flex; align-items: center; gap: var(--space-2); font-size: .88rem; color: var(--color-text-muted); margin-top: var(--space-4); flex-wrap: wrap; }
.byline strong { color: var(--color-text); }
/* Segments (author / published / read time / language) ran together as one
   grey line with no delimiter -- a small separator between them reads far
   more like a byline and less like a wrapped sentence, and stays RTL-safe
   since it's inserted by content order, not a physical side. */
.byline > span + span::before { content: "·"; margin-inline-end: var(--space-2); color: var(--color-text-muted); }
.article-hero-media { max-width: 1040px; margin: var(--space-5) auto; padding-inline: var(--space-4); }
.article-hero-media img { width: 100%; height: auto; aspect-ratio: 16/9; object-fit: cover; }
.article-hero-media figcaption { font-size: .8rem; color: var(--color-text-muted); padding-top: var(--space-2); }

.article-body { font-size: 1.08rem; line-height: 1.75; }
.article-body h2 { font-size: 1.4rem; margin-top: var(--space-6); }
.article-body h3 { font-size: 1.25rem; margin-top: var(--space-5); }
.article-body blockquote {
  border-inline-start: 3px solid var(--color-gold); margin: var(--space-5) 0; padding-inline-start: var(--space-4);
  font-style: italic; color: var(--color-text-muted);
}
.article-body a { text-decoration: underline; }
.article-body figure { margin: var(--space-5) 0; }
.article-footer { margin: var(--space-6) auto 0; padding-top: var(--space-4); border-top: var(--border); }
.tag-row { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-3); }

/* Share row: plain buttons styled like the masthead's icon buttons, so a
   distribution-dependent, 9-locale site has at least a copy-link/native-share
   affordance at the point a reader is most likely to want it. */
.share-row { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-4); flex-wrap: wrap; }
.share-row .btn-outline { color: var(--color-heading); border-color: var(--color-line); }
.share-row .btn-outline:hover { background: var(--color-paper-dim); border-color: var(--color-heading); }

.sponsor-notice {
  max-width: 65ch; margin: var(--space-4) auto; padding: var(--space-3) var(--space-4);
  background: var(--color-paper-dim); border: 1px dashed var(--color-sponsored);
  font-size: .85rem; color: var(--color-sponsored);
}

.sources-block {
  max-width: 65ch; margin-top: var(--space-5); padding-top: var(--space-4);
  border-top: var(--border); font-size: .85rem;
}
.sources-block ul { list-style: none; padding: 0; margin: var(--space-2) 0; display: flex; flex-direction: column; gap: var(--space-1); }
.sources-block .dek { color: var(--color-text-muted); font-size: .8rem; margin-top: var(--space-2); }

.breadcrumbs { font-size: .82rem; color: var(--color-text-muted); padding-block: var(--space-3); }
.breadcrumbs a { color: var(--color-text-muted); }
.breadcrumbs .sep { margin-inline: var(--space-2); }

/* ============ Ad slots ============ */
/* Ads are opt-in to layout: a slot occupies zero space (height 0, clipped, no
   margins) until main.js confirms a real fill via AdSense's data-ad-status and
   adds .is-filled, at which point it expands to fit the rendered ad. While a
   slot is still trying to fill, the page reads exactly as if there were no ads
   at all -- and Google's iframe (which paints white before content arrives)
   stays clipped, so it can never flash against the dark theme. A confirmed
   non-fill (.is-empty) stays collapsed for good. The container keeps its full
   width while collapsed so adsbygoogle.js can still measure availableWidth;
   only its height is zeroed, never display:none, which would break that. */
.ad-slot {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-2);
  height: 0; min-height: 0; margin-block: 0; overflow: hidden;
}
/* overflow stays hidden even when filled: if the viewport crosses the 961px
   breakpoint after injection (tablet rotation, window drag), the already-
   rendered iframe keeps its request-time pixel width and could otherwise
   spill out of a narrower rail and force a page scrollbar. */
.ad-slot.is-filled {
  height: auto; margin-block: var(--space-6);
}
/* align-items:center un-stretches flex children, which would leave the empty
   responsive <ins> at shrink-to-fit width 0 -- and adsbygoogle.js sizes
   "auto"/fluid units from the ins's own width, throwing "No slot size for
   availableWidth=0" when it's 0. Stretch it explicitly; the fixed-size desktop
   sidebar variant wins over this via its inline width/height from main.js. */
.ad-slot ins.adsbygoogle { width: 100%; }
.ad-slot .ad-label {
  display: none;
  font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--color-text-muted);
}
.ad-slot.is-filled .ad-label { display: block; }
/* .is-empty needs no rules of its own: an unfilled slot simply keeps the
   base collapsed state (height 0, clipped). Deliberately NOT display:none --
   the late-fill path in main.js lets AdSense finish rendering a slow ad
   after the settle timer, and that needs a live, measurable subtree. */
/* No .is-filled min-heights: by the time main.js flips the class, AdSense has
   already written the real rendered height onto the <ins>, so a min-height
   could only ever pad a shorter ad with blank space, never prevent shift. */
.ad-slot--leaderboard { max-width: 970px; margin-inline: auto; }
/* Matches .article-body/.article-footer's reading width -- without this, the fluid
   in-article unit has no container width to size against and stretches full-bleed. */
.ad-slot--inArticle { max-width: 65ch; margin-inline: auto; }

/* Sticky reading rail. Gated three ways per AdSense's sticky-ad rules
   (support.google.com/adsense/answer/10734935):
   - width: >=961px only (desktop -- sticky is not allowed on mobile/tablet
     layouts, and that's also where .two-col grows the real rail);
   - .is-desktop-ad: main.js stamps this class only when it injected the
     >=961px ad variant, so a mobile unit that's still on the page after a
     rotation/resize across the breakpoint never picks up sticky rules
     calibrated for the 300px rail unit;
   - min-height 780px: top offset (7.5rem = 120px) + a 600px-tall fill +
     label must fit fully on screen while stuck -- the policy requires the
     whole ad visible at all times, so short viewports just don't stick.
   top clears the sticky site header (7rem tall above 900px, see
   scroll-padding-top); travel room comes from .two-col's stretched aside. */
@media (min-width: 961px) and (min-height: 780px) {
  .ad-slot--sidebar.is-filled.is-desktop-ad {
    position: sticky;
    top: 7.5rem;
  }
}

/* ============ Sidebar widgets ============ */
.widget { margin-bottom: var(--space-6); }
.widget h2 { font-size: 1.05rem; border-bottom: 2px solid var(--color-heading); padding-bottom: var(--space-2); margin-bottom: var(--space-3); }
.widget ol { counter-reset: widget-counter; }
.widget ol li { counter-increment: widget-counter; display: flex; gap: var(--space-3); padding-block: var(--space-2); border-bottom: var(--border); }
.widget ol li::before { content: counter(widget-counter); font-family: var(--font-serif); font-weight: 700; color: var(--color-gold-text); font-size: 1.2rem; }
/* A tappable row list (country hub's "Sections" widget) instead of cramped
   tag-badge chips, which read as decorative labels rather than navigation. */
.widget-list li { border-bottom: var(--border); }
.widget-list li:last-child { border-bottom: none; }
.widget-list a { display: block; padding: var(--space-2) 0; font-size: .92rem; color: var(--color-text); }
.widget-list a:hover { color: var(--color-heading); text-decoration: none; }

/* ============ Footer ============ */
.site-footer { background: var(--color-navy-deep); color: var(--color-text-on-navy); margin-top: var(--space-8); }
.footer-top { padding-block: var(--space-7); display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: var(--space-5); }
.footer-brand .logo-text .mark { color: var(--color-text-on-navy); }
.footer-brand .logo-text .full { color: rgba(244,241,232,.6); }
.footer-brand p { color: rgba(244,241,232,.75); font-size: .9rem; margin-top: var(--space-3); max-width: 34ch; }
.footer-col h3 { font-family: var(--font-sans); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; color: var(--color-gold-bright); margin-bottom: var(--space-3); }
.footer-col ul li { margin-bottom: var(--space-1); }
.footer-col a { display: inline-block; padding-block: 3px; color: rgba(244,241,232,.85); font-size: .88rem; }
.footer-col a:hover { color: #fff; }
.footer-brand .footer-entity { font-size: .8rem; color: rgba(244,241,232,.55); }
/* Buttons that sit inside footer link lists (e.g. Manage Preferences) render as links */
.footer-link-button {
  display: inline-block; background: none; border: none; padding: 3px 0; cursor: pointer;
  color: rgba(244,241,232,.85); font-size: .88rem; font-family: inherit; text-align: inherit;
}
.footer-link-button:hover { color: #fff; text-decoration: underline; }
.footer-bottom {
  border-top: 1px solid rgba(244,241,232,.15); padding-block: var(--space-4);
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--space-3);
  font-size: .78rem; color: rgba(244,241,232,.65);
}
.footer-bottom a { color: rgba(244,241,232,.65); }
.footer-disclaimer { font-size: .76rem; color: rgba(244,241,232,.55); padding-bottom: var(--space-5); max-width: 90ch; }

@media (max-width: 980px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .footer-top { grid-template-columns: 1fr; }
}

/* ============ Cookie consent ============ */
.cookie-banner {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 300;
  background: var(--color-ink); color: var(--color-text-on-navy);
  padding: var(--space-4); display: none;
}
.cookie-banner.is-visible { display: block; }
.cookie-banner .container { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); flex-wrap: wrap; }
.cookie-banner p { margin: 0; font-size: .88rem; max-width: 70ch; }
.cookie-banner a { color: var(--color-gold-bright); }
.cookie-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.btn {
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  padding: var(--space-2) var(--space-4); border-radius: var(--radius); font-size: .85rem; font-weight: 600;
  border: 1px solid transparent;
}
.btn-primary { background: var(--color-gold-bright); color: var(--color-ink); }
.btn-primary:hover { background: var(--color-gold); text-decoration: none; }
.btn-outline { background: transparent; border-color: rgba(244,241,232,.4); color: var(--color-text-on-navy); }
.btn-outline:hover { border-color: #fff; text-decoration: none; }

/* ============ "See more" reveal on listing pages ============ */
/* A transparent fill with a hairline --color-line border made this read as an
   empty box the same colour as the page rather than as the one control on the
   listing. It now carries the masthead navy as a solid fill, which is distinct
   from --color-paper in both themes, with gold on hover to match the nav's
   own active marker. */
.load-more {
  display: block;
  width: 100%;
  max-width: 420px;
  margin: var(--space-6) auto 0;
  padding: var(--space-4) var(--space-6);
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: .04em;
  /* A <button> centres its own label; the sector index uses this same treatment
     on an <a>, which is display:block and would otherwise sit left-aligned. */
  text-align: center;
  color: var(--color-text-on-navy);
  background: var(--color-navy);
  border: 1px solid var(--color-navy);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
/* .load-more is self-sufficient; if a template still also applies btn-outline
   (styled for the on-navy cookie banner) its :hover{border-color:#fff} would
   otherwise win, so the fill above has to carry the contrast on its own. */
.load-more:hover {
  background: var(--color-navy-deep);
  border-color: var(--color-gold);
  color: var(--color-text-on-navy);
  text-decoration: none;
}
/* Same reason the footer overrides it: --color-link fails against navy. */
.load-more:focus-visible { outline-color: var(--color-gold-bright); }

/* ============ Search page ============ */
.search-form { display: flex; gap: var(--space-2); margin-block: var(--space-4) var(--space-4); }
.search-form input[type="search"] {
  flex: 1;
  padding: var(--space-3) var(--space-3);
  border: var(--border);
  border-radius: var(--radius);
  background: var(--color-paper-dim);
  color: var(--color-text);
  font-size: 1rem;
}
.search-hint { color: var(--color-text-muted); }
.search-count { margin-bottom: var(--space-3); font-size: .9rem; }
#js-search-results .dek { font-size: .9rem; color: var(--color-text-muted); margin-block: var(--space-1); }

/* ============ Policy / long-form pages ============ */
.policy-page { max-width: 780px; margin-inline: auto; padding-block: var(--space-6); padding-inline: var(--space-4); }
.policy-page h1 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.3rem); }
.policy-page .updated { font-size: .85rem; color: var(--color-text-muted); margin-bottom: var(--space-5); }
.policy-page h2 { font-size: 1.25rem; margin-top: var(--space-6); }
.policy-page ul, .policy-page ol { list-style: disc; margin-inline-start: 1.4em; margin-bottom: var(--space-4); }
.policy-page ol { list-style: decimal; }
.policy-page li { margin-bottom: var(--space-2); }
.policy-page table { border-collapse: collapse; width: 100%; margin-bottom: var(--space-4); font-size: .92rem; }
.policy-page th, .policy-page td { border: var(--border); padding: var(--space-2) var(--space-3); text-align: left; }

/* ============ RTL ============ */
[dir="rtl"] .hero-lead .dek,
[dir="rtl"] body { direction: rtl; }
[dir="rtl"] .breadcrumbs .sep { transform: scaleX(-1); display: inline-block; }
[dir="rtl"] .widget ol li::before { order: 2; }
/* .article-body blockquote and every skip-link/mega-menu/lang-panel rule above
   now use logical (inset-inline-*/margin-inline-*/padding-inline-*) properties,
   which already flip for dir="rtl" on their own -- no override needed here. */

/* ============ Print ============ */
@media print {
  .site-header, .site-footer, .ad-slot, .cookie-banner, .lang-switcher { display: none !important; }
  .article-body { max-width: 100%; }
}
