/* ==========================================================================
   RTNS additive CSS — T1b (Director dispatch, plan §Workstream A / T1b row)
   NEVER edits donor/site styles.css. Loaded AFTER styles.css (and after
   donor script.js, before site.js — site.js wraps window.openRtEvent, see
   qa/refs/T1b-notes.md "Include order"). Domi's design system (Georgia
   display / Arial body, gold #b98132 / #d8ad63, paper #fffdf8 / #f6f2ea) is
   canonical for this file; every rule below is scoped to a named selector
   or a body/page class, never a blanket rewrite.
   ========================================================================== */

/* Verify-phase fix (2026-09-25, defect 7 -- palette): named tokens for the
   colours this file introduced (nav/footer/marquee/waitlist chrome), each
   with a one-line reason. Rendered colours unchanged. See DESIGN-PROMPT
   §3 for the dated changelog entry. */
:root {
  --rt-live-dot: #e3342f; /* EXPO REAL pill's small "live" dot */
  --rt-chrome-border: #333333; /* waitlist dialog / CTA hairline borders on dark chrome */
  --rt-chrome-field-bg: #161918; /* waitlist form input background */
  --rt-chrome-muted: #b9b6ae; /* waitlist/teaser secondary text on dark chrome */
  --rt-chrome-body: #d4d0c8; /* footer/teaser body copy on dark chrome */
  /* Round-2 VA-BPS gate (26 Sep 2026): /news/ "Editor's note" box used raw
     inline hex instead of a named token -- these are the SAME values as
     rtns-dive.css's --rt-editor-green-* set (the deliberate brighter
     second green, documented in DESIGN-PROMPT.md §3), reused here for
     visual consistency across the two editor's-note components. Mirrored
     into this file's own :root (rather than reaching into rtns-dive.css,
     which /news/ never loads) so the token is defined on every page. */
  --rt-news-editor-bg: #173d34;
  --rt-news-editor-border: #7ebda9;
  --rt-news-editor-eyebrow: #8fd2bd;
  --rt-news-editor-text: #d7e4df;
  /* Gate round 4 (2026-09-26), rendered-vabps MED: named token for the
     darkened gold this file already used as bare hex (#77592a) in two
     light-surface .kicker/.eyebrow remap groups below. Measured live
     (Playwright + pixel sampling, not a DOM background-color probe) at
     6.36:1 on #fffdf8, 5.69:1 on #f4f0e8, 5.80:1 on #f7f2ea -- all
     clear 4.5:1. Dark-surface .kicker/.eyebrow instances (.section.dark,
     .rt-dive-hero-copy, .pod-v2-copy, .event-v2-copy) are untouched and
     keep var(--gold)/var(--gold2) -- this token is for light hosts only. */
  --rt-gold-a11y: #77592a;
}

/* nav
   ------------------------------------------------------------------------
   Her .navlinks already hide at max-width:1100px (styles.css L761) and
   .actions .light hides at max-width:700px (styles.css L799) — two
   DIFFERENT breakpoints. The hamburger appears at the same 1100px break
   as .navlinks, matching the point where the inline links actually
   disappear (not only at phone width). .logo min-width:210px is released
   at the same break so the mast doesn't force horizontal crowding once
   the nav links are gone. See notes "Nav breakpoints — verified" for the
   full trace.
   -------------------------------------------------------------------- */

.mast {
  --nav-h: 76px; /* mirrors her .nav{height:76px} (styles.css L52) */
}
@media (max-width: 700px) {
  .mast {
    --nav-h: 64px; /* mirrors her .nav{height:64px} override, styles.css L791 */
  }
}

.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  margin: 0;
  border: 1px solid #666; /* her .btn.light border-color, styles.css L110 */
  background: transparent;
  color: #fff;
  cursor: pointer;
  flex: 0 0 auto;
}
.nav-toggle:hover {
  border-color: var(--gold2);
}
.nav-toggle svg {
  width: 20px;
  height: 20px;
  display: block;
  fill: currentColor;
}
.nav-toggle .icon-close {
  display: none;
}
.nav-toggle[aria-expanded="true"] .icon-menu {
  display: none;
}
.nav-toggle[aria-expanded="true"] .icon-close {
  display: block;
}

@media (max-width: 1100px) {
  .logo {
    min-width: 0;
  }
  .nav-toggle {
    display: inline-flex;
  }
}

.nav-panel {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  top: var(--nav-h, 76px);
  height: calc(100vh - var(--nav-h, 76px));
  height: calc(100dvh - var(--nav-h, 76px)); /* dvh with vh fallback, per brief */
  background: var(--dark); /* her .mast bg, styles.css L48 */
  color: #fff;
  z-index: 150; /* above .mast (z-index:100, styles.css L50) */
  overflow-y: auto;
  padding: 28px 34px 40px;
  border-top: 1px solid #262926;
}
.nav-panel.is-open {
  display: block;
}
.nav-panel .panel-links {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 28px;
  padding: 0;
  list-style: none;
}
.nav-panel .panel-links a {
  display: block;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 28px;
  line-height: 1.3;
  padding: 12px 0;
  color: #eee9e1;
  border-bottom: 1px solid #262926;
}
.nav-panel .panel-links a:hover,
.nav-panel .panel-links a.active {
  color: var(--gold2);
}
/* Override her `.actions .light{display:none}` (max-width:700px, styles.css
   L799) INSIDE the open panel only — both her buttons stay visible here
   regardless of viewport width, per brief item 1. */
.nav-panel .actions {
  flex-wrap: wrap;
  gap: 10px;
}
.nav-panel .actions .light {
  display: inline-flex !important;
}

html.nav-panel-open,
body.nav-panel-open {
  overflow: hidden; /* scroll-lock only while the panel is open, set/unset in site.js */
}

/* type
   ------------------------------------------------------------------------
   Base .kicker rule (mirrors .eyebrow, styles.css L119-126 — six-plus Edge
   .kicker instances render unstyled today, none of the scoped overrides
   that DO exist, e.g. `.pulse-v4 .kicker`/`.ask-v4 .kicker`, define a base;
   see notes). .demo-note lifted 8px→11px, dark hosts keep her original
   #718c83, paper hosts remapped darker for AA. Gold-on-paper text-color
   remap (#b98132→#8c6a32); dark-surface gold (#d8ad63 / #d9aa5d etc.)
   is untouched — full trace + surface-by-surface reasoning in notes.
   -------------------------------------------------------------------- */

[id] {
  scroll-margin-top: 80px;
}

/* Round-2 VA-BPS gate (26 Sep 2026): a precise per-word Range measurement
   (not eyeballed) across every route x width found 139 unique h1/h2/h3
   elements -- headlines and card titles alike -- whose last rendered line
   holds exactly one word (frequently a trailing year: "Mid-Summer Night
   2026" wraps to "2026" alone). A single shared browser primitive fixes
   the whole class without touching any copy: `text-wrap: balance`
   distributes a heading's own text across its own lines so the last line
   is never a lone orphan, purely a line-break decision -- box size, font
   size and wording are all unchanged. (Evergreen Chrome/Firefox/Safari
   all support it; unsupported browsers simply keep today's wrap.) */
h1, h2, h3 {
  text-wrap: balance;
}

.kicker {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  font-weight: 700;
  color: var(--gold);
  margin-bottom: 12px;
}

/* Gate round 3 (2026-09-26), rendered-vabps MED: the base .kicker gold
   above (var(--gold) #b98132) clears AA on the dark Edge/PTC26 hosts that
   already have higher-specificity overrides (.section.dark, .pulse-v4,
   .ask-v4, .room-v4/.rtns-session, plus the two donor gradient-background
   cards below whose visible background is still dark despite a live
   background-color probe reading through to a lighter ancestor) -- but on
   Edge's actual light/cream cards (solid #fff / #f2eee7 backgrounds,
   verified via computed background-color, not a gradient) it read
   2.91-3.36:1. Reuses the same darker-gold token already proven >=4.5:1
   on cream/white (.eyebrow/.more remap above).
   Gate round 4 (2026-09-26) fix: `.edge-v4-main > .edge-v4-greeting .kicker`
   never matched -- the live DOM nests a `.shell` wrapper between the two
   (`.edge-v4-main > .shell > .edge-v4-greeting`), so the direct-child `>`
   silently failed and "Sample edition" kept falling through to the base
   var(--gold) rule above at 2.91:1. Changed to a descendant combinator and
   moved to the named --rt-gold-a11y token (same value, now shared). */
.edge-v4-main .edge-v4-greeting .kicker,
.brief-v4 .kicker,
.opps-v4 .kicker,
.edge-where .kicker,
.next-v4 .kicker,
.people-v4 .kicker {
  color: var(--rt-gold-a11y);
}

.demo-note {
  font-size: 11px;
  line-height: 1.4;
}
/* paper/light-surface .demo-note hosts (see notes "demo-note hosts"):
   darker so 11px still clears AA against #fffdf8/#f6f2ea/#ece5d9/#f1ebdf. */
.card .demo-note,
.cre-calendar-section .demo-note,
.event-v2-section.soft .demo-note,
.edge-cal-card .demo-note {
  color: #5f7a71;
}

/* Gold text-color remap — #b98132 used as text on paper/light surfaces
   (verified: none of these selectors sit inside a dark component; her
   dark overrides — .event-v2-copy .eyebrow, .pulse-v4 .kicker,
   .ask-v4 .kicker — have higher specificity and are untouched).
   Round-2 VA-BPS gate (26 Sep 2026): a real-background recheck (not the
   assumed-white pass) found this token still 3.65-4.46:1 against the
   cream card/section backgrounds it actually renders on across /about/,
   /people/, /podcasts/, /news/ and /events/PTC26-London/ -- darkened
   further (~15% lower lightness, same hue) so every observed cream host
   clears 4.5:1 (worst case 4.86:1 on #eadfce). */
.eyebrow,
.more,
.card .tag,
.stack-item .k,
.latest-item small,
.compact-news .cat,
.section-rule a,
.feed-item .cat,
.brief-type {
  /* .brief-type joined this remap round 3 (2026-09-26): donor's own
     #a66f25 still read 4.27:1 on brief-v4's white -- one token below the
     4.5:1 floor -- the shared darker gold clears 6.47:1 there.
     Gate round 4 (2026-09-26): moved to the named --rt-gold-a11y token
     (same #77592a value; see :root). */
  color: var(--rt-gold-a11y);
}
/* .section.dark (donor styles.css, background var(--dark) #0c0e0d) never
   overrode the base .eyebrow rule above -- e.g. /about/'s "International
   presence" eyebrow (`.section.dark .eyebrow`, no other scoping class)
   inherited the light-surface token and read 3.89-3.97:1 on near-black.
   Reuses the donor's own dark-surface gold (.event-v2-copy .eyebrow,
   styles.css) which already clears 9:1+ on this exact background. */
.section.dark .eyebrow,
.section.dark .kicker,
.event-v2-section.dark .eyebrow,
.event-v2-section.dark .kicker,
/* .pod-v2-series (#111513) and .home-calendar (#111714) are two more
   donor solid-dark hosts (both set color:white, donor styles.css) that
   the base .eyebrow rule's light-remap also read wrong (2.81-2.85:1) --
   found via a live computed-background walk, not a screenshot pixel
   sample. (.pod-v2-hero was checked and excluded: it's a real dark
   gradient but only sets background-IMAGE, not background-color, so its
   own donor override `.pod-v2-copy .eyebrow{color:#d8a45a}` already
   clears 7.2:1+ and is untouched here.) */
.pod-v2-series .eyebrow,
.pod-v2-series .kicker,
.home-calendar .eyebrow,
.home-calendar .kicker {
  color: #d9aa5d;
}
/* VA-BPS sweep 2026-09-26: "All coverage ->" is 83x10/73x20 -- under both
   the 44px touch and 24px desktop floors. .section-rule is a flex row
   (donor styles.css) so align-items:center already centers a taller box. */
.section-rule a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
/* Round-2 gate (2026-09-27), rendered MED: her card-CTA links render at
   9px (styles.pretty.css `.section-rule a`, `.edge-v4-profile a`,
   `.brief-next a`, `.opp-card > a`, `.edge-where-head > a`), identical at
   1440/1024/390 -- not a mobile-only defect, and below the site's own
   small-caps convention (11-14px used by `.latest-time`/`.cre-fit`/
   `.hero-stat span` etc. a few lines above). Bumped to 12px on all five so
   "All stories ->" (/news/), "Edit interests", "See matched
   opportunities ->", "Open context ->", "Compare lenders ->", "See your 6
   matches ->", "View person ->" and "Full CRE calendar ->" (/edge/) match.
   Colour/weight/case untouched -- size only. */
.section-rule a,
.edge-v4-profile a,
.brief-next a,
.opp-card > a,
.edge-where-head > a {
  font-size: 12px;
}
@media (max-width: 1100px) {
  .section-rule a {
    min-height: 44px;
  }
  /* Round-3 gate (2026-09-27), rendered MED: the round-2 font-size fix
     (9px->12px above) left these four still padding:0 display:block/
     inline-block (donor styles.css), so the rendered tap target stayed
     14px tall at 390px (measured 97x14, 145x14) -- same root cause as
     .dive-call-card .more below. inline-flex + align-items:center pads
     the box to a real 44px hit area without changing text size/colour;
     mobile-only so desktop's tighter donor spacing is untouched. */
  .edge-v4-profile a,
  .brief-next a,
  .opp-card > a,
  .edge-where-head > a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* Named-selector readability lifts ONLY (no blanket rule). Her literal
   ".hero-meta small" and ".edge-cal-grid small" don't exist as written —
   the real DOM/CSS selectors are `.hero-stat span` (nested inside
   .hero-meta) and `.edge-cal-card small` (nested inside .edge-cal-grid);
   mapped 1:1 to what she actually built, see notes "Selector name fixes". */
.latest-time,
.cre-fit,
.hero-stat span {
  /* all ≥9px today (9,9,10) — lift 650px-and-below only */
}
@media (max-width: 650px) {
  .latest-time {
    font-size: 11px;
  }
  .cre-fit {
    font-size: 11px;
  }
  .hero-stat span {
    font-size: 11px;
  }
}
/* .edge-cal-card small and .home-cal-item small are 8px today (under the
   9px floor) — lifted on desktop too, per the brief's own exception. */
.edge-cal-card small {
  font-size: 10px;
}
.home-cal-item[hidden] {
  display: none;
}
.home-cal-item small {
  font-size: 10px; /* color #8fa198 unchanged: already on a dark card, AA-safe */
}

/* modal
   ------------------------------------------------------------------------
   All markup/behaviour here is HERS (.cre-modal / #creEventModal /
   openRtEvent in donor/script.js) — site.js wraps her open/close functions
   at runtime; this block only raises the layer and enlarges the close
   target. z-index:110 clears her sticky .mast (z-index:100).
   -------------------------------------------------------------------- */

.cre-modal {
  z-index: 110;
}
.cre-modal-close {
  width: 44px;
  height: 44px;
  font-size: 22px;
  line-height: 1;
}

/* buttons
   ------------------------------------------------------------------------
   `.round-btn.ghost{color:#fff}` (styles.css L1297) is unscoped — fine on
   her dark .event-v2-hero, invisible on the three light/paper hosts where
   she also uses it (verified: .event-v2-section.soft #f1ebdf,
   .cre-calendar-section #ece5d9, .cre-modal-panel #f9f5ee — see notes).
   -------------------------------------------------------------------- */

.event-v2-section.soft .round-btn.ghost,
.cre-calendar-section .round-btn.ghost,
.cre-modal-panel .round-btn.ghost {
  color: var(--ink);
}

/* Contrast round 2026-09-27 (rendered-QA re-check, real per-viewport
   background sampling): the rule above scopes by SECTION background
   (.event-v2-section.soft's own cream, #f1ebdf), but two of its ghost CTAs
   -- "Enter event" / "Explore series" on the two .upcoming-side cards --
   don't sit on that cream background at all. They sit inside
   .upcoming-copy, which is absolutely positioned over a photo with its own
   near-black gradient overlay (donor styles.css .upcoming-side:after,
   linear-gradient to rgba(0,0,0,.92) at the bottom, exactly where the CTA
   row renders). The section-level rule above darkened them to near-black
   ink on that near-black photo -- measured 1.07-1.14:1 (needs 4.5:1). This
   selector is more specific (adds .upcoming-copy) so it wins regardless of
   source order, and restores donor's own unscoped `.round-btn.ghost{color:
   #fff}` for just this photo-backed context -- white on the >=.92-opacity
   black overlay clears 4.5:1 with a wide margin at every measured stop. */
.event-v2-section.soft .upcoming-copy .round-btn.ghost {
  color: #fff;
}

/* Contrast round 2026-09-27: .cre-calendar-head h2 ("Where the industry
   will be.") inherits color:white from the page's own <main class=
   "event-v2">{color:white} (donor styles.css) -- correct on the dark
   .event-v2-hero/.event-v2-section.dark panels this main also holds, but
   .cre-calendar-section is a sibling section with its OWN cream background
   (#ece5d9, donor styles.css) that never resets the inherited colour, so
   the h2 rendered pale/white-on-cream at 1.25:1 (needs 3:1 at 48px large
   text). .cre-calendar-head p and >a already set their own explicit dark
   colour (donor styles.css) -- only the h2 was left to inherit. */
.cre-calendar-section {
  color: var(--ink);
}

/* Contrast round 2026-09-27, borderline items (real per-viewport sampling,
   4.17-4.50:1, need 4.5:1): .bubble's translucent white chip
   (rgba(255,255,255,.14), donor styles.css) composites its background from
   whatever photo pixels sit behind it in .upcoming-copy -- a light patch of
   sky or stone in the source photo pushes the composited background light
   enough that white text falls under AA. Flipping the chip's own colour to
   a translucent DARK base fixes this independently of the photo: even
   against a worst-case pure-white photo pixel the composite stays <=~103
   grey (contrast ~5.7:1 with white text); against the actual darker photo
   crops here it is considerably higher. backdrop-filter:blur(8px) is kept
   (already smooths localised bright spots before the alpha blend). */
.upcoming-copy .bubble {
  background: rgba(8, 10, 9, 0.62);
}

/* Pass 7 (#48): the ERA26 card's image is the ERA26 key visual (Palace of
   Culture and Science in the left-hand window). The donor's object-fit:
   cover crops the sides equally; on the narrow 1-column phone card that
   centre crop drops the Palace out of frame, and the Palace is what makes
   the picture read as Warsaw. Anchoring the crop left of centre keeps it in
   view at every card width. */
.upcoming-side img[data-event-image="era26"] {
  object-position: 18% 50%;
}

/* Contrast round 2026-09-27, borderline (4.24-4.44:1, need 4.5:1):
   .cre-cal-date / .cre-cal-city / .cre-industry-badge (donor styles.css)
   sit on white .cre-cal-card backgrounds and the light .cre-industry-badge
   chip background (#eee8df) respectively. .cre-cal-date reuses the shared
   --rt-gold-a11y token (already measured 6.36:1+ on light hosts elsewhere
   in this file); the other two get a matched-darkness neutral so they read
   as the same "quiet metadata" grey the donor intended, just dark enough
   to clear 4.5:1 on their specific backgrounds. */
.cre-cal-date {
  color: var(--rt-gold-a11y, #77592a);
}
.cre-cal-city {
  color: var(--muted);
}
.cre-industry-badge {
  color: #5c554b;
}

/* Contrast round 2026-09-27, borderline (3.48:1, needs 4.5:1): the middle
   "Iconic places" card of .experience-grid (donor styles.css
   .experience-card:nth-child(2)) is the one card with a mid-tone brown
   background (#7e5d30) instead of the near-black default (#151816) or dark
   green (#173d34) the other two cards use -- .experience-card p's fixed
   light-grey colour (#c7c5be) was tuned for the near-black/dark-green
   cards only and drops to 3.48:1 on this one. Scoped to just this card
   (the other two already clear AA); white matches this card's own h3,
   which already inherits the section's white at full contrast. */
.experience-card:nth-child(2) p {
  color: #fff;
}

/* Video facade primitive for B7 (session/article templates). Contract:
   <div class="yt-lite" data-id="VIDEO_ID" data-title="..."
        style="--poster:url(...)">
     <button class="yt-lite-play" aria-label="Play: TITLE"></button>
   </div>
   plus a sibling <a> "Watch on YouTube" that B7 adds outside this block. */
.yt-lite {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background-color: var(--ink);
  background-image: var(--poster, none);
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.yt-lite iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.yt-lite-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 56px;
  height: 56px;
  border-radius: 999px; /* rounded gen2 idiom, matches .round-btn radius family */
  border: 0;
  background: var(--gold);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.yt-lite-play:hover {
  background: var(--gold2);
}
.yt-lite-play svg {
  width: 20px;
  height: 20px;
  margin-left: 3px; /* optical centring of the play triangle */
  fill: currentColor;
}

/* calendar
   ------------------------------------------------------------------------
   Fit-score truth on public pages: T1a sets `body.public` on every page
   except edge.html (see notes "body.public contract"). On Edge these
   three blocks stay, visibly illustrative. */

body.public .cre-fit,
body.public .cre-modal-score,
body.public .cre-modal-section.fitbox {
  display: none;
}

/* a11y
   ------------------------------------------------------------------------ */

a:focus-visible,
button:focus-visible,
input:focus-visible,
.round-btn:focus-visible,
.btn:focus-visible,
.nav-toggle:focus-visible,
.cre-cal-card:focus-visible,
.yt-lite-play:focus-visible {
  outline: 2px solid var(--gold2);
  outline-offset: 2px;
}

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

/* Hero collage at ≤650: her .event-collage has no overflow rule of its own
   (styles.css L1300-1302) but the absolutely-positioned .event-poster
   tiles can clip against an ancestor at narrow widths — defensive
   overflow:visible plus the chip-legibility bump the brief asks for. */
@media (max-width: 650px) {
  .event-collage {
    overflow: visible;
  }
  .event-floating {
    font-size: 11px;
  }
}

/* session — reserved for B7 (event.html / article.html session blocks) */

/* article — reserved for B7 (article.html body/quote-panel scale) */

/* P4.1 defect 4 (2026-09-15): footer links are 11px/1.4 = 15px tall, under the
   24px pointer-target floor. Padding grows the hit area without overlapping the next link
   (a negative margin made the targets overlap and fail again); the stack is about 10px looser per link. */
footer a {
  padding: 5px 0;
}
/* Footer canon port fix 2026-09-30 (QA at 1440, T11 footer follow-up):
   canon SiteFooter.tsx's copyright line is a bare <span> styled by
   `.cf-footer span { font-size: .82rem }` -- slightly SMALLER than the
   sibling links (.86rem). RTNS's port carried no `footer span` rule at
   all, so the "(c) 2026 RealTimes" span fell through to the browser's
   16px body default instead -- rendering visibly larger than the 11px
   footer links around it. 10px (not a literal rem->px transcription of
   the canon's absolute value, which belongs to a different base scale)
   keeps the same SMALLER-than-link relationship on RTNS's own px scale,
   and matches the 10px caption size already used sitewide (hero-stat
   span, event-band span, .meta, .tag, .tower .city) plus the #9a9a9a
   muted tone already used in this file for .rt-footer-cta-help /
   -fauxinput. The more specific .rt-footer-cta-label/-help/-fauxinput/
   -event-badge class rules all win over this element selector by
   specificity, so they are unaffected. */
footer span {
  color: #9a9a9a;
  font-size: 10px;
}
/* VA-BPS sweep 2026-09-26 (build.py._mark_leading_bold_labels): a leading
   "<b>Label.</b> body" / "<strong>Label:</strong> body" run-on line, added
   to every <p> that opens with a bare strong/b and no preceding text.
   display:block puts the label on its own line; the small gap keeps it
   from crowding the body that follows. Content/wording untouched. */
.rt-bl-lbl {
  display: block;
  margin-bottom: 4px;
}

/* VA-BPS sweep 2026-09-26: podcast platform badges (.platform, Spotify/
   YouTube) render 80x33 -- clears the 24px desktop floor already, fails the
   44px touch floor. Donor's own .platform is already inline-flex+centered. */
@media (max-width: 1100px) {
  .platform {
    min-height: 44px;
  }
}

/* Gate round 3 (2026-09-26), rendered-vabps HIGH: .platform's own background
   is always the near-white donor token (#faf8f3-ish) but the badge sits
   inside .pod-v2-hero, which sets color:#fff on every descendant for its
   dark gradient background -- the inherited white text lands on the badge's
   own light chip, 1.06:1 (needs 4.5:1). .platform never sets its own text
   color, so it silently inherits whatever the surrounding section uses.
   Pin it to the donor ink token so the badge is legible regardless of the
   section it's rendered in (contrast against #faf8f3 clears 4.5:1). */
.platform {
  color: var(--ink, #11120f);
}

/* VA-BPS sweep 2026-09-26: footer sitemap links pass the 24px desktop floor
   (padding above) but stay under 44px on touch widths. WCAG 2.5.5/2.5.8 asks
   44px on touch, 24px is the accepted desktop minimum -- so this only grows
   on the touch breakpoint already used site-wide (.rt-expo-pill hides at the
   same 1100px cut). display:flex + min-height keeps the hit area growing
   without the two-links-overlap regression the 2026-09-15 fix already hit. */
@media (max-width: 1100px) {
  footer a {
    /* footer a stays display:block (donor styles.css) -- symmetric padding
       grows the box without a display-mode change; 11px/1.4 line is ~15px,
       so 14.5px top+bottom clears the 44px floor. button.rt-footer-waitlist
       gets the identical touch-target rule further down (near its own
       base rule, not here) -- see the note there: same-specificity CSS
       source order means a rule added HERE would lose to the later
       unconditional button.rt-footer-waitlist base rule (padding:5px 0)
       regardless of this media query matching. */
    padding: 14.5px 0;
  }
}

/* Gate round 3 (2026-09-26), rendered-vabps MED: .round-btn (event/hub
   header CTAs, "Explore upcoming", "Enter event", etc.) measures 39px tall
   at every width <=1100px against donor's own 13px 20px padding + 10px font
   -- under the 44px touch floor. Same touch-breakpoint pattern as footer a
   above; desktop (1440) is untouched since 39px already clears the 24px
   desktop floor. */
@media (max-width: 1100px) {
  .round-btn {
    padding: 16px 20px;
  }
}

/* Gate round 3 (2026-09-26), rendered-vabps MED: /about/'s three-button
   footer CTA row ("Partner with RealTimes", "Meet us at an event",
   "Contact us", #final .actions) wrapped its trailing arrow onto its own
   line at 320px. Gluing the arrow to the last word (content/pages/about/
   page.json, non-breaking space) fixes the orphan but pushes the row's
   min-content width to 337px in a no-wrap flex row, 17px past the 320px
   viewport (measured, not assumed) -- so the arrow-glue alone traded one
   defect for horizontal overflow. flex-wrap lets the row's three buttons
   pack two-then-one instead of forcing all three onto one overflowing
   line; unaffected above 340px, where the row already fits without
   wrapping (measured: 0 overflow from 340px up). */
@media (max-width: 340px) {
  #final .actions {
    flex-wrap: wrap;
    row-gap: 10px;
  }
}

/* ==========================================================================
   Wave 2 -- content-page fillers (M2's content/pages/{dives,about,team/*}/
   page.json): .rt-note, .rt-figure(--16x9/--4x5/--3x2/--2x3), .rt-grid-2,
   .rt-text, .rt-logo-row. Every one sits inside an existing donor class
   (.brief-box, .card, .feed-item, figure) -- fillers only, per the Dive
   design prompt's own "clone, don't invent" rule extended to these pages.
   ========================================================================== */

/* .rt-note -- a .brief-box with no intrinsic max-width issue (donor's
   .brief-box already spans its container), kept here as a hook for a
   slightly tighter top rule so it doesn't look identical to an inline
   dive-editor box. */
.rt-note {
  border-top-width: 3px;
}

/* .rt-figure -- wraps <picture>/<img>, which already carry the correct
   intrinsic width/height attributes (no CLS). The aspect-ratio modifiers
   force a CONSISTENT crop for card/grid layout regardless of the source
   image's exact pixel ratio; object-fit:cover never distorts. */
.rt-figure {
  margin: 0;
  overflow: hidden;
  line-height: 0;
}
.rt-figure img,
.rt-figure picture,
.rt-figure picture img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.rt-figure--16x9 {
  aspect-ratio: 16 / 9;
}
.rt-figure--4x5 {
  aspect-ratio: 4 / 5;
}
.rt-figure--3x2 {
  aspect-ratio: 3 / 2;
}
.rt-figure--2x3 {
  aspect-ratio: 2 / 3;
}
.rt-figure figcaption,
figure.rt-figure figcaption {
  line-height: 1.4;
}

/* .rt-grid-2 -- two .card articles side by side (about's team section,
   team pages' two-up "stories" section). */
.rt-grid-2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
@media (max-width: 700px) {
  .rt-grid-2 {
    grid-template-columns: 1fr;
  }
}

/* .rt-text -- a .feed-item with no image (the "Format"/method list on the
   team pages): drop the donor 165px image column so the text runs full
   width instead of leaving a blank gutter. */
.feed-item.rt-text {
  grid-template-columns: 1fr;
}

/* 320px overflow fix (2026-09-27 re-check): donor's .feed-item is a CSS
   Grid with an explicit "115px 1fr" track (mobile breakpoint, donor
   styles.css). Grid items default to min-width:auto, i.e. their own
   min-content size -- an unbreakable text run in the text column (a long
   word, an &nbsp;-glued phrase from the widow guard above/in build.py, a
   bare URL) can exceed the 1fr track's available space and blow the whole
   grid past the 320px viewport, exactly as measured on the About-Alex
   "Engaged Investments" cards. min-width:0 is the standard fix: it lets
   the column shrink to the track size and wrap/overflow its OWN content
   instead of forcing the grid wider than its container. Applies to every
   .feed-item (all pages, all sibling cards), so no future long heading or
   unbreakable phrase can reopen this class of overflow. */
.feed-item > div {
  min-width: 0;
}

/* Widow-guard follow-on (2026-09-27 re-check): min-width:0 above stops the
   GRID from blowing out, but an unbreakable text run (this file's own
   &nbsp; widow-glues just below, e.g. "operational&nbsp;conviction") can
   still be WIDER than the 153px text column at 320-370px viewports
   (115px image + 16px gap eaten out of ~284-304px of content width) --
   with the grid track held fixed, that unbreakable run then paints past
   its own box (default overflow:visible) instead of past the grid, same
   visible defect from the reader's side. Measured: "operational
   conviction" alone needs ~206px, more than the ~153-173px column gives
   at any width under ~370px. Rather than truncate/hyphenate a heading
   (worse legibility) or drop the widow-glue (reopens the reported widow),
   stack the donor 2-column .feed-item to a single full-width column below
   400px -- image on top, text below, both edge to edge -- which hands the
   text column the full ~284-364px content width instead of ~153-173px,
   comfortably clearing every widow-glue in this file with room to spare.
   A generic responsive pattern (not a one-off hack): every .feed-item
   benefits from the wider text measure at this width, not just the one
   flagged card. */
@media (max-width: 400px) {
  .feed-item {
    grid-template-columns: 1fr;
  }
  .feed-item .feed-img {
    height: 160px;
  }
}

/* .rt-logo-row -- a flex row of partner/media-brand marks ("Eight
   conference brands", "members" bands). White-on-dark PNG variants
   (*-white.png), so no filter is applied; height-capped, width auto. */
.rt-logo-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 28px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.rt-logo-row li {
  display: flex;
  align-items: center;
}
.rt-logo-row img {
  height: 26px;
  width: auto;
  display: block;
}
/* Round-4 fix (27 Sep 2026): the event-logo anchors (team pages' "Events
   she/he builds" row) rendered a 20-26px tall tap target -- below the
   44px floor -- because only the <img> inside carried a height, not the
   <a>. Padding on the anchor grows the CLICKABLE area only; the logo's
   own visual height is untouched. */
.rt-logo-row a {
  display: flex;
  align-items: center;
  padding: 12px 0;
}
@media (max-width: 700px) {
  .rt-logo-row {
    gap: 18px;
  }
  .rt-logo-row img {
    height: 20px;
  }
}

/* .rt-logo-row-co -- one .rt-logo-row item that needs a small caption under
   the mark (2026-09-26, PCG26 "co-produced" label). Column layout, scoped
   to this one modifier so the other logo tiles are untouched. */
.rt-logo-row-co {
  flex-direction: column !important;
  align-items: flex-start !important;
  gap: 4px !important;
}
.rt-logo-row-co .meta {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--rt-chrome-muted);
}

/* Wave 2, M7 fix-list F2/LOW sweep (qa/2026-09-25-defect-sweep/fix-list.md):
   .rtns-article-body / .rtns-article-video are shared by rtns-event.css
   (PTC26 + Dive articles both use the class), so the fix lives HERE
   (rtns.css, loaded before rtns-event.css but text-wrap is otherwise
   unset there, so this value stands) rather than editing rtns-event.css,
   which is out of M1's owned-paths list. Better wrap only, no layout
   change -- the 720px/780px max-width stays wherever each file set it. */
.rtns-article-body,
.rtns-article-video {
  text-wrap: pretty;
}

/* sr-only -- visually hidden but readable by assistive tech (marquee's
   accessible <ul> twin, waitlist status region's default text). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Active-route styling drives off aria-current ONLY (not a .active class) so
   the nav identity check (P5 M1 brief S5.2, "active states can use
   aria-current only") sees byte-identical markup across every route. */
.navlinks a[aria-current="page"] {
  color: var(--gold2);
}
/* VA-BPS sweep 2026-09-26: 13px text = 33x15 box, under the 24px desktop
   floor (WCAG 2.5.8); this row only renders >1100px (.navlinks hides at the
   same cut the mobile panel takes over at), so no touch-floor case applies
   here -- the panel-links twin already sits in a 44px-tall row. */
.navlinks a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
.nav-panel .panel-links a[aria-current="page"] {
  color: var(--gold2);
}

/* nav -- P5 M1 Wave 1 (ONE nav-chrome partial, every route). EXPO REAL 2026
   text pill: no organiser logo (Alex's decision, plan "Pass 5"), a small
   red live dot, white text. */
.rt-expo-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 6px 10px;
  border: 1px solid var(--rt-chrome-border);
}
.rt-expo-pill:hover,
.rt-expo-pill:focus-visible,
.rt-expo-pill[aria-current="page"] {
  border-color: var(--gold2);
  color: var(--gold2);
}
.rt-expo-pill-dot {
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--rt-live-dot);
  box-shadow: 0 0 0 0 rgba(227, 52, 47, 0.7);
  animation: rt-expo-pill-pulse 2s ease-out infinite;
}
@keyframes rt-expo-pill-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(227, 52, 47, 0.6);
  }
  70% {
    box-shadow: 0 0 0 6px rgba(227, 52, 47, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(227, 52, 47, 0);
  }
}
/* T7 (30 Sep 2026): the pill is now nav_links[0], rendered inside BOTH
   .navlinks (desktop) and .nav-panel .panel-links (mobile) -- see
   templates/partials/nav-chrome.html's nav_link() macro. Scoped to
   .navlinks only (not a blanket .rt-expo-pill hide) so the mobile-panel
   copy stays visible below 1100px; .navlinks itself already hides at this
   break (donor styles.css), making this rule a defensive no-op belt, not
   the mobile-visibility switch. This replaces the pre-T7 rule that hid
   .rt-expo-pill everywhere under 1100px, which is exactly why the pill
   never reached the phone panel before. */
@media (max-width: 1100px) {
  .navlinks .rt-expo-pill {
    display: none;
  }
}
/* QA 1 Oct 2026: in the phone panel the generic `.nav-panel .panel-links a`
   row rule (display:block, 28px Georgia, padding 12px 0, bottom rule only)
   out-ranked .rt-expo-pill, so the dot span went inline and rendered 0px
   wide and the text sat on the pill's left border. This restores the
   desktop pill inside the panel: inline-flex box, 7px round dot, 10px
   inner padding, same 11px type, with the row's 44px tap height. */
.nav-panel .panel-links a.rt-expo-pill {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  margin: 4px 0 10px;
  padding: 0 14px 0 12px;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.06em;
  border: 1px solid var(--rt-chrome-border);
}
.nav-panel .panel-links a.rt-expo-pill:hover,
.nav-panel .panel-links a.rt-expo-pill:focus-visible,
.nav-panel .panel-links a.rt-expo-pill[aria-current="page"] {
  border-color: var(--gold2);
  color: var(--gold2);
}

/* waitlist CTA + shimmer -- ::after gradient sweep, transform only (no
   layout shift), 5s, once per visit (site.js sets .is-shimmer via the
   rt_wl_shimmer sessionStorage key). Tap target >=44x44 (brief hard don't). */
.rt-waitlist-cta {
  position: relative;
  overflow: hidden;
  min-height: 44px;
}
/* Round-4 fix (27 Sep 2026): "Join waiting list" wraps to 3 lines at
   320px with "LIST" stranded alone on the last line (widow). Below 340px
   the shorter label renders instead -- CSS-only swap (no JS, no layout
   shift, shimmer ::after untouched since it targets the whole button,
   not either span). */
.rt-waitlist-cta-short {
  display: none;
}
@media (max-width: 340px) {
  .rt-waitlist-cta-full {
    display: none;
  }
  .rt-waitlist-cta-short {
    display: inline;
  }
}

/* Round-5 fix (27 Sep 2026, re-check): the Round-4 swap above still wraps
   to "JOIN"/"WAITLIST" at 320px -- "Join waitlist" (uppercase via .btn's
   own text-transform) measures ~86px at the donor 11px/700/0.04em
   lettering, but .nav is a flex row with .logo + .nav-toggle (flex:0 0
   auto, never shrinks) + this CTA all competing for 284px of content width
   at 320px (.shell padding:0 18px, donor styles.css) -- there isn't enough
   room left for the CTA's own natural content+padding size, so the flex
   algorithm shrinks it below the text's single-line width. Three
   cooperating changes claw back just enough width without growing the
   button's footprint on the row: nowrap so the browser never silently
   re-wraps once it fits; letter-spacing:0 on the short label only
   (saves ~6px, donor's 0.04em is a spacing choice, not legibility-load-
   bearing at this size); and tighter horizontal padding on the button
   itself (17px -> 8px each side, still inside the >=44px tap-height floor
   this rule already sets) so the flex-shrink algorithm has less to shrink
   away from a smaller starting demand. Verified via rendered probe (no
   hand-waved arithmetic): single line, header row 0 overflow at 320px. */
@media (max-width: 340px) {
  .rt-waitlist-cta {
    padding: 0 8px;
  }
  .rt-waitlist-cta-short {
    white-space: nowrap;
    letter-spacing: 0;
  }
}
.rt-waitlist-cta.is-shimmer::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 20%, rgba(255, 255, 255, 0.55) 50%, transparent 80%);
  transform: translateX(-120%);
  animation: rt-waitlist-shimmer 5s ease-out 1;
  pointer-events: none;
}
@keyframes rt-waitlist-shimmer {
  0% {
    transform: translateX(-120%);
  }
  40% {
    transform: translateX(120%);
  }
  100% {
    transform: translateX(120%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .rt-waitlist-cta.is-shimmer::after {
    animation: none;
    display: none;
  }
}

/* waitlist dialog */
.rt-waitlist-dialog {
  border: 1px solid var(--rt-chrome-border);
  background: var(--dark);
  color: #fff;
  padding: 0;
  max-width: 420px;
  width: calc(100vw - 48px);
}
.rt-waitlist-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}
.rt-waitlist-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 32px 28px 28px;
  position: relative;
}
.rt-waitlist-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 22px;
  cursor: pointer;
}
.rt-waitlist-close:hover,
.rt-waitlist-close:focus-visible {
  color: var(--gold2);
}
.rt-waitlist-form h2 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 24px;
  margin: 0;
}
.rt-waitlist-intro {
  font-size: 13px;
  color: var(--rt-chrome-muted);
  line-height: 1.5;
  margin: 0;
}
.rt-waitlist-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--rt-chrome-muted);
}
.rt-waitlist-req {
  color: var(--gold2);
}
.rt-waitlist-field input {
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--rt-chrome-border);
  background: var(--rt-chrome-field-bg);
  color: #fff;
  font-size: 14px;
  text-transform: none;
  letter-spacing: normal;
}
.rt-waitlist-field input:focus-visible {
  outline: 2px solid var(--gold2);
  outline-offset: 1px;
}
.rt-waitlist-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.rt-waitlist-submit {
  width: 100%;
}
.rt-waitlist-status {
  font-size: 12px;
  color: var(--rt-chrome-muted);
  margin: 0;
  line-height: 1.5;
}
.rt-waitlist-status a {
  color: var(--gold2);
}

/* launch teaser (Wave 2, M6b) -- a dismissible bottom panel, never a hard
   gate; the article stays fully readable behind/above it. Shown once per
   visit (site.js, sessionStorage rt_teaser_shown), dismissed with "Keep
   reading". [hidden] is the default state set by the template; site.js
   removes it (never inline style) after the once-per-visit check. */
.rt-teaser {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 140;
  background: var(--dark);
  color: #fff;
  border-top: 1px solid var(--rt-chrome-border);
}
.rt-teaser[hidden] {
  display: none;
}
.rt-teaser-inner {
  max-width: 780px;
  margin: 0 auto;
  padding: 20px 48px 22px 20px;
  position: relative;
}
.rt-teaser-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold2);
  margin: 0 0 6px;
}
.rt-teaser-inner h2 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 20px;
  margin: 0 0 8px;
}
.rt-teaser-inner p {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--rt-chrome-body);
  line-height: 1.5;
}
.rt-teaser-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.rt-teaser-dismiss {
  position: absolute;
  top: 10px;
  right: 10px;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid #444;
  background: transparent;
  color: #fff;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
}
.rt-teaser-dismiss:hover,
.rt-teaser-dismiss:focus-visible {
  border-color: var(--gold2);
  color: var(--gold2);
}
@media (max-width: 700px) {
  .rt-teaser-inner {
    padding: 18px 44px 18px 16px;
  }
}

/* Verify-phase fix (2026-09-25, defect 2): .section.dark sets color:white
   (donor styles.css), which .brief-box (a light cream card, #eee7db) never
   overrides -- ghost white-on-cream text at 1.23:1 on both team pages'
   closing "book" band. Ink text restores the card to its normal (light-
   surface) contrast; nothing else in the dark band is touched. */
.section.dark .brief-box,
.section.dark .brief-box h3,
.section.dark .brief-box li,
.section.dark .brief-box p,
.section.dark .brief-box a {
  color: var(--ink);
}
.section.dark .brief-box a {
  text-decoration: underline;
}

/* /news/ "Editor's note" .brief-box variant -- named-token version of the
   inline style the template used to carry. See --rt-news-editor-* above. */
.brief-box.news-editor-box {
  background: var(--rt-news-editor-bg);
  color: #fff;
  border-color: var(--rt-news-editor-border);
}
.brief-box.news-editor-box .eyebrow {
  color: var(--rt-news-editor-eyebrow);
}
.brief-box.news-editor-box .news-editor-body {
  font-size: 11px;
  line-height: 1.6;
  color: var(--rt-news-editor-text);
}

/* Verify-phase fix (2026-09-25, defects 9): donor .btn is 42px tall
   (styles.css) at every width, and .logo img shrinks to 30px at <=700px
   with no padding on the <a> itself -- both under the 44px tap-target
   floor. Padding-only, no visible size change: .btn's own text/icon and
   .logo's own image keep their current rendered size. */
.btn {
  min-height: 44px;
}
@media (max-width: 700px) {
  .logo {
    min-height: 44px;
  }
}

/* Verify-phase fix (2026-09-25, defects 7/10 -- contrast): donor colours
   that read <4.5:1 (body) / <3:1 (large) on the light surfaces they
   actually render on. Every value below is picked to clear 4.5:1 on its
   OWN background(s), computed via the WCAG relative-luminance formula;
   donor styles.css stays frozen, everything here is an additive override. */
.newsletter p,
.newsletter-grid p {
  /* 4.42:1 -> 5.64:1 on the newsletter band's #ece3d6 (shared by /news/
     and every page with the newsletter band, incl. PTC26). */
  color: #5c574f;
}
.newsletter .demo-note,
.card .demo-note,
.cre-calendar-section .demo-note,
.event-v2-section.soft .demo-note,
.edge-cal-card .demo-note {
  /* extends the existing "demo-note hosts" darken list (was missing
     .newsletter, 2.86:1 there) with one value that clears 4.5:1 on every
     host background, incl. the news-body's white .demo-note a link. */
  color: #496359;
}
.news-body-grid .demo-note,
.news-body-grid .demo-note a,
.latest-rail .demo-note {
  color: #496359;
}
/* Gate round 3 (2026-09-26), rendered-vabps MED: donor's own .demo-note
   default (#718c83, styles.css) still renders on three light hosts none
   of the lists above catch -- a bare <section class="section"> (cities'
   /cities/ and people's /people/ hub sections, both fall through to
   body's #fffdf8) and .pod-v2-section (podcasts, its own #f7f2ea), plus
   Edge's opps-v4 card (solid #fff, verified via computed background-
   color). :not(.dark) keeps .section.dark's demo-notes (none currently
   exist, but future-proofs against re-darkening a light-only fix). */
.section:not(.dark) .demo-note,
.opps-v4 .demo-note {
  color: #496359;
}
.latest-time {
  /* 3.19:1 on white -> darkened; own rule since donor never colours
     .latest-time at all (inherits an ambient grey). */
  color: #5e564c;
}
.meta {
  /* 3.55-3.61:1 on white/paper -> 5.67:1. Bare .meta only -- more specific
     dark-surface rules (.dive-hero .meta, .edge-op .meta) already win the
     cascade and are untouched. */
  color: #6b655c;
}
.section.dark .meta {
  /* the darkened light-surface value above regresses .meta's OWN already-
     passing dark-surface instances (donor #8c867d was 5.37:1 there) --
     lightened back up for this dark host specifically. */
  color: #b4afa6;
}
.event-v2-section.soft .event-v2-head p {
  /* 4.18:1 -> 6.19:1 on the .soft band's #f1ebdf. */
  color: #5c554c;
}
.event-v2-section.soft .section-rule a,
.event-v2-section.soft .card .tag,
.event-v2-section.soft .eyebrow,
.event-v2-section.soft .more,
.event-v2-section.soft .feed-item .cat {
  /* the existing #8c6a32 gold-on-paper remap is 4.89:1 on #fff5ee but only
     4.19:1 on the .soft band's warmer #f1ebdf -- scoped darker value for
     that one background only. */
  color: #7a5c2c;
}
.foot-bottom {
  /* 4.37:1 -> 5.87:1 on the dark footer's #101210. */
  color: #8d918b;
}

/* /dives/ full-bleed hero (Alex's picked concept v2, 2026-09-25). Full
   16:9 on desktop (nothing cropped); a height cap kicks in under 700px so
   the section never eats the whole first viewport on a phone -- the
   diver sits in the image's own upper third, so object-position stays
   biased toward the top at every width (never crops the diver out). */
.rt-dive-hero {
  padding: 0;
  border-bottom: 0;
}
.rt-dive-hero-figure {
  position: relative;
  margin: 0;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  line-height: 0;
}
.rt-dive-hero-figure picture,
.rt-dive-hero-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 15%;
}
.rt-dive-hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(11, 13, 12, 0.92) 0%, rgba(11, 13, 12, 0.55) 32%, rgba(11, 13, 12, 0) 62%);
  pointer-events: none;
}
.rt-dive-hero-copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 40px 0 40px;
  /* Verify-phase fix (2026-09-25): the whole-IMAGE scrim above only
     guarantees darkness in the image's own bottom ~62% -- at narrow
     widths the heading wraps to 3 lines and its FIRST line can sit
     above that darkened band, over a bright light-shaft, reading as low
     as 1.7:1. This second scrim is anchored to the COPY BLOCK'S OWN
     content height (not the image's), so it always covers exactly
     where the text is, however many lines it wraps to. */
  background: linear-gradient(to top, rgba(11, 13, 12, 0.97) 55%, rgba(11, 13, 12, 0.88) 100%);
}
.rt-dive-hero-copy .eyebrow {
  color: var(--gold2, #d8ad63);
}
.rt-dive-hero-copy h1,
.rt-dive-hero-copy p {
  color: #ffffff;
}
.rt-ai-label {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffffff;
  background: rgba(11, 13, 12, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.35);
}
@media (max-width: 700px) {
  .rt-dive-hero-figure {
    aspect-ratio: auto;
    height: 62vh;
    max-height: 420px;
  }
  .rt-dive-hero-copy {
    padding: 18px 0 24px;
  }
}

/* footer fillers */
.rt-footer-grid {
  grid-template-columns: 1.4fr repeat(3, 1fr);
}
/* T11 (30 Sep 2026): canon-ported brand-column early-access CTA block
   (SiteFooter.tsx .cf-footer-cta*). Button, not an <a href="/#waitlist">,
   so it wires into RTNS's existing dialog-open convention
   (data-rt-waitlist-open, same as the nav CTA and .rt-footer-waitlist
   above) instead of a bare anchor the RTNS site.js waitlist dialog
   doesn't listen for. */
.rt-footer-brand {
  display: flex;
  flex-direction: column;
}
.rt-footer-cta {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 380px;
  text-align: left;
}
.rt-footer-cta-label {
  color: var(--gold2);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.rt-footer-cta-link {
  display: flex;
  align-items: stretch;
  width: 100%;
  padding: 0;
  margin: 0;
  border: 1px solid var(--rt-chrome-border);
  background: transparent;
  cursor: pointer;
  font: inherit;
  min-height: 44px;
}
.rt-footer-cta-link:hover,
.rt-footer-cta-link:focus-visible {
  border-color: var(--gold2);
}
.rt-footer-cta-fauxinput {
  flex: 1;
  display: flex;
  align-items: center;
  padding: 0 12px;
  color: #9a9a9a;
  font-size: 12px;
  text-align: left;
}
.rt-footer-cta-btn {
  display: flex;
  align-items: center;
  padding: 0 12px;
  background: rgba(216, 173, 99, 0.12);
  color: var(--gold2);
  font-size: 11px;
  white-space: nowrap;
}
.rt-footer-cta-help {
  color: #9a9a9a;
  font-size: 10px;
  line-height: 1.5;
}
.rt-footer-cta-partner {
  color: var(--gold2) !important;
}
.rt-footer-cta-partner:hover {
  color: #fff !important;
}
@media (max-width: 650px) {
  .rt-footer-brand {
    align-items: center;
    text-align: center;
  }
  .rt-footer-cta {
    align-items: center;
    text-align: center;
  }
}
button.rt-footer-waitlist {
  display: block;
  width: auto;
  /* Footer canon port fix 2026-09-30 (QA at 1440): was `padding:0` +
     unconditional `min-height:44px`, which made this button 44px tall
     at EVERY width (desktop rows measured 25/44/25/25 against sibling
     footer links) instead of matching them like a canon-ported "Early
     Access" link should. Dropped min-height; padding now mirrors
     `footer a`'s own 5px/14.5px desktop/touch split above, so the
     button renders identical to its siblings at 1440 and only grows
     for the touch floor under 1100px. */
  padding: 5px 0;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 11px;
  color: #a9a59e;
  margin: 7px 0;
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
}
button.rt-footer-waitlist:hover,
button.rt-footer-waitlist:focus-visible {
  color: #fff;
}
/* Footer canon port fix 2026-09-30 (QA at 1440, touch breakpoint):
   mirrors `footer a`'s own 14.5px touch-target padding (defined earlier
   in this file, in the shared @media (max-width:1100px) block) so the
   button's row height matches its link siblings at BOTH breakpoints.
   Placed HERE, after the button's own base rule above, on purpose: an
   earlier same-specificity `button.rt-footer-waitlist{padding:...}`
   media rule would still lose the cascade to the later unconditional
   base rule above it in source order, media match notwithstanding --
   this one now has to be later than the base rule, not merely inside
   a matching media query. */
@media (max-width: 1100px) {
  button.rt-footer-waitlist {
    padding: 14.5px 0;
  }
}
.rt-footer-event-featured {
  color: var(--gold2) !important;
  font-weight: 700;
  /* Footer canon port fix 2026-09-30 (QA at 1440): was `inline-flex`,
     whose outer display is INLINE, so it did not take part in the
     normal block margin-collapsing that gives every other footer link
     its even 7px stack gap (donor `footer a{margin:7px 0}`) -- Events
     column gaps measured 14/14/7 instead of even. `flex` keeps the
     same internal flex layout (dot + label + badge) but is block-level
     on the outside, so it collapses margins with its siblings exactly
     like a plain `<a>` does. */
  display: flex !important;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}
.rt-footer-event-dot {
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--gold2);
  box-shadow: 0 0 0 0 rgba(216, 173, 99, 0.7);
  animation: rt-footer-pulse 2s ease-out infinite;
}
/* VA-BPS sweep 2026-09-26: 218x30 on mobile, under the 44px touch floor;
   desktop stays untouched (30px already clears the 24px desktop floor). */
@media (max-width: 1100px) {
  .rt-footer-event-featured {
    min-height: 44px;
  }
}
.rt-footer-event-badge {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold2);
  border: 1px solid rgba(216, 173, 99, 0.55);
  padding: 2px 7px;
  white-space: nowrap;
}
@keyframes rt-footer-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(216, 173, 99, 0.6);
  }
  70% {
    box-shadow: 0 0 0 6px rgba(216, 173, 99, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(216, 173, 99, 0);
  }
}
@media (max-width: 980px) {
  .rt-footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 650px) {
  .rt-footer-grid {
    grid-template-columns: 1fr;
  }
}

/* top marquee -- rendered at build time; absent-file = no element at all
   (build.py never emits an empty .rt-marquee shell). Pure-CSS pause on
   hover/focus; reduced motion swaps the animated track for a horizontal
   scroller with no animation.
   Cluster C4 (Alex, 2026-09-30): "moving too fast; slow down, use bold
   fonts; apply design as used for Stock exchange tickers" -- speed is
   now driven by site.js's initMarquee() via the --rt-marquee-duration
   custom property (content-width / ~40px-per-second, recomputed on
   resize/content-change), the 90s value below is only the no-JS /
   pre-measurement fallback (previously a flat 60s, which is the "too
   fast" Alex flagged -- raised as the safety floor, not the real speed).
   Board look: dark board background (--dark, the same token the nav/
   .mast chrome uses), bold uppercase city/label with light tracking,
   bold tabular-nums figures, thin vertical separators, white body text
   (>=4.5:1 on --dark, measured -- see qa/2026-09-30-ticker/). No red/
   green up-down cues yet -- .rt-marquee-marker is reserved DOM for that,
   parked per brief until Alex picks a monthly edition, and renders
   nothing today because build.py never emits the span (see the
   file:line note in the QA report handed back with this change). */
.rt-marquee {
  /* SAR-fix 2026-09-30: the reserved gutter must track the badge's own
     width, not a hardcoded guess -- a label-copy change ("RT/PRIME
     OFFICE" vs the old shorter text) silently outgrew a fixed
     padding-right and ran scrolling items under the opaque badge. Both
     declarations below read this ONE variable.
     30 Sep umbrella split: the badge now reads "RT/PRIME" (natural width
     81.4px at 375 and 1440, measured with Playwright), so the variable
     drops from 138px to 88px: about 6px spare, and the strip gets ~50px
     back. Re-measure if the label changes. */
  --rt-marquee-badge-w: 88px;
  position: relative;
  background: var(--dark); /* board look -- same token as .mast/nav chrome */
  border-bottom: 1px solid #262926;
  color: #fff; /* >=4.5:1 on var(--dark) #0c0e0d -- see qa/2026-09-30-ticker/ */
  font-size: 11px;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: 44px; /* tap-target floor also governs the Methodology link's height (top:0;bottom:0) */
  padding-right: calc(var(--rt-marquee-badge-w) + 4px); /* badge width + breathing room */
}
.rt-marquee-viewport {
  overflow: hidden;
  width: 100%;
}
.rt-marquee-track {
  display: inline-flex;
  white-space: nowrap;
  animation: rt-marquee-scroll var(--rt-marquee-duration, 90s) linear infinite;
  will-change: transform;
}
.rt-marquee:hover .rt-marquee-track,
.rt-marquee:focus-within .rt-marquee-track {
  animation-play-state: paused;
}
.rt-marquee-item {
  display: inline-block;
  padding: 8px 28px;
  border-right: 1px solid #3a3d3a; /* thin board separator, lifted from #262926 for visibility on --dark */
  font-weight: 700; /* bold: applies to the city/label letters, inert on digits */
  text-transform: uppercase; /* bold uppercase city/label, inert on digits and punctuation */
  letter-spacing: 0.03em; /* light tracking, board-ticker feel */
  font-variant-numeric: tabular-nums; /* bold tabular figures, inert on letters */
}
/* Reserved for the up/down marker Alex parked (no red/green today, per
   brief). build.py never emits this span -- see the exact file:line
   change needed to add it, reported in the QA handoff for this task.
   Kept here, inert, so the DOM slot is ready without shipping any
   colour cue ahead of Alex's monthly-edition decision. */
.rt-marquee-marker {
  display: none;
}
@keyframes rt-marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}
.rt-marquee-methodology {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  min-height: 44px; /* the .rt-marquee border-bottom shaved 1px off a bare top:0/bottom:0 span */
  min-width: var(--rt-marquee-badge-w); /* same var as .rt-marquee padding-right, see above */
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 14px;
  background: var(--dark);
  color: var(--gold2);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-left: 1px solid #262926;
  white-space: nowrap;
}
.rt-marquee-methodology:hover,
.rt-marquee-methodology:focus-visible {
  color: #fff;
}
@media (prefers-reduced-motion: reduce) {
  .rt-marquee-track {
    animation: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
  }
  .rt-marquee-viewport {
    overflow-x: auto;
  }
}
/* Reduced motion, JS present (QA 1 Oct 2026): the plain scroller above cut
   the first item mid-word at the badge edge ("1,250/M²/YR"). site.js's
   initMarquee() adds .is-static and shows whole items only: every item that
   would cross the viewport's right edge is hidden, and when not even the
   first item fits on one line (phones) it wraps inside the strip instead.
   The no-JS fallback keeps the scroller. */
.rt-marquee.is-static .rt-marquee-viewport {
  overflow: hidden;
}
.rt-marquee.is-static .rt-marquee-track {
  display: flex;
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
  animation: none;
}
.rt-marquee.is-static .rt-marquee-item {
  flex: 0 0 auto;
}
.rt-marquee.is-static .rt-marquee-item[hidden] {
  display: none;
}
.rt-marquee.is-static .rt-marquee-item.is-wrap {
  flex: 0 1 auto;
  min-width: 0;
  white-space: normal;
  padding: 7px 16px;
  line-height: 1.35;
  text-wrap: balance; /* no lone "2026" on a last line at 320px */
}

.rt-methodology-pending td {
  background: #fbeee0;
  color: #6c675e;
  font-style: italic;
}

/* marquee methodology page table (P5 M1 brief S2.8) */
/* Verify-phase fix (2026-09-25, defect 3): the 10-column table forced the
   whole PAGE wider than the viewport at 768/390/320 (page-level overflow,
   not a contained scroll). Wrapping it in a keyboard-focusable, labelled
   scroll region contains the overflow to the table itself. */
.rt-methodology-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-top: 20px;
}
.rt-methodology-scroll:focus-visible {
  outline: 2px solid var(--gold2, #d8ad63);
  outline-offset: 2px;
}
.rt-methodology-table {
  width: 100%;
  min-width: 760px;
  border-collapse: collapse;
  font-size: 13px;
  margin-top: 0;
}
.rt-methodology-table th,
.rt-methodology-table td {
  border: 1px solid var(--line, #ddd5c9);
  padding: 8px 10px;
  text-align: left;
}

/* Team-page "About" contact list (LinkedIn / realtimes.co / email) --
   2026-09-26. Two faults fixed: (1) donor a{color:inherit;text-decoration:
   none} made these <ul><li><a> links visually indistinguishable from plain
   text (Alex, 26 Sep, from his phone: "Why no URLs?"); (2) the email line
   sat in its own <p>, outside the <ul>, so it rendered with no bullet while
   the other two got the browser default disc -- inconsistent markers.
   Donor CSS never resets `ul{list-style}` (verified: no such rule in
   donor/styles.css), so the Languages/Education <ul>s elsewhere in this
   same .analysis-grid already render default disc bullets -- this class
   keeps that SAME default-bullet vertical-list idiom (consistent bullets
   across all 3 items) rather than inventing a new bulletless/flex-row
   pattern, and only adds colour + underline + a 44px tap target so the
   links are visibly links. Scoped to this named list only. Reuses
   --rt-gold-a11y, already measured 6.36:1+ on the light section
   backgrounds this list renders on. */
.rt-contact-links {
  margin: 16px 0 0;
  padding-left: 20px;
}
.rt-contact-links li {
  margin: 6px 0;
}
.rt-contact-links a {
  color: var(--rt-gold-a11y, #77592a);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.dark .rt-contact-links a {
  color: var(--gold2);
}

/* --------------------------------------------------------------------
   RTPRI -- the RealTimes Prime Rent Index (/data/prime-rent-index/,
   build.py's render_rtpri_page). Card grid on mobile, table on desktop
   (the breakpoint below), one shared data source per section.rtpri.md.
   All link text below uses --rt-gold-a11y (already measured 6.36:1+ on
   the paper2 background this page renders on -- same token as the
   About-page contact list above).
   -------------------------------------------------------------------- */
.rtpri-page {
  /* padding-top/-bottom only -- a shorthand `padding: 40px 0 64px` here
     would zero out the left/right gutter .shell already sets (same
     specificity, this rule loads after styles.css and wins the cascade),
     which is exactly how the page lost its gutter at every width. */
  padding-top: 40px;
  padding-bottom: 64px;
}
.rtpri-page h1 {
  font-size: 38px;
  margin: 0 0 12px;
}
.rtpri-intro {
  max-width: 720px;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.6;
  margin: 0 0 28px;
}
.rtpri-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 2px solid var(--line);
  margin-bottom: 24px;
  /* Office/Shopping Centres/Industrial need ~305px; a 320px viewport with
     the page's own gutter only leaves ~284px. Scroll horizontally within
     the tablist itself (same pattern as .rtpri-table-scroll) instead of
     letting the row push past the viewport edge -- restoring the page's
     gutter (this fix round, defect 3) is what exposed this, since 0
     gutter used to leave just enough width for the row to fit. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.rtpri-tabs [role="tab"] {
  appearance: none;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  padding: 12px 16px;
  min-height: 44px;
  cursor: pointer;
  flex: 0 0 auto;
  white-space: nowrap;
}
.rtpri-tabs [role="tab"][aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--gold);
}
.rtpri-tabs [role="tab"]:focus-visible {
  outline: 2px solid var(--gold2);
  outline-offset: 2px;
}
@media (max-width: 400px) {
  /* scrollWidth 373 vs clientWidth 339 clipped "INDUSTRIAL" to "INDUSTRI"
     with no scroll cue; tighter tab padding closes most of the gap and
     the row still scrolls (overflow-x:auto above) for any remainder. */
  .rtpri-tabs [role="tab"] {
    padding: 12px 10px;
  }
}
.rtpri-panel[hidden] {
  display: none;
}
.rtpri-coming-soon {
  color: var(--muted);
  font-size: 15px;
  padding: 24px 0;
}

/* mobile city cards -- hidden at/above the desktop breakpoint, where the
   table takes over (see the @media block below). */
.rtpri-city-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
}
.rtpri-city-card {
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 18px 20px;
  background: var(--paper2);
}
.rtpri-city-card h3 {
  margin: 0 0 6px;
  font-size: 20px;
}
.rtpri-submarket {
  color: var(--muted);
  font-size: 13px;
  margin: 0 0 10px;
}
.rtpri-range {
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 2px;
}
.rtpri-unit {
  font-size: 13px;
  font-weight: 400;
  color: var(--muted);
}
.rtpri-median {
  font-size: 13px;
  color: var(--muted);
  margin: 0 0 8px;
}
.rtpri-brokers {
  font-size: 12px;
  color: var(--muted);
  margin: 0 0 8px;
}
.rtpri-sources {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 12px;
}
.rtpri-sources a,
.rtpri-csv-link,
.rtpri-table a {
  color: var(--rt-gold-a11y);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.rtpri-table-scroll {
  display: none; /* table is desktop-only; see the @media block below */
}
.rtpri-how {
  margin-top: 40px;
}
.rtpri-how ul {
  padding-left: 20px;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.7;
}
.rtpri-cite,
.rtpri-next {
  font-size: 13px;
  color: var(--muted);
  margin-top: 18px;
}
/* Pass 7 (#32): the methodology page (/data/prime-rent-index/methodology/)
   reuses this page's shell, intro and .rtpri-how sections; these rules only
   add what its prose needs. Links use the same --rt-gold-a11y token as the
   broker links above (6.36:1+ on paper2), underlined because donor
   styles.css strips link underlines site-wide. */
.rtpri-method-link a,
.rtpri-method-back a,
.rtpri-method .rtpri-how a {
  color: var(--rt-gold-a11y);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.rtpri-method-link {
  margin: 12px 0 0;
  font-size: 14px;
}
.rtpri-method-back {
  margin: 0 0 4px;
  font-size: 13px;
}
.rtpri-method .rtpri-how h2 {
  font-size: 28px;
  line-height: 1.15;
  margin: 0 0 12px;
}
.rtpri-method .rtpri-how p {
  max-width: 720px;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.7;
  margin: 12px 0 8px;
}
.rtpri-method .rtpri-how ul {
  max-width: 720px;
  margin: 8px 0;
}
.rtpri-method .rtpri-faq h3 {
  font-size: 17px;
  line-height: 1.3;
  margin: 22px 0 4px;
}
.rtpri-method .rtpri-faq p {
  margin-top: 4px;
}
.rtpri-csv {
  margin-top: 14px;
}
.rtpri-country {
  color: var(--muted);
  font-size: 12px;
}
.rtpri-table {
  width: 100%;
  min-width: 760px;
  border-collapse: collapse;
  font-size: 13px;
}
.rtpri-table th,
.rtpri-table td {
  border: 1px solid var(--line);
  padding: 10px 12px;
  text-align: left;
}

@media (min-width: 760px) {
  .rtpri-city-cards {
    display: none;
  }
  .rtpri-table-scroll {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .rtpri-table-scroll:focus-visible {
    outline: 2px solid var(--gold2);
    outline-offset: 2px;
  }
}

/* --------------------------------------------------------------------
   RTPRI explainer bar (26 Sep fix round, item A2) -- one line under the
   rent strip, with a phone-width popover fallback when the sentence
   would wrap. site.js's initRtpriExplainer() wires the popover toggle;
   the bar itself works with no JS (the sentence + link always render).
   -------------------------------------------------------------------- */
.rt-rtpri-explainer {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 6px 44px;
  background: var(--dark);
  border-bottom: 1px solid var(--rt-chrome-border);
  font-size: 12px;
  line-height: 1.4;
}
.rt-rtpri-explainer-text {
  margin: 0;
  color: #d9d5c9; /* >=4.5:1 on var(--dark) */
  text-align: center;
}
.rt-rtpri-explainer-text a {
  color: var(--gold2); /* dark chrome (var(--dark)) -- --rt-gold-a11y is light-host only */
  font-weight: 700;
  text-decoration: underline;
  white-space: nowrap; /* the longer umbrella sentence (30 Sep) wraps at 521 to 1023px; never split "How it works →" */
}
.rt-rtpri-explainer-btn {
  display: none;
  min-height: 44px;
  min-width: 44px;
  padding: 0 10px;
  border: none;
  background: transparent;
  color: #d9d5c9;
  font-size: 12px;
  cursor: pointer;
}
.rt-rtpri-explainer-popover {
  position: absolute;
  top: 100%;
  left: 8px;
  right: 8px;
  z-index: 120;
  background: var(--ink, #11120f);
  color: #fff;
  border: 1px solid var(--rt-chrome-border);
  padding: 12px 14px;
  font-size: 13px;
  line-height: 1.5;
}
.rt-rtpri-explainer-popover p {
  margin: 0;
}
.rt-rtpri-explainer-popover a {
  color: var(--gold2); /* dark chrome (var(--ink)) -- --rt-gold-a11y is light-host only */
  font-weight: 700;
}
@media (max-width: 520px) {
  .rt-rtpri-explainer-text {
    display: none;
  }
  .rt-rtpri-explainer-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* --------------------------------------------------------------------
   RTPRI unit/currency/period switcher (item A3).
   -------------------------------------------------------------------- */
.rtpri-switcher {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 18px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.rtpri-unit-group {
  display: inline-flex;
  border: 1px solid var(--ink, #11120f);
}
.rtpri-unit-opt {
  min-height: 44px;
  min-width: 44px;
  padding: 0 12px;
  border: none;
  border-right: 1px solid var(--ink, #11120f);
  background: transparent;
  color: inherit;
  font-size: 13px;
  cursor: pointer;
}
.rtpri-unit-opt:last-child {
  border-right: none;
}
.rtpri-unit-opt[aria-checked="true"] {
  background: var(--ink, #11120f);
  color: #fff;
}
.rtpri-unit-reset {
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--ink, #11120f);
  background: transparent;
  color: inherit;
  font-size: 13px;
  cursor: pointer;
}
.rtpri-unit-reset[aria-pressed="true"] {
  background: var(--ink, #11120f);
  color: #fff;
}
.rtpri-fx-footnote {
  flex: 1 1 100%;
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--muted, #5b574e);
}
.rtpri-published-note {
  display: block;
  font-size: 11px;
  color: var(--muted, #5b574e);
}
@media (max-width: 520px) {
  .rtpri-unit-group,
  .rtpri-unit-reset {
    flex: 1 1 auto;
  }
}

/* --------------------------------------------------------------------
   Home pop-up (26 Sep brief, item B) -- copy is Variant A of
   qa/2026-09-26-popup/mock.html, rendered verbatim. Colours match the
   mock's own verified-contrast tokens (paper on ink 18.49:1, gold-lt on
   ink 9.02:1), scoped so they never leak onto the rest of the site.
   -------------------------------------------------------------------- */
.rt-home-popup {
  padding: 0;
  border: 0;
  background: transparent;
  max-width: calc(100vw - 32px);
  width: 440px;
  overflow: visible;
}
.rt-home-popup::backdrop {
  background: rgba(12, 14, 13, 0.72);
}
@media (prefers-reduced-motion: no-preference) {
  .rt-home-popup[open] {
    animation: rtHomePopupIn 0.22s ease-out;
  }
}
@keyframes rtHomePopupIn {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.rt-home-popup .rtp {
  position: relative;
  background: #11120f;
  color: #fffdf8;
  border-top: 3px solid #d8ad63;
  padding: 28px 24px 20px;
  width: 100%;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
}
.rt-home-popup .rtp-kicker {
  font: 700 11px/1.4 Arial, Helvetica, sans-serif;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #d8ad63;
  margin: 0 44px 10px 0;
}
.rt-home-popup .rtp-h {
  font: 400 25px/1.2 Georgia, "Times New Roman", serif;
  margin: 0 44px 16px 0;
  color: #fffdf8;
}
.rt-home-popup .rtp-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
}
.rt-home-popup .rtp-list li {
  position: relative;
  padding: 0 0 0 20px;
  margin: 0 0 10px;
  font: 15px/1.5 Arial, Helvetica, sans-serif;
  color: #fffdf8;
}
.rt-home-popup .rtp-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 8px;
  height: 8px;
  background: #d8ad63;
}
.rt-home-popup .rtp-list b {
  color: #d8ad63;
  font-weight: 700;
}
.rt-home-popup .rtp-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  padding: 12px 16px;
  background: #b98132;
  color: #11120f;
  border: 0;
  font: 700 14px/1 Arial, Helvetica, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}
.rt-home-popup .rtp-cta:hover,
.rt-home-popup .rtp-cta:focus-visible {
  background: #d8ad63;
}
.rt-home-popup .rtp-foot {
  margin: 14px 0 0;
  font: 12px/1.4 Arial, Helvetica, sans-serif;
  letter-spacing: 0.04em;
  color: #c9c3b6;
}
.rt-home-popup .rtp-x {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: #fffdf8;
  cursor: pointer;
}
.rt-home-popup .rtp-x:hover,
.rt-home-popup .rtp-x:focus-visible {
  color: #d8ad63;
}
.rt-home-popup .rtp-x svg {
  width: 20px;
  height: 20px;
}

/* --------------------------------------------------------------------
   RT MIP (26 Sep brief, item C) -- the Dive-hub band + the /intelligence/
   page itself.
   -------------------------------------------------------------------- */
.dive-mip-band {
  margin: 12px 0 0;
  padding: 12px 16px;
  background: var(--dark);
  color: #d9d5c9;
  font-size: 13px;
  border-left: 3px solid var(--gold2);
}
.dive-mip-band a {
  color: var(--gold2); /* dark chrome (var(--dark)) -- --rt-gold-a11y is light-host only */
  font-weight: 700;
}
.mip-page {
  max-width: 78ch;
  margin: 0 auto;
  padding: 48px 16px 64px;
}
.mip-eyebrow {
  font: 700 12px/1.4 Arial, Helvetica, sans-serif;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rt-gold-a11y);
  margin: 0 0 10px;
}
.mip-subhead {
  font-size: 18px;
  font-weight: 700;
  margin: 0 0 8px;
}
.mip-intro {
  color: var(--muted, #5b574e);
  margin: 0 0 28px;
}
.mip-what-you-get {
  list-style: none;
  margin: 0 0 32px;
  padding: 0;
  display: grid;
  gap: 20px;
}
.mip-what-you-get h3 {
  margin: 0 0 6px;
  font-size: 18px;
}
.mip-what-you-get p {
  margin: 0;
  color: var(--muted, #5b574e);
}
.mip-real-today {
  margin: 0 0 32px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.mip-waitlist-cta {
  min-height: 48px;
}
/* RT MIP gallery (26 Sep): the 4 real-data shots that replaced
   .mip-screens-note. Additive; single column inside the 78ch shell. */
.mip-gallery {
  list-style: none;
  /* Break out of the 78ch reading column so the 1200px captures stay
     legible on desktop; collapses to the column's own width (margin 0)
     once 100vw - 32px is narrower than the column. */
  width: min(1120px, calc(100vw - 32px));
  margin: 0 0 32px calc(50% - min(560px, 50vw - 16px));
  padding: 0;
  display: grid;
  gap: 28px;
}
.mip-shot {
  margin: 0;
}
.mip-shot picture {
  display: block;
  text-align: center;
}
.mip-shot img {
  display: inline-block;
  width: auto; /* donor sets img{width:100%}; keep the shot's own 1x size */
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line);
  vertical-align: top;
}
.mip-shot figcaption {
  margin-top: 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink, #111);
}

/* "Send to RealTimes" tip tools (Alex's 27 Sep 2026 approval) -- /tip/
   page, light "public" theme (donor --paper/--ink/--muted/--line tokens),
   mirroring .rt-waitlist-* shape but on a light background. Every
   interactive control here is explicitly >=44px tall (donor .btn is 42px
   sitewide; overridden here on purpose). */
.rt-tip-hero {
  padding-bottom: 24px;
}
.rt-tip-hero p {
  max-width: 640px;
}
.rt-tip-grid {
  display: grid;
  grid-template-columns: 1.2fr 0.8fr;
  gap: 40px;
  padding-bottom: 56px;
  align-items: start;
}
@media (max-width: 900px) {
  .rt-tip-grid {
    grid-template-columns: 1fr;
  }
}
.rt-tip-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.rt-tip-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.rt-tip-req {
  color: var(--rt-gold-a11y, #77592a);
}
.rt-tip-field input,
.rt-tip-field textarea {
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink);
  font-size: 14px;
  font-family: inherit;
  text-transform: none;
  letter-spacing: normal;
  resize: vertical;
}
.rt-tip-field input:focus-visible,
.rt-tip-field textarea:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.rt-tip-submit {
  min-height: 44px;
  width: 100%;
}
.rt-tip-status {
  font-size: 12px;
  color: var(--muted);
  margin: 0;
  line-height: 1.5;
}
.rt-tip-status a {
  color: var(--rt-gold-a11y, #77592a);
  text-decoration: underline;
}
.rt-tip-noscript {
  font-size: 12px;
  color: var(--muted);
  margin: 0;
}
.rt-tip-noscript a {
  color: var(--rt-gold-a11y, #77592a);
}
.rt-tip-bookmark {
  border: 1px solid var(--line);
  padding: 24px;
  background: var(--paper);
}
.rt-tip-bookmark h2 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 20px;
  margin: 0 0 10px;
}
.rt-tip-bookmark p {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.5;
  margin: 0 0 14px;
}
.rt-tip-bookmarklet {
  min-height: 44px;
  cursor: grab;
}

/* ==========================================================================
   Contrast round 2026-09-27 (rendered-QA re-check, real per-viewport
   background sampling) -- /news/ page items.
   ========================================================================== */

/* .news-meta (donor styles.css, "ANALYSIS · 6 MIN READ · EUROPE") sits on
   .newsroom-hero's own #fffdf8 background (donor styles.css) at 3.49:1
   (needs 4.5:1). Reuses the existing --muted token (5.52:1 on this
   background) instead of inventing a new grey -- same token .section-sub
   and .compact-news p already use on lighter/darker paper hosts. */
.news-meta {
  color: var(--muted);
}

/* .brief-line b (donor styles.css, the London/Warsaw/Amsterdam/Paris/
   Madrid city labels in the "Market by city" .brief-box) sits on
   .brief-box's own #eee7db background at 4.05:1 (needs 4.5:1). Reuses the
   shared --rt-gold-a11y token (already measured 6.36:1+ on light hosts
   elsewhere in this file; 5.26:1 on this specific #eee7db background). */
.brief-line b {
  color: var(--rt-gold-a11y, #77592a);
}

/* ==========================================================================
   QA-fix 2026-09-28 (pre-ship QA, peerview-qa/report.md). Scoped overrides
   only; donor styles.css untouched.
   ========================================================================== */
/* #5: PeerView hub module (home + Dive) at >=1024px. rtns-dive.css places
   the still in column 2 / row 1 only, so row 1 grew to the image height
   and the H2 started ~420px below the eyebrow, leaving an empty left
   column. The still now spans every row; the auto rows size to the text
   alone and the trailing 1fr row absorbs any image height the text does
   not use (grid items spanning a flexible track are sized in the flex
   step, never distributed across the auto rows). Specificity (0,2,0)
   beats rtns-dive.css's later (0,1,0) rules. */
@media (min-width: 1024px) {
  .dive-peerview .dive-peerview-card { grid-template-rows: repeat(12, auto) 1fr; }
  .dive-peerview .dive-peerview-still { grid-row: 1 / -1; }
}
/* LOW #13: "Watch RealTimes PeerViews" link was 15px tall. */
.dive-peerview .dive-peerview-film { display: inline-flex; align-items: center; min-height: 44px; margin: 0; }
/* #7: /events/ "View event recap" links were ~10px tall (9px caps text). */
.past-v2 .past-info a { display: inline-flex; align-items: center; min-height: 44px; }
/* LOW #8: MSN27 card dek (11px) over the brightest lantern pixels fell to
   3.97:1. A soft shadow keeps it legible over any photo patch. */
.upcoming-side .upcoming-copy p { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85); }

/* ==========================================================================
   RT/PRIME source list (Cluster C1, 2026-09-30). One source per line, its
   definition and "not in the median" note in the muted tone. --muted
   #6c675e measures 5.52:1 on the city card (--paper2 #fffdf8) and 5.03:1 on
   the page (--paper #f6f2ea): AA for 12px text on both real backgrounds.
   ========================================================================== */
.rtpri-sources{flex-direction:column;gap:2px}
.rtpri-sources li{line-height:1.45}
.rtpri-src-def,.rtpri-src-out{color:var(--muted)}
.rtpri-range-cell{white-space:nowrap}
.rtpri-held-list{padding-left:20px}

/* ==========================================================================
   Share-shape follow-up (Cluster C2, 2026-09-30). Two small share-adjacent
   notes and one native-share/lead toggle, shared by every Dive share row
   (dive_ix.py render_share_row / render_share_row_v2, dive_share_pages.py
   _share_block, dive_myday.py's sheet). --muted #6c675e measures 3.45:1 on
   --dark #0c0e0d and 3.18:1 on --dark2 #151816 -- both fail 4.5:1 for 12px
   text, so the three dark bands that host a mini-share (.dive-snapshot,
   .dive-route-band, .dive-cycles-share -- see .dive-mini-share > summary
   a few blocks up in rtns-dive.css) get a scoped override to #cfd3cf, the
   same secondary-text tone already used on those bands (.dv-ix-asof):
   12.79:1 on --dark, 11.81:1 on --dark2, both well clear of AA.
   ========================================================================== */
.rtns-share-custom{flex-basis:100%;font-size:12px;color:var(--muted);margin:0}
.dive-share-native.is-phone ~ .dive-share-lead{display:none}
.dive-snapshot .rtns-share-custom,
.dive-route-band .rtns-share-custom,
.dive-cycles-share .rtns-share-custom{color:#cfd3cf}

/* /news/ invitation (T8, Alex 30 Sep 2026, b1): one line plus one button
   under the preview-edition topline. Ink #11120f on #fffdf8 and #111 on
   gold #b98132 (5.7:1) both clear 4.5:1; the button is a 44px target. */
.news-invite{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;margin:0 0 16px}
.news-invite-line{margin:0;flex:1 1 320px;font-size:15px;line-height:1.45;color:var(--ink)}
.news-invite .news-invite-btn{min-height:44px;flex:0 0 auto}
/* the address stays visible beside the mailto CTA (SAR-2026-09-30);
   muted #6c675e on #fffdf8 is 5.4:1 */
.news-invite-addr{flex:0 0 auto;font-size:12px;color:var(--muted)}
@media (max-width: 640px){
  .news-invite{flex-direction:column;align-items:stretch}
  .news-invite-line{flex:0 0 auto}
  .news-invite .news-invite-btn{width:100%}
  .news-invite-addr{text-align:center}
}

/* ==========================================================================
   BREAKING strip and urgent-news lane (plan for-our-expo-dive-soft-teapot,
   Phase 3). Every selector is scoped to .rt-breaking*, .rt-news-* or
   [data-expires]; nothing else on the site is touched. The strip renders
   only while a News item is `urgency: breaking`, as the first child of
   <body> above the marquee, on the same --dark board background. Contrast
   on --dark #0c0e0d: white #fff 19.9:1, --gold2 #d8ad63 9.7:1. The link is
   the whole strip, at least 44px tall at every width. site.js initExpiry()
   sets [hidden] once data-expires passes; the rule below makes sure no
   display value here can override it.
   ========================================================================== */
[data-expires][hidden] {
  display: none !important;
}
.rt-breaking {
  background: var(--dark);
  border-bottom: 1px solid #3a3d3a;
  color: #fff;
}
.rt-breaking .rt-breaking-link {
  display: flex;
  align-items: center;
  gap: 8px 14px;
  min-height: 44px;
  max-width: var(--max);
  margin: 0 auto;
  padding: 8px 34px;
  box-sizing: border-box;
  color: #fff;
}
.rt-breaking .rt-breaking-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  color: var(--gold2);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.rt-breaking .rt-breaking-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.35;
  text-wrap: balance; /* no lone last word on a narrow phone */
}
.rt-breaking .rt-breaking-go {
  flex: 0 0 auto;
  color: var(--gold2);
}
.rt-breaking .rt-breaking-link:hover .rt-breaking-title,
.rt-breaking .rt-breaking-link:focus-visible .rt-breaking-title {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.rt-breaking .rt-breaking-link:focus-visible {
  outline: 2px solid var(--gold2);
  outline-offset: -2px;
}
@media (max-width: 650px) {
  .rt-breaking .rt-breaking-link {
    flex-wrap: wrap;
    padding: 8px 16px;
  }
  .rt-breaking .rt-breaking-title {
    flex-basis: 100%;
    order: 2;
  }
  .rt-breaking .rt-breaking-go {
    display: none;
  }
}
/* /news/ lead and rail, real items (light host #fffdf8). The Breaking label
   in the lead's eyebrow is red-dot plus ink text: #11120f on #fffdf8 18.6:1. */
.rt-news-lead .rt-news-lead-link {
  display: block;
  color: inherit;
}
.rt-news-lead .rt-news-lead-link:hover h1,
.rt-news-lead .rt-news-lead-link:focus-visible h1 {
  text-decoration: underline;
  text-underline-offset: 4px;
}
.rt-news-lead .rt-breaking-label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-right: 12px;
  color: var(--ink);
}
.rt-news-latest:hover h3,
.rt-news-latest:focus-visible h3 {
  text-decoration: underline;
}
.rt-news-latest-split {
  grid-column: 1 / -1;
  margin: 10px 0 2px;
}
/* News article hero under the headline block, full shell width. The donor
   img rule (height:100%) is reset so the intrinsic 1920x1088 ratio holds. */
.rt-news-hero {
  margin: 0 0 8px;
}
.rt-news-hero img {
  width: 100%;
  height: auto;
  max-height: 620px;
  object-fit: cover;
}
/* "Answer this piece" on a News article: article.html furniture plus a 44px
   CTA (the donor .btn is 42px) and the visible address line. */
.rt-news-call .rt-news-call-questions li {
  margin: 0 0 8px;
}
.rt-news-call .rt-news-call-cta .btn {
  min-height: 44px;
}
.rt-news-call .rt-news-call-consent {
  font-size: 13px;
  color: var(--muted);
}
.rt-news-call .rt-news-call-consent a {
  color: var(--ink);
  text-decoration: underline;
}
/* /BREAKING strip and urgent-news lane */

/* ==========================================================================
   Footer canon formatting (2026-10-16, Alex: "great formatting canon; apply").
   Canon: rt-www-home SiteFooter.tsx + globals.css .cf-footer* (read-only) and
   rt-brand-golden-standard.md Footer Standard: 4 columns 1.5fr 1fr 1fr 1fr,
   2 columns at 980px, 1 centred column at 720px, gold mono uppercase
   headings, .86rem links, even column gap. Dark-surface contract
   (rendered-deliverable-qa.md): body text pure #ffffff, gold full brightness.
   Placed LAST on purpose: it overrides the earlier px-scale footer rules
   above (kept so the older source-order tests still read their rules).
   ========================================================================== */
footer {
  padding: 3.5rem 0 2.5rem;
  border-top: 1px solid var(--rt-chrome-border);
}
footer .rt-footer-grid {
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 2.5rem;
}
footer .rt-footer-grid > div:not(.rt-footer-brand) {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
footer h4 {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  color: #c5a55a;
  margin: 0 0 0.9rem;
}
footer a,
footer button.rt-footer-waitlist {
  font-size: 0.86rem;
  line-height: 1.4;
  color: #ffffff;
  margin: 0;
  padding: 4px 0;
  transition: color 180ms ease;
}
footer a:hover,
footer button.rt-footer-waitlist:hover {
  color: #c5a55a;
}
footer .rt-footer-brand p {
  font-size: 0.88rem;
  line-height: 1.55;
  color: #ffffff;
  margin: 0.8rem 0 0;
  max-width: 420px;
}
footer span {
  color: #ffffff;
  font-size: 0.82rem;
}
footer .rt-footer-cta {
  margin-top: 1.4rem;
  gap: 0.5rem;
  max-width: 420px;
}
footer .rt-footer-cta-label {
  color: #c5a55a;
  font-size: 0.7rem;
}
footer .rt-footer-cta-fauxinput {
  color: #ffffff;
  font-size: 0.85rem;
  padding: 0 0.9rem;
}
footer .rt-footer-cta-btn {
  color: #c5a55a;
  font-size: 0.82rem;
  padding: 0 0.9rem;
}
footer .rt-footer-cta-help {
  color: #ffffff;
  font-size: 0.78rem;
}
footer a.rt-footer-cta-partner,
footer a.rt-footer-event-featured {
  color: #c5a55a !important;
}
footer a.rt-footer-cta-partner:hover,
footer a.rt-footer-event-featured:hover {
  color: #ffffff !important;
}
footer a.rt-footer-event-featured {
  gap: 0.45rem;
}
footer .rt-footer-event-badge {
  color: #c5a55a;
  font-size: 0.62rem;
  padding: 0.12rem 0.45rem;
}
@media (max-width: 1100px) {
  footer a,
  footer button.rt-footer-waitlist {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
  }
  footer .rt-footer-grid > div:not(.rt-footer-brand) {
    gap: 0;
  }
}
@media (max-width: 980px) {
  footer .rt-footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 720px) {
  footer {
    text-align: center;
  }
  footer .rt-footer-grid {
    grid-template-columns: 1fr;
  }
  footer .rt-footer-brand {
    align-items: center;
  }
  footer .rt-footer-brand p {
    max-width: none;
  }
  footer .rt-footer-cta {
    margin-left: auto;
    margin-right: auto;
    width: 100%;
    align-items: center;
    text-align: center;
  }
  footer .rt-footer-grid > div:not(.rt-footer-brand) {
    align-items: center;
  }
  footer a,
  footer button.rt-footer-waitlist {
    justify-content: center;
    text-align: center;
  }
  footer a.rt-footer-event-featured {
    width: 100%;
    flex-wrap: wrap;
  }
}
footer .rt-footer-grid > div:not(.rt-footer-brand) > span {
  padding-top: 0.6rem;
}
/* Footer improvement 2026-10-16: between 721 and 980px the brand block spans
   the full row and the three link columns sit side by side, instead of a
   2x2 grid with a large empty area under the brand block. Narrower than 720
   the canon single column applies; above 980 the canon 4 columns. */
@media (min-width: 721px) and (max-width: 980px) {
  footer .rt-footer-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  footer .rt-footer-brand {
    grid-column: 1 / -1;
  }
}

/* ==========================================================================
   Footer v2 (2026-10-16, Alex: "all are bad, improve"). Same links, same
   copy, same canon colour contract (#ffffff text, #c5a55a accents). Changes:
   clear hierarchy (serif tagline, solid-gold primary action), Platform links
   in two sub-columns so the four columns balance, featured event as a card,
   Become a Partner as an outlined button, gold hairline at the top edge,
   left-aligned two-column link grid on phones instead of a long centred list.
   ========================================================================== */
footer {
  position: relative;
  border-top: 0;
  padding: 4rem 0 3rem;
}
footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, #c5a55a 0%, rgba(197, 165, 90, 0) 70%);
}
footer .rt-footer-grid {
  gap: 3rem 2.5rem;
}
footer .rt-footer-brand p {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 1.3rem;
  line-height: 1.35;
  margin-top: 1.1rem;
  max-width: 24rem;
}
footer .rt-footer-cta {
  margin-top: 1.8rem;
  max-width: 24rem;
}
footer .rt-footer-cta-link {
  border-color: #c5a55a;
  min-height: 48px;
}
footer .rt-footer-cta-fauxinput {
  background: var(--rt-chrome-field-bg);
}
footer .rt-footer-cta-btn {
  background: #c5a55a;
  color: #101210;
  font-weight: 700;
}
footer .rt-footer-cta-link:hover .rt-footer-cta-btn,
footer .rt-footer-cta-link:focus-visible .rt-footer-cta-btn {
  background: #ffffff;
}
footer .rt-footer-cta-help {
  font-size: 0.8rem;
}
footer .rt-footer-grid > div:nth-child(2) {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 1.25rem;
  align-content: start;
}
footer .rt-footer-grid > div:nth-child(2) > h4 {
  grid-column: 1 / -1;
}
footer h4 {
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--rt-chrome-border);
  margin-bottom: 0.9rem;
}
footer a.rt-footer-event-featured {
  display: grid !important;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: 0.55rem;
  row-gap: 0.5rem;
  margin: 0.4rem 0 0.9rem;
  padding: 0.8rem 0.9rem;
  border: 1px solid rgba(197, 165, 90, 0.55);
  background: rgba(197, 165, 90, 0.08);
}
footer a.rt-footer-event-featured .rt-footer-event-badge {
  grid-column: 2;
  justify-self: start;
}
footer a.rt-footer-event-featured:hover {
  background: rgba(197, 165, 90, 0.16);
}
footer .rt-footer-grid > div:nth-child(3) > a[href="/events/"]:not(:first-of-type) {
  font-size: 0.8rem;
  line-height: 1.7;
  padding: 0;
  color: #ffffff;
}
footer a.rt-footer-cta-partner {
  align-self: flex-start;
  margin-top: 0.9rem;
  padding: 0.6rem 1rem;
  border: 1px solid #c5a55a;
}
footer a.rt-footer-cta-partner:hover {
  background: #c5a55a;
  color: #101210 !important;
}
@media (max-width: 1100px) {
  footer .rt-footer-grid > div:nth-child(3) > a[href="/events/"]:not(:first-of-type) {
    min-height: 44px;
    padding: 0.5rem 0;
    display: flex;
    align-items: center;
  }
}
@media (max-width: 720px) {
  footer {
    text-align: left;
    padding: 3rem 0 2.5rem;
  }
  footer .rt-footer-brand,
  footer .rt-footer-cta,
  footer .rt-footer-grid > div:not(.rt-footer-brand) {
    align-items: flex-start;
    text-align: left;
  }
  footer .rt-footer-cta {
    margin-left: 0;
    margin-right: 0;
  }
  footer a,
  footer button.rt-footer-waitlist {
    justify-content: flex-start;
    text-align: left;
  }
  footer a.rt-footer-event-featured {
    width: auto;
  }
  footer a.rt-footer-cta-partner {
    justify-content: center;
  }
}
footer h4 {
  align-self: stretch;
}

/* News sidebar legibility (Alex, 2026-10-16: "too small font"). Sidebar asides
   in .news-body-grid only; the main article column is untouched. Body lines
   16px, labels and eyebrows 12px (donor letter-spacing kept), colours, rules and
   padding unchanged. Contrast: ink #11120f on #eee7db 15.3:1; city labels
   --rt-gold-a11y #77592a on #eee7db 5.26:1; Editor's note #d7e4df on #173d34 9.2:1. */
.news-body-grid aside .brief-line {
  font-size: 16px;
  line-height: 1.45;
}
.news-body-grid aside .brief-line b {
  font-size: 12px;
  margin-bottom: 4px;
}
.news-body-grid aside .eyebrow,
.news-body-grid aside .rail-title {
  font-size: 12px;
}
.news-body-grid aside .news-editor-box .news-editor-body {
  font-size: 16px;
  line-height: 1.55;
}
