/*
Theme Name: SilverTrade News
Theme URI: https://silvertrade.com
Author: SilverTrade
Description: Block theme for the SilverTrade editorial property. Design tokens come
  from the Astro rebuild (src/styles/tokens.css) so silvertrade.com and the news
  archive read as one site. Replaces Brisk + Elementor: the design system is
  theme.json and the templates are files, so a change can be diffed and reviewed.
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.1
Version: 0.29.2
License: Proprietary
Text Domain: silvertrade-news
Tags: block-theme, news, editorial
*/

/*
 * Almost everything lives in theme.json. This file holds only what theme.json
 * cannot express.
 */

/* The eyebrow: uppercase, wide-tracked. Lifted from the Astro components, where
   letter-spacing 0.12-0.14em on an 11-12px label is the recurring motif. */
.is-style-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
  font-size: var(--wp--preset--font-size--eyebrow);
  color: var(--wp--preset--color--silver-600);
}

/* Long-form reading measure. theme.json contentSize is 720px, which sets the
   column; this caps line length in ch so it holds at any font size. */
.st-article :where(p, ul, ol, blockquote) {
  max-width: var(--wp--custom--measure);
}

/* Article body needs a looser rhythm than the marketing site's dense UI type. */
.st-article p {
  margin-block: 0 1.15em;
}

/* Dark section, used by header and footer. */
.st-dark {
  background: var(--wp--preset--color--navy-900);
  color: var(--wp--preset--color--silver-200);
}
.st-dark :where(h1, h2, h3, h4, strong) {
  color: var(--wp--preset--color--white);
}
.st-dark a {
  color: var(--wp--preset--color--gold-400);
}

/* Editorial disclosure. Deliberately quiet but never hidden: it has to be
   findable by a reviewer and readable by a reader. Never display:none. */
.st-disclosure {
  border-top: 1px solid var(--wp--preset--color--silver-200);
  border-bottom: 1px solid var(--wp--preset--color--silver-200);
  background: var(--wp--preset--color--silver-50);
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--silver-600);
  line-height: 1.6;
}
.st-disclosure strong {
  color: var(--wp--preset--color--text);
}

/* Syndicated-column label (A10): one line under the standfirst, rendered only
   when post_author is one of the syndicated writers — the byline is the state,
   so there is no per-post list to drift. Quiet, but adjacent to the claim. */
.st-syndication-label {
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--silver-600);
  border-left: 3px solid var(--wp--preset--color--silver-200);
  padding-left: 10px;
  margin-block: 4px 0;
}

/* In-content syndication lines written by the compliance scripts: the
   provenance line at the top of a column (A1) and the no-compensation note at
   the bottom (A3). Muted, never hidden. */
.st-article :where(.st-syndication-provenance, .st-syndication-note) {
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--silver-600);
}

/* Skip link, visible on focus. */
.skip-link:focus {
  position: fixed;
  inset-block-start: 8px;
  inset-inline-start: 8px;
  z-index: 999;
  background: var(--wp--preset--color--white);
  padding: 8px 14px;
  border-radius: var(--wp--custom--radius--sm);
}

/* ---------------------------------------------------------------------------
   Fixes found by rendering the theme in Playground rather than reading it.
   --------------------------------------------------------------------------- */

/* An eyebrow made of category links was inheriting link colour and underline,
   so "UNCATEGORIZED" rendered as blue underlined body text instead of a quiet
   silver label. The style has to reach the inner anchor. */
.is-style-eyebrow a {
  color: inherit;
  text-decoration: none;
}
.is-style-eyebrow a:hover {
  text-decoration: underline;
}

/* On navy, silver-600 is too dark to read. Dark contexts get a lighter step. */
.st-dark .is-style-eyebrow {
  color: var(--wp--preset--color--silver-500);
}

/* The masthead is a wordmark, not a link to be styled like body copy. White
   reads as a masthead; gold reads as a call to action, which it is not. */
.wp-block-site-title a {
  color: var(--wp--preset--color--white);
  text-decoration: none;
}

/* Article titles that happen to be links are still HEADINGS. Inheriting the
   blue link colour made every headline in the archive look like a body link. */
.wp-block-post-title a {
  color: var(--wp--preset--color--ink);
  text-decoration: none;
}
.wp-block-post-title a:hover {
  color: var(--wp--preset--color--blue-600);
}

/* Grid cards need a floor so a single post does not sit in a third of the page. */
.wp-block-post-template.is-layout-grid {
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

/* ---------------------------------------------------------------------------
   Fixes found by testing against the real 461-post archive on staging.
   --------------------------------------------------------------------------- */

/* Featured images are YouTube thumbnails, and many are near-square (816x825
   observed), which rendered 728px tall and pushed the article body below the
   fold. Cap the frame and let the image cover it. */
.wp-block-post-featured-image {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--wp--custom--radius--md);
}
.wp-block-post-featured-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* These are custom YouTube thumbnails with text baked into the lower third
     and a face in the upper half. A centred crop cuts the face; biasing upward
     keeps it. The lost text is duplicated by the headline anyway. Revisit if
     the art direction changes. */
  object-position: center 30%;
}

/* Elementor renders its own sections inside post_content. They assume full
   width, so a 720px reading column clips them and produces horizontal
   overflow. Legacy pages get to be as wide as they were built. */
.st-page .wp-block-post-content .elementor {
  max-width: none;
}
.st-page .wp-block-post-content > .elementor {
  margin-inline: calc(50% - 50vw);
  padding-inline: 20px;
}

/* YouTube oEmbed lands in post_content as a bare <iframe> with fixed width and
   height attributes and no responsive wrapper. add_theme_support(
   'responsive-embeds' ) only covers core EMBED BLOCKS, so these overflowed:
   observed 500x281 and 1000x563 iframes on a 390px viewport, pushing the page
   to 1060px wide. The generic rule stops the overflow for any iframe; the
   YouTube rule also preserves the 16:9 ratio rather than squashing it. */
.wp-block-post-content iframe,
.st-page .wp-block-post-content iframe {
  max-width: 100%;
}
.wp-block-post-content iframe[src*="youtube"],
.wp-block-post-content iframe[src*="youtu.be"] {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
}

/* Same class of problem for anything else wide that authors paste in. */
.st-article :where(table, pre) {
  display: block;
  max-width: 100%;
  overflow-x: auto;
}


/* ═══════════════════════════════════════════════════════════════════════════
   THE INSIDER LAYOUT
   Front page, section archive and article, per the approved design.

   A note on selectors: the core Post Template block renders a <ul
   class="wp-block-post-template"> of <li class="wp-block-post"> items, so the
   per-item layouts below hang off .wp-block-post rather than off a class of
   ours. That is the contract with core, not a shortcut.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Reused by the server-rendered blocks, which cannot carry a block style. */
.st-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
  font-size: var(--wp--preset--font-size--eyebrow);
  color: var(--wp--preset--color--silver-600);
  margin: 0 0 12px;
}
.st-meta {
  font-size: 13px;
  color: var(--wp--preset--color--silver-600);
  margin: 0;
}
.st-meta a { color: inherit; text-decoration: none; }
.st-meta a:hover { text-decoration: underline; }

/* Screen-reader text: block themes do not ship this, and the guest rail needs
   it so "14" is announced as "14 interviews". */
.screen-reader-text {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ── the boundary bar + masthead ──────────────────────────────────────────── */
.st-boundary {
  border-bottom: 1px solid var(--wp--preset--color--silver-200);
  padding-block: 12px;
}
.st-boundary p { margin: 0; }
.st-boundary__back a,
.st-boundary__links a {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
  text-decoration: none;
}
.st-boundary__back a:hover,
.st-boundary__links a:hover { color: var(--wp--preset--color--ink); }

.st-masthead {
  padding-block: 32px 24px;
  border-bottom: 3px solid var(--wp--preset--color--ink);
  margin-bottom: 48px;
}
.st-masthead__kicker { color: var(--wp--preset--color--gold-700); margin-bottom: 8px; }
.st-masthead__title { margin: 0; }
.st-masthead__title a {
  font-size: clamp(30px, 4vw, 44px);
  font-weight: 800;
  letter-spacing: -0.038em;
  line-height: 1;
  color: var(--wp--preset--color--ink);
  text-decoration: none;
}
/* The gap is not decoration. Until v0.19 this nav was a wp:navigation block,
   which supplied `display:flex` and a gap of its own; replacing the block with
   four plain anchors rendered them as inline text with nothing between them —
   "LatestMetalsMiningExclusive Interviews". Screenshotting after the swap is what
   caught it, because every structural measurement (right-aligned, 4 links, no
   overflow) had already passed. */
.st-masthead__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 24px;
  font-size: 15px;
  font-weight: 700;
  padding-bottom: 4px;
}
.st-masthead__nav a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-masthead__nav a:hover { color: var(--wp--preset--color--gold-700); }

/* ── front page: lead + secondaries ──────────────────────────────────────── */
/* ONE grid for the whole front page. The previous two-band arrangement put a
   short right column beside a tall left one twice over, which is where 528px of
   measured dead space came from. A single grid cannot do that. */
.st-front__grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 64px;
  /* Deliberately NOT align-items:start. A start-aligned grid item is only as
     tall as its content, which leaves a sticky child nothing to travel within.
     Stretch (grid's default) makes the rail column as tall as the river beside
     it, and the sticky wrapper then moves through that height. */
}
.st-front__col {
  display: flex;
  flex-direction: column;
  gap: 48px;
  min-width: 0;
}

/* The slack that remains under the rail becomes useful instead of empty: it
   travels with the reader. This is what turns the measured 363px void into
   something that does work. */
.st-front__col--rail > .st-rail-sticky {
  position: sticky;
  top: 24px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.st-lead {
  padding-bottom: 32px;
  border-bottom: 1px solid var(--wp--preset--color--silver-200);
}
.st-lead .wp-block-post-template { list-style: none; margin: 0; padding: 0; }
.st-lead__media { margin-bottom: 24px; }
.st-lead__media img { border-radius: var(--wp--custom--radius--md); }
.st-lead__title { margin: 0 0 16px; }
.st-lead__title a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-lead__title a:hover { color: var(--wp--preset--color--blue-600); }
.st-lead__title {
  font-size: clamp(30px, 3.4vw, 42px);
  letter-spacing: -0.036em;
  line-height: 1.06;
}
.st-lead__standfirst {
  font-size: var(--wp--preset--font-size--lead);
  line-height: 1.5;
  color: var(--wp--preset--color--text);
  margin: 0 0 16px;
  max-width: 60ch;
}

.st-seconds .wp-block-post-template {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 24px;
}
.st-seconds .wp-block-post {
  padding-bottom: 24px;
  border-bottom: 1px solid var(--wp--preset--color--silver-100);
}
.st-seconds .wp-block-post:last-child { border-bottom: 0; padding-bottom: 0; }
.st-seconds__title { font-size: 22px; letter-spacing: -0.022em; line-height: 1.2; margin: 0 0 8px; }
.st-seconds__title a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-seconds__title a:hover { color: var(--wp--preset--color--blue-600); }

/* ── front page: river + rail ───────────────────────────────────────────── */
.st-river__label { margin-bottom: 2px; color: var(--wp--preset--color--ink); }
.st-river .wp-block-post-template { list-style: none; margin: 0; padding: 0; }
.st-river .wp-block-post {
  display: grid;
  grid-template-columns: 60px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
  padding-block: 16px;
  border-top: 1px solid var(--wp--preset--color--silver-100);
}
.st-river__when {
  font-size: 13px;
  font-weight: 700;
  color: var(--wp--preset--color--silver-500);
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.st-river__title { font-size: 20px; font-weight: 700; letter-spacing: -0.018em; line-height: 1.25; margin: 0 0 4px; }
.st-river__title a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-river__title a:hover { color: var(--wp--preset--color--blue-600); }
.st-allstories { margin: 24px 0 0; }
.st-allstories a {
  font-size: 14px; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase;
  color: var(--wp--preset--color--ink); text-decoration: none;
  border-bottom: 2px solid var(--wp--preset--color--gold-500); padding-bottom: 3px;
}

/* ── the guest rail ──────────────────────────────────────────────────────── */
.st-guest-rail {
  background: var(--wp--preset--color--silver-50);
  border-radius: var(--wp--custom--radius--md);
  padding: 24px;
}
.st-guest-rail__intro {
  font-size: 14px; line-height: 1.5;
  color: var(--wp--preset--color--silver-600);
  margin: 0 0 16px;
}
.st-guest-rail__row {
  display: flex; align-items: center; gap: 12px;
  padding-block: 12px;
  border-top: 1px solid var(--wp--preset--color--silver-200);
  text-decoration: none;
}
.st-guest-rail__row:hover .st-guest-rail__name { color: var(--wp--preset--color--blue-600); }
.st-guest-rail__who { flex-grow: 1; min-width: 0; }
.st-guest-rail__name {
  display: block; font-size: 15px; font-weight: 700;
  color: var(--wp--preset--color--ink); line-height: 1.3;
}
.st-guest-rail__count {
  font-size: 13px; font-weight: 700;
  color: var(--wp--preset--color--gold-700);
  font-variant-numeric: tabular-nums;
}

.st-startbox {
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md);
  padding: 24px;
  margin-top: 24px;
}
.st-startbox__intro { font-size: 15px; line-height: 1.55; margin: 0 0 16px; }
.st-startbox__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 15px; font-weight: 600; }

/* ── topic strips ────────────────────────────────────────────────────────── */
.st-strip { padding-block: 32px; border-top: 3px solid var(--wp--preset--color--ink); }
.st-strip__title { font-size: 26px; letter-spacing: -0.026em; margin: 0 0 24px; }
.st-strip .wp-block-post-template { list-style: none; margin: 0; padding: 0; }
/* Four across on wide screens, three below. The container went to 1460, which
   makes a 3-up strip 460px per card — wider than the archive cards and wider
   than these headlines need. Four gives ~340px, which matches the card size
   used everywhere else on the site.
   `!important` because the Grid layout block writes its own
   grid-template-columns inline from columnCount, and inline wins. */
.st-strip__grid {
  gap: 32px !important;
  grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
}
@media (max-width: 1200px) {
  .st-strip__grid { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
}
@media (max-width: 860px) {
  .st-strip__grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}
.st-strip__media { margin-bottom: 12px; }
.st-strip__media img { border-radius: var(--wp--custom--radius--sm); }
.st-strip__head { font-size: 19px; letter-spacing: -0.018em; line-height: 1.25; margin: 0 0 8px; }
.st-strip__head a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-strip__head a:hover { color: var(--wp--preset--color--blue-600); }

/* ── section archive: one lead, then a river ──────────────────────────────
   The lead is :first-child of a single INHERITED query, not a second query.
   Offsetting an inherited archive query breaks its pagination. */
.st-section__head {
  padding-block: 8px 24px;
  border-bottom: 3px solid var(--wp--preset--color--ink);
  margin-bottom: 32px;
}
.st-section__title { font-size: clamp(28px, 3.4vw, 40px); letter-spacing: -0.036em; margin: 0; }
.st-section__desc { font-size: 17px; color: var(--wp--preset--color--silver-600); margin: 12px 0 0; max-width: 70ch; }

/* The old lead-and-river archive layout lived here. Removed with the
   templates that emitted it — see the ARCHIVES block below. */

/* ── the article ─────────────────────────────────────────────────────────── */
/*
 * WHAT WAS WRONG, MEASURED
 * ------------------------
 * At a 1512px viewport this computed to:
 *
 *   .st-article-wrap   x=0    w=1497   max-width: none
 *   .st-article        x=20   w=720
 *   .st-rail           x=804  w=673
 *
 * The wrap spanned the ENTIRE viewport with no max-width, pinned against the
 * left edge, and the sidebar was 673px — very nearly as wide as the article it
 * was meant to sit beside. On a wider monitor the rail kept growing, because it
 * was `1fr` of an unbounded container.
 *
 * The cause: `display: grid` here replaces WordPress's constrained layout.
 * Constrained puts `max-width` on the CHILDREN and centres them. Once this
 * element is a grid, that max-width lands on `.st-article` and `.st-rail` (both
 * computed to a useless `max-width: 1200px`, already sized by the grid) and the
 * CONTAINER gets nothing — so the centring silently disappeared.
 *
 * The fix is for the grid to own its width rather than inherit one it never
 * gets: explicit max-width plus `margin-inline: auto`, and a FIXED rail so the
 * article takes the slack instead of the other way round. The article column
 * becomes 1200 - 340 - 64 = 796px, wider than the 720px it was, which is what
 * makes the body span the page. It stays within the 72ch measure, so line
 * length is still controlled.
 */
.st-article-wrap {
  display: grid;
  /* ── THE ARTICLE COLUMN IS CAPPED, NOT ELASTIC ────────────────────────────
     It used to be `minmax(0, 1fr)`, and the comment above still describes the
     world where that was right: the wrap was 1200px, so 1fr resolved to 796px
     and the 720px content measure very nearly filled it.

     Widening the wrap to 1460 (to answer a complaint about side whitespace on
     large screens) quietly broke that. 1fr became 948px while the content
     stayed at theme.json's 720px contentSize, CENTRED — so every paragraph sat
     (948 - 720) / 2 = 114px to the right of the headline and the hero image,
     which were using the full column. The text looked like it belonged to a
     different page.

     Capping the column at the measure fixes the alignment at the source rather
     than nudging margins: the column IS the measure, so the headline, the hero
     image, the body, the share row and Read next all share one left edge and one
     right edge. 820px at 18px Inter is ~86 characters — at the long end of the
     comfortable range, chosen over 720 (~75, ideal) because a 128px-narrower
     column would have widened the outer margins this layout was widened to
     avoid. `justify-content: center` puts the leftover space symmetrically
     outside the grid, where it reads as a centred page rather than a gap. */
  grid-template-columns: minmax(0, 820px) 400px;
  justify-content: center;
  gap: 64px;
  max-width: 1460px;
  margin-inline: auto;
  padding-block: 8px 64px;
  /* Keeps text off the glass between 1200px and the first breakpoint. */
  padding-inline: 24px;
}

/* Grid items size from the grid; the inherited constrained max-width is noise. */
.st-article-wrap > .st-article,
.st-article-wrap > .st-rail {
  max-width: none;
}

/* "More in <section>" scrolls away; Trending and the newsletter are what stick.
   It used to be the first thing inside .st-rail__sticky, which meant the module
   pinned to the viewport was a list of three related links — useful once, at the
   top, and then furniture for the rest of a long article. Trending refreshes on
   a decay window and the newsletter is the conversion, so those are the two
   worth carrying down the page. The related list stays where a reader meets it
   first and then behaves like the rest of the page. */
.st-rail__track > .st-rail__box:first-child {
  margin-bottom: 24px;
}

/* And the content fills the column rather than being re-centred inside it.
   WordPress's constrained layout emits `.wp-container-N > * { max-width: 720px;
   margin-inline: auto }`; this is one class deeper, so it wins without
   !important. This is the half of the fix that actually aligns the text — the
   grid change above only decides how wide "aligned" is. */
.st-article .wp-block-post-content > *,
.st-article > .wp-block-group:not(.st-disclosure) > * {
  max-width: none;
  margin-inline: 0;
}

/* Below full width, give the rail less room before it drops away entirely: a
   340px rail beside a 500px article reads as two columns of equal weight, which
   is not the hierarchy. */
@media (max-width: 1100px) {
  .st-article-wrap {
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 40px;
  }
}
.st-article__standfirst {
  font-size: var(--wp--preset--font-size--lead);
  line-height: 1.5;
  color: var(--wp--preset--color--text);
  margin: 0 0 24px;
}
.st-article__media { margin-block: 0 32px; }

.st-guest-id {
  display: flex; align-items: center; gap: 16px;
  padding: 16px 24px;
  background: var(--wp--preset--color--silver-50);
  border-radius: var(--wp--custom--radius--md);
  margin-bottom: 24px;
}
.st-guest-id__who { flex-grow: 1; min-width: 0; }
.st-guest-id__name {
  display: block; font-size: 17px; font-weight: 800;
  color: var(--wp--preset--color--ink); letter-spacing: -0.015em;
}
.st-guest-id__role { display: block; font-size: 14px; color: var(--wp--preset--color--silver-600); line-height: 1.4; }
.st-guest-id__more {
  flex-shrink: 0; font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--wp--preset--color--ink); text-decoration: none;
  border-bottom: 2px solid var(--wp--preset--color--gold-500); padding-bottom: 2px;
}

.st-byline { gap: 8px; align-items: baseline; margin-bottom: 24px; font-size: 14px; color: var(--wp--preset--color--silver-600); }
.st-byline p, .st-byline div { margin: 0; }
.st-byline__label { font-size: 14px; }
.st-byline__author { font-size: 14px; font-weight: 700; }
.st-byline__author a { color: var(--wp--preset--color--text); text-decoration: none; }
.st-byline__date { font-size: 14px; }

/* the extractable summary */
.st-short {
  border-left: 3px solid var(--wp--preset--color--gold-500);
  padding: 4px 0 4px 24px;
  margin-bottom: 32px;
}
.st-short__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.st-short__list li { font-size: 18px; line-height: 1.55; color: var(--wp--preset--color--text); }

/* article rail */
.st-rail { display: flex; flex-direction: column; gap: 24px; }
.st-related, .st-rail__box {
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md);
  padding: 24px;
}
.st-rail__box { background: var(--wp--preset--color--silver-50); border-color: transparent; }
.st-related__item { display: block; text-decoration: none; padding-block: 12px; border-top: 1px solid var(--wp--preset--color--silver-200); }
.st-related__item:first-of-type { border-top: 0; padding-top: 0; }
.st-related__head { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.015em; line-height: 1.3; color: var(--wp--preset--color--ink); margin-bottom: 3px; }
.st-related__when { font-size: 12px; color: var(--wp--preset--color--silver-500); }
.st-rail__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }
/* Two shapes, deliberately: the Query Loop renders `<h3 class="st-rail__title"><a>`,
   while the related module renders `<a class="st-rail__title">` directly. A rule
   written only for the first left the second as default blue-and-underlined
   links in the rail. */
.st-rail__title,
a.st-rail__title { font-size: 16px; font-weight: 700; letter-spacing: -0.012em; line-height: 1.3; margin: 0 0 3px; display: block; }
.st-rail__title a,
a.st-rail__title { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-rail__title a:hover,
a.st-rail__title:hover { color: var(--wp--preset--color--blue-600); }

/* ── responsive: collapse every two-column band at one breakpoint ────────── */
@media (max-width: 900px) {
  .st-front__top,
  .st-front__mid,
  .st-article-wrap {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .st-masthead { margin-bottom: 32px; }
  .st-strip__grid { grid-template-columns: minmax(0, 1fr) !important; }
  .st-river .wp-block-post {
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
  }
  .st-guest-id { flex-wrap: wrap; }
  .st-guest-id__more { flex-basis: 100%; }
}


/* Watch: video-led, deliberately NOT a second river.
   The posts ARE the video write-ups, so an embedded feed would duplicate the
   river and cost roughly 500KB per iframe. This links to the POST, shows the
   thumbnail at rail width, and carries one channel CTA. Nothing third-party
   loads, so it needs no consent gate. */
.st-watch {
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md);
  padding: 24px;
}
.st-watch__item {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 12px;
  align-items: start;
  padding-block: 12px;
  border-top: 1px solid var(--wp--preset--color--silver-200);
  text-decoration: none;
}
.st-watch__item:first-of-type {
  border-top: 0;
  padding-top: 0;
}
.st-watch__thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--wp--custom--radius--sm);
  overflow: hidden;
  background: var(--wp--preset--color--navy-900);
}
.st-watch__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}
.st-watch__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.st-watch__play svg {
  filter: drop-shadow(0 1px 3px rgba(4, 16, 30, 0.55));
}
.st-watch__head {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.3;
  color: var(--wp--preset--color--ink);
}
.st-watch__item:hover .st-watch__head {
  color: var(--wp--preset--color--blue-600);
}
.st-watch__cta {
  display: block;
  margin-top: 16px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--wp--preset--color--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--wp--preset--color--gold-500);
  padding-bottom: 2px;
  width: fit-content;
}

@media (max-width: 900px) {
  .st-front__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .st-front__col {
    gap: 32px;
  }
  /* Sticky in a single column would pin the rail over the river. */
  .st-front__col--rail > .st-rail-sticky {
    position: static;
  }
}

/* ── grounding the imagery ────────────────────────────────────────────────────
   The thumbnails are dark, busy, high-contrast art on a white page, so they
   float without an edge. A hairline INSET ring gives them one without adding a
   visible frame or changing their footprint — measured crop loss is only 0-6%,
   so the art itself needed no reframing. */
.wp-block-post-featured-image,
.st-watch__thumb {
  box-shadow: inset 0 0 0 1px rgba(4, 16, 30, 0.1);
}

/* A restrained hover: the image is the affordance on a card, so it should
   acknowledge the pointer. Opacity only - no scale, which would resample the
   art and soften it. */
.st-strip .wp-block-post-featured-image img,
.st-lead__media img,
.st-watch__thumb img {
  transition: opacity 160ms var(--wp--custom--ease, ease);
}
.st-strip .wp-block-post:hover .wp-block-post-featured-image img,
.st-lead:hover .st-lead__media img,
.st-watch__item:hover .st-watch__thumb img {
  opacity: 0.88;
}

@media (prefers-reduced-motion: reduce) {
  .st-strip .wp-block-post-featured-image img,
  .st-lead__media img,
  .st-watch__thumb img {
    transition: none;
  }
}

/* ── prose rhythm inside the article body ─────────────────────────────────────
   Measured on the real corpus after the byline-nesting bug was fixed:

     h3 -> p    0px    headings had no bottom margin, so the next paragraph sat
                       flush against them
     h2  above 16px    far too tight under a 34px heading
     p  bottom 20.7px  1.15em, which is defensible for prose but off the scale

   The relationship that matters in prose is ASYMMETRIC: generous space ABOVE a
   heading, tight space below it, so the heading binds to the text it introduces
   rather than floating between two blocks. Equal margins are the single most
   common way body copy reads as unedited.

   `:where()` keeps specificity at zero so an editor's own block settings still
   win — this sets the rhythm, it does not enforce it. */
.st-article .wp-block-post-content :where(p) {
  margin-block: 0 24px;
}
.st-article .wp-block-post-content :where(h2, h3, h4) {
  margin-block: 48px 16px;
}
.st-article .wp-block-post-content :where(h2) {
  /* A section break earns more air than a subhead. */
  margin-block-start: 64px;
}
.st-article .wp-block-post-content :where(ul, ol) {
  margin-block: 0 24px;
  padding-inline-start: 24px;
}
.st-article .wp-block-post-content :where(li) {
  margin-block-end: 8px;
}
.st-article .wp-block-post-content :where(li:last-child) {
  margin-block-end: 0;
}
.st-article .wp-block-post-content :where(blockquote, figure, .wp-block-embed) {
  margin-block: 32px;
}

/* Nothing pushes the top of the body away from the block above it. */
.st-article .wp-block-post-content > :first-child {
  margin-block-start: 0;
}
/* And nothing leaves a gap before the disclosure. */
.st-article .wp-block-post-content > :last-child {
  margin-block-end: 0;
}

/* Empty paragraphs in the corpus (pasted content leaves them behind) rendered
   as two ~42px voids mid-article. Collapsing them is safe: an empty <p> carries
   no content and no accessible name. */
.st-article .wp-block-post-content p:empty {
  display: none;
}

/* ══════════════════════════════════════════════════════════════════════════════
   WebP delivery, converted pages, and the contact form.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The <picture> wrapper added by inc/webp.php introduces a new DOM level around
   every image. `display: contents` makes it vanish from layout entirely, so
   every existing rule — `.st-lead__media img`, the featured-image sizing, the
   hover transforms — keeps applying exactly as it did. Without this, <picture>
   defaults to an inline box that will not stretch, and every framed image
   collapses. All the img selectors in this file are descendant selectors rather
   than direct-child, which is the only reason one line is enough. */
picture { display: contents; }

/* ── the metal quote strip (patterns/metal-quote-strip.php) ───────────────── */
.st-quotes {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-block: 48px;
  padding: 24px;
  background: var(--wp--preset--color--silver-50);
  border-radius: var(--wp--custom--radius--md);
}
.st-quotes__item { min-width: 0; }
.st-quotes__link {
  display: inline-block; margin-top: 8px;
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--wp--preset--color--silver-600); text-decoration: none;
}
.st-quotes__link:hover { color: var(--wp--preset--color--gold-700); text-decoration: underline; }
/* TradingView injects a fixed-width iframe; without this it forces horizontal
   page scroll on a phone, which is the defect the verifier checks for. */
.st-quotes iframe { max-width: 100% !important; }

@media (max-width: 900px) { .st-quotes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .st-quotes { grid-template-columns: 1fr; padding: 16px; } }

/* ── latest news grid (patterns/latest-news-grid.php) ─────────────────────── */
.st-latest { margin-block: 64px; }
.st-latest__title { font-size: clamp(26px, 3vw, 34px); letter-spacing: -0.03em; margin: 0 0 32px; }
.st-latest__grid { gap: 32px 24px; }
.st-latest__media img { border-radius: var(--wp--custom--radius--md); width: 100%; height: auto; }
.st-latest__kicker {
  margin: 12px 0 8px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--wp--preset--color--gold-700);
}
.st-latest__kicker a { color: inherit; text-decoration: none; }
.st-latest__heading { font-size: 19px; font-weight: 700; letter-spacing: -0.016em; line-height: 1.28; margin: 0 0 8px; }
.st-latest__heading a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-latest__heading a:hover { color: var(--wp--preset--color--gold-700); }
.st-latest__date { font-size: 13px; color: var(--wp--preset--color--silver-600); margin: 0; }
.st-latest__more { margin-top: 40px; }

/* ── cards, from Elementor image-box / icon-box ───────────────────────────── */
.st-card {
  padding: 24px;
  background: var(--wp--preset--color--silver-50);
  border-radius: var(--wp--custom--radius--md);
}
.st-card img { border-radius: var(--wp--custom--radius--sm); width: 100%; height: auto; }
.st-card h3 { font-size: 20px; letter-spacing: -0.018em; margin: 16px 0 8px; }
.st-card p:last-child { margin-bottom: 0; }

/* ── highlighted-text, from Elementor ────────────────────────────────────── */
.st-highlight { color: var(--wp--preset--color--gold-700); }

/* ── the map, replacing the Elementor Google Maps widget ─────────────────── */
.st-map { width: 100%; margin-block: 32px; border-radius: var(--wp--custom--radius--md); overflow: hidden; }

/* ── contact form (inc/contact-form.php) ─────────────────────────────────── */
.st-form-wrap { max-width: 640px; margin-block: 32px; }
.st-form__row { display: flex; flex-direction: column; gap: 8px; margin: 0 0 24px; }
.st-form__row label {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--wp--preset--color--silver-600);
}
.st-form__req { color: var(--wp--preset--color--gold-700); margin-left: 2px; }

.st-form__row input,
.st-form__row select,
.st-form__row textarea {
  width: 100%;
  padding: 12px 16px;
  font: inherit;
  /* 16px minimum: below it, iOS Safari zooms the viewport on focus, which reads
     as the page jumping when a visitor taps a field. */
  font-size: 16px;
  color: var(--wp--preset--color--ink);
  background: #fff;
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--sm);
}
.st-form__row textarea { resize: vertical; min-height: 140px; }

.st-form__row input:focus-visible,
.st-form__row select:focus-visible,
.st-form__row textarea:focus-visible,
.st-form__submit:focus-visible {
  outline: 2px solid var(--wp--preset--color--gold-500);
  outline-offset: 2px;
}

/* The invalid state is a border AND a message, never colour alone — colour on
   its own is invisible to a colour-blind visitor and to a screen reader. */
.st-form__row.is-invalid input,
.st-form__row.is-invalid select,
.st-form__row.is-invalid textarea { border-color: #b3261e; }
.st-form__err { font-size: 13px; color: #b3261e; }

.st-form__submit {
  padding: 14px 32px;
  font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--wp--preset--color--navy-900);
  background: var(--wp--preset--color--gold-500);
  border: 0; border-radius: var(--wp--custom--radius--sm);
  cursor: pointer;
}
.st-form__submit:hover { background: var(--wp--preset--color--gold-400); }

.st-form__notice { padding: 16px 20px; margin: 0 0 24px; border-radius: var(--wp--custom--radius--sm); font-size: 15px; }
.st-form__notice--ok  { background: #edf7ed; border-left: 3px solid #2e7d32; }
.st-form__notice--bad { background: #fdeded; border-left: 3px solid #b3261e; }

/* The honeypot. Positioned off-screen rather than display:none, because some
   bots skip fields that are display:none — which would defeat the trap. */
.st-form__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}

/* ── the masthead logo (inc/blocks.php: st_render_masthead_title) ─────────── */
/* The wordmark reads "The [logo] Insider", so the logo has to sit on the text
   baseline at roughly cap height. Sizing in `em` means it tracks the title's
   clamp() rather than needing its own breakpoints. */
.st-masthead__title a {
  display: flex;
  align-items: baseline;
  gap: 0.28em;
  flex-wrap: wrap;
}
.st-masthead__logo {
  /* 1.1em: the wordmark reads LARGER than "The" and "Insider" rather than
     smaller, which makes the brand the subject of the masthead and the two words
     its frame. Rendered at 0.62 / 1.1 / 1.45 before choosing — 1.45 tipped into
     the wordmark being the whole masthead with the words hanging off it.
     The logo is 7.83:1, so height drives width hard: 1.1em is 48px tall and
     379px wide, and the wordmark row plus the nav still fits on one line at a
     1280px viewport. */
  /* ── the baseline, derived rather than nudged ─────────────────────────────
     `align-items: baseline` aligns an image by its BOX BOTTOM, so any transparent
     padding under the glyphs sits between them and the text baseline and lifts the
     wordmark off the line. The correction is exactly that padding, as a fraction
     of the box height — measured off the asset's alpha channel, not eyeballed:

         SilverTrade-Logo-Web-v2.png   360x46   ink 348x31 at +6+8    7/46 = 0.1522
         ST-Web-Logo.png              1700x214  ink 1632x142 at +19+37  35/214 = 0.1636

     The masthead now uses ST-Web-Logo (see st_masthead_logo_file() — the old file
     was a 360px original in a ~207px box, soft on every 2x screen), so the ratio
     moved with it. A hand-picked number here would have gone stale silently and
     the wordmark would ride 0.011em high; keeping the derivation in the comment is
     what makes the next asset swap a two-minute change.

     THIS NUMBER IS ASSET-SPECIFIC. Change the file, re-measure the alpha box. */
  --st-logo-box: 1.1em;
  --st-logo-ink-below: 0.1636;

  height: var(--st-logo-box);
  width: auto;
  transform: translateY(calc(var(--st-logo-box) * var(--st-logo-ink-below)));
}
/* The <picture> wrapper from inc/webp.php is display:contents, so it does not
   participate here - but the flex container would otherwise stretch the image. */
.st-masthead__title picture { display: contents; }

@media (max-width: 600px) {
  /* On a phone the three-part wordmark wraps awkwardly mid-lockup; stacking the
     logo onto its own line keeps "The ... Insider" legible. */
  .st-masthead__title a { gap: 0.2em; }
  .st-masthead__logo { --st-logo-box: 0.95em; }
}

/* ── pages are not articles ───────────────────────────────────────────────── */
/*
 * Measured on /about/ at a 1920px viewport: post-content computed to 720px.
 * That is the ARTICLE reading measure, inherited because page.html reuses the
 * .st-article class, and it is wrong for a marketing page — it forced four
 * feature cards that were designed as a row to stack into a single column down
 * the middle of a very wide screen.
 *
 * So the page container gets 1040px, and PROSE alone keeps the reading measure.
 * Groups, grids, images and embeds may use the full width; paragraphs and lists
 * stay comfortable to read. Widening the container without this second rule
 * would just trade a too-narrow page for unreadable 1040px line lengths.
 */
/* ── WHY THIS MEASURE IS IN PIXELS AND NOT `ch` ──────────────────────────────
   It used to be `72ch`, which looks like the textbook way to express a reading
   measure and is wrong for a SHARED one: `ch` resolves against each element's
   own font-size. On the price pages that produced a different width per element
   and, because WordPress also centres constrained children, a different left
   edge for each:

       h2 at 34px  ->  72ch = 1694px  ->  full width, left edge  20
       h3 at 26px  ->  72ch = 1295px  ->  centred,    left edge 101
       p  at 18px  ->  72ch =  818px  ->  centred,    left edge 340

   So a heading, its subheading and its paragraph each started at a different
   x — a 320px stair-step down the page. One measure in px gives every element
   the same box, and `margin-inline: 0` stops WordPress re-centring them inside
   it, so the whole column shares one left edge with the headings above it. */
/* `figure` and `.wp-block-image` are in this list because leaving them out is
   what produced the last EDGES error on the price pages: one image sat at 164px
   while all sixteen text blocks sat at 114px, because WordPress was still
   applying the 720px contentSize and centring it. An image in a text column
   belongs on the text column's edge. */
.st-page .wp-block-post-content > :where(p, ul, ol, blockquote, h2, h3, h4, h5, figure, .wp-block-image, .wp-block-embed, table) {
  max-width: var(--wp--custom--measure);
  /* `!important` because WordPress's own generated layout CSS says
     `margin-left: auto !important; margin-right: auto !important` for every
     constrained child, and that is not a stylesheet this theme can edit. Without
     matching it, the max-width above applies and the element is still centred —
     which is precisely the state that produced the stair-step.

     Note the article column gets away without this, and the reason is worth
     knowing rather than copying: there the override is `max-width: none`, so the
     element fills its container and `auto` margins resolve to 0 on their own.
     That only works when you do NOT want a measure. Here we do. */
  margin-inline: 0 !important;
}

/* The newsletter panel is not prose, so it is not caught by the rule above — it
   was stretching the full 1457px while its kicker, body text and fine print sat
   in the left 550px, leaving two thirds of a bordered box empty. Aligned to the
   text column instead, where it reads as part of the page rather than a banner
   that failed to fill. The charts above it keep the full width, which is the
   one thing on these pages that genuinely wants it. */
.st-page .wp-block-post-content > .st-news {
  max-width: var(--wp--custom--measure);
  margin-inline: 0 !important;
}

/* The contact form and the contact panel need the same treatment, and for the
   same reason — but this is also the answer to "the address area doesn't look
   properly designed", which turned out not to be about the address at all.
   Measured on /contact-us/ at a 1400px viewport:

       paragraphs      820px   (the measure, correctly)
       the form       1360px
       the panel      1360px
       the newsletter  870px

   Four different widths in one column. Nothing on the page shared an edge, so
   whatever went in the address slot was going to look unplaced. The panel is not
   prose so the rule above misses it, and `.st-form-wrap`'s own `max-width: 640px`
   loses to WordPress's generated layout CSS, which is emitted after this
   stylesheet. Both are pinned to the measure here, where the `!important` note
   above already explains why that is needed. */
.st-page .wp-block-post-content > .st-contact,
.st-page .wp-block-post-content > .st-form-wrap {
  max-width: var(--wp--custom--measure);
  margin-inline: 0 !important;
}

/* `border-box` so the measure is the OUTER edge. Without it a padded, bordered
   panel lands at 820 + 56 + 2 = 878px and overhangs the text column it is
   supposed to line up with by 58px — near enough to look like a mistake rather
   than a decision, which is the worst width to be. Scoped to page content so the
   footer's own newsletter panel, which is meant to be full-bleed, is untouched. */
.st-page .wp-block-post-content > .st-contact,
.st-page .wp-block-post-content > .st-news {
  box-sizing: border-box;
}

/* Feature cards, from Elementor image-boxes that used to sit in columns. */
.st-cards {
  gap: 24px;
  margin-block: 40px;
  /* auto-fit rather than a fixed count: the converter writes columnCount from
     how many cards were adjacent, and a hard 4 would overflow on a tablet. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
}
.st-cards .st-card { margin: 0; height: 100%; }
.st-cards .st-card h3 { font-size: 18px; }
.st-cards .st-card p { font-size: 15px; line-height: 1.55; }
/* Inside a card the heading and copy are furniture, not prose, so the reading
   measure must not apply or each card's text would be capped at 72ch of a
   220px column and wrap oddly. */
.st-page .st-cards :where(p, h3) { max-width: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   SITE CHROME
   A replica of the main site's header and footer, transcribed from
   web/src/components/chrome/{Header,Footer}.astro and web/src/styles/*.css
   rather than approximated from a screenshot. Values are the source's values.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Astro's --container / .container, so the chrome aligns with the main site's
   gutters exactly rather than approximately. */
/* ── how wide, and why not simply 1200 ──────────────────────────────────────
   The Astro site is 1200px, and this chrome was a faithful copy of it — measured
   at a 1920px viewport, the main site leaves 353px of gutter each side and so
   did this.
   That is defensible on a MARKETING page: a big hero and short copy blocks, where
   whitespace reads as premium. It is not defensible on a dense index. The
   newsroom's front page and archives are grids of articles, and there empty
   gutters are not luxury, they are unsold inventory — every 240px recovered is
   another column of headlines a reader can see without scrolling.
   So the index surfaces and the chrome grow together on large screens, while the
   ARTICLE stays at 1200 because a reading column has an optimum that is not "as
   wide as the monitor". Below ~1540px viewports nothing changes at all.
   This does mean the chrome is now wider here than on the Astro site above that
   width. The right resolution is the same token change there — see the note in
   the handoff — rather than keeping this one narrow to match. */
.st-hdr__inner,
.st-ftr__inner {
  width: min(calc(100% - 40px), 1460px);
  margin-inline: auto;
}

/* ── header ──────────────────────────────────────────────────────────────── */
.st-hdr {
  position: sticky;
  top: 0;
  z-index: 100;
  /* --header-height: 78px */
  height: 78px;
  /* navy-900 #071525 at 0.9, over an 18px blur. The translucency is the point:
     content scrolling beneath it stays faintly visible, which is what makes it
     read as the product's chrome rather than a painted bar. */
  background: rgba(7, 21, 37, 0.9);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}
.st-hdr__inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 30px;
}
.st-hdr__brand { display: inline-flex; align-items: center; text-decoration: none; flex: 0 0 auto; }
.st-hdr__logo { width: 196px; height: auto; display: block; }

.st-hdr__nav { display: flex; align-items: center; gap: 26px; }
/* `:not(.st-btn)` is load-bearing, and the Astro source carries the same warning:
   without it this selector out-specifies the gold button's own colour and
   repaints the CTA label pale silver on gold at about 1.5:1 contrast. */
.st-hdr__nav a:not(.st-btn) {
  color: #dce6ef;
  text-decoration: none;
  font-size: 14px;
  font-weight: 650;
  transition: color 0.2s ease;
  white-space: nowrap;
}
.st-hdr__nav a:not(.st-btn):hover,
.st-hdr__nav a:not(.st-btn):focus-visible,
.st-hdr__nav a[aria-current="page"] { color: #fff; }

/* ── the gold CTA (.button.button--small.button--gold) ───────────────────── */
.st-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* --small: 42px / 17px / 13px */
  min-height: 42px;
  padding-inline: 17px;
  font-size: 13px;
  /* 10px, NOT a pill. The first attempt at this used 999px and it read wrong
     immediately — the radius is one of the few things that makes a button look
     like a specific brand's button. */
  border-radius: 10px;
  font-weight: 800;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease;
}
.st-btn:hover { transform: translateY(-2px); }
.st-btn:active { transform: translateY(0); }
.st-btn--gold {
  color: var(--wp--preset--color--ink);
  /* Three stops, not a flat fill — gold-300 #f4d37a and gold-400 #edbd4a. */
  background: linear-gradient(135deg, #f8dc82, #f4d37a 48%, #edbd4a);
  box-shadow:
    0 12px 30px rgba(217, 164, 49, 0.22),
    inset 0 0 0 1px rgba(255, 255, 255, 0.35);
  letter-spacing: 0.01em;
}
.st-btn--gold:hover { background: linear-gradient(135deg, #fbe6a0, #f8dc82 48%, #f4d37a); }
.st-btn--gold:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ── the hamburger ───────────────────────────────────────────────────────── */
.st-hdr__toggle {
  display: none;
  width: 44px;
  height: 44px;
  background: transparent;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
}
.st-hdr__toggle span:not(.screen-reader-text) {
  display: block;
  width: 22px;
  height: 2px;
  margin: 5px auto;
  background: #fff;
  border-radius: 999px;
  transition: 0.25s ease;
}
.st-hdr__toggle:focus-visible { outline: 2px solid var(--wp--preset--color--gold-400); outline-offset: 2px; }

/* Astro's breakpoint is 1000px, and the menu JS uses the same number — they
   have to agree or the menu can be open with no way to close it. */
@media (max-width: 1000px) {
  .st-hdr__toggle { display: block; }
  .st-hdr__nav {
    position: absolute;
    inset: 78px 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 12px 20px 20px;
    background: var(--wp--preset--color--navy-900);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    display: none;
  }
  .st-hdr__nav[data-open="true"] { display: flex; }
  .st-hdr__nav a:not(.st-btn) {
    padding: 14px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    font-size: 16px;
  }
  .st-hdr__nav .st-btn { margin-top: 14px; }
  .st-hdr__logo { width: 164px; }
}

/* ── footer ──────────────────────────────────────────────────────────────── */
.st-ftr {
  /* Deliberately darker than the header: #020b14, not navy-900. */
  background: #020b14;
  color: #8fa2b5;
  padding: 64px 0 34px;
  font-size: 13.5px;
  margin-top: 80px;
}
.st-ftr__grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(4, 1fr);
  gap: 36px;
}
.st-ftr__brandlink { display: inline-flex; margin-bottom: 16px; }
.st-ftr__logo { width: 172px; height: auto; display: block; }
.st-ftr__tagline { margin: 0; font-size: 13px; color: #dbe6f1; }
.st-ftr__lineage { margin: 8px 0 0; font-size: 12px; color: #6d8296; max-width: 30ch; }

.st-ftr__col h2 {
  margin: 0 0 14px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #dbe6f1;
}
.st-ftr__col a { display: block; margin-bottom: 9px; color: #8fa2b5; text-decoration: none; }
.st-ftr__col a:hover { color: #fff; }
.st-ftr__col a:focus-visible { outline: 2px solid var(--wp--preset--color--gold-400); outline-offset: 2px; }

.st-ftr__legal { margin-top: 44px; padding-top: 26px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
.st-ftr__disclose { margin: 0 0 12px; font-size: 12.5px; line-height: 1.6; color: #8fa2b5; }
.st-ftr__disclose strong { color: #dbe6f1; }
.st-ftr__disclose--fine { font-size: 11.5px; color: #6d8296; }
.st-ftr__copy { margin: 12px 0 0; font-size: 11.5px; color: #6d8296; }

/* The editorial strip is the newsroom's addition to the product footer, and it
   is marked out rather than blended in: it has to be findable by a reviewer and
   readable by a reader. Never display:none. */
.st-ftr__editorial {
  margin: 0 0 20px;
  padding: 16px 20px;
  border-inline-start: 3px solid var(--wp--preset--color--gold-500);
  background: rgba(255, 255, 255, 0.03);
  border-radius: 8px;
}
.st-ftr__editorial p { margin: 0; font-size: 13px; line-height: 1.6; color: #a8bacb; }
.st-ftr__editorial strong { color: #fff; }
.st-ftr__editorial-links { margin-top: 8px !important; }
.st-ftr__editorial-links a { color: var(--wp--preset--color--gold-400); text-decoration: none; }
.st-ftr__editorial-links a:hover { text-decoration: underline; }

@media (max-width: 1000px) {
  .st-ftr__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 700px) {
  .st-ftr__grid { grid-template-columns: 1fr; }
  .st-ftr { padding: 48px 0 28px; margin-top: 56px; }
}

/* The old thin boundary strip is replaced by the chrome above. */
.st-boundary { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   ARCHIVES — category, guest and tag pages
   Replaces a layout in which the first item's featured image rendered at the
   full 1200px content width (a YouTube thumbnail filling an entire viewport,
   headline pushed below the fold) and every other item was a bare title beside
   a 60px date column. One image, no density, no context, no route to product.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 8px, not 40px: the masthead already contributes a 48px bottom margin and a
   3px rule, so 40px on top of that left roughly 100px of dead space between the
   rule and the section title — the same compounding-margin problem that put 528px
   of it on the front page. */
.st-arch { padding-block: 8px 72px; }

/* ── section header ──────────────────────────────────────────────────────── */
.st-arch__head {
  padding-bottom: 20px;
  margin-bottom: 40px;
  border-bottom: 3px solid var(--wp--preset--color--ink);
}
.st-arch__eyebrow {
  margin: 0 0 10px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--wp--preset--color--gold-700);
}
/* The page's own H1. Named separately from the card titles: sharing one class
   made the header indistinguishable from an article in any selector or count,
   which is exactly how a verification count silently read zero. */
.st-arch__heading {
  margin: 0;
  font-size: clamp(32px, 4.2vw, 52px);
  font-weight: 800;
  letter-spacing: -0.038em;
  line-height: 1.02;
}
.st-arch__strap {
  margin: 12px 0 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--wp--preset--color--silver-600);
  max-width: 62ch;
}
.st-arch__count {
  margin: 14px 0 0;
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--wp--preset--color--silver-500);
  font-variant-numeric: tabular-nums;
}

/* ── the grid ────────────────────────────────────────────────────────────── */
.st-arch__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* Row gap larger than column gap: cards read as rows, and equal gaps make a
     grid look like a spreadsheet. */
  gap: 44px 28px;
}
.st-arch__list > .wp-block-post { display: flex; flex-direction: column; min-width: 0; }

.st-arch__media { margin: 0 0 14px; }
.st-arch__media img {
  width: 100%;
  height: auto;
  border-radius: var(--wp--custom--radius--md);
}
.st-arch__kicker {
  margin: 0 0 8px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.13em;
  color: var(--wp--preset--color--gold-700);
}
.st-arch__kicker a { color: inherit; text-decoration: none; }
.st-arch__kicker a:hover { text-decoration: underline; }
.st-arch__title-card { margin: 0; }
.st-arch__list .st-arch__title {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.017em;
  line-height: 1.26;
  margin: 0 0 8px;
}
.st-arch__list .st-arch__title a { color: var(--wp--preset--color--ink); text-decoration: none; }
.st-arch__list .st-arch__title a:hover { color: var(--wp--preset--color--blue-600); }
.st-arch__when {
  margin: auto 0 0;
  padding-top: 10px;
  font-size: 12.5px;
  color: var(--wp--preset--color--silver-500);
  font-variant-numeric: tabular-nums;
}
/* The standfirst is suppressed on cards and shown only on the hero: at card
   width it is three lines of grey that push the date out of alignment across
   the row and add nothing a headline has not already said. */
.st-arch__list .st-arch__standfirst { display: none; }

/* ── the hero ────────────────────────────────────────────────────────────── */
.st-arch__list > .wp-block-post:first-child {
  grid-column: 1 / -1;
  display: grid;
  /* Image slightly wider than the text, which is the newsroom convention and
     keeps a 16:9 crop from looking letterboxed beside a short headline. */
  grid-template-columns: 1.15fr 1fr;
  gap: 40px;
  align-items: center;
  padding-bottom: 44px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--wp--preset--color--silver-200);
}
.st-arch__list > .wp-block-post:first-child .st-arch__media { margin: 0; }
.st-arch__list > .wp-block-post:first-child .st-arch__title {
  font-size: clamp(26px, 2.6vw, 34px);
  letter-spacing: -0.032em;
  line-height: 1.1;
  margin-bottom: 14px;
}
.st-arch__list > .wp-block-post:first-child .st-arch__standfirst {
  display: block;
  margin: 0 0 14px;
  font-size: 17px;
  line-height: 1.55;
  color: var(--wp--preset--color--text);
  max-width: 46ch;
}
.st-arch__list > .wp-block-post:first-child .st-arch__when { margin: 0; padding: 0; }

/* ── conversion band ─────────────────────────────────────────────────────── */
.st-cta {
  grid-column: 1 / -1;
  margin-block: 56px 8px;
  padding: 36px 40px;
  border-radius: var(--wp--custom--radius--md);
  background: linear-gradient(170deg, var(--wp--preset--color--navy-900), #061727 60%);
  color: var(--wp--preset--color--silver-200);
}
.st-cta__kicker {
  margin: 0 0 10px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--wp--preset--color--gold-400);
}
.st-cta__head {
  margin: 0 0 10px;
  font-size: clamp(24px, 2.4vw, 30px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.12;
  color: #fff;
}
.st-cta__body { margin: 0 0 22px; font-size: 16px; line-height: 1.55; max-width: 58ch; }
.st-cta__actions { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; margin: 0; }
.st-cta__link { color: var(--wp--preset--color--gold-400); font-size: 14px; font-weight: 700; text-decoration: none; }
.st-cta__link:hover { text-decoration: underline; }
/* Never display:none — the qualifier has to travel with the offer. */
.st-cta__fine { margin: 18px 0 0; font-size: 12px; color: #6d8296; }

.st-pagination { padding-top: 40px; }

/* ── responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 1000px) {
  .st-arch__list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 24px; }
  .st-arch__list > .wp-block-post:first-child { grid-template-columns: 1fr; gap: 20px; align-items: start; }
  .st-arch__list > .wp-block-post:first-child .st-arch__standfirst { max-width: none; }
}
@media (max-width: 620px) {
  .st-arch { padding-block: 28px 48px; }
  .st-arch__list { grid-template-columns: 1fr; gap: 32px; }
  .st-arch__head { margin-bottom: 28px; }
  /* On one column a hero and a card differ only by an excerpt, so the divider
     under the hero is the only thing telling a reader it was the lead. */
  .st-arch__list > .wp-block-post:first-child { padding-bottom: 32px; }
  .st-cta { padding: 26px 22px; margin-block: 40px 4px; }
  .st-cta__actions { gap: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE ARTICLE RAIL
   Measured before this: article 4299px, rail column 4283px, 505px of content.
   88% empty, and what was there scrolled away after the first screen.
   ═══════════════════════════════════════════════════════════════════════════ */

.st-rail__sticky {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* ── newsletter ──────────────────────────────────────────────────────────── */
.st-news {
  padding: 24px;
  border-radius: var(--wp--custom--radius--md);
  background: var(--wp--preset--color--silver-50);
  border: 1px solid var(--wp--preset--color--silver-100);
}
.st-news__kicker {
  margin: 0 0 8px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--wp--preset--color--gold-700);
}
.st-news__head { margin: 0 0 8px; font-size: 20px; font-weight: 800; letter-spacing: -0.022em; line-height: 1.18; }
.st-news__body { margin: 0 0 16px; font-size: 14px; line-height: 1.55; color: var(--wp--preset--color--silver-600); }
.st-news__fine { margin: 12px 0 0; font-size: 11.5px; color: var(--wp--preset--color--silver-500); }
/* MailerLite injects its own form chrome; keep it inside our box. */
.st-news .ml-embedded { max-width: 100%; }
.st-news .ml-embedded form { margin: 0; }
.st-news--compact { padding: 20px; }
.st-news--compact .st-news__head { font-size: 17px; }
.st-news--compact .st-news__body { font-size: 13px; margin-bottom: 12px; }

/* ── most read ───────────────────────────────────────────────────────────── */
.st-pop {
  padding: 20px;
  border-radius: var(--wp--custom--radius--md);
  border: 1px solid var(--wp--preset--color--silver-100);
}
.st-pop__list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 14px; counter-reset: none; }
.st-pop__item { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px; align-items: start; }
.st-pop__rank {
  font-size: 15px; font-weight: 800; line-height: 1.3;
  color: var(--wp--preset--color--gold-500);
  font-variant-numeric: tabular-nums;
}
.st-pop__link {
  font-size: 14.5px; font-weight: 700; line-height: 1.32;
  color: var(--wp--preset--color--ink); text-decoration: none;
}
.st-pop__link:hover { color: var(--wp--preset--color--blue-600); }

/* ── the product band, in rail form ──────────────────────────────────────── */
.st-rail .st-cta {
  margin: 0;
  padding: 22px;
  grid-column: auto;
}
.st-rail .st-cta__head { font-size: 19px; }
.st-rail .st-cta__body { font-size: 14px; margin-bottom: 16px; }
.st-rail .st-cta__actions { gap: 14px; }
.st-rail .st-cta__fine { margin-top: 14px; font-size: 11.5px; }

@media (max-width: 900px) {
  /* Below the article on a phone, so it must not be sticky or it pins to the
     bottom of a viewport the reader is trying to scroll past. */
  .st-rail__sticky { position: static; gap: 20px; }
}

.st-rail .st-cta { margin-top: 24px; }

/* ── on sticking, and why there is no scrollbar here ─────────────────────────
   A sticky element taller than the viewport strands its lower half out of
   reach. The first fix for that was `max-height` plus `overflow-y: auto`, which
   traded the problem for a visible scrollbar inside the rail — worse, because
   it looks like a defect on every article rather than only on short viewports.

   Instead the rail simply does not stick unless there is room for it. Below
   860px of viewport height it scrolls with the page, which is the correct
   behaviour for a column that does not fit. Above it, it sticks and everything
   in it stays reachable. */
.st-rail__sticky { position: static; }

@media (min-height: 860px) {
  .st-rail__sticky {
    position: sticky;
    top: 98px;
  }
}
@media (max-width: 900px) {
  .st-rail__sticky { position: static; }
}

/* The sticky track. `.st-rail` is a grid item stretched to the article's height,
   so a track with flex:1 fills everything the product band does not — giving the
   sticky group a bottom edge to stop at instead of sliding over the band. */
.st-rail__track { flex: 1 1 auto; min-height: 0; }

/* ── MailerLite's injected form ───────────────────────────────────────────────
   The embed brings its OWN 20px padding inside the module's 24px, so the form
   had 258px of a 340px rail to fit an email field and a Subscribe button side by
   side — which is why it read as clipped. Its padding is removed (the module
   already provides the inset), the row is allowed to wrap, and the field is
   given min-width:0 so it can actually shrink instead of forcing the button out.

   `!important` throughout, reluctantly: these rules are fighting a stylesheet
   MailerLite injects at runtime, so specificity alone cannot win reliably. */
.st-news .ml-embedded,
.st-news .ml-form-embedContainer,
.st-news .ml-form-align-center,
.st-news .ml-form-embedWrapper {
  width: 100% !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
  background: transparent !important;
  border: 0 !important;
}
.st-news .ml-form-embedBody,
.st-news .ml-form-embedContent,
.st-news .ml-form-formContent {
  padding: 0 !important;
  margin: 0 !important;
}
/* The field row: wrap rather than overflow. */
.st-news .ml-form-fieldRow,
.st-news .ml-form-horizontalRow {
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 8px !important;
  width: 100% !important;
  margin: 0 !important;
}
.st-news .ml-form-fieldRow input,
.st-news .ml-form-embedBody input[type="email"],
.st-news .ml-form-embedBody input[type="text"] {
  flex: 1 1 140px !important;
  /* min-width:0 is the load-bearing part — a flex item defaults to min-content
     width, which is what pushed the button past the edge. */
  min-width: 0 !important;
  width: auto !important;
  box-sizing: border-box !important;
}
.st-news .ml-form-embedSubmit,
.st-news .ml-form-embedSubmitLoad {
  flex: 0 0 auto !important;
  margin: 0 !important;
  width: auto !important;
}
.st-news .ml-form-embedSubmit button {
  width: auto !important;
  white-space: nowrap !important;
}
/* Their success/error messages inherit the module's type rather than theirs. */
.st-news .ml-form-successBody,
.st-news .ml-form-embedBody p {
  font-size: 13px !important;
  color: var(--wp--preset--color--silver-600) !important;
}

/* ── the disclosure band ──────────────────────────────────────────────────────
   The band was `constrained` with no contentSize, so it inherited theme.json's
   global 720px while every other surface had moved to 1460. The grey stripe ran
   full width but the text sat in a narrow centred column, out of line with the
   footer directly beneath it and with the masthead above.
   Now it shares the page container, so its left edge lines up with everything
   else. The paragraphs are still capped: 13px type across 1460px is about 180
   characters a line, and a disclosure nobody can read is a compliance problem
   rather than a design one. Left-aligned to the container rather than centred,
   which is what makes it read as part of the page. */
/* Aligned to the page, and using the band rather than floating in it.
   Two problems here, measured: the children sat at x=289 while every other
   element on the page starts at x=20, and they were 918px inside a 1460
   container — so the block neither lined up nor filled the space.
   The centring was WordPress's constrained layout, whose
   `:where(.wp-block-group) > :not(.alignleft)...` auto margins out-specify a
   plain `margin-inline: 0`. Hence the explicit selector below.
   The width is used with COLUMNS instead of one long measure: 13px type across
   1460px is about 220 characters a line, and a disclosure nobody can read is a
   compliance problem. Two columns fill the band at ~700px each. */
/* ── the disclosure appears in TWO places ────────────────────────────────────
   As a full-width band before the footer on index pages, and INSIDE the article
   column on a post. The rules below are written for the band, and applying them
   to the nested one made it worse than what it replaced: it lost its inset
   entirely (padding 0) and ran two columns of 13px type in a 908px box.

   So the nested instance is put back to being a plain inset panel — one column,
   its own padding, aligned to the article. It is a callout inside a story, not a
   page-wide legal band, and it should not pretend otherwise. */
.st-article .st-disclosure {
  padding-inline: 24px !important;
}
/* Inside a story the band is a callout, not a page-wide legal strip: it already
   sits within the article column, so the inner wrapper must not inset it a
   second time, and one column of ~800px needs no splitting. */
.st-article .st-disclosure__inner {
  width: 100%;
  padding-block: 18px 20px;
}
.st-article .st-disclosure__cols {
  grid-template-columns: 1fr;
  gap: 12px;
}
.st-article .st-disclosure > :where(p, .is-style-eyebrow),
.st-article .wp-block-group.st-disclosure > p {
  width: auto;
  max-width: none;
  margin-inline: 0 !important;
  columns: 1;
}

/* The same container formula the chrome and the index surfaces use, so the left
   edge lands on exactly the same pixel rather than 4px off it — the block's own
   16px padding did not match the page's 20px gutter. */
.st-disclosure {
  padding-inline: 0 !important;
}

/* The band bleeds; its contents do not. Same container formula as the chrome and
   the index surfaces, so the left edge lands on the same pixel rather than 4px
   off it. The block padding is the other half of the old defect: with none, the
   text sat flush against the band's own top and bottom rules. */
.st-disclosure__inner {
  width: min(calc(100% - 40px), 1460px);
  margin-inline: auto;
  padding-block: 22px 24px;
}

/* One paragraph per column — NOT `columns: 2`, which tore a single sentence
   across the gutter and left the right-hand side half empty. See the note in
   inc/disclosure.php. */
.st-disclosure__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 56px;
  align-items: start;
}
.st-disclosure__cols > p { margin: 0; }
.st-disclosure .is-style-eyebrow { margin: 0 0 10px; }

@media (max-width: 1000px) {
  /* Two 13px columns in less than 1000px are too narrow to read comfortably. */
  .st-disclosure__cols { grid-template-columns: 1fr; gap: 12px; }
}

/* ── the price pages ─────────────────────────────────────────────────────────
   Before: a full-bleed quote row holding four FIXED 300px widgets (260px of dead
   gaps), a chart, then an 820px prose column with 630px of nothing beside it and
   the newsletter panel stretched across the full width with its content in the
   left third. The audit flagged the row as an ORPHAN at every width from 744px up.

   After: the widgets get the full width, because a chart is the one thing on this
   page that genuinely wants it; the prose gets a rail, the same as an article. */
.st-price__head { margin-block: 8px 20px; }
.st-price__title {
  margin: 0;
  font-size: clamp(30px, 3.4vw, 42px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
}
.st-price__kicker {
  margin: 8px 0 0;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
}

/* The quote strip. `1fr` per card, so the widgets stretch instead of sitting at a
   fixed 300px — that fixed width, four times, is what left the row marooned. */
.st-quotes {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-block: 0 20px;
}
.st-quote {
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md, 10px);
  background: var(--wp--preset--color--white);
  padding: 14px 16px 6px;
  min-width: 0;
}
/* The page you are on, marked. Without it the strip is four identical cards and
   the reader has to check the URL to know where they are. */
.st-quote--current {
  border-color: var(--wp--preset--color--gold-500);
  box-shadow: inset 0 0 0 1px var(--wp--preset--color--gold-500);
}
.st-quote__link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  text-decoration: none;
  min-height: 32px;
}
.st-quote__metal {
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--wp--preset--color--ink);
}
.st-quote__unit {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
}
.st-quote__widget { min-height: 58px; }
/* TradingView injects its own wrappers; they must not impose a width. */
.st-quote__widget .tradingview-widget-container,
.st-quote__widget iframe { width: 100% !important; max-width: 100% !important; }

.st-chart {
  margin-block: 0 40px;
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md, 10px);
  overflow: hidden;
}
.st-chart iframe { display: block; width: 100% !important; }

/* Prose plus rail, mirroring the article layout so the two page types feel like
   the same site rather than two projects. */
.st-price__grid {
  display: grid;
  grid-template-columns: minmax(0, 820px) 400px;
  justify-content: center;
  gap: 64px;
  padding-block: 0 56px;
}
.st-price__grid > .st-price__body,
.st-price__grid > .st-rail { max-width: none; }
.st-price__body .wp-block-post-content > :where(p, ul, ol, blockquote, h2, h3, h4, h5, figure, .wp-block-image, .wp-block-embed, table) {
  max-width: none;
  margin-inline: 0 !important;
}
.st-price__body .wp-block-post-content img { max-width: 100%; height: auto; }
/* The inline newsletter is removed from these pages' content — it lives in the
   rail now — but if an editor pastes one back, keep it inside the column. */
.st-price__body .st-news { max-width: none; margin-inline: 0 !important; }

.st-metals__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.st-metals__list a {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding-inline: 2px;
  font-size: 15px;
  font-weight: 700;
  color: var(--wp--preset--color--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--wp--preset--color--silver-200);
}
.st-metals__list li:last-child a { border-bottom: 0; }
.st-metals__list a:hover { color: var(--wp--preset--color--gold-700); }

@media (max-width: 1100px) {
  .st-price__grid { grid-template-columns: minmax(0, 1fr) 300px; gap: 40px; }
}
@media (max-width: 900px) {
  /* The rail drops below the prose; a 300px sidebar beside a 400px article is
     two columns of equal weight, which is not the hierarchy. */
  .st-price__grid { grid-template-columns: 1fr; gap: 40px; }
  .st-quotes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
  .st-quotes { grid-template-columns: 1fr; gap: 12px; }
}

/* ── the newsletter, where the header CTA lands ───────────────────────
   "Get the newsletter" sits in the header of every page and points at
   #st-newsletter. That anchor used to land on the compact rail card at the bottom
   of the footer, so the reward for clicking a call to action was the smallest
   version of the thing you asked for, in the darkest part of the page.

   The feature variant inverts the emphasis: light band against the dark footer so
   it reads as a panel rather than a footer row, two columns so the copy and the
   field are side by side instead of stacked, and type at a size that matches the
   intent of the click. */
.st-news--feature {
  background: var(--wp--preset--color--white);
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--lg, 14px);
  padding: 0;
  box-shadow: 0 18px 44px rgba(4, 16, 30, 0.16);
}
.st-news--feature .st-news__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 40px;
  align-items: center;
  padding: 34px 36px;
}
.st-news--feature .st-news__kicker {
  color: var(--wp--preset--color--gold-700);
  margin-bottom: 10px;
}
.st-news--feature .st-news__head {
  font-size: clamp(24px, 2.4vw, 31px);
  line-height: 1.1;
  letter-spacing: -0.028em;
  color: var(--wp--preset--color--ink);
  margin-bottom: 10px;
}
.st-news--feature .st-news__body {
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--wp--preset--color--text);
  margin-bottom: 16px;
}

/* What actually arrives. The commonest reason a reader does not hand over an
   address is not knowing what comes back. */
.st-news__points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 7px;
}
.st-news__points li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 14px;
  line-height: 1.4;
  color: var(--wp--preset--color--text);
}
.st-news__tick {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--wp--preset--color--success);
}

/* the field, and the MailerLite specificity wall
   ---------------------------------------------------------------------------
   MailerLite's embed script injects its own <style> into the page at run time,
   and every rule in it is written as

     #mlb2-34100947.ml-form-embedContainer .ml-form-embedWrapper
       .ml-form-embedBody .ml-form-horizontalRow button { ... !important }

   which is (1 id, 4 classes, 1 element) AND !important AND later in document
   order than our stylesheet. No number of classes outranks an ID, so the first
   attempt at this, `.st-news--feature ... button { background: gold !important }`
   at (0,2,1), lost silently and the button stayed MailerLite blue.

   The way through is an ID we own: #st-newsletter is the anchor the header CTA
   already points at, and it is an ANCESTOR of the embed. Leading with it and
   naming enough of the chain puts these at (1,6,1), which beats their (1,4,1)
   on specificity so source order never comes into it. Hardcoding their numeric
   form id would also have worked, and would have broken the day the form is
   rebuilt.

   Worth counting carefully rather than eyeballing: the first attempt at this was
   `#st-newsletter .st-news--feature .ml-form-embedWrapper .ml-form-embedBody
   button`, which LOOKS more specific but is (1,4,1) — an exact tie — so their
   later-injected <style> still won, and the button stayed blue while every other
   declaration in the same rule (height, padding, radius) applied. A rule that
   half-applies is the tell for a specificity tie. */
.st-news--feature .st-news__form { min-width: 0; }

#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedBody input[type="email"],
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedBody .form-control {
  box-sizing: border-box !important;
  width: 100% !important;
  min-height: 54px !important;
  height: 54px !important;
  font-size: 16px !important;
  padding: 0 16px !important;
  border-radius: var(--wp--custom--radius--sm, 8px) !important;
  border: 1px solid var(--wp--preset--color--silver-300) !important;
  background: #fff !important;
  color: var(--wp--preset--color--ink) !important;
}

/* Their horizontal row is a floated arrangement sized for a narrow sidebar.
   Given a real column it should simply be a flex row: field takes the space,
   button takes its label. */
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-horizontalRow {
  display: flex !important;
  align-items: stretch !important;
  gap: 10px !important;
  float: none !important;
  width: 100% !important;
}
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-input-horizontal,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .horizontal-fields,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-field-group {
  float: none !important;
  width: auto !important;
  flex: 1 1 auto !important;
  min-width: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
}
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-button-horizontal {
  float: none !important;
  width: auto !important;
  flex: 0 0 auto !important;
  padding: 0 !important;
  margin: 0 !important;
}

#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedBody button,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-horizontalRow button,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedSubmit button {
  box-sizing: border-box !important;
  width: auto !important;
  min-height: 54px !important;
  height: 54px !important;
  padding: 0 26px !important;
  margin: 0 !important;
  white-space: nowrap !important;
  font-size: 15.5px !important;
  font-weight: 800 !important;
  letter-spacing: 0.01em !important;
  border-radius: var(--wp--custom--radius--sm, 8px) !important;
  /* Gold, not their default blue: this is the one conversion on the page and it
     should read as the same brand action as the header button it came from. */
  background-color: var(--wp--preset--color--gold-500) !important;
  color: var(--wp--preset--color--ink) !important;
  border: 0 !important;
  cursor: pointer !important;
}
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedBody button:hover,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-horizontalRow button:hover,
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedSubmit button:hover {
  background-color: var(--wp--preset--color--gold-400) !important;
}

/* Their wrapper carries its own card chrome, border, padding and centring, which
   double-frames ours. */
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper,
#st-newsletter .st-news--feature .ml-form-embedContainer,
#st-newsletter .st-news--feature .ml-form-align-center {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
  text-align: start !important;
  max-width: none !important;
  width: 100% !important;
}
#st-newsletter .st-news--feature .st-news__form .ml-embedded .ml-form-embedWrapper .ml-form-embedBody {
  padding: 0 !important;
  margin: 0 !important;
}

/* Mobile: their script swaps in a separate stacked button element below ~500px.
   Match it to the desktop one rather than leaving one blue button behind. */
#st-newsletter .st-news--feature .ml-mobileButton-horizontal button {
  width: 100% !important;
  min-height: 54px !important;
  border-radius: var(--wp--custom--radius--sm, 8px) !important;
  background-color: var(--wp--preset--color--gold-500) !important;
  color: var(--wp--preset--color--ink) !important;
  font-weight: 800 !important;
  border: 0 !important;
}
.st-news--feature .st-news__fine {
  margin-top: 10px;
  font-size: 11.5px;
  color: var(--wp--preset--color--silver-600);
}

/* Arriving via the anchor should feel like an arrival. A ring that fades once,
   rather than a permanent highlight, so a reader who scrolled here on their own
   is not shouted at. `:target` means it costs no JavaScript. */
#st-newsletter { scroll-margin-top: 96px; }
#st-newsletter:focus { outline: none; }
#st-newsletter:target .st-news--feature {
  animation: st-news-land 2.4s ease-out 1;
}
@keyframes st-news-land {
  0%, 18%   { box-shadow: 0 0 0 4px var(--wp--preset--color--gold-500), 0 18px 44px rgba(4, 16, 30, 0.16); }
  100%      { box-shadow: 0 0 0 0 rgba(217, 164, 49, 0), 0 18px 44px rgba(4, 16, 30, 0.16); }
}
@media (prefers-reduced-motion: reduce) {
  /* Still mark it, just without the movement. */
  #st-newsletter:target .st-news--feature {
    animation: none;
    box-shadow: 0 0 0 3px var(--wp--preset--color--gold-500), 0 18px 44px rgba(4, 16, 30, 0.16);
  }
}

@media (max-width: 860px) {
  .st-news--feature .st-news__inner {
    grid-template-columns: 1fr;
    gap: 22px;
    padding: 26px 22px;
  }
}

/* ── form controls must not be wider than the screen ─────────────────────────
   Measured by scripts/layout-audit.mjs: /contact-us/ overflowed by exactly 14px
   at 320, 390, 430 and 744px. The inputs were `box-sizing: content-box` with a
   fixed `width: 350px`, so their real width was 350 + 32 padding + 2 border =
   384px, starting at the 20px gutter — 404px inside a 390px viewport.

   content-box on a form control is almost always a bug rather than a decision:
   it means every padding change silently changes the element's outer width. */
.st-page input:not([type="checkbox"]):not([type="radio"]),
.st-page textarea,
.st-page select,
.st-article input:not([type="checkbox"]):not([type="radio"]),
.st-article textarea {
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
}

/* ── tap targets ─────────────────────────────────────────────────────────────
   WCAG 2.2 asks for 24x24 CSS pixels on anything you have to hit. The audit
   found pagination numbers at 11x21 — a single digit with no padding, which on a
   phone is a coin toss — and the header and footer wordmark links at 21-22px
   tall because the anchor shrink-wrapped the logo image.

   Inline links inside a paragraph are exempt from the rule and are left alone. */
.st-pagination a,
.st-pagination span {
  min-width: 40px;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: 6px;
}
.st-hdr__brand,
.st-ftr__brandlink {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
/* The quote-strip links sit under a fixed-height widget, so they get padding
   rather than a min-height that would push the widget around. */
.st-quotes__link {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding-block: 6px;
}
/* Footer link rows were 23px — one pixel under, which is the most annoying kind
   of failure to find by hand. */
.st-ftr__col a {
  padding-block: 3px;
}
/* The category kicker above an article headline is a real link at 15px tall. */
.st-eyebrow a,
.taxonomy-category a,
.st-arch__kicker a,
.st-card__kicker a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

/* The byline's author link and date were 15-17px tall: real links, in a meta row
   rather than a sentence, so the prose exemption does not apply to them. Padded
   rather than given a min-height, which would space the byline row out. */
.st-byline a,
.st-byline__author a,
.st-byline__author {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

/* ── About: lead paragraph and the leadership section ────────────────────────
   Two people, side by side, each a named heading with a role above the bio. The
   role is a separate line rather than part of the heading so the document outline
   stays clean — a screen reader hears "Dr. Tyler Wall" as the heading, not
   "Dr. Tyler Wall, Co-founder". */
.st-page__lead {
  font-size: var(--wp--preset--font-size--lead, 21px);
  line-height: 1.5;
  color: var(--wp--preset--color--ink);
  margin-block: 0 32px !important;
}
.st-people {
  display: grid;
  align-items: start;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
  margin-block: 24px 8px;
  max-width: none !important;
}
/* WordPress's flow layout adds `margin-block-start` to every child except the
   first, which in a two-column grid drops the SECOND card 16px below the first
   for no reason a reader could interpret. */
.st-people > * { margin-block-start: 0 !important; }
.st-person {
  padding: 28px 30px;
  background: var(--wp--preset--color--silver-50);
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md, 10px);
}
.st-person__name {
  margin: 0 0 2px !important;
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -0.015em;
}
.st-person__role {
  margin: 0 0 14px !important;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wp--preset--color--gold-700);
}
.st-person p:not(.st-person__role) {
  font-size: 15.5px;
  line-height: 1.65;
  margin-block: 0 12px;
}
.st-person p:last-child { margin-bottom: 0; }

@media (max-width: 820px) {
  .st-people { grid-template-columns: 1fr; gap: 24px; }
}

/* ── the author archive: a card grid, not a stack of rows ────────────────────
   The category and tag archives use a wide image-left row per item, which suits
   a section front where each story is being sold individually. An author archive
   is a different job: it answers "what else has this person written", so the
   reader is scanning, not browsing — and at one row per screen, 457 articles is
   an unusable amount of scrolling.

   Three across, image on top, matching the design this site had before the
   rebuild. Kept from the new design: the author bio above the grid, which the
   old page did not have at all and which is the one thing on the page that
   establishes why this byline is worth reading. */
.st-arch--cards .st-cardgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 48px 32px;
  margin-block: 8px 48px;
  /* The post-template emits media and body as SIBLINGS per post rather than
     wrapping each pair, so the grid is fed a flat list: media, body, media,
     body. `grid-auto-flow: row dense` would interleave them wrongly — instead
     each card is a subgrid of two rows so a pair stays together. */
  grid-auto-rows: min-content;
}
.st-arch--cards .st-card__media {
  margin: 0;
  grid-row: span 1;
}
.st-arch--cards .st-card__media img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center 30%;
  border-radius: var(--wp--custom--radius--md, 10px);
  display: block;
}
.st-arch--cards .st-card__body { margin-block: 12px 0; }
.st-arch--cards .st-card__kicker {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wp--preset--color--gold-700);
}
.st-arch--cards .st-card__kicker a {
  color: inherit;
  text-decoration: none;
}
.st-arch--cards .st-card__title {
  margin: 0 0 8px;
  font-size: 19px;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.015em;
}
.st-arch--cards .st-card__title a {
  color: var(--wp--preset--color--ink);
  text-decoration: none;
}
.st-arch--cards .st-card__title a:hover { color: var(--wp--preset--color--gold-700); }
.st-arch--cards .st-card__standfirst {
  margin: 0 0 10px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--wp--preset--color--text);
}
.st-arch--cards .st-card__meta {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
  display: flex;
  gap: 8px;
  align-items: baseline;
}

@media (max-width: 1000px) {
  .st-arch--cards .st-cardgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 24px; }
}
@media (max-width: 640px) {
  .st-arch--cards .st-cardgrid { grid-template-columns: 1fr; gap: 32px; }
}

/* ── "Read next" ─────────────────────────────────────────────────────────────
   Sits between the article body and the disclosure. Four cards, thumbnails
   lazy — everything here is below the fold by definition, so none of it can
   affect LCP. */
.st-next { margin-block: 56px 0; padding-top: 40px; border-top: 3px solid var(--wp--preset--color--ink); }
.st-next__head {
  margin: 0 0 24px;
  font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.13em;
  color: var(--wp--preset--color--ink);
}
.st-next__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px;
}
.st-next__link { display: flex; flex-direction: column; text-decoration: none; height: 100%; }
.st-next__img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; object-position: center 30%; border-radius: var(--wp--custom--radius--sm); }
.st-next__body { display: flex; flex-direction: column; flex: 1; padding-top: 12px; }
.st-next__kicker {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.13em;
  color: var(--wp--preset--color--gold-700); margin-bottom: 6px;
}
.st-next__title {
  font-size: 16px; font-weight: 700; line-height: 1.28; letter-spacing: -0.014em;
  color: var(--wp--preset--color--ink);
}
.st-next__link:hover .st-next__title { color: var(--wp--preset--color--blue-600); }
.st-next__date { margin-top: auto; padding-top: 8px; font-size: 12.5px; color: var(--wp--preset--color--silver-500); }

@media (max-width: 900px) { .st-next__list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; } }
@media (max-width: 520px) { .st-next__list { grid-template-columns: 1fr; } }

/* ── the masthead nav sits on the wordmark's baseline ────────────────────────
   Now that the kicker is on its own row, this line holds only the wordmark and
   the nav — so `baseline` aligns the nav's text to the wordmark's text, which is
   what a nav beside a masthead wants. It also scales with the wordmark's
   clamp() automatically, where a px nudge would have needed a media query per
   breakpoint.
   Two earlier attempts and why they could not work: `center` centred the nav
   against the kicker+wordmark stack, 14px out; `flex-end` aligned the BOXES,
   leaving the glyphs 29px apart because the nav's line box centres its text and
   the wordmark's line-height:1 lets its ink spill below the box. */
.st-masthead__row {
  align-items: baseline !important;
  gap: 24px;
}

/* ── follow, and share ──────────────────────────────────────────────────────
   Two components, one icon set. See inc/social.php for why follow and share are
   answered differently: a follow icon sends the READER away, a share button
   sends the PAGE away, so the first is rationed and the second sits at the end
   of the article where finishing is the trigger. */

/* Every icon inherits its colour from the control around it, so the brand marks
   and the stroked utility glyphs need no per-icon colour rules. */
.st-ico { display: block; width: var(--st-ico, 20px); height: var(--st-ico, 20px); }

.st-social__row { display: flex; align-items: center; gap: 8px; }
.st-social__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* The glyph is 18-20px, so the BOX is padded out to 36px to clear the WCAG 2.2
     target-size minimum. A 20px tap target on a phone is a miss half the time. */
  width: 36px;
  height: 36px;
  border-radius: 999px;
  color: var(--wp--preset--color--silver-600);
  transition: color 0.15s ease, background-color 0.15s ease;
}
.st-social__link:hover,
.st-social__link:focus-visible {
  color: var(--wp--preset--color--ink);
  background: var(--wp--preset--color--silver-100);
}
.st-social__link:focus-visible {
  outline: 2px solid var(--wp--preset--color--gold-500);
  outline-offset: 1px;
}

/* Masthead pair. Deliberately NOT brand-coloured on hover: a red YouTube glyph
   and a black X glyph beside a gold kicker reads as a widget bolted on, which
   is the opposite of what a masthead is for. */
.st-masthead__top {
  /* !important for the same reason .st-masthead__row needs it below — WordPress
     prints its flex-layout rules for the group AFTER this stylesheet, at equal
     specificity, so the later rule would otherwise win. */
  align-items: center !important;
  gap: 16px;
  margin-bottom: 8px;
}
.st-masthead__top .st-masthead__kicker { margin-bottom: 0; }
.st-social--masthead { --st-ico: 18px; }
/* The padded box is what breaks alignment, so it is unpicked in both axes:
   -8px vertically so the 36px targets do not deepen what is a 20px kicker line,
   and -9px on the right so the last GLYPH — not its invisible box — lines up
   with the nav's right edge on the row below. Measured: the glyph sat 9px
   inside, which is exactly half the 36px box minus the 18px icon. */
.st-social--masthead .st-social__row { margin-block: -8px; margin-right: -9px; }

/* The footer follow row, on navy. Colours match .st-ftr__col a rather than the
   light-mode tokens above, which do not have the contrast for this background.

   Nothing here is per-network, and that is on purpose (see the masthead note
   above): every glyph inherits `currentColor`, so adding an account to
   st_social_accounts() needs no CSS at all. Facebook was added in August 2026
   and this block did not change. */
.st-social--footer { margin-top: 22px; }
.st-social__head {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #dbe6f1;
}
.st-social--footer .st-social__link { color: #8fa2b5; }
.st-social--footer .st-social__link:hover,
.st-social--footer .st-social__link:focus-visible {
  color: #fff;
  background: rgba(255, 255, 255, 0.09);
}
.st-social--footer .st-social__link:focus-visible {
  outline-color: var(--wp--preset--color--gold-400);
}

/* ── the share row ───────────────────────────────────────────────────────── */
.st-share {
  margin: 44px 0 0;
  padding-top: 22px;
  border-top: 1px solid var(--wp--preset--color--silver-200);
}
.st-share__head {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
}
.st-share__row { display: flex; flex-wrap: wrap; gap: 10px; }
.st-share__btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 0 15px;
  border: 1px solid var(--wp--preset--color--silver-300);
  border-radius: 999px;
  background: var(--wp--preset--color--white);
  color: var(--wp--preset--color--ink);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
/* Load-bearing. `.st-share__btn { display: inline-flex }` and the UA sheet's
   `[hidden] { display: none }` are BOTH one class/attribute deep, and the author
   sheet wins — so without this the two progressive-enhancement buttons would
   render for everyone, including the browsers whose missing APIs are the whole
   reason they ship hidden. */
.st-share__btn[hidden] { display: none; }
.st-share__btn:hover {
  border-color: var(--wp--preset--color--ink);
  background: var(--wp--preset--color--silver-50);
}
.st-share__btn:focus-visible {
  outline: 2px solid var(--wp--preset--color--gold-500);
  outline-offset: 2px;
}
.st-share__btn .st-ico { --st-ico: 17px; }
/* The X button is icon-only (see inc/social.php), so it would otherwise be a
   short pill with a lopsided 15px of padding on each side of a 17px glyph. */
.st-share__btn--x { padding-inline: 18px; }
.st-share__btn[data-copied] {
  border-color: var(--wp--preset--color--success);
  color: var(--wp--preset--color--success);
}

/* Desktop hides the native button even where the API exists (Safari and Edge
   both have it) — a fifth button that opens an OS sheet next to four explicit
   targets is noise. */
@media (min-width: 901px) {
  .st-share__btn--native { display: none; }
}

/* Phones get the sheet INSTEAD of the row: it lists WhatsApp, Signal, Messages
   and whatever else this reader has, which a fixed row cannot. Gated on
   data-native, set by script only after confirming navigator.share exists, so a
   phone without it keeps the working anchors. */
@media (max-width: 900px) {
  .st-share[data-native="true"] .st-share__btn:not(.st-share__btn--native) { display: none; }
  .st-share[data-native="true"] .st-share__btn--native {
    flex: 1 1 100%;
    justify-content: center;
    min-height: 48px;
  }
  /* The follow pair beside the kicker, not below it. At 390px the two sat on
     separate lines by 2px — kicker 252 + gap 16 + row 80 = 348 against 350 of
     content — which cost 36px of height directly above the wordmark, the last
     place on a phone worth spending it. A tighter gap and a 32px target bring
     the row to 334 and it fits.
     Wrap stays ALLOWED rather than forced off, because at 320px it genuinely
     does not fit; margin-left:auto is what makes that fallback look deliberate,
     since space-between puts a lone item on a wrapped line at flex-start. */
  /* Sections read left-to-right under the wordmark on a phone. Right-aligned
     they wrapped with "Exclusive Interviews" stranded alone on a second line,
     which looks like a mistake rather than a choice. They are also simply VISIBLE
     now: the wp:navigation block hid them behind a hamburger directly below the
     product header's own hamburger, which is a confusing thing to show a reader
     twice. Four short section names do not need to be hidden. */
  .st-masthead__nav { justify-content: flex-start; gap: 16px 20px; }
  .st-masthead__top { gap: 10px; }
  .st-social--masthead { margin-left: auto; }
  .st-social--masthead { --st-ico: 17px; }
  .st-social--masthead .st-social__link { width: 32px; height: 32px; }
  .st-social--masthead .st-social__row { margin-block: -6px; margin-right: -7.5px; }
}

/* ── the Prices submenu ──────────────────────────────────────────────────────
   Opened by hover AND by keyboard, using :focus-within rather than a click
   handler — so it needs no JavaScript and works for a screen reader. The parent
   stays a real link, because Prices goes somewhere on its own and must not
   become a dead toggle for anyone who taps it. */
.st-hdr__has-sub { position: relative; display: inline-flex; align-items: center; }
.st-hdr__has-sub > a { display: inline-flex; align-items: center; gap: 5px; }
.st-hdr__caret { transition: transform 0.2s ease; opacity: 0.75; }
.st-hdr__has-sub:hover > a .st-hdr__caret,
.st-hdr__has-sub:focus-within > a .st-hdr__caret { transform: rotate(180deg); opacity: 1; }

.st-hdr__sub {
  position: absolute;
  /* Below the header's own height, so the submenu clears the bar rather than
     overlapping the link it belongs to. */
  top: calc(100% + 14px);
  left: -14px;
  z-index: 200;
  min-width: 208px;
  margin: 0;
  padding: 8px;
  list-style: none;
  background: var(--wp--preset--color--navy-900);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.4);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
}
.st-hdr__has-sub:hover > .st-hdr__sub,
.st-hdr__has-sub:focus-within > .st-hdr__sub {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* A hover bridge: without it the pointer crosses a 14px gap between the link and
   the panel and the menu closes on the way down. */
.st-hdr__has-sub::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  height: 16px;
}
.st-hdr__sub li { margin: 0; }
.st-hdr__sub a {
  display: block;
  padding: 9px 12px;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  color: #dce6ef;
  text-decoration: none;
  white-space: nowrap;
}
.st-hdr__sub a:hover,
.st-hdr__sub a:focus-visible { background: rgba(255, 255, 255, 0.08); color: #fff; }

@media (max-width: 1000px) {
  /* In the drawer there is no hover, and a nested popover on a phone is a trap.
     The submenu is simply always open, indented under its parent. */
  .st-hdr__has-sub { display: block; }
  .st-hdr__has-sub > a { padding: 14px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
  .st-hdr__caret { display: none; }
  .st-hdr__sub {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    margin: 0 0 8px;
    padding: 4px 0 4px 16px;
    background: transparent;
    border: 0;
    box-shadow: none;
  }
  .st-hdr__sub a { padding: 10px 0; font-size: 15px; }
  .st-hdr__has-sub::after { display: none; }
}

/* ── the newsletter in the footer ────────────────────────────────────────────
   Production's footer carries a signup, so the editorial footer does too. It is
   also the target of the pre-launch header CTA, hence the id. */
.st-ftr__news {
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  /* No max-width. The 560px cap belonged to the compact card that used to live
     here; the feature panel is the destination of a header CTA and takes the
     full footer measure. */
}

/* The dark treatment is for the COMPACT card only. Applied to the feature panel
   it painted a white heading on a white background, which is the whole point of
   the variant, so these must not reach it. */
.st-ftr__news .st-news--compact {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.1);
  max-width: 560px;
}
.st-ftr__news .st-news--compact .st-news__head { color: #fff; }
.st-ftr__news .st-news--compact .st-news__body,
.st-ftr__news .st-news--compact .st-news__fine { color: #8fa2b5; }

/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE: pictures, at the size the picture is worth — and the reading order

   ── THE FIRST VERSION OF THIS BLOCK GOT IT HALF RIGHT ────────────────────────
   It measured two sites, found Fox at 16-of-16 full-width thumbnails and CNN at
   8-of-14, and gave every item on this site a full content-width 16:9 image. The
   picture argument was correct — these are interview thumbnails of recognisable
   faces, so the image IS the reason someone taps — but the sample was two sites
   and it missed what the pictures COST. Re-measured across eight, at a 390px
   viewport, counting the first 16 headline items and the scroll distance to
   reach the tenth:

     site            with image   full-width   median card   y to headline #10
     Fox News          12/16        12           341px           3,194px
     BBC News          11/16         1            61px           2,069px
     CNN                5/16         4            93px           1,951px
     AP                 3/16         1           141px           1,951px
     CNBC               3/16         3           228px           1,248px
     Kitco              1/16         0            74px           2,217px
     NYT                1/16         0           169px           2,944px
     THIS SITE         10/16        10           345px           4,115px

   This site was the most expensive page in the sample. Fox is the only site that
   does what we were doing, and it is the outlier — not the norm the first
   version took it for.

   ── BBC IS THE ANSWER, AND IT IS NOT A COMPROMISE ────────────────────────────
   BBC carries pictures on ELEVEN of sixteen items — more than CNN, AP, CNBC,
   Kitco or NYT — at a median card height of 61px, because the thumbnail is
   132x74 beside the headline rather than 358x201 above it. It is the only site
   in the sample that is picture-rich AND dense. You do not have to choose.

   So: the lead keeps its full-width hero, because a lead is supposed to cost
   something. Everything below it becomes a 116px thumbnail beside the headline.
   A face is still legible at 116px — that is roughly the size of the avatars on
   every app on the phone — so the tap signal survives.

   ── AND NOT EVERY ITEM NEEDS ONE ─────────────────────────────────────────────
   The media column is sized `auto`, with the gap carried as a margin on the
   thumbnail rather than as `column-gap`. A post with no featured image therefore
   renders no thumbnail element, the column collapses to zero, and the headline
   takes the full width with no reserved hole and no placeholder. Pictures become
   a property of the story, not a requirement of the layout.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Desktop keeps the dense text river it was designed as. `display: none` plus
   the lazy loading these blocks emit means the files are not fetched here — a
   hidden lazy image never intersects the viewport, so it never downloads. */
.st-river__media,
.st-seconds__media { display: none; }

@media (max-width: 900px) {
  /* ── reading order ─────────────────────────────────────────────────────────
     The front page is a two-column grid: lead + river on the left, secondaries
     + watch + guests on the right. Stacking it put the SECONDARIES — stories
     two through five — at y=2454, below ten lesser stories in the river.
     `display: contents` dissolves both columns so their sections become direct
     children of the flex container, which is what makes `order` able to
     interleave them. */
  .st-front__grid { display: flex; flex-direction: column; gap: 0; }
  /* `.st-front__col--rail > .st-rail-sticky` is spelled out because a
     single-class `.st-rail-sticky` loses to the existing two-selector sticky
     rule — which left the whole rail as ONE flex item at order 0, ahead of the
     lead. The measurable symptom was the lead story appearing below the
     secondaries, the watch rail and the guest list. */
  .st-front__col { display: contents; }
  .st-front__col--rail > .st-rail-sticky {
    display: contents;
    position: static;
  }

  .st-lead        { order: 1; }
  .st-seconds     { order: 2; }
  .st-river-wrap  { order: 3; }
  .st-watch       { order: 4; }
  .st-guest-rail  { order: 5; }
  .st-startbox    { order: 6; }
  .st-allstories  { order: 7; }

  .st-lead, .st-seconds, .st-river-wrap, .st-watch, .st-guest-rail, .st-startbox {
    margin-bottom: 32px;
  }

  /* ── pictures: a thumbnail beside the headline, BBC-style ───────────────── */
  /* Two rows so the date can sit under the title while the thumbnail spans both.
     The media column is `auto`, not a fixed track: when a post has no featured
     image core renders no element at all, the column collapses, and the headline
     gets the full width. */
  .st-river .wp-block-post,
  .st-seconds .wp-block-post {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "title thumb"
      "meta  thumb";
    align-items: start;
    row-gap: 4px;
    padding-block: 0 16px;
  }

  /* ── the size is set on the FRAME, not the image ──────────────────────────
     `wp:post-featured-image` with an `aspectRatio` attribute emits an INLINE
     style on the <img> — `aspect-ratio:16/9; width:100%; height:100%;
     object-fit:cover` — and an inline style beats every class selector in this
     file no matter how specific. Sizing the img here therefore did nothing: the
     first version of this block set `width: 116px` on the image, the inline
     `width: 100%` won, the `auto` grid column sized itself to the full-width
     picture, the title column collapsed to 0px, and every headline wrapped one
     word per line. The front page went from 8,000px tall to 24,718px.

     So the frame carries the width and the inline `width: 100%` fills it, which
     is what that declaration is for. No `!important` needed, and it keeps working
     if core changes what it inlines. */
  .st-river__media,
  .st-seconds__media {
    display: block;
    grid-area: thumb;
    align-self: start;
    width: 116px;
    /* The gutter lives here rather than in `column-gap` so an item with no image
       loses the gutter along with the picture. */
    margin: 2px 0 0 14px;
    border-radius: var(--wp--custom--radius--sm);
  }
  .st-river__media img,
  .st-seconds__media img {
    /* Not width/height — those are inlined by core and already correct. Only the
       crop bias, which core does not inline: faces sit in the upper half of these
       thumbnails and a centred crop cuts them. */
    object-position: center 30%;
  }

  .st-river__body,
  .st-seconds__title { grid-area: title; }
  .st-river__when,
  .st-seconds .st-meta { grid-area: meta; margin: 0; }

  /* Type comes down with the pictures. At 21px a two-line headline beside a
     116px thumbnail sets the row height from the TEXT, which would give back
     most of what the smaller image just saved. */
  .st-river__title { font-size: 17px; line-height: 1.3; margin: 0; }
  /* Secondaries stay a step larger than the river: they are stories two through
     five and the hierarchy has to survive the density change. */
  .st-seconds__title { font-size: 19px; line-height: 1.27; margin: 0; }
  .st-seconds .wp-block-post { padding-block: 0 18px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE QUOTE CARDS ARE LINKS, ALL THE WAY ACROSS
   (inc/prices.php: st_render_quote_strip)

   A TradingView single-quote widget is an iframe whose contents link to
   tradingview.com. So the biggest, most obviously tappable thing in each card —
   the price — sent the reader to a third party, and only the small metal name
   above it came back to us.

   Production fixes this with a transparent <a> absolutely positioned over each
   widget at z-index 10. Same idea here, one difference: the card's EXISTING link
   is stretched over it with a pseudo-element, so there is no second anchor in the
   accessibility tree and no link without an accessible name — which is what an
   empty overlay <a> is.

   `isolation: isolate` on the card keeps the z-index local, so the ::after cannot
   ever paint over the sticky header.
   ═══════════════════════════════════════════════════════════════════════════ */
.st-quote {
  position: relative;
  isolation: isolate;
}
.st-quote__link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 10;
}
/* The card also has to LOOK clickable, or the affordance is a secret. */
.st-quote:hover { border-color: var(--wp--preset--color--gold-500); }
.st-quote:hover .st-quote__metal { color: var(--wp--preset--color--gold-700); }
.st-quote__link:focus-visible::after {
  outline: 2px solid var(--wp--preset--color--blue-600);
  outline-offset: 2px;
  border-radius: var(--wp--custom--radius--md, 10px);
}

/* The card for the page you are already on. The shield swallows the click so the
   iframe underneath is unreachable, WITHOUT making the card a link to itself —
   production's version reloads the gold page when you tap gold on the gold page.
   Not focusable, not in the a11y tree, no cursor change: it is not a control. */
.st-quote__shield {
  position: absolute;
  inset: 0;
  z-index: 10;
}
.st-quote--current:hover { border-color: var(--wp--preset--color--gold-500); }
.st-quote--current:hover .st-quote__metal { color: var(--wp--preset--color--ink); }

/* ═══════════════════════════════════════════════════════════════════════════
   THE NEWS BAND UNDER THE CHART  (inc/price-news.php)

   Four stories, thumbnail above headline, in a row on desktop and two-up on a
   phone. It sits between the chart and the prose because a reader who has just
   read a number is at the exact moment of deciding whether there is anything
   else here.
   ═══════════════════════════════════════════════════════════════════════════ */
.st-pnews {
  margin-block: 0 44px;
  padding-top: 28px;
  border-top: 1px solid var(--wp--preset--color--silver-200);
}
.st-pnews__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.st-pnews__heading {
  margin: 0;
  font-size: clamp(20px, 2vw, 26px);
  font-weight: 800;
  letter-spacing: -0.026em;
  line-height: 1.1;
  color: var(--wp--preset--color--ink);
}
.st-pnews__more { margin: 0; }
.st-pnews__more a {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--wp--preset--color--gold-700);
  text-decoration: none;
}
.st-pnews__more a:hover { text-decoration: underline; }

.st-pnews__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
}
.st-pnews__link {
  display: block;
  text-decoration: none;
  color: inherit;
}
.st-pnews__media {
  margin-bottom: 10px;
  border-radius: var(--wp--custom--radius--sm);
  overflow: hidden;
  background: var(--wp--preset--color--silver-200);
}
.st-pnews__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* These are interview thumbnails; the face sits high in the frame. */
  object-position: center 30%;
}
.st-pnews__title {
  margin: 0 0 6px;
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.28;
  color: var(--wp--preset--color--ink);
}
.st-pnews__link:hover .st-pnews__title { color: var(--wp--preset--color--blue-600); }
.st-pnews__when {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
}

@media (max-width: 900px) {
  .st-pnews__list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 16px; }
}
@media (max-width: 480px) {
  /* One column, but as a thumbnail ROW rather than four stacked heroes — the
     same reasoning as the front-page river below. */
  .st-pnews__list { grid-template-columns: 1fr; gap: 16px; }
  .st-pnews__link {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
  .st-pnews__media {
    order: 2;
    width: 116px;
    margin: 0 0 0 14px;
  }
  .st-pnews__body { order: 1; }
  .st-pnews__title { font-size: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE CONTACT PANEL  (inc/contact-details.php)

   Replaces "Mailing" / "Address:" / a bordered box holding two lines — three
   labels for one fact — and demotes a 606px Google Maps iframe to a link.
   ═══════════════════════════════════════════════════════════════════════════ */
.st-contact {
  margin-block: 40px 8px;
  padding: 26px 28px 24px;
  border: 1px solid var(--wp--preset--color--silver-200);
  border-radius: var(--wp--custom--radius--md, 10px);
  background: var(--wp--preset--color--silver-50);
}
.st-contact__head {
  margin: 0 0 20px;
  color: var(--wp--preset--color--ink);
}
.st-contact__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 22px 32px;
}
.st-contact__row { min-width: 0; }
.st-contact__label {
  margin: 0 0 4px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wp--preset--color--silver-600);
}
.st-contact__value {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--wp--preset--color--ink);
  /* An email address must never be the thing that makes a phone scroll sideways. */
  overflow-wrap: anywhere;
}
.st-contact__value a { color: var(--wp--preset--color--blue-600); text-decoration: none; }
.st-contact__value a:hover { text-decoration: underline; }
.st-contact__note {
  margin: 4px 0 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--wp--preset--color--silver-600);
}
.st-contact__map { margin: 20px 0 0; }
.st-contact__map a {
  font-size: 13px;
  font-weight: 700;
  color: var(--wp--preset--color--gold-700);
  text-decoration: none;
}
.st-contact__map a:hover { text-decoration: underline; }

@media (max-width: 600px) {
  .st-contact { padding: 20px 18px; }
  .st-contact__grid { grid-template-columns: 1fr; gap: 18px; }
}

/* The fine print now carries a link to the Privacy Policy (inc/newsletter.php:
   st_newsletter_fine_print), so it needs a colour that reads as a link in both
   the light feature panel and the dark footer card. */
.st-news__fine a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.st-news__fine a:hover { color: var(--wp--preset--color--gold-700); }
.st-ftr__news .st-news--compact .st-news__fine a:hover { color: #fff; }
